//! Strategy resolver for the heartbeat path. The actual SQL lives in //! `Database::strategy_resolve_for` — this module exists to give the //! heartbeat handler a stable import surface and to centralize how a //! resolved strategy is converted into the wire-shape JSON the client //! expects (`strategy.config_options` + `strategy.extra` per //! CONSOLE_API.md §6.1). use crate::api::state::AppState; use crate::database::ResolvedStrategy; use serde_json::{json, Value}; /// Resolve and serialize a strategy for `peer_id`. Returns /// `(modified_at, strategy_value)` where `strategy_value` is the JSON object /// the heartbeat reply embeds under `strategy`. When no strategy applies, we /// return an empty `{config_options: {}, extra: {}}` and `modified_at = 0`. pub async fn resolve_for(state: &AppState, peer_id: &str) -> (i64, Value) { let resolved = state .db .strategy_resolve_for(peer_id) .await .unwrap_or_default(); serialize(&resolved) } fn serialize(r: &ResolvedStrategy) -> (i64, Value) { let cfg: Value = serde_json::from_str(&r.config_options_json).unwrap_or_else(|_| json!({})); let extra: Value = serde_json::from_str(&r.extra_json).unwrap_or_else(|_| json!({})); ( r.modified_at, json!({ "config_options": cfg, "extra": extra, }), ) }