use mold_db::{MetadataDb, Settings, DEFAULT_PROFILE};
pub const SERVER_INSTANCE_ID_KEY: &str = "server.instance_id";
pub fn instance_id_key(port: u16) -> String {
format!("{SERVER_INSTANCE_ID_KEY}.{port}")
}
pub fn resolve_instance_id(db: Option<&MetadataDb>, port: u16) -> String {
if let Some(db) = db {
let settings = Settings::for_profile(db, DEFAULT_PROFILE);
let key = instance_id_key(port);
match settings.get_str(&key) {
Ok(Some(id)) if !id.trim().is_empty() => return id,
Ok(_) => {
let adopted = match settings.get_str(SERVER_INSTANCE_ID_KEY) {
Ok(Some(id)) if !id.trim().is_empty() => Some(id),
Ok(_) => None,
Err(e) => {
tracing::warn!("failed to read legacy server instance id: {e:#}");
None
}
};
let id = adopted
.clone()
.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
if let Err(e) = settings.set_str(&key, &id) {
tracing::warn!(
"failed to persist server instance id: {e:#} — using ephemeral id"
);
} else if adopted.is_some() {
if let Err(e) = settings.delete(SERVER_INSTANCE_ID_KEY) {
tracing::warn!("failed to retire legacy server instance id key: {e:#}");
}
}
return id;
}
Err(e) => {
tracing::warn!("failed to read server instance id: {e:#} — using ephemeral id");
}
}
}
uuid::Uuid::new_v4().to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn instance_id_persists_across_resolver_calls() {
let db = MetadataDb::open_in_memory().unwrap();
let first = resolve_instance_id(Some(&db), 7680);
let second = resolve_instance_id(Some(&db), 7680);
assert_eq!(first, second);
uuid::Uuid::parse_str(&first).expect("instance id must be a valid UUID");
}
#[test]
fn two_ports_on_one_db_get_distinct_ids() {
let db = MetadataDb::open_in_memory().unwrap();
let a = resolve_instance_id(Some(&db), 7680);
let b = resolve_instance_id(Some(&db), 7681);
assert_ne!(a, b);
assert_eq!(resolve_instance_id(Some(&db), 7680), a);
assert_eq!(resolve_instance_id(Some(&db), 7681), b);
}
#[test]
fn legacy_portless_id_is_adopted_by_the_first_port() {
let db = MetadataDb::open_in_memory().unwrap();
let settings = Settings::for_profile(&db, DEFAULT_PROFILE);
settings
.set_str(SERVER_INSTANCE_ID_KEY, "legacy-id-1234")
.unwrap();
let first = resolve_instance_id(Some(&db), 7680);
assert_eq!(first, "legacy-id-1234");
assert_eq!(
settings.get_str(&instance_id_key(7680)).unwrap().as_deref(),
Some("legacy-id-1234")
);
assert_eq!(settings.get_str(SERVER_INSTANCE_ID_KEY).unwrap(), None);
let second = resolve_instance_id(Some(&db), 7681);
assert_ne!(second, "legacy-id-1234");
}
#[test]
fn instance_id_is_stored_under_the_default_profile() {
let db = MetadataDb::open_in_memory().unwrap();
let id = resolve_instance_id(Some(&db), 7680);
let default_view = Settings::for_profile(&db, DEFAULT_PROFILE);
assert_eq!(
default_view
.get_str(&instance_id_key(7680))
.unwrap()
.as_deref(),
Some(id.as_str())
);
let other_view = Settings::for_profile(&db, "staging");
assert_eq!(other_view.get_str(&instance_id_key(7680)).unwrap(), None);
}
#[test]
fn instance_id_ephemeral_fallback_without_db() {
let id = resolve_instance_id(None, 7680);
uuid::Uuid::parse_str(&id).expect("ephemeral id must be a valid UUID");
assert_ne!(id, resolve_instance_id(None, 7680));
}
}