use crate::envelope::{Envelope, MsgKind, Outcome, Principal};
use crate::event::{EventTier, LedgerState, Lifecycle, Presence};
use crate::lifecycle::{AgentPhase, DeliveryPhase, RecoveryPhase, ResourcePhase};
use chrono::{DateTime, Utc};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::Value;
fn is_zero(count: &u32) -> bool {
*count == 0
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct Receipt {
pub msg_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub op_id: Option<String>,
pub kind: MsgKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub task: Option<String>,
pub state: LedgerState,
pub enqueued_at: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct SessionProjection {
#[serde(alias = "public_lifecycle")]
pub lifecycle: Lifecycle,
pub agent: AgentPhase,
pub delivery: DeliveryPhase,
pub resource: ResourcePhase,
pub recovery: RecoveryPhase,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub outcome: Option<Outcome>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub observed: Option<Value>,
}
impl SessionProjection {
pub fn default_working() -> Self {
SessionProjection {
lifecycle: Lifecycle::Created,
agent: AgentPhase::Booting,
delivery: DeliveryPhase::NoIntent,
resource: ResourcePhase::Detached,
recovery: RecoveryPhase::NoRecovery,
outcome: None,
observed: None,
}
}
}
pub const DETAILS_MAX_BYTES: usize = 64 * 1024;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case", tag = "kind", content = "data")]
pub enum Report {
Ready {
task_id: String,
session_id: String,
generation: u64,
seq: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
cluster_ref: Option<String>,
},
Heartbeat {
task_id: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
session_id: String,
generation: u64,
seq: u64,
observed: Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
projection: Option<SessionProjection>,
#[serde(default, skip_serializing_if = "Option::is_none")]
cluster_ref: Option<String>,
},
Complete {
task_id: String,
outcome: Outcome,
#[serde(default, skip_serializing_if = "Option::is_none")]
head: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
details: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
files: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
reply_to: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
cluster_ref: Option<String>,
},
Fault {
#[serde(default, skip_serializing_if = "Option::is_none")]
task_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
session_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
generation: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
seq: Option<u64>,
kind: String,
reason: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
desired: Option<Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
observed: Option<Value>,
},
}
impl Report {
pub fn kind_name(&self) -> &'static str {
match self {
Report::Ready { .. } => "ready",
Report::Heartbeat { .. } => "heartbeat",
Report::Complete { .. } => "complete",
Report::Fault { .. } => "fault",
}
}
pub fn task_id(&self) -> Option<&str> {
match self {
Report::Ready { task_id, .. }
| Report::Heartbeat { task_id, .. }
| Report::Complete { task_id, .. } => Some(task_id),
Report::Fault { task_id, .. } => task_id.as_deref(),
}
}
pub fn version(&self) -> Option<(u64, u64)> {
match self {
Report::Ready {
generation, seq, ..
} => Some((*generation, *seq)),
Report::Heartbeat {
generation, seq, ..
} => Some((*generation, *seq)),
Report::Fault {
generation, seq, ..
} => Some((
(*generation).unwrap_or_default(),
(*seq).unwrap_or_default(),
)),
Report::Complete { .. } => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct PullArgs {
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
pub limit: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub hold_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub control_only: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct Delivery {
pub msg_id: String,
pub envelope: Box<Envelope>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct PullReply {
pub deliveries: Vec<Delivery>,
pub seq: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct AckArgs {
pub msg_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub op_id: Option<String>,
pub accepted: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct Subscribe {
pub since_seq: u64,
pub tiers: Vec<EventTier>,
pub kinds: Vec<String>,
pub roles: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct LedgerQuery {
#[serde(skip_serializing_if = "Option::is_none")]
pub task: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub op_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub msg_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<LedgerState>,
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<MsgKind>,
pub limit: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct QuerySessionsArgs {
#[serde(skip_serializing_if = "Option::is_none")]
pub task_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lifecycle: Option<Lifecycle>,
pub limit: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub fresh_wait_ms: Option<u64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum FreshRead {
Probed,
Offline,
Unanswered,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct SessionRow {
pub session_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub task_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
pub generation: u64,
pub seq: u64,
pub public_lifecycle: Lifecycle,
pub projection: SessionProjection,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub outcome: Option<Outcome>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_seen: Option<String>,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub heartbeat_stale: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub fresh: Option<FreshRead>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct LedgerEntry {
pub msg_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub op_id: Option<String>,
pub kind: MsgKind,
pub from: Principal,
pub to: Principal,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub task: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent_task: Option<String>,
pub hop: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub family: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub hop_budget: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub origin: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deadline: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub labels: Option<std::collections::BTreeMap<String, String>>,
pub attempt: u32,
pub state: LedgerState,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub out_head: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub body_json: Option<String>,
pub enqueued_at: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub acked_at: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct GhostSweep {
pub id: i64,
pub task_id: String,
pub role: String,
pub session_id: String,
pub generation: u64,
pub seq_before: u64,
pub seq_after: u64,
pub outcome: Outcome,
pub evidence: String,
pub swept_at: i64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct RoleRuntime {
#[serde(default)]
pub drive: Drive,
#[serde(default)]
pub command: Vec<String>,
}
impl Default for RoleRuntime {
fn default() -> Self {
Self {
drive: Drive::Plugin,
command: Vec::new(),
}
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum Drive {
#[default]
Plugin,
Acp,
Exec,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct RoleInfo {
pub name: String,
pub admin: bool,
pub max_sessions: u32,
#[serde(default)]
pub runtime: RoleRuntime,
pub spec_hash: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub prose: Option<String>,
pub state: Presence,
pub sessions: u32,
#[serde(default, skip_serializing_if = "is_zero")]
pub queued: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
#[serde(default)]
pub edges: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub aggregate: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct QueryRolesArgs {
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct QueryFaultsArgs {
#[serde(skip_serializing_if = "Option::is_none")]
pub role: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub task_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
pub open_only: bool,
pub limit: u32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct ControlArgs {
#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<String>,
pub op: crate::envelope::ControlOp,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct ByeArgs {
pub reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub drain_ms: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct PublishEventArgs {
pub class: String,
#[serde(default)]
pub payload: serde_json::Value,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct HandshakeArgs {
pub protocol: u16,
pub role: String,
pub key: String,
pub signature: String,
pub agent: String,
pub version: String,
pub aggregate: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub live_sessions: Vec<LiveSession>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct LiveSession {
pub session_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub task_id: Option<String>,
pub suspended: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case", tag = "op", content = "args")]
pub enum ClientOp {
Hello(HandshakeArgs),
Send(Box<Envelope>),
Pull(PullArgs),
Ack(AckArgs),
Report(Report),
Subscribe(Subscribe),
QueryLedger(LedgerQuery),
QuerySessions(QuerySessionsArgs),
QueryRoles(QueryRolesArgs),
QueryFaults(QueryFaultsArgs),
Control(ControlArgs),
PublishEvent(PublishEventArgs),
Bye(ByeArgs),
}
impl ClientOp {
pub fn name(&self) -> &'static str {
match self {
ClientOp::Hello(_) => "hello",
ClientOp::Send(_) => "send",
ClientOp::Pull(_) => "pull",
ClientOp::Ack(_) => "ack",
ClientOp::Report(_) => "report",
ClientOp::Subscribe(_) => "subscribe",
ClientOp::QueryLedger(_) => "query_ledger",
ClientOp::QuerySessions(_) => "query_sessions",
ClientOp::QueryRoles(_) => "query_roles",
ClientOp::QueryFaults(_) => "query_faults",
ClientOp::Control(_) => "control",
ClientOp::PublishEvent(_) => "publish_event",
ClientOp::Bye(_) => "bye",
}
}
pub fn is_pre_auth(self) -> bool {
matches!(self, ClientOp::Hello(_))
}
pub fn is_readonly(self) -> bool {
matches!(
self,
ClientOp::QueryLedger(_)
| ClientOp::QuerySessions(_)
| ClientOp::QueryRoles(_)
| ClientOp::QueryFaults(_)
| ClientOp::Subscribe(_)
| ClientOp::Pull(_)
)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct Welcome {
pub cluster: String,
pub server: String,
pub role: String,
pub admin: bool,
pub max_sessions: u32,
pub prose: String,
pub spec_hash: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub aggregate: Option<String>,
pub allowed_targets: Vec<String>,
pub allowed_senders: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub runtime: Option<RoleRuntime>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timeout_ready_ms: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timeout_idle_ms: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub intent_attempts: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub intent_backoff_ms: Option<Vec<u64>>,
pub seq: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case", tag = "op", content = "args")]
pub enum AdminOp {
Status(Value),
Roles(QueryRolesArgs),
Sessions(QuerySessionsArgs),
Ledger(LedgerQuery),
Faults(QueryFaultsArgs),
QueryGhostSweeps(usize),
Watch(Subscribe),
History(HistoryArgs),
SpecDiff(Value),
Reload(Value),
SpecGet(Value),
SpecApply(SpecApply),
Subscribe(Subscribe),
Send(AdminSend),
Control(AdminControl),
Report(AdminReport),
RepairInspect(RepairTarget),
RepairAdopt(RepairAdopt),
RepairRebind(RepairRebind),
RepairRetry(RepairTarget),
RepairFail(RepairFail),
RepairClose(RepairTarget),
RepairAck(RepairAck),
Shutdown(ShutdownArgs),
}
impl AdminOp {
pub fn name(&self) -> &'static str {
match self {
AdminOp::Status(_) => "status",
AdminOp::Roles(_) => "roles",
AdminOp::Sessions(_) => "sessions",
AdminOp::Ledger(_) => "ledger",
AdminOp::Faults(_) => "faults",
AdminOp::QueryGhostSweeps(_) => "query_ghost_sweeps",
AdminOp::Watch(_) => "watch",
AdminOp::History(_) => "history",
AdminOp::SpecDiff(_) => "spec_diff",
AdminOp::Reload(_) => "reload",
AdminOp::SpecGet(_) => "spec_get",
AdminOp::SpecApply(_) => "spec_apply",
AdminOp::Subscribe(_) => "subscribe",
AdminOp::Send(_) => "send",
AdminOp::Control(_) => "control",
AdminOp::Report(_) => "report",
AdminOp::RepairInspect(_) => "repair_inspect",
AdminOp::RepairAdopt(_) => "repair_adopt",
AdminOp::RepairRebind(_) => "repair_rebind",
AdminOp::RepairRetry(_) => "repair_retry",
AdminOp::RepairFail(_) => "repair_fail",
AdminOp::RepairClose(_) => "repair_close",
AdminOp::RepairAck(_) => "repair_ack",
AdminOp::Shutdown(_) => "shutdown",
}
}
pub fn is_readonly(self) -> bool {
matches!(
self,
AdminOp::Status(_)
| AdminOp::Roles(_)
| AdminOp::Sessions(_)
| AdminOp::Ledger(_)
| AdminOp::Faults(_)
| AdminOp::QueryGhostSweeps(_)
| AdminOp::Watch(_)
| AdminOp::History(_)
| AdminOp::SpecDiff(_)
| AdminOp::SpecGet(_)
| AdminOp::Subscribe(_)
| AdminOp::RepairInspect(_)
)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct SpecView {
pub path: String,
pub source_hash: String,
pub spec: Value,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct SpecApply {
pub base_hash: String,
pub edits: Vec<SpecEdit>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case", tag = "edit", content = "args")]
pub enum SpecEdit {
UpsertRole(UpsertRole),
RemoveRole(RemoveRole),
SetTargets(SetTargets),
SetSenders(SetSenders),
SetProse(SetProse),
SetSession(SetSession),
SetRuntime(SetRuntime),
}
impl SpecEdit {
pub fn name(&self) -> &'static str {
match self {
SpecEdit::UpsertRole(_) => "upsert_role",
SpecEdit::RemoveRole(_) => "remove_role",
SpecEdit::SetTargets(_) => "set_targets",
SpecEdit::SetSenders(_) => "set_senders",
SpecEdit::SetProse(_) => "set_prose",
SpecEdit::SetSession(_) => "set_session",
SpecEdit::SetRuntime(_) => "set_runtime",
}
}
pub fn role(&self) -> &str {
match self {
SpecEdit::UpsertRole(edit) => &edit.role,
SpecEdit::RemoveRole(edit) => &edit.role,
SpecEdit::SetTargets(edit) => &edit.role,
SpecEdit::SetSenders(edit) => &edit.role,
SpecEdit::SetProse(edit) => &edit.role,
SpecEdit::SetSession(edit) => &edit.role,
SpecEdit::SetRuntime(edit) => &edit.role,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct UpsertRole {
pub role: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prose: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub admin: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_sessions: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct RemoveRole {
pub role: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct SetTargets {
pub role: String,
pub targets: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct SetSenders {
pub role: String,
pub senders: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct SetProse {
pub role: String,
pub prose: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct SetSession {
pub role: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub ready_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub idle_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attempts: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub backoff_ms: Option<Vec<u64>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct SetRuntime {
pub role: String,
pub runtime: RoleRuntime,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct HistoryArgs {
pub since_seq: u64,
pub limit: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub task_id: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct AdminSend {
pub from: String,
pub envelope: Box<Envelope>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct AdminControl {
pub from: String,
pub op: crate::envelope::ControlOp,
#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct AdminReport {
pub from: String,
pub report: Box<Report>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct RepairTarget {
pub task_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct RepairAdopt {
pub task_id: String,
pub backend: String,
pub backend_ref: Value,
pub reason: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct RepairRebind {
pub task_id: String,
pub session_id: String,
pub backend: String,
pub backend_ref: Value,
pub reason: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct RepairFail {
pub task_id: String,
pub reason: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct RepairAck {
pub fault_id: i64,
pub reason: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct ShutdownArgs {
pub reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub grace_ms: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case", tag = "op", content = "args")]
pub enum GatewayOp {
Hello(HandshakeArgs),
RegisterChannel(RegisterChannelArgs),
Deliver(Delivery),
Health(HealthArgs),
Bye(ByeArgs),
}
impl GatewayOp {
pub fn name(&self) -> &'static str {
match self {
GatewayOp::Hello(_) => "hello",
GatewayOp::RegisterChannel(_) => "register_channel",
GatewayOp::Deliver(_) => "deliver",
GatewayOp::Health(_) => "health",
GatewayOp::Bye(_) => "bye",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct RegisterChannelArgs {
pub platform: String,
pub channel: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub conversations: Option<Vec<ConversationInfo>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct ConversationInfo {
pub conversation: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "snake_case", default)]
pub struct HealthArgs {
pub state: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
pub uptime_s: u64,
}