supercode-interchange 0.4.18

Canonical, provider-neutral session interchange primitives for Supercode
Documentation
//! Delivery obligations (ยง2.6; Hermes `delivery_obligations`).

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::ontology::{Residue, SurfaceKey};

/// Something attached to an outbound message.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct Attachment {
    /// `image` | `file` | `video` | `audio`.
    pub kind: String,
    /// File name.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// MIME type.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub mime: Option<String>,
    /// Size in bytes.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub size: Option<u64>,
    /// A URL to fetch it from.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,
    /// A local path.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub path: Option<String>,
    /// Adapter data to re-fetch it.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub r#ref: Option<Value>,
}

/// What is delivered.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct OutboundContent {
    /// The text.
    pub text: String,
    /// Attachments.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub attachments: Option<Vec<Attachment>>,
    /// The message this replies to.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reply_to: Option<String>,
    /// `text` | `markdown`.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub format: Option<String>,
}

/// Delivery state; `sent` is Hermes's `delivered`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ObligationState {
    /// Not yet delivered.
    Pending,
    /// Delivered.
    Sent,
    /// Gave up.
    Failed,
    /// Dropped on purpose.
    Dropped,
}

impl ObligationState {
    /// Hermes's `delivery_obligations.state` word.
    pub fn hermes_word(self) -> &'static str {
        match self {
            Self::Pending => "pending",
            Self::Sent => "delivered",
            Self::Failed => "failed",
            Self::Dropped => "dropped",
        }
    }

    /// The state for a Hermes word (`sent` is accepted as `delivered`).
    pub fn from_hermes_word(word: &str) -> Option<Self> {
        Some(match word {
            "pending" => Self::Pending,
            "delivered" | "sent" => Self::Sent,
            "failed" => Self::Failed,
            "dropped" => Self::Dropped,
            _ => return None,
        })
    }
}

/// The platform's handle for what was sent.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct Posted {
    /// The platform message id.
    pub message_id: String,
}

/// Where an obligation came from.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ObligationSource {
    /// A conversation's turn.
    Turn {
        /// The surface, when recorded.
        #[serde(default, skip_serializing_if = "Option::is_none")]
        key: Option<SurfaceKey>,
    },
    /// A job fire.
    Fire {
        /// The fire.
        fire_id: String,
    },
    /// A webhook.
    Webhook {
        /// The subscription name.
        name: String,
    },
}

/// One delivery obligation.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct Obligation {
    /// The id.
    pub id: String,
    /// The surface it goes to.
    pub target: SurfaceKey,
    /// Hermes's `session_key` column, verbatim.
    #[serde(default)]
    pub session_key: Option<String>,
    /// What is delivered.
    pub content: OutboundContent,
    /// State.
    pub state: ObligationState,
    /// Attempts so far.
    #[serde(default)]
    pub attempts: u64,
    /// The last failure.
    #[serde(default)]
    pub last_error: Option<String>,
    /// Creation instant (Hermes: epoch seconds as text).
    pub created_at: String,
    /// Last transition instant.
    pub updated_at: String,
    /// When it was sent.
    #[serde(default)]
    pub delivered_at: Option<String>,
    /// The platform's handle for what was sent.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub posted: Option<Posted>,
    /// Where it came from.
    pub source: ObligationSource,
    /// Ledger columns the record does not model, verbatim.
    #[serde(default)]
    pub residue: Residue,
}