ircv3_metadata_db: persist channel metadata across restart

This commit is contained in:
Jean Chevronnet 2026-08-09 07:25:42 +00:00
parent ef219bc98f
commit 5f3ae2123d
3 changed files with 49 additions and 0 deletions

View file

@ -73,6 +73,7 @@ impl Ircd {
) -> Ircd {
let mut server = Server::new(cfg, event_tx, conn_counter);
server.load_xlines(); // restore persisted bans (m_xline_db)
crate::modules::metadata::load(&mut server); // restore channel metadata (m_metadata_db)
Ircd {
server,
commands: command_table(),

View file

@ -160,6 +160,9 @@ impl Command for MetadataCmd {
}
}
}
if key.starts_with('#') {
save(s); // persist channel metadata (m_ircv3_metadata_db)
}
let setter = s.users.get(&uid).map(|u| u.prefix()).unwrap_or_default();
let note = match &value {
Some(v) => format!(":{setter} METADATA {disp} {mkey} * :{v}"),
@ -192,6 +195,9 @@ impl Command for MetadataCmd {
if let Some(st) = s.ext.get_mut::<MetaStore>() {
st.0.remove(&key);
}
if key.starts_with('#') {
save(s);
}
}
"SUB" | "UNSUB" => {} // all metadata is public here; subscriptions are a no-op
_ => {
@ -202,3 +208,44 @@ impl Command for MetadataCmd {
CmdResult::Ok
}
}
/// Where channel metadata is persisted (beside the config).
fn db_path(s: &Server) -> String {
format!("{}.metadata", s.conf_path)
}
/// Persist channel metadata (the `#`-keyed entries) so it survives a restart —
/// InspIRCd `m_ircv3_metadata_db`. Per-user metadata (`u<uid>`) is intentionally
/// not saved: uids don't persist across restarts.
pub fn save(s: &Server) {
let mut out = String::new();
if let Some(st) = s.ext.get::<MetaStore>() {
for (key, kv) in &st.0 {
if !key.starts_with('#') {
continue;
}
for (mk, v) in kv {
out.push_str(&format!("{key} {mk} {v}\n"));
}
}
}
let _ = std::fs::write(db_path(s), out);
}
/// Reload persisted channel metadata at startup.
pub fn load(s: &mut Server) {
let Ok(text) = std::fs::read_to_string(db_path(s)) else {
return;
};
let store = s.ext.get_or_insert_with::<MetaStore>(MetaStore::default);
for line in text.lines() {
let mut it = line.splitn(3, ' ');
if let (Some(key), Some(mk), Some(v)) = (it.next(), it.next(), it.next()) {
store
.0
.entry(key.to_string())
.or_default()
.insert(mk.to_string(), v.to_string());
}
}
}