Skip to content
Snippets Groups Projects

ENH: Add minimal functionality

Merged Florian Spreckelsen requested to merge f-minimal into dev

Files

+ 77
372
@@ -3,6 +3,7 @@
@@ -3,6 +3,7 @@
#
#
# Copyright (C) 2021 Indiscale GmbH <info@indiscale.com>
# Copyright (C) 2021 Indiscale GmbH <info@indiscale.com>
# Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com>
# Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com>
 
# Copyright (C) 2021 Alexander Kreft
Please register or sign in to reply
#
#
# This program is free software: you can redistribute it and/or modify
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# it under the terms of the GNU Affero General Public License as
@@ -23,10 +24,75 @@
@@ -23,10 +24,75 @@
module CaosDB
module CaosDB
 
using Libdl
 
"""
"""
Chose the name of the library according to the OS you're running.
Chose the name of the library according to the OS you're running.
"""
"""
library_name = (@static Sys.iswindows() ? "ccaosdb" : "libccaosdb")
library_name = (@static Sys.iswindows() ? "ccaosdb" : "libccaosdb")
 
if isempty(find_library(library_name))
 
@error "Could not find $library_name"
 
end
 
 
module Exceptions
 
 
export evaluate_return_code, CaosDBException, GenericCaosDBException, CaosDBMessage
 
 
using Logging
 
using CaosDB
 
 
"""
 
The parent type of all CaosDB errors that can also be used for testing.
 
"""
 
abstract type CaosDBException <: Exception end
 
 
"""
 
A generic exception that will be raised in case of non-zero return
 
values of the calls to libccaosdb. May carry a message string and a
 
code.
 
"""
 
struct GenericCaosDBException <: CaosDBException
 
msg::String
 
code::Cint
 
end
 
 
Base.showerror(io::IO, e::CaosDBException) =
 
print(io, "CaosDBException: ", e.msg, " (Status code ", e.code, ")")
 
 
"""
 
Struct containing Messages and codes for status codes<0 that do not
 
correspond to errors or success.
 
"""
 
struct CaosDBMessage
 
msg::String
 
code::Cint
 
end
 
 
Base.show(io::IO, m::CaosDBMessage) = print(io, m.msg, " (Status code ", m.code, ")")
 
 
"""
 
function evaluate_return_code(code::Cint)
 
 
Evaluate the return code of a libccaosdb ccall and raise a
 
`GenericCaosDBException` in case of a non-zero return code.
 
"""
 
function evaluate_return_code(code::Cint)
 
if code != 0
 
msg = ccall(
 
(:caosdb_get_status_description, CaosDB.library_name),
 
Cstring,
 
(Cint,),
 
code,
 
)
 
if code > 0
 
throw(GenericCaosDBException(unsafe_string(msg), code))
 
else
 
@info CaosDBMessage(unsafe_string(msg), code)
    • Inform about status but don't return or throw anything in case of an ongoing transaction. This is implemented so that the functionality is already here, and so that no errors are raised erroneously in case of status codes <0, but this should only become relevant to Julia (or any higher order client) once we have real asynchronous transactions in the cpp-Client. This is probably something for 0.2 and for after August 31.

Please register or sign in to reply
 
end
 
end
 
end
 
 
end # Exceptions
module Info
module Info
@@ -90,13 +156,13 @@ authenticator object from a configuration.
@@ -90,13 +156,13 @@ authenticator object from a configuration.
mutable struct _Authenticator
mutable struct _Authenticator
wrapped_authenticator::Ptr{Cvoid}
wrapped_authenticator::Ptr{Cvoid}
function _Authenticator()
function _Authenticator(managed_by_julia::Bool = false)
    • We changed the way of adding a finalizer to the objects again. There are cases -- most importantly, connections managed by libcaosdb's connection manager -- in which the wrapped object is created and destroyed by the owning cpp object. In order to prevent errors when Julia tries to delete the structs, we now have to explicitly state when the wrapped objects have to be deleted by the finalizer.

      However this is not important to almost all users since they never interact with these kind of objects anyway. They'll rather use high-level functions like connect instead, or, alternatively, will use create_something.

Please register or sign in to reply
auth = new()
auth = new()
# force this to point to C_NULL after initialization
if managed_by_julia
auth.wrapped_authenticator = C_NULL
# Only append a finalizer for this if the object is
function f(t)
# actually managed by Julia and not created and destroyed
if t.wrapped_authenticator != C_NULL
# internally by libcaosdb.
# Only if pointer was filled after real initialization
function f(t)
ccall(
ccall(
(:caosdb_authentication_delete_authenticator, CaosDB.library_name),
(:caosdb_authentication_delete_authenticator, CaosDB.library_name),
Cint,
Cint,
@@ -104,8 +170,9 @@ mutable struct _Authenticator
@@ -104,8 +170,9 @@ mutable struct _Authenticator
Ref{_Authenticator}(t),
Ref{_Authenticator}(t),
)
)
end
end
 
finalizer(f, auth)
end
end
finalizer(f, auth)
return auth
end
end
end
end
@@ -124,7 +191,7 @@ function create_plain_password_authenticator(
@@ -124,7 +191,7 @@ function create_plain_password_authenticator(
password::AbstractString,
password::AbstractString,
)
)
auth = Ref{_Authenticator}(_Authenticator())
auth = Ref{_Authenticator}(_Authenticator(true))
err_code = ccall(
err_code = ccall(
(:caosdb_authentication_create_plain_password_authenticator, CaosDB.library_name),
(:caosdb_authentication_create_plain_password_authenticator, CaosDB.library_name),
@@ -135,11 +202,7 @@ function create_plain_password_authenticator(
@@ -135,11 +202,7 @@ function create_plain_password_authenticator(
password,
password,
)
)
if err_code != 0
CaosDB.Exceptions.evaluate_return_code(err_code)
@error "Creating authenticator failed with code $err_code"
end
return auth
return auth
@@ -147,365 +210,7 @@ end
@@ -147,365 +210,7 @@ end
end # Authentication
end # Authentication
module Connection
include("Connection.jl")
Please register or sign in to reply
using ..CaosDB
export connect
"""
Struct containing the actual connection to a CaosDB server. Meant for
internal use; call a `CaosDB.Connection.create_<connection>` function
to create an connection object from a configuration.
"""
mutable struct _Connection
wrapped_connection::Ptr{Cvoid}
function _Connection()
conn = new()
conn.wrapped_connection = C_NULL
function f(t)
if t.wrapped_connection != C_NULL
ccall(
(:caosdb_connection_delete_connection, CaosDB.library_name),
Cint,
(Ref{_Connection},),
Ref{_Connection}(t),
)
end
end
finalizer(f, conn)
end
end
"""
Struct containing a pointer to the wrapped cpp class providing the
certificate provider. Meant for internal use; call a
`CaosDB.Connection.create_<certificate_provider>` function to create
an certificate-provider object from a configuration.
"""
mutable struct _CertificateProvider
wrapped_certificate_provider::Ptr{Cvoid}
function _CertificateProvider()
prov = new()
prov.wrapped_certificate_provider = C_NULL
function f(t)
if t.wrapped_certificate_provider != C_NULL
ccall(
(:caosdb_connection_delete_certificate_provider, CaosDB.library_name),
Cint,
(Ref{_CertificateProvider},),
Ref{_CertificateProvider}(t),
)
end
end
finalizer(f, prov)
end
end
"""
Struct containing a pointer to the wrapped cpp class for storing the
connection configuration. Meant for internal use; call a
`CaosDB.Connection.create_<configuration>` function to create
an connection-configuration object from a configuration.
"""
mutable struct _Configuration
wrapped_connection_configuration::Ptr{Cvoid}
function _Configuration()
config = new()
config.wrapped_connection_configuration = C_NULL
function f(t)
if t.wrapped_connection_configuration != C_NULL
ccall(
(
:caosdb_connection_delete_connection_configuration,
CaosDB.library_name,
),
Cint,
(Ref{_Configuration},),
Ref{_Configuration}(t),
)
end
end
finalizer(f, config)
end
end
"""
create_pem_file_certificate_provider(path::AbstractString)
Return a `_CertificateProvider` for the pem certificate located at
`path`.
"""
function create_pem_file_certificate_provider(path::AbstractString)
cert_provider = Ref{_CertificateProvider}(_CertificateProvider())
err_code = ccall(
(:caosdb_connection_create_pem_file_certificate_provider, CaosDB.library_name),
Cint,
(Ref{_CertificateProvider}, Cstring),
cert_provider,
path,
)
if err_code != 0
@error "PEM certificate creation returned code $err_code."
end
return cert_provider
end
"""
create_tls_connection_configuration(
host::AbstractString,
port::Cint,
authenticator::Ref{CaosDB.Authentication._Authenticator},
provider::Ref{_CertificateProvider}
)
Return a TLS connection configuration with authentication.
"""
function create_tls_connection_configuration(
host::AbstractString,
port::Cint,
authenticator::Ref{CaosDB.Authentication._Authenticator},
provider::Ref{_CertificateProvider},
)
config = Ref{_Configuration}(_Configuration())
err_code = ccall(
(:caosdb_connection_create_tls_connection_configuration, CaosDB.library_name),
Cint,
(
Ref{_Configuration},
Cstring,
Cint,
Ref{CaosDB.Authentication._Authenticator},
Ref{_CertificateProvider},
),
config,
host,
port,
authenticator,
provider,
)
if err_code != 0
@error "TLS-configuration creation returned code $err_code."
end
return config
end
function create_insecure_connection_configuration(host::AbstractString, port::Cint)
config = Ref{_Configuration}(_Configuration())
err_code = ccall(
(:caosdb_connection_create_insecure_connection_configuration, CaosDB.library_name),
Cint,
(Ref{_Configuration}, Cstring, Cint),
config,
host,
port,
)
if err_code != 0
@error "Insecure configuration creation returned code $err_code."
end
return config
end
"""
create_connection(config::Ref{_Configuration})
Return a connection based on the given `config`.
"""
function create_connection(config::Ref{_Configuration})
connection = Ref{_Connection}(_Connection())
err_code = ccall(
(:caosdb_connection_create_connection, CaosDB.library_name),
Cint,
(Ref{_Connection}, Ref{_Configuration}),
connection,
config,
)
if err_code != 0
@error "Creating connection failed with code $err_code."
end
return connection
end
"""
get_version_info(con::Ref{_Connection})
Return the version of the CaosDB server that `con` is connected
to.
"""
function get_version_info(con::Ref{_Connection})
info = Ref{CaosDB.Info._VersionInfo}(CaosDB.Info._VersionInfo())
err_code = ccall(
(:caosdb_connection_get_version_info, CaosDB.library_name),
Cint,
(Ref{CaosDB.Info._VersionInfo}, Ref{_Connection}),
info,
con,
)
# TODO Real error-code handling
if err_code != 0
@error "Version info returned with code $err_code"
end
return info
end
"""
print_version_info(con::Ref{_Connection})
Retrieve the version info for the CaosDB server `con` is connected to,
and print the version in a nice message.
"""
function print_version_info(con::Ref{_Connection})
# Dereference to access the fields
info = get_version_info(con)[]
major = info.major
minor = info.minor
patch = info.patch
pre_release_str = unsafe_string(info.pre_release)
build_str = unsafe_string(info.build)
println(
"Connected to a CaosDB server with version $major.$minor.$patch-$pre_release_str-$build_str.",
)
end
"""
function connect([;
host::AbstractString="",
port_str::AbstractString="undefined",
cacert::AbstractString="",
username::AbstractString="",
password::AbstractString="undefined"]
)
Return a connection object created for the given `host`:`port` with an
SSL certificate located at `cacert` with the given credentials.
# Extended help
!!! info
Because of type-stability, and since an empty string may be a
valid password, the value of `password`, for which it is fetched
from an environmental variable, is "undefined". This means that if
you absolutely must use "undefined" as your password, you have to
specify it via the `CAOSDB_PASSWORD` variable.
# Arguments
- `host::AbstractString=""`: The hostname of the CaosDB server. If
none is provided, the `CAOSDB_SERVER_HOST` environmental variable is
used instead. If that's not defined, "localhost" is used.
- `port_str::AbstractString="undefined"`: The port of the CaosDB
server, given as string. If none is provided, the
`CAOSDB_SERVER_GRPC_PORT_HTTPS` environmental variable is used
instead. If that's not defined, "8443" is used. The default value is
"undefined" rather than an empty string because an empty string
could be a valid port, too, i.e. the CaosDB server is available at
`host` without a port.
- `cacert::AbstractString=""`: The path to the SSL certificate of the
CaosDB server. If none is provided, the `CAOSDB_SERVER_CERT`
environmental variable is used instead.
- `username::AbstractString=""`: The username with which to log in
into the CaosDB server. If none is provided, the `CAOSDB_USER`
environmental variable is used instead. If that's not defined,
"admin" is used.
- `password::AbstractString="undefined"`: The password with which to
log in into the CaosDB server. If none is provided, the
`CAOSDB_PASSWORD` environmental variable is used instead. If that's
not defined, "caosdb" is used. The default value is "undefined"
rather than an empty string to allow an empty password.
"""
function connect(;
host::AbstractString = "",
port_str::AbstractString = "undefined",
cacert::AbstractString = "",
username::AbstractString = "",
password::AbstractString = "undefined",
)
if host == ""
host = CaosDB.Utility.get_env_var("CAOSDB_SERVER_HOST", "localhost")
end
if port_str == "undefined"
port_str = CaosDB.Utility.get_env_var("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443")
end
port = parse(Cint, port_str)
if cacert == ""
cacert = CaosDB.Utility.get_env_var("CAOSDB_SERVER_CERT")
end
if username == ""
username = CaosDB.Utility.get_env_var("CAOSDB_USER", "admin")
end
if password == "undefined"
password = CaosDB.Utility.get_env_var("CAOSDB_PASSWORD", "caosdb")
end
provider = create_pem_file_certificate_provider(cacert)
authenticator =
CaosDB.Authentication.create_plain_password_authenticator(username, password)
config = create_tls_connection_configuration(host, port, authenticator, provider)
connection = create_connection(config)
print_version_info(connection)
return connection
end
end # Connection
module Entity end
module Entity end
Loading