yengine 0.0.8

Communication library for the Yate Engine external module protocol.
Documentation
//! Wire-format (de)serialization.
//!
//! ## Command direction
//!
//! Command direction is anotated by the following prefixes in the
//! structures documentations:
//! - **(>)**: _Application_ to _Engine_
//! - **(<)**: _Engine_ to _Application_
//! - **(~)**: _Bi_-directional

use std::collections::BTreeMap;

#[cfg(test)]
mod tests;

mod error;
pub use error::{Error, Result};

pub mod upcode;

mod de;
pub use de::*;

mod ser;
pub use ser::*;

/// **(<)** The engine sends this notification as answer to a syntactically
/// incorrect line it received from the application.
///
/// Note: _The external module SHOULD NOT send anything back to Yate
/// in response to such a notification as it can result in an infinite loop._
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "Error in")]
pub struct ErrorIn {
    /// The original line exactly as received (not escaped or something).
    pub original: String,
}

/// **(~)** Requests a **message** to be processed by the other party.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>message")]
pub struct Message {
    /// An obscure unique message ID string generated by the sender.
    pub id: String,

    /// Time (in seconds) the message was initially created.
    pub time: u64,

    /// Name of the message.
    pub name: String,

    /// Default textual return value of the message.
    pub retvalue: String,

    /// Enumeration of the key-value pairs of the message.
    pub kv: BTreeMap<String, String>,
}

/// **(~)** Confirmation that the **message** has been processed properly or not.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%<message")]
pub struct MessageAck {
    /// Same message ID string received trough [`Message`].
    pub id: String,

    /// Indication if the message has been processed or it should be passed to the next handler.
    pub processed: bool,

    /// New name of the message, if empty keep unchanged.
    pub name: Option<String>,

    /// New textual return value of the message.
    pub retvalue: String,

    /// Enumeration of the key-value pairs of the message.
    pub kv: BTreeMap<String, String>,
}

/// **(>)** Requests the installing of a message **handler**.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>install")]
pub struct Install {
    /// Priority in chain, use default (`100`) if `None`.
    pub priority: Option<u64>,

    /// Name of the messages for that a handler should be installed.
    pub name: String,

    /// Filter for the installed handler;
    /// - name of a variable the handler will filter,
    /// - matching value for the filtered variable.
    #[facet(default)]
    pub filter: Option<(String, Option<String>)>,
}

/// **(<)** Confirmation that the **handler**
/// has been installed properly or not.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%<install")]
pub struct InstallAck {
    /// Priority of the installed handler.
    pub priority: u64,

    /// Name of the messages asked to handle.
    pub name: String,

    /// Success of operation.
    pub success: bool,
}

/// **(>)** Requests uninstalling a previously installed message **handler**.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>uninstall")]
pub struct Uninstall {
    /// Name of the message handler thst should be uninstalled.
    pub name: String,
}

/// **(<)** Confirmation that the **handler**
/// has been uninstalled properly or not.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%<uninstall")]
pub struct UninstallAck {
    /// Priority of the previously installed handler.
    pub priority: u64,

    /// Name of the message handler asked to uninstall.
    pub name: String,

    /// Success of operation.
    pub success: bool,
}

/// **(>)** Requests the installing of a message **watcher**
/// (post-dispatching notifier).
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>watch")]
pub struct Watch {
    /// Name of the messages for that a watcher should be installed.
    pub name: String,
}

/// **(<)** Confirmation that the **watcher**
/// has been installed properly or not.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%<watch")]
pub struct WatchAck {
    /// Name of the messages asked to watch.
    pub name: String,

    /// Success of operation.
    pub success: bool,
}

/// **(>)** Requests uninstalling a previously installed message **watcher**.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>unwatch")]
pub struct Unwatch {
    /// Name of the message watcher thst should be uninstalled.
    pub name: String,
}

/// **(<)** Confirmation that the **watcher**
/// has been uninstalled properly or not.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%<unwatch")]
pub struct UnwatchAck {
    /// Name of the message watcher asked to uninstall.
    pub name: String,

    /// Success of operation.
    pub success: bool,
}

/// **(>)** Requests the change of a **local parameter**.
///
/// Currently supported parameters:
/// - `id` (string) - Identifier of the associated channel, if any
/// - `disconnected` (bool) - Enable or disable sending "chan.disconnected" messages
/// - `trackparam` (string) - Set the message handler tracking name, cannot be made empty
/// - `reason` (string) - Set the disconnect reason that gets received by the peer channel
/// - `timeout` (int) - Timeout in milliseconds for answering to messages
/// - `timebomb` (bool) - Terminate this module instance if a timeout occured
/// - `bufsize` (int) - Length of the incoming line buffer (default 8192)
/// - `setdata` (bool) - Attach channel pointer as user data to generated messages
/// - `reenter` (bool) - If this module is allowed to handle messages generated by itself
/// - `selfwatch` (bool) - If this module is allowed to watch messages generated by itself
/// - `restart` (bool) - Restart this global module if it terminates unexpectedly. Must be turned off to allow normal termination
///
/// Engine read-only run parameters:
/// - `engine.version` (string,readonly) - Version of the engine, like "2.0.1"
/// - `engine.release` (string,readonly) - Release type and number, like "beta2"
/// - `engine.nodename` (string,readonly) - Server's node name as known by the engine
/// - `engine.runid` (int,readonly) - Engine's run identifier
/// - `engine.configname` (string,readonly) - Name of the master configuration
/// - `engine.sharedpath` (string,readonly) - Path to the shared directory
/// - `engine.configpath` (string,readonly) - Path to the program config files directory
/// - `engine.cfgsuffix` (string,readonly) - Suffix of the config files names, normally ".conf"
/// - `engine.modulepath` (string,readonly) - Path to the main modules directory
/// - `engine.modsuffix` (string,readonly) - Suffix of the loadable modules, normally ".yate"
/// - `engine.logfile` (string,readonly) - Name of the log file if in use, empty if not logging
/// - `engine.clientmode` (bool,readonly) - Check if running as a client
/// - `engine.supervised` (bool,readonly) - Check if running under supervisor
/// - `engine.maxworkers` (int,readonly) - Maximum number of message worker threads
///
/// Engine configuration file parameters:
/// - `config.<section>.<key>` (readonly) - Content of `key=` in `[section]` of main config file (`yate.conf`, `yate-qt4.conf`)
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>setlocal")]
pub struct SetLocal {
    /// Name of the parameter to modify.
    pub name: String,

    /// New value to set in the local module instance,
    /// `None` to just query.
    pub value: Option<String>,
}

/// **(<)** Confirmation that the **local parameter**
/// has been changed successfully or not.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%<setlocal")]
pub struct SetLocalAck {
    /// Name of the modified parameter.
    pub name: String,

    /// Value of the local parameter.
    pub value: String,

    /// Success of operation.
    pub success: bool,
}

/// **(>)** Setup the connection for
/// external modules that attach to the _socket interface_.
///
/// As the conection is initiated from the external module
/// the engine must be informed on the role of the connection.
/// This must be the first request sent over a newly
/// established socket connection.
/// The role and direction of the connection is established
/// and then this keyword cannot be used again on the same connection.
///
/// There is no answer to this request, if it fails
/// the engine will slam the connection shut.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>connect")]
pub struct Connect {
    /// Role of this connection.
    pub role: ConnectRole,

    /// Channel to connect this socket to, with it's `id` and optional `type`, assuming `audio` if `None`.
    #[facet(default)]
    pub channel: Option<(String, Option<String>)>,
}

/// The _role_ of the connection, for the [`Connect`] message.
#[derive(Debug, facet::Facet)]
#[facet(rename_all = "lowercase")]
#[repr(C)]
pub enum ConnectRole {
    /// The `global` role.
    Global,

    /// The `channel` role.
    Channel,

    /// The `play` role.
    Play,

    /// The `record` role.
    Record,

    /// The `playrec` role.
    PlayRec,
}

/// **(>)** An _arbitrary message_ to be sent
/// to engine's logging output.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>output")]
pub struct Output {
    /// Arbitrary unescaped string.
    pub text: String,
}

/// **(>)** A _debug message_ to be sent
/// to engine's logging output.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>debug")]
pub struct Debug {
    /// The log _level_ of the message.
    pub level: DebugLevel,

    /// Arbitrary unescaped string.
    pub text: String,
}

/// The _log level_ of the [`struct@Debug`] message.
#[derive(Debug, facet::Facet)]
#[repr(C)]
pub enum DebugLevel {
    /// The `TEST` log level.
    #[facet(rename = "1")]
    Test,

    /// The `CRIT` log level.
    #[facet(rename = "2")]
    Crit,

    /// The `CONF` log level.
    #[facet(rename = "3")]
    Conf,

    /// The `STUB` log level.
    #[facet(rename = "4")]
    Stub,

    /// The `WARN` log level.
    #[facet(rename = "5")]
    Warn,

    /// The `MILD` log level.
    #[facet(rename = "6")]
    Mild,

    /// The `NOTE` log level.
    #[facet(rename = "7")]
    Note,

    /// The `CALL` log level.
    #[facet(rename = "8")]
    Call,

    /// The `INFO` log level.
    #[facet(rename = "9")]
    Info,

    /// The `ALL` log level.
    #[facet(rename = "10")]
    All,
}

/// **(>)** Tell the engine we'd like to stop processing messages.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%>quit")]
pub struct Quit;

/// **(<)** Signals we can proceed to exit.
#[derive(Debug, facet::Facet)]
#[facet(type_tag = "%%<quit")]
pub struct QuitAck;