From 51566d7610963b1eaf78b3f3938f95fa661dd93d Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sat, 07 Jan 2023 23:41:15 +0000 Subject: [PATCH] Add config file with MOTD support --- Cargo.lock | 25 +++++++++++++++++++++++++ Cargo.toml | 2 ++ config.toml | 11 +++++++++++ src/config.rs | 22 ++++++++++++++++++++++ src/main.rs | 13 ++++++++++--- src/server.rs | 15 +++++++++++++-- src/server/response.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 143 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2389c9..b9d2640 100644 --- a/Cargo.lock +++ a/Cargo.lock @@ -794,6 +794,20 @@ version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "serde_json" @@ -927,9 +941,11 @@ "futures", "irc-proto", "itertools", + "serde", "tokio", "tokio-stream", "tokio-util", + "toml", "tracing", "tracing-subscriber", ] @@ -988,6 +1004,15 @@ "pin-project-lite", "tokio", "tracing", +] + +[[package]] +name = "toml" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +dependencies = [ + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 625ecc4..1329604 100644 --- a/Cargo.toml +++ a/Cargo.toml @@ -12,8 +12,10 @@ chrono = "0.4" clap = { version = "4.0", features = ["cargo", "derive", "std", "suggestions", "color"] } futures = "0.3" +serde = { version = "1.0", features = ["derive"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } +toml = "0.5" tokio = { version = "1.23", features = ["full"] } tokio-stream = { version = "0.1", features = ["net"] } tokio-util = { version = "0.7", features = ["codec"] } diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..b5aac20 100644 --- /dev/null +++ a/config.toml @@ -1,0 +1,11 @@ +listen-address = "[::]:6667" + +motd = """ +Welcome to our IRC server + +This network does NOT condone or allow any illegal +activities. + +Any such occurrence of this activity will result +in immediate bans and removal from the network. +""" diff --git a/src/config.rs b/src/config.rs index 042fdef..90cf2f0 100644 --- a/src/config.rs +++ a/src/config.rs @@ -1,4 +1,7 @@ +use std::{net::SocketAddr, str::FromStr}; + use clap::Parser; +use serde::Deserialize; #[derive(Parser)] #[clap(version = clap::crate_version!(), author = clap::crate_authors!())] @@ -6,4 +9,23 @@ /// Turn debugging information on #[clap(short, long, action = clap::ArgAction::Count)] pub verbose: u8, + #[clap(short, long)] + pub config: Config, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "kebab-case")] +pub struct Config { + pub listen_address: SocketAddr, + pub motd: Option, +} + +impl FromStr for Config { + type Err = std::io::Error; + + fn from_str(path: &str) -> Result { + let contents = std::fs::read(path)?; + toml::from_slice(&contents) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e)) + } } diff --git a/src/main.rs b/src/main.rs index cc9072c..3723f92 100644 --- a/src/main.rs +++ a/src/main.rs @@ -44,12 +44,19 @@ .pretty(); subscriber.init(); - let server = Server::default().start(); - let listener = TcpListener::bind("127.0.0.1:6697").await?; + let listen_address = opts.config.listen_address; + let server = Server { + channels: HashMap::default(), + clients: HashMap::default(), + config: opts.config, + } + .start(); + let listener = TcpListener::bind(listen_address).await?; + actix_rt::spawn(start_tcp_acceptor_loop(listener, server)); - info!("Server listening on 127.0.0.1:6697"); + info!("Server listening on {}", listen_address); tokio::signal::ctrl_c().await?; System::current().stop(); diff --git a/src/server.rs b/src/server.rs index 50f0b24..2222d9e 100644 --- a/src/server.rs +++ a/src/server.rs @@ -11,19 +11,21 @@ use crate::{ channel::Channel, client::Client, + config::Config, connection::InitiatedConnection, messages::{ Broadcast, ChannelFetchTopic, ChannelJoin, ChannelList, ChannelMemberList, FetchClientByNick, ServerDisconnect, UserConnected, UserNickChange, }, + server::response::Motd, SERVER_NAME, }; /// The root actor for arbitration between clients and channels. -#[derive(Default)] pub struct Server { - channels: HashMap>, - clients: HashMap, InitiatedConnection>, + pub channels: HashMap>, + pub clients: HashMap, InitiatedConnection>, + pub config: Config, } /// Received when a user connects to the server, and sends them the server preamble @@ -72,6 +74,13 @@ prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())), command: Command::Response(response, arguments), }, + }); + } + + for message in Motd::new(self).into_messages(msg.connection.nick.clone()) { + msg.handle.do_send(Broadcast { + span: Span::current(), + message, }); } diff --git a/src/server/response.rs b/src/server/response.rs index 1e8180a..ac743d9 100644 --- a/src/server/response.rs +++ a/src/server/response.rs @@ -1,6 +1,66 @@ use irc_proto::{Command, Message, Prefix, Response}; -use crate::SERVER_NAME; +use crate::{server::Server, SERVER_NAME}; + +#[derive(Default)] +pub struct Motd { + pub motd: Option, +} + +impl Motd { + #[must_use] + pub fn new(server: &Server) -> Self { + Self { + motd: server.config.motd.clone(), + } + } + + #[must_use] + pub fn into_messages(self, for_user: String) -> Vec { + if let Some(motd) = self.motd { + let mut motd_messages = vec![Message { + tags: None, + prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())), + command: Command::Response( + Response::RPL_MOTDSTART, + vec![ + for_user.to_string(), + format!("- {SERVER_NAME} Message of the day -"), + ], + ), + }]; + + motd_messages.extend(motd.trim().split('\n').map(|v| Message { + tags: None, + prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())), + command: Command::Response( + Response::RPL_MOTD, + vec![for_user.to_string(), v.to_string()], + ), + })); + + motd_messages.push(Message { + tags: None, + prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())), + command: Command::Response( + Response::RPL_ENDOFMOTD, + vec![for_user, "End of /MOTD command.".to_string()], + ), + }); + + motd_messages + } else { + vec![Message { + tags: None, + prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())), + command: Command::Response( + Response::ERR_NOMOTD, + vec![for_user, "MOTD File is missing".to_string()], + ), + }] + } + } +} #[derive(Default)] pub struct ChannelList { -- rgit 0.1.3