diff --git a/README.md b/README.md index bdc14c4..77bab07 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,19 @@ derived from any project's source. ## Design -- **`proto/`** the ircd link layer. A `Protocol` trait maps raw server-to-server - lines to and from a normalized `NetEvent`/`NetAction` model, so the engine never - touches a raw line and a new ircd is one new module. InspIRCd is the first. -- **`engine/`** the services engine: live network `state`, the account store, and - the `Service` trait. The store is event-sourced: every change is an `Event` +The core lives in `src/`; the pluggable parts live in `modules/` (see +`modules/README.md`). + +- **`src/engine/`** the services engine: live network `state`, the account store, + and the `Service` trait. The store is event-sourced: every change is an `Event` appended to a per-node log, and state is a fold over that log. -- **`gossip/`** node-to-node replication over the logs. -- **`services/`** the pseudo-clients: NickServ first, then ChanServ / OperServ. +- **`src/gossip.rs`** node-to-node replication over the logs. +- **`modules/protocol/`** the ircd link layer. A `Protocol` trait maps raw + server-to-server lines to and from a normalized `NetEvent`/`NetAction` model, so + the engine never touches a raw line and a new ircd is one new module. InspIRCd is + the first. +- **`modules/nickserv/`, `modules/chanserv/`** the pseudo-clients, one directory + each. OperServ and others follow the same shape. ## Replication diff --git a/modules/README.md b/modules/README.md new file mode 100644 index 0000000..7b5e502 --- /dev/null +++ b/modules/README.md @@ -0,0 +1,19 @@ +# modules/ + +The pluggable parts of fedserv: one directory per protocol and per pseudoclient. +The core (engine, event log, gossip, link loop) stays in `../src/`. + +``` +modules/ + protocol/ ircd link protocols (inspircd.rs) + nickserv/ NickServ pseudoclient + chanserv/ ChanServ pseudoclient +``` + +`src/main.rs` pulls each in with `#[path = "../modules/..."]`, so crate paths +stay flat (`crate::proto`, `crate::nickserv`, `crate::chanserv`). + +## Naming + +A service directory holds its pseudoclient file plus, as commands are split out, +one file per command with the service prefix: `ns_register.rs`, `cs_mode.rs`, etc. diff --git a/src/services/chanserv.rs b/modules/chanserv/chanserv.rs similarity index 100% rename from src/services/chanserv.rs rename to modules/chanserv/chanserv.rs diff --git a/src/services/nickserv.rs b/modules/nickserv/nickserv.rs similarity index 100% rename from src/services/nickserv.rs rename to modules/nickserv/nickserv.rs diff --git a/src/proto/inspircd.rs b/modules/protocol/inspircd.rs similarity index 100% rename from src/proto/inspircd.rs rename to modules/protocol/inspircd.rs diff --git a/src/proto/mod.rs b/modules/protocol/mod.rs similarity index 100% rename from src/proto/mod.rs rename to modules/protocol/mod.rs diff --git a/src/engine/mod.rs b/src/engine/mod.rs index 6f3ed06..37737de 100644 --- a/src/engine/mod.rs +++ b/src/engine/mod.rs @@ -542,7 +542,7 @@ impl RegLimiter { #[cfg(test)] mod tests { use super::*; - use crate::services::nickserv::NickServ; + use crate::nickserv::NickServ; fn plain(authzid: &[u8], authcid: &[u8], passwd: &[u8]) -> String { let mut payload = Vec::new(); @@ -934,7 +934,7 @@ mod tests { // only the founder can drop. #[test] fn chanserv_register_info_drop() { - use crate::services::chanserv::ChanServ; + use crate::chanserv::ChanServ; let path = std::env::temp_dir().join("fedserv-chanserv.jsonl"); let _ = std::fs::remove_file(&path); let mut db = Db::open(&path, "42S"); diff --git a/src/engine/scram.rs b/src/engine/scram.rs index 3554ca8..c468bd1 100644 --- a/src/engine/scram.rs +++ b/src/engine/scram.rs @@ -1,6 +1,5 @@ //! SCRAM (RFC 5802 / RFC 7677) server side for SASL SCRAM-SHA-256 and -//! SCRAM-SHA-512. The stored verifier is byte-compatible with the rest of the -//! stack (Anope m_apiauth / Django): `v=1,i=,s=,sk=,sv=` where +//! SCRAM-SHA-512. Stored verifier format `v=1,i=,s=,sk=,sv=` where //! //! SaltedPassword = Hi(password, salt, i) (PBKDF2, dklen = hash len) //! ClientKey = HMAC(SaltedPassword, "Client Key") diff --git a/src/gossip.rs b/src/gossip.rs index 6a7d988..e077184 100644 --- a/src/gossip.rs +++ b/src/gossip.rs @@ -263,7 +263,7 @@ async fn send(tx: &mpsc::Sender, msg: &Msg) -> Result<(), ()> { mod tests { use super::*; use crate::engine::db::Db; - use crate::services::nickserv::NickServ; + use crate::nickserv::NickServ; fn engine(origin: &str, tag: &str) -> (Shared, Outbound) { let path = std::env::temp_dir().join(format!("fedserv-gossip-{tag}.jsonl")); diff --git a/src/main.rs b/src/main.rs index 7ef8091..216d9aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,24 @@ +// Core lives in src/; pluggable modules live in ../modules/. mod config; mod engine; mod gossip; mod link; +#[path = "../modules/protocol/mod.rs"] mod proto; -mod services; +#[path = "../modules/nickserv/nickserv.rs"] +mod nickserv; +#[path = "../modules/chanserv/chanserv.rs"] +mod chanserv; use anyhow::Result; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; use tokio::sync::Mutex; +use chanserv::ChanServ; use engine::Engine; +use nickserv::NickServ; use proto::inspircd::InspIrcd; -use services::chanserv::ChanServ; -use services::nickserv::NickServ; #[tokio::main] async fn main() -> Result<()> { diff --git a/src/services/mod.rs b/src/services/mod.rs deleted file mode 100644 index 1459fce..0000000 --- a/src/services/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod chanserv; -pub mod nickserv;