Skip to main content

clawdesk-channel

Defines the channel abstraction layer — the core Channel trait (Layer 0) plus optional Layer 1 capability traits. Also provides health checking, rate limiting, and registry infrastructure for managing multiple channels.

Dependencies

Internal: clawdesk-types

External: async-trait, thiserror, tracing, tokio

Modules

ModuleDescription
healthHealthCheck — periodic channel health monitoring
rate_limitRateLimiter — per-channel send rate enforcement
registryChannelRegistry — dynamic channel registration & lookup

Key Traits

/// Layer 0: Core channel interface (required)
#[async_trait]
pub trait Channel: Send + Sync {
fn id(&self) -> &ChannelId;
fn name(&self) -> &str;
async fn send(&self, session: &Session, message: &Message) -> Result<(), ChannelError>;
async fn receive(&self) -> Result<Option<Message>, ChannelError>;
}

/// Layer 1: Thread support
#[async_trait]
pub trait Threaded: Channel {
async fn reply_in_thread(&self, thread_id: &str, message: &Message) -> Result<(), ChannelError>;
async fn create_thread(&self, session: &Session, title: &str) -> Result<String, ChannelError>;
}

/// Layer 1: Real-time streaming
#[async_trait]
pub trait Streaming: Channel {
async fn stream_response(&self, session: &Session) -> Result<StreamHandle, ChannelError>;
}

/// Layer 1: Emoji reactions
#[async_trait]
pub trait Reactions: Channel {
async fn add_reaction(&self, message_id: &str, emoji: &str) -> Result<(), ChannelError>;
async fn remove_reaction(&self, message_id: &str, emoji: &str) -> Result<(), ChannelError>;
}

/// Layer 1: Group/room management
#[async_trait]
pub trait GroupManagement: Channel {
async fn list_groups(&self) -> Result<Vec<GroupInfo>, ChannelError>;
async fn join_group(&self, group_id: &str) -> Result<(), ChannelError>;
async fn leave_group(&self, group_id: &str) -> Result<(), ChannelError>;
}

/// Layer 1: User directory lookup
#[async_trait]
pub trait Directory: Channel {
async fn lookup_user(&self, query: &str) -> Result<Vec<UserInfo>, ChannelError>;
}

/// Layer 1: DM pairing
#[async_trait]
pub trait Pairing: Channel {
async fn pair(&self, user_id: &str) -> Result<Session, ChannelError>;
}

Registry

pub struct ChannelRegistry {
channels: HashMap<ChannelId, Box<dyn Channel>>,
}

impl ChannelRegistry {
pub fn register(&mut self, channel: Box<dyn Channel>) {
self.channels.insert(channel.id().clone(), channel);
}

pub fn get(&self, id: &ChannelId) -> Option<&dyn Channel> {
self.channels.get(id).map(|c| c.as_ref())
}

pub fn list(&self) -> Vec<&dyn Channel> {
self.channels.values().map(|c| c.as_ref()).collect()
}
}

Example Usage

use clawdesk_channel::{Channel, Threaded, ChannelRegistry};
use clawdesk_types::{ChannelId, Message, Session};

async fn send_reply(
registry: &ChannelRegistry,
channel_id: &ChannelId,
session: &Session,
message: &Message,
) -> Result<(), ChannelError> {
let channel = registry.get(channel_id)
.ok_or(ChannelError::NotFound(channel_id.to_string()))?;

channel.send(session, message).await
}
info

See Adding a Channel for a step-by-step guide to implementing a new channel.