diff --git a/test/agent/README.md b/test/agent/README.md index 63be79b074b42494a73922b6cabde6d25a603457..37f6cf2a7340a6b4450f9d741c374324f789f365 100644 --- a/test/agent/README.md +++ b/test/agent/README.md @@ -2,13 +2,13 @@ Last revision: 2021-08-31 # Requirements -Guile library version 3.0.7 or higher is required. Guile lib may require other +Guile library version 3.0.7 or higher is required. Guile lib may require other dependencies in particular libunistring-dev and libgc-deb packages. -Guile can be provided by the distro if available, or built locally. Note that -Guile v3.0.7 is quite recent and most likely not yet provided by most linux +Guile can be provided by the distro if available, or built locally. Note that +Guile v3.0.7 is quite recent and most likely not yet provided by most linux distributions. -If the required version is available on your distro, just install it using your +If the required version is available on your distro, just install it using your distro's package manager. Development packages must be installed as well. # Build Guile library @@ -16,7 +16,7 @@ To build Guile locally, you first need to enable it when building contrib, then recompile contrib: ```sh -cd daemon/contribu/native +cd daemon/contrib/native ../bootstrap --enable-guile make list make fetch @@ -35,20 +35,34 @@ make check ``` # Running the agent -The agent expects a Scheme file has its first parameter. This scheme file will -be interpreted by Guile. In the script, you can control the agent. - -Usage: -```sh -./agent ./examples/passive-agent.scm -``` +The agent is actually a wrapper around Guile's Scheme shell. By default, you +enter an interactive prompt that allows you to interact with Jami using the +primitive bindings or by using the agent helper. For help for running the +agent, run `./agent --help`. # Guile bindings -In order for Guile to control the agent, bindings have to be added to the global -environment where the configuration file is being interpreted. This is done in -`main.cpp` in the function `install_scheme_primitive()`. All scheme bindings -should have the prefix `agent:` to be clear that the procedure is one that -control the agent. +Guile needs primitive bindings to communicate with Jami. Usually, these +bindings can written in pure Scheme using the foreign function interface (FFI) +and some dlopen() magics. However, this method cannot applies here for two main +reasons: + + 1. Jami source code is in C++ not C. + 2. Dynamic loading is not present on some platform supported by Jami. + +The first reason makes it hard to interface C++ container types and other +standard types to bytevector used by Guile to interface with foreign functions. +In C, it's trivial to just types and pointers to bytevector. + +The second reason is a constraint on the agent. Since the goal is to have a set +of bindings that can run on any platform where Jami is supported, bindings +should be registered in C++. + +All bindings can be found under `src/bindings/*`. Bindings should be decouple +into module that reflect their common functionnality. For example, +`src/bindings/account.h` has all the Jami's bindings for managing accounts. When +a set of bindings is to be added to a new module, the latter has to be +registered into Guile. In order accomplish this, one has to include the +bindings and define the module under `src/bindings/bindings.cpp`. When a binding is called from Guile, the arguments passed are Scheme objects of type `SCM`. This is an opaque type that is generic. In order to be clear on @@ -56,26 +70,17 @@ what the underlying type needed by the primitive procedure is, one should add th suffix of the type at the end. For example, `my_primitive_procedure()` expects that `some_variable_str` -will be of type `string`. This is enforced by using an assertion: -```c++ -static SCM my_primitive_procedure(SCM some_variable_str) -{ - AGENT_ASSERT(scm_is_string(some_variable_str), "`some_variable_str` must be of type string"); - ... -} -``` +will be of type `string`. -Here is another example where `my_second_primitive()` expects that -`some_variable_vector_or_str` to be of type `string` or `vector`: -```c++ -static SCM my_second_primitive(SCM some_variable_vector_or_str) -{ - AGENT_ASSERT(scm_is_string(some_variable_vector_or_str) || - scm_is_simple_vector(some_variable_vector_or_str), - "`scm_some_variable_vector_or_str` must either be of type vector or string"); - ... -} -``` +There's also a set of utilities that can be used to convert C++ object to Scheme +and vice versa. These utilities can be found under `src/utils.h` and are all +template based and can usually be used without specifying any type thanks to +type inference. -# Writing scenarios +For example, to convert `std::string bar` to `SCM baz`, onw would do +`baz = to_guile(bar)`. One can also do the oposite like so +`bar = from_guile(baz)`. + +# Examples See `examples/` +