Add config file with MOTD support
Diff
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(-)
@@ -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]]
@@ -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"] }
@@ -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.
"""
@@ -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 @@
#[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<String>,
}
impl FromStr for Config {
type Err = std::io::Error;
fn from_str(path: &str) -> Result<Self, Self::Err> {
let contents = std::fs::read(path)?;
toml::from_slice(&contents)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
}
}
@@ -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();
@@ -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,
};
#[derive(Default)]
pub struct Server {
channels: HashMap<String, Addr<Channel>>,
clients: HashMap<Addr<Client>, InitiatedConnection>,
pub channels: HashMap<String, Addr<Channel>>,
pub clients: HashMap<Addr<Client>, InitiatedConnection>,
pub config: Config,
}
@@ -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,
});
}
@@ -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<String>,
}
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<Message> {
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 {