holochain_types 0.7.0-dev.28

Holochain common types
Documentation
//! Signals which can be emitted from within Holochain, out across an interface.
//! There are two main kinds of Signal: system-defined, and app-defined:
//! - App-defined signals are produced via the `emit_signal` host function.
//! - System-defined signals are produced in various places in the system

use crate::app::{InstalledAppId, UnrecoverableCellReason};
use crate::impl_from;
use holochain_serialized_bytes::prelude::*;
use holochain_zome_types::prelude::*;

/// A Signal is some information emitted from within Holochain out through
/// an Interface
#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes, PartialEq, Eq)]
#[serde(tag = "type", content = "value", rename_all = "snake_case")]
pub enum Signal {
    /// Signal from a Cell, generated by `emit_signal`
    App {
        /// The Cell from which the signal was emitted
        cell_id: CellId,
        /// The Zome from which the signal was emitted
        zome_name: ZomeName,
        /// The actual signal that was emitted
        signal: AppSignal,
    },
    /// A direct signal, sent with an app call to `SendDirectSignal`.
    AppDirect {
        /// The receiving `CellId`.
        cell_id: CellId,

        /// The payload sent by the remote agent.
        signal: Vec<u8>,
    },
    /// System-defined signals
    System(SystemSignal),
}

impl Signal {
    /// Parse from vec.
    pub fn try_from_vec(v: Vec<u8>) -> Result<Self, SerializedBytesError> {
        Self::try_from(SerializedBytes::from(UnsafeBytes::from(v)))
    }
}

/// A Signal which originates from within the Holochain system, as opposed to
/// from within a Cell
#[derive(Clone, Debug, Serialize, Deserialize, SerializedBytes, PartialEq, Eq)]
#[serde(tag = "type", content = "value", rename_all = "snake_case")]
pub enum SystemSignal {
    /// A countersigning session has successfully completed.
    SuccessfulCountersigning(EntryHash),
    /// A countersigning session has been abandoned.
    AbandonedCountersigning(EntryHash),
    /// A single cell within an app has finished restoring its source chain from the DHT.
    RestoreComplete {
        /// The cell that finished restoring.
        cell_id: CellId,
    },
    /// All cells of an app have finished restoring; the app is now Disabled(NeverStarted).
    AppRestoreComplete {
        /// The app that finished restoring.
        installed_app_id: InstalledAppId,
    },
    /// A cell's restore hit a permanent failure (e.g. validated ChainIntegrityWarrant). The whole
    /// app transitions to [`crate::app::AppStatus::Unrecoverable`] at the same moment.
    RestoreFailed {
        /// The cell that failed to restore.
        cell_id: CellId,
        /// Why the restore is unrecoverable.
        reason: UnrecoverableCellReason,
    },
}

impl_from! {
    SystemSignal => Signal, |s| { Self::System(s) },
}

/// The maximum size that Holochain will permit sending or receiving in a single direct signal.
pub const DIRECT_SIGNAL_MAX_SIZE: usize = 1024 * 1024;

/// Wrapper type for transmitting a signed direct signal over the network.
#[derive(Debug, Clone, Serialize, Deserialize, SerializedBytes)]
pub struct DirectSignal(pub Vec<u8>);

#[cfg(test)]
mod tests {
    use super::*;
    use crate::app::{UnrecoverableCellReason, WarrantSummary};
    use ::fixt::prelude::*;
    use holo_hash::fixt::*;

    #[test]
    fn restore_system_signals_serde_round_trip() {
        let cell_id = CellId::new(fixt!(DnaHash), fixt!(AgentPubKey));
        let summary = WarrantSummary {
            author: fixt!(AgentPubKey),
            warrantee: fixt!(AgentPubKey),
            timestamp: Timestamp::from_micros(1_000_000),
        };
        let reason = UnrecoverableCellReason::ChainForkWarrant(Box::new(summary));

        let signals: Vec<SystemSignal> = vec![
            SystemSignal::RestoreComplete {
                cell_id: cell_id.clone(),
            },
            SystemSignal::AppRestoreComplete {
                installed_app_id: "my_app".to_string(),
            },
            SystemSignal::RestoreFailed {
                cell_id: cell_id.clone(),
                reason: reason.clone(),
            },
        ];

        for signal in &signals {
            let json = serde_json::to_string(signal).unwrap();
            let recovered: SystemSignal = serde_json::from_str(&json).unwrap();
            assert_eq!(signal, &recovered);
        }
    }
}