Skip to main content
Notifications are generated by the TAPLE node to inform about important events in the system. These notifications identify the type of message and its content, allowing you to build reactive applications that respond to changes in the ledger.

Notification Enum

The Notification enum represents all possible notification types that can be emitted by a TAPLE node.
NewSubject
variant
Emitted when a new subject has been created in the ledger.Fields:
  • subject_id (String): The unique identifier of the newly created subject
Example:
Notification::NewSubject {
    subject_id: "JJhGN...".to_string(),
}
NewEvent
variant
Emitted when a new event has been successfully added to a subject’s chain.Fields:
  • sn (u64): The sequence number of the new event
  • subject_id (String): The unique identifier of the subject
Example:
Notification::NewEvent {
    sn: 1,
    subject_id: "JJhGN...".to_string(),
}
StateUpdated
variant
Emitted when a subject’s state has been synchronized or updated.Fields:
  • sn (u64): The sequence number of the event that updated the state
  • subject_id (String): The unique identifier of the subject
Example:
Notification::StateUpdated {
    sn: 5,
    subject_id: "JJhGN...".to_string(),
}
ApprovalReceived
variant
Emitted when an approval request has been received and is pending a response.Fields:
  • id (String): The unique identifier of the approval request
  • subject_id (String): The unique identifier of the subject requiring approval
  • sn (u64): The sequence number of the event pending approval
Example:
Notification::ApprovalReceived {
    id: "J7BgL...".to_string(),
    subject_id: "JJhGN...".to_string(),
    sn: 2,
}
ObsoletedApproval
variant
Emitted when an approval request has become obsolete, either because the governance version changed or the event was confirmed without the approval.Fields:
  • id (String): The unique identifier of the obsoleted approval request
  • subject_id (String): The unique identifier of the subject
  • sn (u64): The sequence number of the obsoleted event
Example:
Notification::ObsoletedApproval {
    id: "J7BgL...".to_string(),
    subject_id: "JJhGN...".to_string(),
    sn: 2,
}
UnrecoverableError
variant
Emitted when an unrecoverable error occurs in the node.Fields:
  • error (String): A description of the error that occurred
Example:
Notification::UnrecoverableError {
    error: "Database connection lost".to_string(),
}

Receiving Notifications

All notifications must be consumed to prevent blocking the node. If the notification buffer is full, the node will block until space becomes available. The TAPLE node provides multiple methods for handling notifications.

Method 1: Receive Individual Notifications

Use recv_notification() to consume notifications one by one while maintaining control of the execution flow:
use taple_core::{Node, Notification};

let (mut node, api) = Node::build(settings, database)?;

// Receive a single notification
if let Some(notification) = node.recv_notification().await {
    match notification {
        Notification::NewEvent { sn, subject_id } => {
            println!("New event {} for subject {}", sn, subject_id);
        }
        Notification::NewSubject { subject_id } => {
            println!("New subject created: {}", subject_id);
        }
        _ => {}
    }
}

Method 2: Handle All Notifications

Use handle_notifications() to process all notifications with a custom handler function. This method blocks until the shutdown signal is received:
use taple_core::{Node, Notification};

let (node, api) = Node::build(settings, database)?;

// Handle all notifications with a custom function
node.handle_notifications(|notification| {
    match notification {
        Notification::NewEvent { sn, subject_id } => {
            println!("Event {}: {}", sn, subject_id);
        }
        Notification::ApprovalReceived { id, subject_id, sn } => {
            println!("Approval needed: {} for event {} of {}", id, sn, subject_id);
        }
        _ => {}
    }
}).await;

Method 3: Drop All Notifications

Use drop_notifications() when you don’t need to process notifications:
use taple_core::Node;

let (node, api) = Node::build(settings, database)?;

// Discard all notifications
node.drop_notifications().await;

Complete Example

Here’s a complete example showing how to create a governance subject and handle the resulting notifications:
use taple_core::{
    crypto::{Ed25519KeyPair, KeyPair},
    identifier::{DigestIdentifier, KeyDerivator},
    request::{EventRequest, StartRequest},
    signature::{Signature, Signed},
    Node, Notification, Settings, MemoryManager,
};

#[tokio::main]
async fn main() {
    // Generate node key pair
    let node_key_pair = KeyPair::Ed25519(Ed25519KeyPair::from_seed(&[]));

    // Configure settings
    let mut settings = Settings::default();
    settings.node.secret_key = hex::encode(node_key_pair.secret_key_bytes());

    // Build node
    let (mut node, api) = Node::build(settings, MemoryManager::new())
        .expect("TAPLE node built");

    // Create a governance subject
    let governance_key = api
        .add_keys(KeyDerivator::Ed25519)
        .await
        .expect("Keys generated");

    let create_request = EventRequest::Create(StartRequest {
        governance_id: DigestIdentifier::default(),
        name: "".to_string(),
        namespace: "".to_string(),
        schema_id: "governance".to_string(),
        public_key: governance_key,
    });

    let signed_request = Signed::<EventRequest> {
        content: create_request.clone(),
        signature: Signature::new(&create_request, &node_key_pair).unwrap(),
    };

    // Send request
    let _request_id = api.external_request(signed_request).await.unwrap();

    // Wait for NewEvent notification
    let subject_id = if let Some(Notification::NewEvent { sn: _, subject_id }) = 
        node.recv_notification().await
    {
        println!("Received NewEvent notification for subject: {}", subject_id);
        subject_id
    } else {
        panic!("Expected NewEvent notification");
    };

    // Get the subject data
    let subject = api
        .get_subject(DigestIdentifier::from_str(&subject_id).unwrap())
        .await
        .expect("Subject retrieved");

    println!("Subject ID: {}", subject.subject_id.to_str());

    // Shutdown gracefully
    node.shutdown_gracefully().await;
}

Buffer Size

The notification channel has a buffer size of 1000 messages. If this buffer fills up, the node will block until notifications are consumed. Make sure to process notifications regularly to prevent blocking.

Thread Safety

The notification receiver (mpsc::Receiver<Notification>) is thread-safe and can be moved across async tasks. However, only one task can receive notifications at a time.

Build docs developers (and LLMs) love