Skip to content
Snippets Groups Projects
Commit e14868e4 authored by Olivier Dion's avatar Olivier Dion Committed by Sébastien Blin
Browse files

doc/agent: Add agent documentation

Change-Id: I028985ac90d07199cfa30d33e21f55ebef228ff3
parent 8bab18aa
No related branches found
No related tags found
No related merge requests found
==================================
Agent build steps (GNU/Linux only)
==================================
Requirements
============
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
distributions. 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
===================
To build Guile locally, you first need to enable it when building contrib, then
recompile contrib::
cd daemon/contrib/native
../bootstrap --enable-guile
make list
make fetch
make -j
Compile
=======
To compile the agent, one has to enable it while configuring the daemon. At this
stage, Guile must be already available::
cd daemon
./configure --enable-agent # other options can be added if needed such as --enable-debug
cd test/agent
make check
==============
Agent workflow
==============
Running the agent
=================
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
==============
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 ``test/agent/src/bindings/*``. Bindings should
be decouple into module that reflect their common functionality. For example,
``test/agent/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 ``test/agent/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
what the underlying type needed by the primitive procedure is, one should add
the suffix of the type at the end.
For example, ``my_primitive_procedure()`` expects that ``some_variable_str``
will be of type ``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 ``test/agent/src/utils.h``
and are all template based and can usually be used without specifying any type
thanks to type inference.
For example, to convert ``std::string bar`` to ``SCM baz``, one would do ``baz =
to_guile(bar)``. One can also do the opposite like so ``bar = from_guile(baz)``.
Examples
========
Examples on how to use the agent can be found under ``test/agent/examples``.
Compiling modules
=================
Modules such as ``(agent)`` and ``(jami logger)`` can be compiled using the
agent itself like so::
./agent.exe compile /path/to/module.scm /path/to/module.scm.go
You however do not need to do this manually. You should instead add your Scheme
(.scm) file to the list MODULES in ``tests/agent/Makefile.am`` and invoke
``make compile``.
Demuxing outputs
================
While developing scenarios, you don't want Jami's output to clobber Guile's
output. One easy way to do so is by using the ``JAMI_LOG_FILE`` environment
variable.
For example::
JAMI_LOG_FILE=jami.log ./agent.exe -s my-scenario.scm
But sometime you want Jami's output on the console. The agent disable the
console output for Jami, but you can do the following as a workaround::
JAMI_LOG_FILE=/dev/stdout ./agent.exe -s my-scenario.scm
Debugging the agent
===================
Since ``agent.exe`` is a regular ELF executable, you can attach a debugger to
it. If you're using GDB, you will need to handle some signals, otherwise your
program will keep getting interrupted. Here's a recommended GDB file to use::
handle SIGPWR noprint pass
handle SIGXCPU noprint pass
set environment XDG_CONFIG_HOME=/tmp/jami-agent
set environment XDG_CACHE_HOME=/tmp/jami-agent
set environment XDG_DATA_HOME=/tmp/jami-agent
set environment SIPLOGLEVEL 5
set environment UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1
set environment ASAN_OPTIONS=print_stacktrace=1:halt_on_error=1
set environment JAMI_LOG_FILE jami.log
run
# Agent build steps (GNU/Linux only) See doc/agent/*.
Last revision: 2021-08-31
# Requirements
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
distributions.
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
To build Guile locally, you first need to enable it when building contrib, then
recompile contrib:
```sh
cd daemon/contrib/native
../bootstrap --enable-guile
make list
make fetch
make -j
```
# Compile
To compile the agent, one has to enable it while configuring the daemon. At this
stage, Guile must be already available.
```sh
cd daemon
./configure --enable-agent # other options can be added if needed such as --enable-debug
cd test/agent
make check
```
# Running the agent
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
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
what the underlying type needed by the primitive procedure is, one should add the
suffix of the type at the end.
For example, `my_primitive_procedure()` expects that `some_variable_str`
will be of type `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.
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/`
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment