use std::path::PathBuf;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::{Map, Value};
use subc_protocol::Principal;
use crate::ops;
pub const ACTIVITY_LEDGER_CAPABILITY: &str = "activity-ledger/v1";
pub const ACTIVITY_KIND_FORBIDDEN: &str = "activity_kind_forbidden";
pub const ACTIVITY_ACTOR_UNKNOWN: &str = "activity_actor_unknown";
pub const ACTIVITY_RATE_LIMITED: &str = "activity_rate_limited";
pub const ACTIVITY_READ_FORBIDDEN: &str = "activity_read_forbidden";
pub const ACTIVITY_TOO_LARGE: &str = "activity_too_large";
pub const ACTIVITY_MALFORMED: &str = "activity_malformed";
pub const ACTIVITY_UNAVAILABLE: &str = "activity_unavailable";
pub const ACTIVITY_CURSOR_INCARNATION_MISMATCH: &str = "activity_cursor_incarnation_mismatch";
pub const ACTIVITY_CURSOR_TOO_OLD: &str = "activity_cursor_too_old";
pub const ACTIVITY_SUBSCRIBER_LAGGED: &str = "activity_subscriber_lagged";
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ActivityCursor {
pub daemon_incarnation: String,
pub seq: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct ActivitySubject {
#[serde(rename = "type")]
pub subject_type: String,
pub id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ActivityActor {
pub principal: Principal,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub scope_owner: Option<Principal>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub agent_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub run_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub flow_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub project_root: Option<PathBuf>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ActivityEntry {
pub seq: u64,
pub at_ms: u64,
pub daemon_incarnation: String,
pub module: String,
pub kind: String,
pub summary: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subject: Option<ActivitySubject>,
pub details: Map<String, Value>,
pub actor: ActivityActor,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct ActivityRoute {
pub channel: u16,
pub epoch: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct ActivityScope {
#[serde(rename = "ref")]
pub scope_ref: String,
pub epoch: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ActivityOn {
Route(ActivityRoute),
Scope(ActivityScope),
}
macro_rules! activity_body {
($(#[$doc:meta])* $name:ident, $op:path, $wire_name:literal,
$(#[$wire_meta:meta])* { $( $(#[$field_meta:meta])* pub $field:ident: $ty:ty, )* }) => {
$(#[$doc])*
#[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(tag = "op", rename = $wire_name)]
pub struct $name {
$( $(#[$field_meta])* pub $field: $ty, )*
}
impl $name {
pub const OP: &'static str = $op;
}
impl<'de> Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
#[derive(Deserialize)]
#[serde(tag = "op")]
$(#[$wire_meta])*
enum Wire {
#[serde(rename = $wire_name)]
Body { $( $(#[$field_meta])* $field: $ty, )* },
}
let Wire::Body { $( $field, )* } = Wire::deserialize(deserializer)?;
Ok(Self { $( $field, )* })
}
}
};
}
fn deserialize_details<'de, D>(deserializer: D) -> Result<Option<Map<String, Value>>, D::Error>
where
D: Deserializer<'de>,
{
Map::deserialize(deserializer).map(Some)
}
activity_body! {
ActivityRecordRequest, ops::ACTIVITY_RECORD, "activity.record",
#[serde(deny_unknown_fields)] {
pub kind: String,
pub summary: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subject: Option<ActivitySubject>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[serde(deserialize_with = "deserialize_details")]
pub details: Option<Map<String, Value>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub on: Option<ActivityOn>,
}
}
activity_body! {
ActivityRecordResponse, ops::ACTIVITY_RECORD, "activity.record", {
pub seq: u64,
}
}
activity_body! {
ActivityQueryRequest, ops::ACTIVITY_QUERY, "activity.query", {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub agent: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub project: Option<PathBuf>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub module: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub since_ms: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub until_ms: Option<u64>,
pub limit: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cursor: Option<u64>,
}
}
activity_body! {
ActivityQueryResponse, ops::ACTIVITY_QUERY, "activity.query", {
pub entries: Vec<ActivityEntry>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cursor: Option<u64>,
pub head: ActivityCursor,
}
}
activity_body! {
ActivitySubscribeRequest, ops::ACTIVITY_SUBSCRIBE, "activity.subscribe", {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub since: Option<ActivityCursor>,
}
}
activity_body! {
ActivitySubscribeResponse, ops::ACTIVITY_SUBSCRIBE, "activity.subscribe", {
pub entry: ActivityEntry,
}
}