mirror of
https://github.com/matrix-construct/construct
synced 2024-11-12 13:01:07 +01:00
Update various documentation and comments.
This commit is contained in:
parent
7cc4ed56ab
commit
54d6793f59
36 changed files with 457 additions and 306 deletions
16
README.md
16
README.md
|
@ -98,17 +98,5 @@ old code has been rewritten but with the same architecture and spirit of the ori
|
||||||
|
|
||||||
## Developers
|
## Developers
|
||||||
|
|
||||||
### Style
|
* Generate doxygen using `/usr/bin/doxygen tools/doxygen.conf` the target
|
||||||
|
directory is doc/html. Browse to doc/html/index.html
|
||||||
#### Misc
|
|
||||||
|
|
||||||
* When using a `switch` over an `enum` type, put what would be the `default` case after/outside
|
|
||||||
of the `switch` unless the situation specifically calls for one. We use -Wswitch so changes to
|
|
||||||
the enum will provide a good warning to update any `switch`.
|
|
||||||
|
|
||||||
* Prototypes should name their argument variables to make them easier to understand, except if
|
|
||||||
such a name is redundant because the type carries enough information to make it obvious. In
|
|
||||||
other words, if you have a prototype like `foo(const std::string &message)` you should name
|
|
||||||
`message` because std::string is common and *what* the string is for is otherwise opaque.
|
|
||||||
OTOH, if you have `foo(const options &, const std::string &message)` one should skip the name
|
|
||||||
for `options &` as it just adds redundant text to the prototype.
|
|
||||||
|
|
53
charybdis/README.md
Normal file
53
charybdis/README.md
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
# Charybdis Server
|
||||||
|
|
||||||
|
Charybdis is the executable running `libircd`. This application provides an
|
||||||
|
interface for the server administrator to start, stop, configure and locally
|
||||||
|
communicate with the daemon. It sets up an `asio::io_service` which is passed
|
||||||
|
to `libircd`, then it sets up signal handling, and then it runs the ios event
|
||||||
|
loop until commanded to exit.
|
||||||
|
|
||||||
|
This program executes in the foreground. It does not "daemonize" anymore with a
|
||||||
|
`fork()` etc. You are free to use your shell to execute or move the program
|
||||||
|
to the background, or simply use a `tmux` or `screen`. Charybdis will output
|
||||||
|
the libircd log to stdout and stderr by default.
|
||||||
|
|
||||||
|
### Signals
|
||||||
|
|
||||||
|
Charybdis handles certain POSIX signals and their behavior is documented
|
||||||
|
below. Signals are only handled here in the Charybdis executable; libircd
|
||||||
|
itself does not use any signal logic (that we know about).
|
||||||
|
|
||||||
|
* Signal handling is accomplished through `boost::asio`'s mechanism which
|
||||||
|
installs a handler to intercept the signal's delivery and posts it to the
|
||||||
|
event loop for execution at the next event slice. This is how signal safety
|
||||||
|
is achieved. Furthermore, according to boost docs, when signals are used
|
||||||
|
this way they can be compatible with windows environments.
|
||||||
|
|
||||||
|
##### SIGINT
|
||||||
|
|
||||||
|
A `ctrl-c` to Charybdis will bring up the command line console interface. It
|
||||||
|
will not halt the daemon. Log messages will be suppressed while the console
|
||||||
|
is waiting for input, but service is still continuing in the background.
|
||||||
|
|
||||||
|
##### SIGTSTP
|
||||||
|
|
||||||
|
A `ctrl-z` or "Terminal SToP" to Charybdis will bring up the command line
|
||||||
|
console like with `SIGINT` except that the entire daemon will pause while
|
||||||
|
waiting for console input. When paused, a second `SIGTSTP` will exhibit default
|
||||||
|
behavior so your shell can offer its functionality here.
|
||||||
|
|
||||||
|
##### SIGHUP
|
||||||
|
|
||||||
|
A "HangUP" to Charybdis is only relevant to the command line console, and
|
||||||
|
signals it to close like an `EOF`. The legacy functionality for reloading
|
||||||
|
server configuration et al is moved to `SIGUSR1`.
|
||||||
|
|
||||||
|
##### SIGQUIT
|
||||||
|
|
||||||
|
A `ctrl-\` to Charybdis will cleanly shut down the server. It will not generate
|
||||||
|
a coredump.
|
||||||
|
|
||||||
|
##### SIGUSR1
|
||||||
|
|
||||||
|
This signal commands the server to reload and refresh various aspects of its
|
||||||
|
configuration and running state.
|
61
include/ircd/README.md
Normal file
61
include/ircd/README.md
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# IRCd Library
|
||||||
|
|
||||||
|
The purpose of `libircd` is to facilitate the execution of a server which
|
||||||
|
handles requests from end-users. The library hosts a set of pluggable modules
|
||||||
|
which introduce the actual application features (or the "business logic") of
|
||||||
|
the server. These additional modules are found in the `modules/` directory;
|
||||||
|
see the section for `Developing a module` for more information. This library
|
||||||
|
can be embedded by developers creating their own server or those who simply
|
||||||
|
want to use the routines it provides; see the section for `Using libircd`.
|
||||||
|
|
||||||
|
### Using libircd
|
||||||
|
|
||||||
|
`libircd` can be embedded in your application. This allows you to customize and
|
||||||
|
extend the functionality of the server and have control over its execution, or,
|
||||||
|
simply use library routines provided by the library without any daemonization.
|
||||||
|
The prototypical embedding of `libircd` is `charybdis` found in the `charybdis/`
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Keeping with the spirit of simplicity of the original architecture, `libircd`
|
||||||
|
continues to be a "singleton" object which uses globals and keeps actual server
|
||||||
|
state. In other words, only one IRC daemon can exist within a process's address
|
||||||
|
space at any time. This is actually a profitable design decision for making
|
||||||
|
IRCd easier to understand for contributors. The original version of this library
|
||||||
|
was created at the dawn of the era of dynamic shared objects and began as an
|
||||||
|
abstraction of code from the server executable. This was done so that additional
|
||||||
|
feature modules could be created while all sharing the same maps of routines.
|
||||||
|
|
||||||
|
The library is based around the `boost::asio::io_service` event loop. It is
|
||||||
|
nominally single threaded and serializes operations on a single asio strand.
|
||||||
|
In other words, most code is executed on the thread where you call `ios.run()`;
|
||||||
|
this is referred to as the "main thread." If ios.run() is called on multiple
|
||||||
|
threads no concurrency will occur. IRCd occasionally uses global and static
|
||||||
|
variables; the expectation is that these will not be contended outside of the
|
||||||
|
main thread. The library may spawn additional threads, mostly from 3rd party
|
||||||
|
libraries and only under daemonization. We don't like this, and try to prevent
|
||||||
|
it, but it may happen under certain circumstances. These are all dealt with
|
||||||
|
internally and shouldn't affect the users of the library.
|
||||||
|
|
||||||
|
|
||||||
|
### Developing a module
|
||||||
|
|
||||||
|
libircd facilitates the development of dynamic shared modules which implement
|
||||||
|
specific application logic used in the server.
|
||||||
|
|
||||||
|
|
||||||
|
### Hacking on libircd
|
||||||
|
|
||||||
|
#### Style
|
||||||
|
|
||||||
|
##### Misc
|
||||||
|
|
||||||
|
* When using a `switch` over an `enum` type, put what would be the `default` case after/outside
|
||||||
|
of the `switch` unless the situation specifically calls for one. We use -Wswitch so changes to
|
||||||
|
the enum will provide a good warning to update any `switch`.
|
||||||
|
|
||||||
|
* Prototypes should name their argument variables to make them easier to understand, except if
|
||||||
|
such a name is redundant because the type carries enough information to make it obvious. In
|
||||||
|
other words, if you have a prototype like `foo(const std::string &message)` you should name
|
||||||
|
`message` because std::string is common and *what* the string is for is otherwise opaque.
|
||||||
|
OTOH, if you have `foo(const options &, const std::string &message)` one should skip the name
|
||||||
|
for `options &` as it just adds redundant text to the prototype.
|
|
@ -20,6 +20,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_COLOR_H
|
#define HAVE_IRCD_COLOR_H
|
||||||
|
|
||||||
|
/// Legacy mIRC color swatch
|
||||||
namespace ircd::color
|
namespace ircd::color
|
||||||
{
|
{
|
||||||
enum mode
|
enum mode
|
||||||
|
|
|
@ -25,23 +25,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_CTX_H
|
#define HAVE_IRCD_CTX_H
|
||||||
|
|
||||||
//
|
/// Userspace Contexts: cooperative threading from stackful coroutines.
|
||||||
// This is the public interface to the userspace context system. No 3rd party
|
///
|
||||||
// symbols are included from here. This file is included automatically in stdinc.h
|
/// This is the public interface to the userspace context system. No 3rd party
|
||||||
// and you do not have to include it manually.
|
/// symbols are included from here. This file is included automatically in stdinc.h
|
||||||
//
|
/// and you do not have to include it manually.
|
||||||
// There are two primary objects at work in the context system:
|
///
|
||||||
//
|
/// There are two primary objects at work in the context system:
|
||||||
// `struct context` <ircd/ctx/context.h>
|
///
|
||||||
// Public interface emulating std::thread; included automatically from here.
|
/// `struct context` <ircd/ctx/context.h>
|
||||||
// To spawn and manipulate contexts, deal with this object.
|
/// Public interface emulating std::thread; included automatically from here.
|
||||||
//
|
/// To spawn and manipulate contexts, deal with this object.
|
||||||
// `struct ctx` (ircd/ctx.cc)
|
///
|
||||||
// Internal implementation of the context. This is not included here.
|
/// `struct ctx` (ircd/ctx.cc)
|
||||||
// Several low-level functions are exposed for library creators. This file is usually
|
/// Internal implementation of the context. This is not included here.
|
||||||
// included when boost/asio.hpp is also included and calls are actually made into boost.
|
/// Several low-level functions are exposed for library creators. This file is usually
|
||||||
//
|
/// included when boost/asio.hpp is also included and calls are actually made into boost.
|
||||||
|
///
|
||||||
namespace ircd::ctx
|
namespace ircd::ctx
|
||||||
{
|
{
|
||||||
using std::chrono::steady_clock;
|
using std::chrono::steady_clock;
|
||||||
|
|
|
@ -46,12 +46,12 @@ namespace ircd::ctx
|
||||||
/// the constructor; the execution will then be posted to the io_service
|
/// the constructor; the execution will then be posted to the io_service
|
||||||
/// event queue instead. `DISPATCH` is an alternative, see boost::asio docs.
|
/// event queue instead. `DISPATCH` is an alternative, see boost::asio docs.
|
||||||
///
|
///
|
||||||
/// Unlike std::thread, when this object goes out of scope the context is
|
/// When this object goes out of scope the context is interrupted and joined
|
||||||
/// interrupted and joined if it has not been already; the current context
|
/// if it has not been already; the current context will wait for this to
|
||||||
/// will wait for this to complete. If the child context does not cooperate
|
/// complete. If the child context does not cooperate the destructor will hang.
|
||||||
/// the destructor will hang. To prevent this behavior `detach()` the ctx
|
/// To prevent this behavior `detach()` the ctx from this handler object; the
|
||||||
/// from this handler object; the detached context will free its own resources
|
/// detached context will free its own resources when finished executing.
|
||||||
/// when finished executing. This is bad practice except in certain cases.
|
/// This is bad practice except in certain cases.
|
||||||
///
|
///
|
||||||
/// To wait for the child context to finish use `join()`. Calling `interrupt()`
|
/// To wait for the child context to finish use `join()`. Calling `interrupt()`
|
||||||
/// will cause an `interrupted` exception to be thrown down the child's stack
|
/// will cause an `interrupted` exception to be thrown down the child's stack
|
||||||
|
|
|
@ -41,7 +41,7 @@ class ircd::ctx::dock
|
||||||
void notify(ctx &) noexcept;
|
void notify(ctx &) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
auto size() const { return q.size(); }
|
size_t size() const;
|
||||||
|
|
||||||
template<class time_point, class predicate> bool wait_until(time_point&& tp, predicate&& pred);
|
template<class time_point, class predicate> bool wait_until(time_point&& tp, predicate&& pred);
|
||||||
template<class time_point> cv_status wait_until(time_point&& tp);
|
template<class time_point> cv_status wait_until(time_point&& tp);
|
||||||
|
@ -72,6 +72,10 @@ noexcept
|
||||||
assert(q.empty());
|
assert(q.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wake up the next context waiting on the dock
|
||||||
|
///
|
||||||
|
/// Unlike notify_one(), the next context in the queue is repositioned in the
|
||||||
|
/// back before being woken up for better fairness.
|
||||||
inline void
|
inline void
|
||||||
ircd::ctx::dock::notify()
|
ircd::ctx::dock::notify()
|
||||||
noexcept
|
noexcept
|
||||||
|
@ -85,6 +89,7 @@ noexcept
|
||||||
notify(*c);
|
notify(*c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wake up the next context waiting on the dock
|
||||||
inline void
|
inline void
|
||||||
ircd::ctx::dock::notify_one()
|
ircd::ctx::dock::notify_one()
|
||||||
noexcept
|
noexcept
|
||||||
|
@ -95,14 +100,15 @@ noexcept
|
||||||
notify(*q.front());
|
notify(*q.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wake up all contexts waiting on the dock.
|
||||||
|
///
|
||||||
|
/// We copy the queue and post all notifications without requesting direct context
|
||||||
|
/// switches. This ensures everyone gets notified in a single transaction without
|
||||||
|
/// any interleaving during this process.
|
||||||
inline void
|
inline void
|
||||||
ircd::ctx::dock::notify_all()
|
ircd::ctx::dock::notify_all()
|
||||||
noexcept
|
noexcept
|
||||||
{
|
{
|
||||||
// We copy the queue and post all notifications without requesting direct context switches.
|
|
||||||
// This ensures everyone gets notified in a single transaction without any interleaving
|
|
||||||
// during this process.
|
|
||||||
|
|
||||||
const auto copy(q);
|
const auto copy(q);
|
||||||
for(const auto &c : copy)
|
for(const auto &c : copy)
|
||||||
ircd::ctx::notify(*c);
|
ircd::ctx::notify(*c);
|
||||||
|
@ -148,7 +154,7 @@ template<class duration,
|
||||||
class predicate>
|
class predicate>
|
||||||
bool
|
bool
|
||||||
ircd::ctx::dock::wait_for(const duration &dur,
|
ircd::ctx::dock::wait_for(const duration &dur,
|
||||||
predicate&& pred)
|
predicate&& pred)
|
||||||
{
|
{
|
||||||
static const duration zero(0);
|
static const duration zero(0);
|
||||||
|
|
||||||
|
@ -173,9 +179,12 @@ template<class time_point>
|
||||||
ircd::ctx::cv_status
|
ircd::ctx::cv_status
|
||||||
ircd::ctx::dock::wait_until(time_point&& tp)
|
ircd::ctx::dock::wait_until(time_point&& tp)
|
||||||
{
|
{
|
||||||
const scope remove(std::bind(&dock::remove_self, this));
|
const scope remove
|
||||||
q.emplace_back(&cur());
|
{
|
||||||
|
std::bind(&dock::remove_self, this)
|
||||||
|
};
|
||||||
|
|
||||||
|
q.emplace_back(&cur());
|
||||||
return ircd::ctx::wait_until<std::nothrow_t>(tp)? cv_status::timeout:
|
return ircd::ctx::wait_until<std::nothrow_t>(tp)? cv_status::timeout:
|
||||||
cv_status::no_timeout;
|
cv_status::no_timeout;
|
||||||
}
|
}
|
||||||
|
@ -184,15 +193,22 @@ template<class time_point,
|
||||||
class predicate>
|
class predicate>
|
||||||
bool
|
bool
|
||||||
ircd::ctx::dock::wait_until(time_point&& tp,
|
ircd::ctx::dock::wait_until(time_point&& tp,
|
||||||
predicate&& pred)
|
predicate&& pred)
|
||||||
{
|
{
|
||||||
if(pred())
|
if(pred())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const scope remove(std::bind(&dock::remove_self, this));
|
const scope remove
|
||||||
|
{
|
||||||
|
std::bind(&dock::remove_self, this)
|
||||||
|
};
|
||||||
|
|
||||||
q.emplace_back(&cur()); do
|
q.emplace_back(&cur()); do
|
||||||
{
|
{
|
||||||
const bool expired(ircd::ctx::wait_until<std::nothrow_t>(tp));
|
const bool expired
|
||||||
|
{
|
||||||
|
ircd::ctx::wait_until<std::nothrow_t>(tp)
|
||||||
|
};
|
||||||
|
|
||||||
if(pred())
|
if(pred())
|
||||||
return true;
|
return true;
|
||||||
|
@ -203,6 +219,14 @@ ircd::ctx::dock::wait_until(time_point&& tp,
|
||||||
while(1);
|
while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The number of contexts waiting in the queue.
|
||||||
|
inline size_t
|
||||||
|
ircd::ctx::dock::size()
|
||||||
|
const
|
||||||
|
{
|
||||||
|
return q.size();
|
||||||
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ircd::ctx::dock::notify(ctx &ctx)
|
ircd::ctx::dock::notify(ctx &ctx)
|
||||||
noexcept
|
noexcept
|
||||||
|
|
|
@ -23,10 +23,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_DB_H
|
#define HAVE_IRCD_DB_H
|
||||||
|
|
||||||
// IRCd Database
|
/// Database: an object store from the primitives of `cell`, `column`, and `row`.
|
||||||
//
|
|
||||||
// Please see db/README.md for documentation.
|
|
||||||
//
|
|
||||||
namespace ircd::db
|
namespace ircd::db
|
||||||
{
|
{
|
||||||
struct init;
|
struct init;
|
||||||
|
@ -62,10 +59,11 @@ namespace ircd::db
|
||||||
extern struct log::log log;
|
extern struct log::log log;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
/// Forward declarations for rocksdb because we do not include it here.
|
||||||
// These are forward declarations to objects we may carry a pointer to.
|
///
|
||||||
// Users of ircd::db should not have to deal directly with these types.
|
/// These are forward declarations to objects we may carry a pointer to.
|
||||||
//
|
/// Users of ircd::db should not have to deal directly with these types.
|
||||||
|
///
|
||||||
namespace rocksdb
|
namespace rocksdb
|
||||||
{
|
{
|
||||||
struct DB;
|
struct DB;
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
## IRCd Database
|
## IRCd Database
|
||||||
|
|
||||||
IRCd's database is presented here primarily as a persistent Object store.
|
The database is an object store built from the primitives of `cell`, `column`, and `row`.
|
||||||
In other words, the structure presented by the database can be represented
|
|
||||||
with JSON. This is built from the primitives of `column`, `row` and `cell`.
|
|
||||||
|
|
||||||
#### Columns
|
#### Columns
|
||||||
While a simple key-value store could naively store a JSON document as a textual
|
While a simple key-value store could naively store a JSON document as a textual
|
||||||
|
|
|
@ -31,25 +31,25 @@ namespace ircd
|
||||||
struct exception;
|
struct exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The root exception type.
|
/// The root exception type.
|
||||||
*
|
///
|
||||||
* All exceptions in the project inherit from this type.
|
/// All exceptions in the project inherit from this type.
|
||||||
* To catch any exception from a project developer's code:
|
/// To catch any exception from a project developer's code:
|
||||||
* catch(const ircd::exception &) {}
|
/// catch(const ircd::exception &) {}
|
||||||
*
|
///
|
||||||
* Remember: not all exceptions are from project developer's code,
|
/// Remember: not all exceptions are from project developer's code,
|
||||||
* such as std::out_of_range. In most contexts if you have to deal with this
|
/// such as std::out_of_range. In most contexts if you have to deal with this
|
||||||
* someone else was lazy, which is bad. To be sure and catch any exception:
|
/// someone else was lazy, which is bad. To be sure and catch any exception:
|
||||||
* catch(const std::exception &) {}
|
/// catch(const std::exception &) {}
|
||||||
*
|
///
|
||||||
* Remember: not all exceptions have to inherit from std::exception, but
|
/// Remember: not all exceptions have to inherit from std::exception, but
|
||||||
* those are rogue exceptions. We do not allow this. To be sure nothing
|
/// those are rogue exceptions. We do not allow this. To be sure nothing
|
||||||
* can possibly get through, add to the bottom:
|
/// can possibly get through, add to the bottom:
|
||||||
* catch(...) {}
|
/// catch(...) {}
|
||||||
*
|
///
|
||||||
* Note: Prefer 'noexcept' instead of catch(...), noexcept is like an 'assert'
|
/// Note: Prefer 'noexcept' instead of catch(...), noexcept is like an 'assert'
|
||||||
* for exceptions, and the rogue can be found-out in testing.
|
/// for exceptions, and the rogue can be found-out in testing.
|
||||||
*/
|
///
|
||||||
struct ircd::exception
|
struct ircd::exception
|
||||||
:std::exception
|
:std::exception
|
||||||
{
|
{
|
||||||
|
@ -73,38 +73,37 @@ struct ircd::exception
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Exception generator convenience macro
|
/// Exception generator convenience macro
|
||||||
*
|
///
|
||||||
* If you want to create your own exception type, you have found the right
|
/// If you want to create your own exception type, you have found the right
|
||||||
* place! This macro allows creating an exception in the the hierarchy.
|
/// place! This macro allows creating an exception in the the hierarchy.
|
||||||
*
|
///
|
||||||
* To create an exception, invoke this macro in your header. Examples:
|
/// To create an exception, invoke this macro in your header. Examples:
|
||||||
*
|
///
|
||||||
* IRCD_EXCEPTION(ircd::exception, my_exception)
|
/// IRCD_EXCEPTION(ircd::exception, my_exception)
|
||||||
* IRCD_EXCEPTION(my_exception, my_specific_exception)
|
/// IRCD_EXCEPTION(my_exception, my_specific_exception)
|
||||||
*
|
///
|
||||||
* Then your catch sequence can look like the following:
|
/// Then your catch sequence can look like the following:
|
||||||
*
|
///
|
||||||
* catch(const my_specific_exception &e)
|
/// catch(const my_specific_exception &e)
|
||||||
* {
|
/// {
|
||||||
* log("something specifically bad happened: %s", e.what());
|
/// log("something specifically bad happened: %s", e.what());
|
||||||
* }
|
/// }
|
||||||
* catch(const my_exception &e)
|
/// catch(const my_exception &e)
|
||||||
* {
|
/// {
|
||||||
* log("something generically bad happened: %s", e.what());
|
/// log("something generically bad happened: %s", e.what());
|
||||||
* }
|
/// }
|
||||||
* catch(const ircd::exception &e)
|
/// catch(const ircd::exception &e)
|
||||||
* {
|
/// {
|
||||||
* log("unrelated bad happened: %s", e.what());
|
/// log("unrelated bad happened: %s", e.what());
|
||||||
* }
|
/// }
|
||||||
* catch(const std::exception &e)
|
/// catch(const std::exception &e)
|
||||||
* {
|
/// {
|
||||||
* log("unhandled bad happened: %s", e.what());
|
/// log("unhandled bad happened: %s", e.what());
|
||||||
* }
|
/// }
|
||||||
*
|
///
|
||||||
* Remember: the order of the catch blocks is important.
|
/// Remember: the order of the catch blocks is important.
|
||||||
*/
|
///
|
||||||
|
|
||||||
#define IRCD_EXCEPTION(parent, name) \
|
#define IRCD_EXCEPTION(parent, name) \
|
||||||
struct name \
|
struct name \
|
||||||
:parent \
|
:parent \
|
||||||
|
@ -122,6 +121,7 @@ struct name \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
|
|
||||||
|
/// Hides the name of the exception when generating a string
|
||||||
#define IRCD_EXCEPTION_HIDENAME(parent, name) \
|
#define IRCD_EXCEPTION_HIDENAME(parent, name) \
|
||||||
struct name \
|
struct name \
|
||||||
:parent \
|
:parent \
|
||||||
|
@ -139,12 +139,12 @@ struct name \
|
||||||
} \
|
} \
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Root error exception type. Inherit from this.
|
/// Root error exception type. Inherit from this.
|
||||||
* List your own exception somewhere else (unless you're overhauling libircd).
|
/// List your own exception somewhere else (unless you're overhauling libircd).
|
||||||
* example, in your namespace:
|
/// example, in your namespace:
|
||||||
*
|
///
|
||||||
* IRCD_EXCEPTION(ircd::error, error)
|
/// IRCD_EXCEPTION(ircd::error, error)
|
||||||
*/
|
///
|
||||||
namespace ircd
|
namespace ircd
|
||||||
{
|
{
|
||||||
IRCD_EXCEPTION(exception, error) // throw ircd::error("something bad")
|
IRCD_EXCEPTION(exception, error) // throw ircd::error("something bad")
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_FMT_H
|
#define HAVE_IRCD_FMT_H
|
||||||
|
|
||||||
|
/// Typesafe format strings from formal grammars & standard RTTI
|
||||||
namespace ircd::fmt
|
namespace ircd::fmt
|
||||||
{
|
{
|
||||||
IRCD_EXCEPTION(ircd::error, error);
|
IRCD_EXCEPTION(ircd::error, error);
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
* AUTOMODPATH = directory for autoloaded modules
|
* AUTOMODPATH = directory for autoloaded modules
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// Tools for working with the local filesystem.
|
||||||
namespace ircd::fs
|
namespace ircd::fs
|
||||||
{
|
{
|
||||||
IRCD_EXCEPTION(ircd::error, error)
|
IRCD_EXCEPTION(ircd::error, error)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_HTTP_H
|
#define HAVE_IRCD_HTTP_H
|
||||||
|
|
||||||
|
/// HyperText TransPort: formal grammars & tools
|
||||||
namespace ircd::http
|
namespace ircd::http
|
||||||
{
|
{
|
||||||
enum code :int;
|
enum code :int;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_INFO_H
|
#define HAVE_IRCD_INFO_H
|
||||||
|
|
||||||
|
/// Information & metadata about the library.
|
||||||
namespace ircd::info
|
namespace ircd::info
|
||||||
{
|
{
|
||||||
struct line;
|
struct line;
|
||||||
|
|
|
@ -31,6 +31,9 @@
|
||||||
#include "stdinc.h"
|
#include "stdinc.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// \brief Internet Relay Chat daemon. This is the principal namespace for IRCd.
|
||||||
|
///
|
||||||
|
///
|
||||||
namespace ircd
|
namespace ircd
|
||||||
{
|
{
|
||||||
extern bool debugmode; ///< Toggled by command line to indicate debug behavior
|
extern bool debugmode; ///< Toggled by command line to indicate debug behavior
|
||||||
|
|
|
@ -29,33 +29,33 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_JS_H
|
#define HAVE_IRCD_JS_H
|
||||||
|
|
||||||
namespace ircd {
|
/// JavaScript Embedded Machine
|
||||||
namespace js {
|
namespace ircd::js
|
||||||
|
|
||||||
// Root exception for this subsystem. The exception hierarchy integrating
|
|
||||||
// with JS itself inherits from this and is defined in TODO: _________
|
|
||||||
IRCD_EXCEPTION(ircd::error, error)
|
|
||||||
|
|
||||||
// Specific logging facility for this subsystem with snomask
|
|
||||||
extern struct log::log log;
|
|
||||||
|
|
||||||
// Fetch version information
|
|
||||||
enum class ver
|
|
||||||
{
|
{
|
||||||
IMPLEMENTATION,
|
// Root exception for this subsystem. The exception hierarchy integrating
|
||||||
};
|
// with JS itself inherits from this and is defined in TODO: _________
|
||||||
const char *version(const ver &ver);
|
IRCD_EXCEPTION(ircd::error, error)
|
||||||
|
|
||||||
|
// Specific logging facility for this subsystem with snomask
|
||||||
|
extern struct log::log log;
|
||||||
|
|
||||||
|
// Fetch version information
|
||||||
|
enum class ver
|
||||||
|
{
|
||||||
|
IMPLEMENTATION,
|
||||||
|
};
|
||||||
|
const char *version(const ver &ver);
|
||||||
|
|
||||||
|
struct init;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the subsystem (singleton held by IRCd main context only)
|
// Initialize the subsystem (singleton held by IRCd main context only)
|
||||||
struct init
|
struct ircd::js::init
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
~init() noexcept;
|
~init() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace js
|
|
||||||
} // namespace ircd
|
|
||||||
|
|
||||||
#ifndef RB_ENABLE_JS
|
#ifndef RB_ENABLE_JS
|
||||||
//
|
//
|
||||||
// Stub definitions for when JS isn't enabled because the definition
|
// Stub definitions for when JS isn't enabled because the definition
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_JSON_H
|
#define HAVE_IRCD_JSON_H
|
||||||
|
|
||||||
|
/// JavaScript Object Notation: formal grammars & tools
|
||||||
///
|
///
|
||||||
/// The IRCd JSON subsystem is meant to be a fast, safe, and extremely
|
/// The IRCd JSON subsystem is meant to be a fast, safe, and extremely
|
||||||
/// lightweight interface. We have taken a somewhat non-traditional approach
|
/// lightweight interface. We have taken a somewhat non-traditional approach
|
||||||
|
|
|
@ -22,15 +22,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_JSON_ARRAY_H
|
#define HAVE_IRCD_JSON_ARRAY_H
|
||||||
|
|
||||||
// ircd::json::array is the rank1 analog to ircd::json::object. It accepts
|
/// Lightweight interface to a JSON array string.
|
||||||
// queries with numerical indexing. The same parsing approach is used in
|
///
|
||||||
// ircd::json::object and that is important to note here: iterating this array
|
/// This is the rank1 analog to ircd::json::object. It accepts queries with
|
||||||
// by incrementing your own numerical index and making calls into this object
|
/// numerical indexing. The same parsing approach is used in ircd::json::object
|
||||||
// is NOT efficient. Simply put, do not do something like
|
/// and that is important to note here: iterating this array by incrementing
|
||||||
// `for(int x=0; x<array.count(); x++) array.at(x)` as that will parse the
|
/// your own numerical index and making calls into this object is NOT efficient.
|
||||||
// array from the beginning on every single iteration. Instead, use the
|
/// Simply put, do not do something like
|
||||||
// provided iterator object.
|
/// `for(int x=0; x<array.count(); x++) array.at(x)` as that will parse the
|
||||||
//
|
/// array from the beginning on every single iteration. Instead, use the
|
||||||
|
/// provided iterator object.
|
||||||
|
///
|
||||||
struct ircd::json::array
|
struct ircd::json::array
|
||||||
:string_view
|
:string_view
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,15 +22,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_JSON_MEMBER_H
|
#define HAVE_IRCD_JSON_MEMBER_H
|
||||||
|
|
||||||
// json::member is a pair of values. The key value (member.first) should always
|
|
||||||
// be a STRING type. We don't use string_view directly in member.first because
|
|
||||||
// json::value can take ownership of a string or use a literal depending on
|
|
||||||
// the circumstance and it's more consistent this way.
|
|
||||||
//
|
|
||||||
// json::member, like json::value, is a runtime construct though still very
|
|
||||||
// lightweight and useful for non-deterministic composition to and extraction
|
|
||||||
// from JSON strings.
|
|
||||||
//
|
|
||||||
namespace ircd::json
|
namespace ircd::json
|
||||||
{
|
{
|
||||||
struct member;
|
struct member;
|
||||||
|
@ -46,6 +37,13 @@ namespace ircd::json
|
||||||
string_view stringify(mutable_buffer &, const std::vector<json::object> &);
|
string_view stringify(mutable_buffer &, const std::vector<json::object> &);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A pair of json::value representing an object member.
|
||||||
|
///
|
||||||
|
/// The key value (member.first) should always be a STRING type. We don't use
|
||||||
|
/// string_view directly in member.first because json::value can take ownership
|
||||||
|
/// of a string or use a literal depending on the circumstance and it's more
|
||||||
|
/// consistent this way.
|
||||||
|
///
|
||||||
struct ircd::json::member
|
struct ircd::json::member
|
||||||
:std::pair<value, value>
|
:std::pair<value, value>
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,42 +27,43 @@ namespace ircd::json
|
||||||
struct object;
|
struct object;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ircd::json::object is an extremely lightweight device for making
|
/// Lightweight interface to a JSON object string.
|
||||||
// queries into a string of JSON. This is a read-only device. It is merely
|
///
|
||||||
// functionality built on top of a string_view which is just a pair of
|
/// This makes queries into a string of JSON. This is a read-only device.
|
||||||
// const char* pointers to the borders of the JSON object.
|
/// It is merely functionality built on top of a string_view which is just a
|
||||||
//
|
/// pair of const char* pointers to the borders of the JSON object.
|
||||||
// This class computes over strings of JSON by parsing it on-the-fly
|
///
|
||||||
// via forward iteration. The const_iterator is fundamental. All other member
|
/// This class computes over strings of JSON by parsing it on-the-fly
|
||||||
// functions are built from this forward iteration and have worst-case linear
|
/// via forward iteration. The const_iterator is fundamental. All other member
|
||||||
// complexity *every time you invoke them*. This is not necessarily a bad
|
/// functions are built from this forward iteration and have worst-case linear
|
||||||
// thing in the appropriate use case. Our parser is pretty efficient; this
|
/// complexity *every time you invoke them*. This is not necessarily a bad
|
||||||
// device conducts zero copies, zero allocations and zero indexing; instead
|
/// thing in the appropriate use case. Our parser is pretty efficient; this
|
||||||
// the parser provides string_views to members during the iteration.
|
/// device conducts zero copies, zero allocations and zero indexing; instead
|
||||||
//
|
/// the parser provides string_views to members during the iteration.
|
||||||
// The returned values are character ranges (string_view's) which themselves
|
///
|
||||||
// are type agnostic to their contents. The type of a value is determined at
|
/// The returned values are character ranges (string_view's) which themselves
|
||||||
// the user's discretion by querying the content of the string_view using a
|
/// are type agnostic to their contents. The type of a value is determined at
|
||||||
// util function like json::type() etc. In other words, a value carries type
|
/// the user's discretion by querying the content of the string_view using a
|
||||||
// data from its own original content. This means the user is responsible for
|
/// util function like json::type() etc. In other words, a value carries type
|
||||||
// removing prefix and suffix characters like '{' or '"' after determining the
|
/// data from its own original content. This means the user is responsible for
|
||||||
// type if they want a truly pure value string. Our zero-copy string_view utils
|
/// removing prefix and suffix characters like '{' or '"' after determining the
|
||||||
// make this to a simple ballet of pointers.
|
/// type if they want a truly pure value string. Our zero-copy string_view utils
|
||||||
//
|
/// make this to a simple ballet of pointers.
|
||||||
// Other devices for dealing with strings of JSON are available: if an index
|
///
|
||||||
// should be populated (ircd::json::index), or if a certain set of keys
|
/// Other devices for dealing with strings of JSON are available: if an index
|
||||||
// should be found and extracted with a single pass (ircd::json::extract).
|
/// should be populated (ircd::json::index), or if a certain set of keys
|
||||||
//
|
/// should be found and extracted with a single pass (ircd::json::extract).
|
||||||
// Some serialization/write functions are actually provided here, these
|
///
|
||||||
// are to *rewrite* JSON into our desired output form.
|
/// Some serialization/write functions are actually provided here, these
|
||||||
//
|
/// are to *rewrite* JSON into our desired output form.
|
||||||
// Recursive traversal cannot be achieved via a single key string value; so
|
///
|
||||||
// any string_view argument for a key will not be recursive. In other words,
|
/// Recursive traversal cannot be achieved via a single key string value; so
|
||||||
// due to the fact that a JS identifier can have almost any character we have
|
/// any string_view argument for a key will not be recursive. In other words,
|
||||||
// to use a different *type* like a vector of strings; in our common case we
|
/// due to the fact that a JS identifier can have almost any character we have
|
||||||
// use an initializer_list typedef'ed as `path` and those overloads will be
|
/// to use a different *type* like a vector of strings; in our common case we
|
||||||
// recursive.
|
/// use an initializer_list typedef'ed as `path` and those overloads will be
|
||||||
//
|
/// recursive.
|
||||||
|
///
|
||||||
struct ircd::json::object
|
struct ircd::json::object
|
||||||
:string_view
|
:string_view
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,17 +22,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_JSON_PROPERTY_H
|
#define HAVE_IRCD_JSON_PROPERTY_H
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// tuple property template. Specify a list of these in the tuple template to
|
|
||||||
// form the members of the object.
|
|
||||||
//
|
|
||||||
|
|
||||||
namespace ircd::json
|
namespace ircd::json
|
||||||
{
|
{
|
||||||
template<const char *const &name, class value_type> struct property;
|
template<const char *const &name, class value_type> struct property;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The property template specifies a key/value member of a json::tuple
|
||||||
|
///
|
||||||
|
///
|
||||||
template<const char *const &name,
|
template<const char *const &name,
|
||||||
class T>
|
class T>
|
||||||
struct ircd::json::property
|
struct ircd::json::property
|
||||||
|
|
|
@ -22,40 +22,37 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_JSON_TUPLE_H
|
#define HAVE_IRCD_JSON_TUPLE_H
|
||||||
|
|
||||||
//
|
|
||||||
// Here we represent a JSON object with a named tuple, allowing the programmer
|
|
||||||
// to create a structure specifying all of the potentially valid members of the
|
|
||||||
// object. Access to a specific member is O(1) just like a native `struct`
|
|
||||||
// rather than a linear or logn lookup into a map. The size of the tuple is
|
|
||||||
// extremely minimal: only the size of the values it stores. This is because
|
|
||||||
// the member keys and type data are all static or dealt with at compile time.
|
|
||||||
//
|
|
||||||
// The member structure for the tuple is called `property` because json::member
|
|
||||||
// is already used to pair together runtime oriented json::values. This system
|
|
||||||
// only decays into runtime members and values when compile-time logic cannot
|
|
||||||
// be achieved.
|
|
||||||
//
|
|
||||||
// Create and use a tuple to efficiently extract members from a json::object.
|
|
||||||
// The tuple will populate its own members during a single-pass iteration of
|
|
||||||
// the JSON input. If the JSON does not contain a member specified in the
|
|
||||||
// tuple, the value will be default initialized. If the JSON contains a member
|
|
||||||
// not specified in the tuple, it is ignored. If you need to know all of the
|
|
||||||
// members specified in the JSON dynamically, use a json::index or iterate
|
|
||||||
// manually.
|
|
||||||
//
|
|
||||||
namespace ircd {
|
namespace ircd {
|
||||||
namespace json {
|
namespace json {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
/// All tuple templates inherit from this non-template type for tagging.
|
||||||
//
|
|
||||||
// ircd::json::tuple template. Create your own struct inheriting this
|
|
||||||
// class template with the members.
|
|
||||||
//
|
|
||||||
struct tuple_base
|
struct tuple_base
|
||||||
{
|
{
|
||||||
// EBO tag
|
// EBO tag
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A compile-time construct to describe a JSON object's members and types.
|
||||||
|
///
|
||||||
|
/// Here we represent a JSON object with a named tuple, allowing the programmer
|
||||||
|
/// to create a structure specifying all of the potentially valid members of the
|
||||||
|
/// object. Thus at runtime, the tuple only carries around its values like a
|
||||||
|
/// `struct`. Unlike a `struct`, the tuple is abstractly iterable and we have
|
||||||
|
/// implemented logic operating on all JSON tuples regardless of their makeup
|
||||||
|
/// without any effort from a developer creating a new tuple.
|
||||||
|
///
|
||||||
|
/// The member structure for the tuple is called `property` because json::member
|
||||||
|
/// is already used to pair together runtime oriented json::values. This system
|
||||||
|
/// only decays into runtime members and values when compile-time logic cannot
|
||||||
|
/// be achieved.
|
||||||
|
///
|
||||||
|
/// Create and use a tuple to efficiently extract members from a json::object.
|
||||||
|
/// The tuple will populate its own members during a single-pass iteration of
|
||||||
|
/// the JSON input. If the JSON does not contain a member specified in the
|
||||||
|
/// tuple, the value will be default initialized. If the JSON contains a member
|
||||||
|
/// not specified in the tuple, it is ignored. If you need to know all of the
|
||||||
|
/// members specified in the JSON dynamically, use a json::index or iterate
|
||||||
|
/// manually.
|
||||||
|
///
|
||||||
template<class... T>
|
template<class... T>
|
||||||
struct tuple
|
struct tuple
|
||||||
:std::tuple<T...>
|
:std::tuple<T...>
|
||||||
|
|
|
@ -22,20 +22,22 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_JSON_VALUE_H
|
#define HAVE_IRCD_JSON_VALUE_H
|
||||||
|
|
||||||
// The ircd::json::value is used if we have to keep non-deterministic runtime
|
/// A primitive of the ircd::json system representing a value at runtime.
|
||||||
// state of values apropos a JSON object. In other words, value is runtime-
|
///
|
||||||
// typed rather than the json::tuple which is compile-time typed. The cost of
|
/// This holds state for values apropos a JSON object.
|
||||||
// using this value structure is in the switching based on the type enum it
|
///
|
||||||
// stores as well as a branch in the destructor to deallocate owned resources.
|
/// Value's data can either be in the form of a JSON string or it can be
|
||||||
// This is still very lightweight. The structure itself is the same size as
|
/// native machine state. The serial flag indicates the former.
|
||||||
// a string_view (two pointers). It is also not template-based, allowing us
|
///
|
||||||
// to keep logic in the definition files and out of the headers. Nevertheless,
|
/// Value is capable of allocation and ownership of its internal data if
|
||||||
// this class should not be abused over an alternative compile-time solution.
|
/// necessary with move semantics, but copying may be not implemented in
|
||||||
//
|
/// exceptional cases.
|
||||||
// Value cannot be copied because it can own resources, and recursively. The
|
///
|
||||||
// resource ownership is necessary in cases like nested initializer_lists
|
/// Value can can hold any of the JSON types in either of these states.
|
||||||
// and other such complex compositions.
|
/// This is accomplished with runtime switching and branching but this is
|
||||||
//
|
/// still lightweight. The structure is just the size of two pointers, the
|
||||||
|
/// same as a string_view.
|
||||||
|
///
|
||||||
struct ircd::json::value
|
struct ircd::json::value
|
||||||
{
|
{
|
||||||
union // xxx std::variant
|
union // xxx std::variant
|
||||||
|
|
|
@ -22,15 +22,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_LIFE_GUARD_H
|
#define HAVE_IRCD_LIFE_GUARD_H
|
||||||
|
|
||||||
//
|
|
||||||
// life_guard is a convenience which takes advantage of
|
|
||||||
// std::enable_shared_from_this<T>. The life_guard glorifies the constructor
|
|
||||||
// of an std::shared_ptr<T> by accepting std::weak_ptr<T> and T& itself all
|
|
||||||
// with proper semantics. Once construction is successful, the user holds it
|
|
||||||
// for the duration of the scope ensuring T& survives context interleaving
|
|
||||||
// without being destructed.
|
|
||||||
//
|
|
||||||
|
|
||||||
namespace ircd
|
namespace ircd
|
||||||
{
|
{
|
||||||
// Tests if type inherits from std::enable_shared_from_this<>
|
// Tests if type inherits from std::enable_shared_from_this<>
|
||||||
|
@ -59,19 +50,25 @@ namespace ircd
|
||||||
template<class T> struct life_guard;
|
template<class T> struct life_guard;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the life_guard to keep an object alive within a function running in a context.
|
/// life_guard is a convenience which takes advantage of std::enable_shared_from_this<T>.
|
||||||
*
|
/// The life_guard glorifies the constructor of an std::shared_ptr<T> by accepting
|
||||||
* Example:
|
/// std::weak_ptr<T> and T& itself all with proper semantics. Once construction is
|
||||||
*
|
/// successful, the user holds it for the duration of the scope ensuring T& survives
|
||||||
void foo(client &c)
|
/// context interleaving without being destructed.
|
||||||
{
|
///
|
||||||
const life_guard<client> lg(c);
|
/// Use the life_guard to keep an object alive within a function running in a context.
|
||||||
|
///
|
||||||
c.call(); // This call was always safe with or w/o life_guard.
|
/// Example:
|
||||||
ctx::wait(); // The context has now yielded and another context might destroy client &c
|
///
|
||||||
c.call(); // The context continues and this would have made a call on a dead c.
|
/// void foo(client &c)
|
||||||
}
|
/// {
|
||||||
*/
|
/// const life_guard<client> lg(c);
|
||||||
|
///
|
||||||
|
/// c.call(); // This call was always safe with or w/o life_guard.
|
||||||
|
/// ctx::wait(); // The context has now yielded and another context might destroy client &c
|
||||||
|
/// c.call(); // The context continues and this would have made a call on a dead c.
|
||||||
|
/// }
|
||||||
|
///
|
||||||
template<class T>
|
template<class T>
|
||||||
struct ircd::life_guard
|
struct ircd::life_guard
|
||||||
:std::shared_ptr<T>
|
:std::shared_ptr<T>
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace ircd
|
||||||
const char *smalldate(const time_t &);
|
const char *smalldate(const time_t &);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Logging system
|
||||||
namespace ircd::log
|
namespace ircd::log
|
||||||
{
|
{
|
||||||
enum facility :int;
|
enum facility :int;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_MAPI_H
|
#define HAVE_IRCD_MAPI_H
|
||||||
|
|
||||||
|
/// Module API: Interface for module developers.
|
||||||
namespace ircd::mapi
|
namespace ircd::mapi
|
||||||
{
|
{
|
||||||
struct header;
|
struct header;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_MODS_H
|
#define HAVE_IRCD_MODS_H
|
||||||
|
|
||||||
|
/// Modules system
|
||||||
namespace ircd::mods
|
namespace ircd::mods
|
||||||
{
|
{
|
||||||
IRCD_EXCEPTION(ircd::error, error)
|
IRCD_EXCEPTION(ircd::error, error)
|
||||||
|
|
|
@ -23,12 +23,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_UTIL_RANDOM_H
|
#define HAVE_IRCD_UTIL_RANDOM_H
|
||||||
|
|
||||||
namespace ircd::rand
|
/// Some character set dictionaries
|
||||||
{
|
|
||||||
extern std::random_device device;
|
|
||||||
extern std::mt19937_64 mt;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ircd::rand::dict
|
namespace ircd::rand::dict
|
||||||
{
|
{
|
||||||
extern const std::string alnum;
|
extern const std::string alnum;
|
||||||
|
@ -38,8 +33,12 @@ namespace ircd::rand::dict
|
||||||
extern const std::string numeric;
|
extern const std::string numeric;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tools for randomization
|
||||||
namespace ircd::rand
|
namespace ircd::rand
|
||||||
{
|
{
|
||||||
|
extern std::random_device device;
|
||||||
|
extern std::mt19937_64 mt;
|
||||||
|
|
||||||
uint64_t integer();
|
uint64_t integer();
|
||||||
uint64_t integer(const uint64_t &min, const uint64_t &max);
|
uint64_t integer(const uint64_t &min, const uint64_t &max);
|
||||||
|
|
||||||
|
|
|
@ -142,8 +142,20 @@ namespace std
|
||||||
// Forward declarations from third party namespaces not included here
|
// Forward declarations from third party namespaces not included here
|
||||||
//
|
//
|
||||||
|
|
||||||
// Boost is not exposed unless explicitly included by a definition file. This
|
/// Forward declarations for boost because it is not included here.
|
||||||
// is a major improvement of project compile time.
|
///
|
||||||
|
/// libircd does not include third party headers along with its own headers
|
||||||
|
/// for the public interface, only standard library headers. boost is only
|
||||||
|
/// included in specific definition files where we use its functionality.
|
||||||
|
/// This is a major improvement in project compile time.
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Forward declarations for boost::asio because it is not included here.
|
||||||
|
///
|
||||||
|
/// Boost headers are not exposed to our users unless explicitly included by a
|
||||||
|
/// definition file.
|
||||||
namespace boost::asio
|
namespace boost::asio
|
||||||
{
|
{
|
||||||
struct io_service; // Allow a reference to an ios to be passed to ircd
|
struct io_service; // Allow a reference to an ios to be passed to ircd
|
||||||
|
|
|
@ -36,13 +36,12 @@ namespace ircd
|
||||||
bool operator!(const string_view &);
|
bool operator!(const string_view &);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
/// Customized std::string_view (experimental TS / C++17)
|
||||||
// Customized std::string_view (experimental TS / C++17)
|
///
|
||||||
//
|
/// This class adds iterator-based (char*, char*) construction to std::string_view which otherwise
|
||||||
// This class adds iterator-based (char*, char*) construction to std::string_view which otherwise
|
/// takes traditional (char*, size_t) arguments. This allows boost::spirit grammars to create
|
||||||
// takes traditional (char*, size_t) arguments. This allows boost::spirit grammars to create
|
/// string_view's using the raw[] directive achieving zero-copy/zero-allocation parsing.
|
||||||
// string_view's using the raw[] directive achieving zero-copy/zero-allocation parsing.
|
///
|
||||||
//
|
|
||||||
struct ircd::string_view
|
struct ircd::string_view
|
||||||
:std::string_view
|
:std::string_view
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_UTIL_H
|
#define HAVE_IRCD_UTIL_H
|
||||||
|
|
||||||
|
/// Tools for developers
|
||||||
|
namespace ircd::util
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
namespace ircd {
|
namespace ircd {
|
||||||
inline namespace util {
|
inline namespace util {
|
||||||
|
|
||||||
|
|
3
ircd/README.md
Normal file
3
ircd/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# IRCd Library Definitions
|
||||||
|
|
||||||
|
This directory contains definitions and linkage for `libircd`
|
|
@ -429,24 +429,21 @@ ircd::async_recv_next(std::shared_ptr<client> client)
|
||||||
async_recv_next(std::move(client), milliseconds(-1));
|
async_recv_next(std::move(client), milliseconds(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// This function is the basis for the client's request loop. We still use
|
||||||
|
/// an asynchronous pattern until there is activity on the socket (a request)
|
||||||
|
/// in which case the switch to synchronous mode is made by jumping into an
|
||||||
|
/// ircd::context drawn from the request pool. When the request is finished,
|
||||||
|
/// the client exits back into asynchronous mode until the next request is
|
||||||
|
/// received and rinse and repeat.
|
||||||
//
|
//
|
||||||
// This function is the basis for the client's request loop. We still use
|
/// This sequence exists to avoid any possible c10k-style limitation imposed by
|
||||||
// an asynchronous pattern until there is activity on the socket (a request)
|
/// dedicating a context and its stack space to the lifetime of a connection.
|
||||||
// in which case we switch to synchronous mode by jumping into an ircd::context
|
/// This is similar to the thread-per-request pattern before async was in vogue.
|
||||||
// drawn from the request pool. When the request is finished, we exit back
|
|
||||||
// into asynchronous mode until the next request is received and rinse and repeat.
|
|
||||||
//
|
|
||||||
// This sequence exists to avoid any possible c10k-style limitation imposed by
|
|
||||||
// dedicating a context and its stack space to the lifetime of a connection.
|
|
||||||
// This is similar to the thread-per-request pattern before async was in vogue.
|
|
||||||
// Except now with userspace threads, a context switch has a cost on the order
|
|
||||||
// of a function call, not nearly that of a system thread. So after enduring
|
|
||||||
// several years of non-blocking stackless callback asynchronous web-scale hell,
|
|
||||||
// we have now made it out alive on the other side. Enjoy.
|
|
||||||
//
|
|
||||||
// Pay close attention to the comments to know exactly where you are and what
|
|
||||||
// you can do at any given point in this sequence.
|
|
||||||
//
|
//
|
||||||
|
/// Developers: Pay close attention to the comments to know exactly where you
|
||||||
|
/// are and what you can do at any given point in this sequence.
|
||||||
|
///
|
||||||
void
|
void
|
||||||
ircd::async_recv_next(std::shared_ptr<client> client,
|
ircd::async_recv_next(std::shared_ptr<client> client,
|
||||||
const milliseconds &timeout)
|
const milliseconds &timeout)
|
||||||
|
|
|
@ -933,6 +933,11 @@ const
|
||||||
return json::string(begin, end);
|
return json::string(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// json/value.h
|
||||||
|
//
|
||||||
|
|
||||||
ircd::json::value::~value()
|
ircd::json::value::~value()
|
||||||
noexcept
|
noexcept
|
||||||
{
|
{
|
||||||
|
|
|
@ -193,29 +193,31 @@ ircd::socket::cancel()
|
||||||
sd.cancel();
|
sd.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
/// Asynchronous callback when the socket is ready
|
||||||
// Overload for operator() without a timeout. see: operator()
|
///
|
||||||
//
|
/// Overload for operator() without a timeout. see: operator()
|
||||||
|
///
|
||||||
void
|
void
|
||||||
ircd::socket::operator()(handler h)
|
ircd::socket::operator()(handler h)
|
||||||
{
|
{
|
||||||
operator()(milliseconds(-1), std::move(h));
|
operator()(milliseconds(-1), std::move(h));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
/// Asynchronous callback when the socket is ready
|
||||||
// This function calls back the handler when the socket has received
|
///
|
||||||
// something and is ready to be read from.
|
/// This function calls back the handler when the socket has received
|
||||||
//
|
/// something and is ready to be read from.
|
||||||
// The purpose here is to allow waiting for data from the socket without
|
///
|
||||||
// blocking any context and using any stack space whatsoever, i.e full
|
/// The purpose here is to allow waiting for data from the socket without
|
||||||
// asynchronous mode.
|
/// blocking any context and using any stack space whatsoever, i.e full
|
||||||
//
|
/// asynchronous mode.
|
||||||
// boost::asio has no direct way to accomplish this, so we use a little
|
///
|
||||||
// trick to read a single byte with MSG_PEEK as our indication. This is
|
/// boost::asio has no direct way to accomplish this because the buffer size
|
||||||
// done directly on the socket and not through the SSL cipher, but we
|
/// must be positive so we use a little trick to read a single byte with
|
||||||
// don't want this byte anyway. This isn't such a great trick, because
|
/// MSG_PEEK as our indication. This is done directly on the socket and
|
||||||
// it may result in an extra syscall; so there's room for improvement here.
|
/// not through the SSL cipher, but we don't want this byte anyway. This
|
||||||
//
|
/// isn't such a great trick.
|
||||||
|
///
|
||||||
void
|
void
|
||||||
ircd::socket::operator()(const milliseconds &timeout,
|
ircd::socket::operator()(const milliseconds &timeout,
|
||||||
handler callback)
|
handler callback)
|
||||||
|
|
|
@ -57,7 +57,7 @@ struct body
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate !accounts:host which is the MXID of the room where the members
|
// Generate !accounts:host which is the MXID of the room where the members
|
||||||
// are the actual account registrations themselves for this homeserver.
|
// are the actual account registrations for this homeserver.
|
||||||
const m::id::room::buf accounts_room_id
|
const m::id::room::buf accounts_room_id
|
||||||
{
|
{
|
||||||
"accounts", home_server
|
"accounts", home_server
|
||||||
|
@ -74,6 +74,7 @@ post_login_password(client &client,
|
||||||
const resource::request &request,
|
const resource::request &request,
|
||||||
const resource::request::body<body> &body)
|
const resource::request::body<body> &body)
|
||||||
{
|
{
|
||||||
|
// Build a canonical MXID from a the user field
|
||||||
const m::id::user::buf user_id
|
const m::id::user::buf user_id
|
||||||
{
|
{
|
||||||
unquote(at<name::user>(body)), home_server
|
unquote(at<name::user>(body)), home_server
|
||||||
|
|
Loading…
Reference in a new issue