Add ChanServ with channel registration
REGISTER/INFO/DROP with founder auth, stored as ChannelRegistered and ChannelDropped events so channel registrations replicate across nodes and compact like accounts. Registration requires an identified account; only the founder can drop.
This commit is contained in:
parent
64c6facd56
commit
89593ebeb4
5 changed files with 227 additions and 25 deletions
79
src/services/chanserv.rs
Normal file
79
src/services/chanserv.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
use crate::engine::db::{ChanError, Db};
|
||||
use crate::engine::service::{Sender, Service, ServiceCtx};
|
||||
|
||||
pub struct ChanServ {
|
||||
pub uid: String,
|
||||
}
|
||||
|
||||
impl Service for ChanServ {
|
||||
fn nick(&self) -> &str {
|
||||
"ChanServ"
|
||||
}
|
||||
fn uid(&self) -> &str {
|
||||
&self.uid
|
||||
}
|
||||
fn gecos(&self) -> &str {
|
||||
"Channel Services"
|
||||
}
|
||||
|
||||
fn on_command(&mut self, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: &mut Db) {
|
||||
let me = self.uid.as_str();
|
||||
match args.first().map(|s| s.to_ascii_uppercase()).as_deref() {
|
||||
Some("REGISTER") => {
|
||||
let Some(&chan) = args.get(1) else {
|
||||
ctx.notice(me, from.uid, "Syntax: REGISTER <#channel>");
|
||||
return;
|
||||
};
|
||||
if !chan.starts_with('#') {
|
||||
ctx.notice(me, from.uid, "Channel names start with #.");
|
||||
return;
|
||||
}
|
||||
// The founder is the account the sender is identified to.
|
||||
let Some(account) = from.account else {
|
||||
ctx.notice(me, from.uid, "You must be identified to register a channel.");
|
||||
return;
|
||||
};
|
||||
match db.register_channel(chan, account) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Channel \x02{chan}\x02 is now registered to \x02{account}\x02.")),
|
||||
Err(ChanError::Exists) => ctx.notice(me, from.uid, format!("\x02{chan}\x02 is already registered.")),
|
||||
Err(_) => ctx.notice(me, from.uid, "Registration failed, please try again later."),
|
||||
}
|
||||
}
|
||||
Some("INFO") => {
|
||||
let Some(&chan) = args.get(1) else {
|
||||
ctx.notice(me, from.uid, "Syntax: INFO <#channel>");
|
||||
return;
|
||||
};
|
||||
match db.channel(chan) {
|
||||
Some(info) => ctx.notice(me, from.uid, format!("\x02{}\x02 is registered to \x02{}\x02 (since {}).", info.name, info.founder, info.ts)),
|
||||
None => ctx.notice(me, from.uid, format!("\x02{chan}\x02 is not registered.")),
|
||||
}
|
||||
}
|
||||
Some("DROP") => {
|
||||
let Some(&chan) = args.get(1) else {
|
||||
ctx.notice(me, from.uid, "Syntax: DROP <#channel>");
|
||||
return;
|
||||
};
|
||||
// Read the founder, then drop, without holding the borrow across the mutation.
|
||||
let founder = match db.channel(chan) {
|
||||
Some(info) => info.founder.clone(),
|
||||
None => {
|
||||
ctx.notice(me, from.uid, format!("\x02{chan}\x02 is not registered."));
|
||||
return;
|
||||
}
|
||||
};
|
||||
if from.account != Some(founder.as_str()) {
|
||||
ctx.notice(me, from.uid, "Only the channel founder can drop it.");
|
||||
return;
|
||||
}
|
||||
match db.drop_channel(chan) {
|
||||
Ok(()) => ctx.notice(me, from.uid, format!("Channel \x02{chan}\x02 has been dropped.")),
|
||||
Err(_) => ctx.notice(me, from.uid, "Drop failed, please try again later."),
|
||||
}
|
||||
}
|
||||
Some("HELP") => ctx.notice(me, from.uid, "Commands: REGISTER <#channel>, INFO <#channel>, DROP <#channel>."),
|
||||
Some(other) => ctx.notice(me, from.uid, format!("Unknown command: {other}. Try HELP.")),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1,2 @@
|
|||
pub mod chanserv;
|
||||
pub mod nickserv;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue