hive-priv: replace json! with typed structs for account sidecar files
This commit is contained in:
parent
9f26c416c0
commit
fa658567db
3 changed files with 37 additions and 2 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1795,6 +1795,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"hive-priv-sock",
|
"hive-priv-sock",
|
||||||
"libc",
|
"libc",
|
||||||
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ workspace = true
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
hive-priv-sock.workspace = true
|
hive-priv-sock.workspace = true
|
||||||
libc.workspace = true
|
libc.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ use hive_priv_sock::{
|
||||||
NetworkIsolation, PAUSED_MARKER_FILE, PRIV_SOCK, PrivEvent, PrivRequest, PrivResponse,
|
NetworkIsolation, PAUSED_MARKER_FILE, PRIV_SOCK, PrivEvent, PrivRequest, PrivResponse,
|
||||||
PrivStream, PrivStreamLine, SIBLING_CONTAINERS,
|
PrivStream, PrivStreamLine, SIBLING_CONTAINERS,
|
||||||
};
|
};
|
||||||
|
use serde::Serialize;
|
||||||
use tokio::io::{AsyncWriteExt, BufReader};
|
use tokio::io::{AsyncWriteExt, BufReader};
|
||||||
use tokio::net::unix::OwnedWriteHalf;
|
use tokio::net::unix::OwnedWriteHalf;
|
||||||
use tokio::net::{UnixListener, UnixStream};
|
use tokio::net::{UnixListener, UnixStream};
|
||||||
|
|
@ -468,7 +469,10 @@ async fn exec(
|
||||||
// when both `account` and `homeserver` are present; the account
|
// when both `account` and `homeserver` are present; the account
|
||||||
// suffix is already validated above.
|
// suffix is already validated above.
|
||||||
if let (Some(a), Some(hs)) = (account, homeserver) {
|
if let (Some(a), Some(hs)) = (account, homeserver) {
|
||||||
let meta = serde_json::json!({ "homeserver": hs }).to_string();
|
let meta = serde_json::to_string(&MatrixAccountSidecar {
|
||||||
|
homeserver: hs.as_str(),
|
||||||
|
})
|
||||||
|
.context("serialize matrix account sidecar")?;
|
||||||
write_agent_state_file(agent_name, &format!("matrix-account-{a}.json"), &meta)?;
|
write_agent_state_file(agent_name, &format!("matrix-account-{a}.json"), &meta)?;
|
||||||
}
|
}
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
|
@ -497,7 +501,10 @@ async fn exec(
|
||||||
)?;
|
)?;
|
||||||
// Sidecar carries the base URL — there's no host-side nix config
|
// Sidecar carries the base URL — there's no host-side nix config
|
||||||
// for extra forges, so this is the only place it's persisted.
|
// for extra forges, so this is the only place it's persisted.
|
||||||
let meta = serde_json::json!({ "base_url": base_url }).to_string();
|
let meta = serde_json::to_string(&ForgeSidecar {
|
||||||
|
base_url: base_url.as_str(),
|
||||||
|
})
|
||||||
|
.context("serialize forge account sidecar")?;
|
||||||
write_agent_state_file(agent_name, &format!("forge-{label}.json"), &meta)?;
|
write_agent_state_file(agent_name, &format!("forge-{label}.json"), &meta)?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
@ -957,6 +964,32 @@ fn write_state_file_nofollow(dir: &Path, filename: &str, content: &str) -> Resul
|
||||||
Ok(file)
|
Ok(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sidecar written alongside an extra matrix account's token
|
||||||
|
/// (`matrix-account-<name>.json`) so `hive-matrix-mcp` can auto-discover
|
||||||
|
/// the account's homeserver without a static `matrixAccounts` config
|
||||||
|
/// entry. Read side: `hive-matrix-mcp/src/accounts.rs`'s
|
||||||
|
/// `read_account_homeserver` (deliberately reads via a bare
|
||||||
|
/// `serde_json::Value` rather than this shape — that side treats a
|
||||||
|
/// malformed/missing sidecar as "skip this account" rather than an
|
||||||
|
/// error, so it stays loosely typed; this side is the one place the
|
||||||
|
/// file is written, so it gets the precise shape).
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct MatrixAccountSidecar<'a> {
|
||||||
|
homeserver: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sidecar written alongside a dashboard-provisioned extra forge
|
||||||
|
/// account's token (`forge-<label>.json`) so `hive-forge` can resolve
|
||||||
|
/// the account's base URL. Read side: `hive-forge/src/client.rs`'s own
|
||||||
|
/// (separately defined, deserialize-only) `ForgeSidecar` — same field
|
||||||
|
/// name (`base_url`), no shared crate between `hive-priv` and
|
||||||
|
/// `hive-forge` to hang a common type off, so the two structs are
|
||||||
|
/// pinned to the same JSON key by convention, not by the compiler.
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct ForgeSidecar<'a> {
|
||||||
|
base_url: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
/// Shared helper for `WriteAgentForgeToken` and `WriteAgentMatrixToken`.
|
/// Shared helper for `WriteAgentForgeToken` and `WriteAgentMatrixToken`.
|
||||||
/// Writes `content` to `AGENT_STATE_ROOT/<agent_name>/state/<filename>`,
|
/// Writes `content` to `AGENT_STATE_ROOT/<agent_name>/state/<filename>`,
|
||||||
/// chowns to the agent user (derived from the state dir's existing owner),
|
/// chowns to the agent user (derived from the state dir's existing owner),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue