0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-06-10 05:58:56 +02:00

Trim outdated README docs in ircd/ modules/.

This commit is contained in:
Jason Volk 2019-06-26 22:39:37 -07:00
parent 8ea404a66a
commit 2301d378fa
2 changed files with 38 additions and 110 deletions

View file

@ -7,11 +7,6 @@ handles requests from end-users. The library hosts a set of pluggable modules
which may introduce the actual application features (or the "business logic")
of the server.
> The executable linking and invoking `libircd` may be referred to as the
"embedding" or "user" or "executable" interchangably in this documentation.
## Organization
##### Implied #include <ircd.h>
The `ircd.h` [standard include group](../include/ircd#what-to-include)
@ -26,10 +21,15 @@ namespaces (see: [Project Namespaces](../include/ircd#project-namespaces)).
##### Dependency Isolation
Compilation units are primarily oriented around the inclusion of a specific
dependency which is not involved in the [ircd.h include group](../include/ircd#what-to-include).
Compilation units are primarily divided around the inclusion of a specific
header or third-party dependency which is not involved in the
[ircd.h include group](../include/ircd#what-to-include). Second to that, units
tend to be divided by namespace and the subsystem they're implementing. Units
can further be divided if they become unwieldy, but we bias toward large aggregate
units. Within these large units, there are divisions which group the definitions
by the `include/ircd/` header which declares them.
For example, the `magic.cc` unit was created to include `<magic.h>`
internally and then provide definitions to our own interfaces in `ircd.h`. We
don't include `<magic.h>` from `ircd.h` nor do we include it from
any other compilation unit. This simply isolates `libmagic` as a dependency.
We do not included third-party headers in our own [headers](../include/ircd)
which are included by others. A developer of an `ircd::` interface can choose
to either forward declare third-party symbols in our headers, or wrap more
complicated functionality.

View file

@ -1,94 +1,44 @@
# IRCd Module Tree
This directory contains dynamically loadable functionality to libircd. These
modules are not mere extensions -- they provide essential application
functionality, but are not always required to be directly linked in libircd
proper. Most application-specific functionality (i.e "business logic") is
contained in modules within this tree. At the time of this writing, a
significant amount of matrix functionality is still contained within libircd
proper, but it is intended that as many definitions as possible are pushed out
into modules.
This directory contains dynamically loadable functionality to libircd. Many of
these modules provide essential application functionality, but are not always
required to be directly linked and loaded into libircd proper. Most application-
specific functionality (i.e "business logic") is contained in modules within this
tree.
#### Layout
The `modules/` directory is primarily shaped the same as the HTTP resource
The `modules/` directory tree is primarily shaped the same as the HTTP resource
tree in which most of its modules register themselves in. This is **not**
automatic and the mere inclusion of files/directories in `modules/`
does not automatically expose them over HTTP.
automatic and the mere inclusion of files/directories in `modules/` does not
automatically expose them over HTTP.
Note that the installation layout is not the same as the development source
layout (i.e in git). Upon installation, the module tree is collapsed into a
single directory and installed into `$prefix/lib/modules/construct/$directory_$module.so`;
this may be subject to improvement.
- `client/` contains resource handlers for the `/_matrix/client/` API
- `federation/` contains resource handlers for the `/_matrix/federation/` API
- `key/` contains resource handlers for the `/_matrix/key/` API
- `media/` contains resource handlers for the `/_matrix/media/` API
- `js/` contains modules specific to the unreleased javascript embedding.
- `s_` modules provide utility to the server's operation.
- `m_` modules implement protocol logic for matrix event types.
- `vm_` modules provide the processing logic for matrix events.
single directory and installed into
`$prefix/lib/modules/construct/$directory_$module.so`; where directories are
replaced by underscores in the final `SONAME`. this may be subject to
improvement.
#### Approach
We use a hybrid system to build modules with two techniques:
Unlike most of the module systems found in traditional free software projects,
our approach is oriented around *global symbol* availability to the address
space rather than explicit imports from self-contained modules. This direction
is made viable by C++ and advances in the compiler and linker toolchains. The
result is significantly simpler and more convenient for developers to work with.
- Self-contained shared objects loaded for explicit import and export
of their symbols. This is the classical module which is safely loaded, unloaded
and accessed at any time via the `ircd::mods::import` system. This approach is
preferred for the majority of module and extension cases. Definitions in these
modules are not declared in `include/ircd` unless a "thunk" definition inside
libircd contains am `ircd::mods::import` calling out to the module (this is not
generated; developer must place this).
- Modules are loaded with `RTLD_GLOBAL` on both posix and windows platforms.
Use of C++ namespaces, visibility attributes, `STB_GNU_UNIQUE`, etc are
adequate to make this modernization.
- "core" modules which directly implement symbols declared in `include/ircd`
headers. When this type of module is not loaded those headers declare an
undefined symbol and accesses will immediately crash. This approach is used
when large interfaces are implemented by modules and individual imports
defined in libircd are too cumbersome. This involves global binding made
possible by the dynamic linker. This approach is satisfactory because of
C++ symbol namespacing and modern compiler and linker controls. These modules
*can* still be unloaded (and are during shutdown) but only after every other
module which has accessed its symbols has also been unloaded. At this time,
we have no access or control over that reference system and the reasons for
a failure to unload may not be immediately clear or easy to trace.
#### Loading
Modules may be automatically loaded based on their prefix. Certain prefixes
are sought by libircd for auto-loading, arbitrarily (i.e there is no magic
autoloading prefix; see: `ircd/m/m.cc` for explicit prefixes). A module may
also be loaded when an attempt is made to call into it (i.e with `m::import`
or low-level with `ircd::mods::*`). Furthermore, a module may be loaded by
the console `mod` command suite, specifically `mod load`. Otherwise the
module is not loaded.
#### Unloading
Unlike previous incarnations of IRCd, every module is [eventually] "unloadable"
and the notion of a "core" module is modernized based on the dynamic linker
technology available.
Many central linkages within libircd (and direct links made by other modules)
are imports which tolerate the unavailability of a module by using weak-pointers
and throwing exceptions. Unlike the Atheme approach as well, importing from a
module does not prevent unloading due to dependency; the unloading of a module is
propagated to linksites through the weak_ptr's dependency graph and exceptions
are thrown from the link upon next use.
Furthermore, modules are free to leverage the ircd::ctx system to wait
synchronously for events which are essential for a clean load or unload, even
during static initialization and destruction. This is a useful feature which
allows all modules to be robustly loadable and unloadable at **any time**
and **every time** in an intuitive manner.
No modules used through imports in this system "stick" whether by accident or
on purpose upon unload. Though we all know that dlclose() does not guarantee
a module is actually unloaded, we expend the extra effort to ensure there is
no reason why dlclose() would not unload the module. This static destruction
of a module is verified and alarms will go off if it is actually "stuck" and
the developer *must* fix this.
- All project code is built to silently weaken undefined symbols. This means
a complicated interface declared in a header, like a class interface with
public and private and static members -- typical in C++ -- can be included
by itself into any part of the project without knowing where the definitions
of that interface are until they are *first used* at runtime. If said
definitions are not available because they are in an unloaded module, a C++
exception is thrown directly from the callsite.
## Getting started
@ -100,25 +50,3 @@ either in the module.
Every loadable module requires a static `ircd::mapi::header` with the explicit
name of `IRCD_MODULE`. This is an object which will be sought by the module
loader in libircd. Nothing else is required.
#### Developer's Approach
The ideal module in this system is one that is self-contained in that its only
interface is through "registrations" to various facilities provided by libircd.
The module can still freely read and write to state within libircd or other
modules.
- An example of such is an HTTP resource (see: ircd/resource.h) registration
of a URL to handle incoming HTTP requests.
- Another example is a Matrix Event Hook (see: ircd/m/hook.h) to process
matrix events.
Next is a module providing definitions and making them available through
exposition (i.e `extern "C"`). In this approach, function definitions are
provided in the module but a "central interface" may be provided by libircd.
That central interface is tolerant of the function call failing when the module
is not available (or automatically tries to load it, see: ircd/m/import.h and
ircd/mods/*.h etc).
Note that many modules use any of these approaches at the same time.