appcore_api/http/state.rs
1// =============================================================================
2// #######
3// ### ### F: state.rs
4// ## ## ## ## P: AppCore-Runtime
5// ## ##
6// C: 2026/06/02 13:08:16 by dnettoRaw
7// ## ## ## ## U: 2026/06/04 11:51:27 by dnettoRaw
8// ########### S: 0.6.0
9// =============================================================================
10
11//! Shared HTTP runtime state and status metadata.
12
13use crate::ApiRouter;
14use appcore_core::{RuntimeController, RuntimeOperationalMode};
15use parking_lot::Mutex;
16use std::sync::atomic::AtomicU64;
17use std::sync::Arc;
18
19use super::auth::HttpCommandAuth;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22/// Runtime HTTP listener and request-size configuration.
23pub struct HttpApiConfig {
24 /// Interface or address to bind.
25 pub host: String,
26 /// TCP port to bind.
27 pub port: u16,
28 /// Whether the embedded listener should run.
29 pub enabled: bool,
30 /// Maximum accepted request body size in bytes.
31 pub max_payload_bytes: usize,
32}
33
34impl Default for HttpApiConfig {
35 fn default() -> Self {
36 Self {
37 host: "127.0.0.1".to_string(),
38 port: 8080,
39 enabled: false,
40 max_payload_bytes: 65_536,
41 }
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
46/// Non-sensitive Runtime facts exposed by health and status routes.
47pub struct RuntimeStaticInfo {
48 /// Application identity hosted by this process.
49 pub app_id: String,
50 /// Runtime node identity.
51 pub node_id: String,
52 /// Tenant isolation boundary.
53 pub tenant_id: String,
54 /// Cluster isolation boundary.
55 pub cluster_id: String,
56 /// Logical Core identity.
57 pub core_id: String,
58 /// Initial operational-mode label.
59 pub operation_mode: String,
60 /// Storage provider health label.
61 pub storage_status: String,
62 /// Whether required security material initialized successfully.
63 pub security_ok: bool,
64 /// Whether HTTP ingress is enabled.
65 pub api_enabled: bool,
66 /// Whether synchronization is enabled.
67 pub sync_enabled: bool,
68 /// Local synchronization role.
69 pub sync_role: String,
70 /// Number of records currently visible in the sync log.
71 pub sync_log_len: usize,
72 /// Optional sync-log path for local diagnostics.
73 pub sync_log_path: Option<String>,
74 /// Optional sync-checkpoint path for local diagnostics.
75 pub sync_checkpoint_path: Option<String>,
76 /// Configured peer addresses without credentials.
77 pub sync_peers: Vec<String>,
78 /// Whether DNS peer discovery is enabled.
79 pub sync_dns_enabled: bool,
80 /// Configured DNS peer seeds.
81 pub sync_dns_seeds: Vec<String>,
82 /// Default port applied to DNS seeds.
83 pub sync_dns_default_port: u16,
84 /// Idempotency retention window in milliseconds.
85 pub idempotency_ttl_ms: u64,
86 /// Optional idempotency-store path for local diagnostics.
87 pub idempotency_path: Option<String>,
88}
89
90#[derive(Clone)]
91pub(crate) struct HttpState {
92 pub(crate) static_info: RuntimeStaticInfo,
93 pub(crate) controller: Option<Arc<Mutex<RuntimeController>>>,
94 pub(crate) app_query_router: Option<Arc<Mutex<ApiRouter>>>,
95 pub(crate) sync_log: Option<Arc<dyn SyncLogView>>,
96 pub(crate) tick_counter: Option<Arc<AtomicU64>>,
97 pub(crate) operation_mode: Option<Arc<Mutex<RuntimeOperationalMode>>>,
98 pub(crate) command_policy: Option<Arc<dyn CommandCapabilityPolicy>>,
99 pub(crate) supervisor: Option<appcore_supervisor::Supervisor>,
100 pub(crate) auth: HttpCommandAuth,
101 pub(crate) max_payload_bytes: usize,
102 pub(crate) clock: Arc<dyn appcore_core::Clock>,
103}
104
105#[derive(Debug, Clone, PartialEq, Eq)]
106/// Stable reason a capability policy rejected a command.
107pub enum CommandCapabilityPolicyError {
108 /// The remote command has no declared capability descriptor.
109 CapabilityNotDeclared,
110 /// The capability requires an idempotency key.
111 MissingIdempotencyKey,
112 /// The capability requires service leadership.
113 RequiresLeader,
114 /// The applicable service lease has expired.
115 LeaseExpired,
116 /// The request uses an obsolete fencing epoch.
117 StaleEpoch,
118 /// Current operational policy permits reads only.
119 ReadOnly,
120 /// Provider-specific policy rejected the command.
121 Rejected(String),
122}
123
124/// Authorizes command execution against capability and leadership policy.
125pub trait CommandCapabilityPolicy: Send + Sync {
126 /// Authorizes a named command at `now_ms`.
127 fn authorize_command(
128 &self,
129 command_name: &str,
130 idempotency_key: Option<&str>,
131 now_ms: u64,
132 ) -> Result<(), CommandCapabilityPolicyError>;
133}
134
135/// Read-only synchronization-log metrics exposed to the HTTP host.
136pub trait SyncLogView: Send + Sync {
137 /// Returns the number of visible replication records.
138 fn len(&self) -> usize;
139
140 /// Reports whether no replication records are visible.
141 fn is_empty(&self) -> bool {
142 self.len() == 0
143 }
144}