Channel Subscription Management
Relevant source files
The following files were used as context for generating this wiki page:
The Channel Subscription Management system in the Tauri Centrifugo plugin provides the mechanism for clients to join and leave communication channels in real-time. This system handles the lifecycle of subscriptions, from initial connection requests to dynamic runtime changes and event-driven data reception. It acts as the bridge between the high-level JavaScript API and the underlying Rust tokio-centrifuge client implementation.
This module ensures that clients can efficiently receive publications (messages) targeted at specific topics. It manages internal state tracking to keep the frontend synchronized with the actual subscription status on the Centrifugo server. The architecture supports both bulk subscriptions during the initial connection phase and individual subscription modifications during an active session.
Subscription Architecture
The subscription management follows a layered approach where the frontend initiates requests that travel through Tauri's IPC layer to the Rust backend, which then interacts with the tokio-centrifuge client.
Core Components
- Centrifugo Core (
src/core.rs): Manages an internalHashMap<String, bool>of subscriptions to track which channels are active. It handles the creation of newSubscriptionobjects from the client. - Command Bridge (
src/commands.rs): Exposes asynchronous commands to the frontend for adding, removing, and querying subscriptions. - JavaScript API (
guest-js/index.ts): Provides typed wrappers for commands and higher-level helpers for combining subscriptions with message listeners.
Sources: src/core.rs:46-51, src/commands.rs:252-288, guest-js/index.ts:182-192
Subscription Workflow
The following diagram illustrates the flow of adding a new channel subscription from the frontend through the backend to the Centrifugo server.
The diagram shows the synchronous request flow to establish a subscription and the asynchronous event flow for data reception. Sources: src/core.rs:255-327, guest-js/index.ts:182-185
Subscription Lifecycle Management
Subscriptions can be managed at two distinct stages: during the initial connection and dynamically during the session.
Initial Subscriptions
When establishing a connection, the StartConfig structure allows providing a list of channels. The connect method iterates through these channels and establishes subscriptions immediately upon successful connection.
| Parameter | Type | Description |
|---|---|---|
channels | Vec<String> | List of channel names to join immediately. |
useProtobuf | bool | Protocol format for the connection and subscriptions. |
Sources: src/models.rs:47-60, src/core.rs:163-200
Dynamic Runtime Subscriptions
The plugin supports modifying subscriptions without reconnecting. This is handled via the add_subscription and remove_subscription commands.
// src/core.rs:255-327
pub async fn add_subscription<R: Runtime>(
&self,
app: AppHandle<R>,
channel: String,
) -> Result<()> {
// ... client state check ...
let subscription = client.new_subscription(&channel);
// ... setup event handlers ...
subscription.subscribe().await?;
// Update local cache
if let Ok(mut guard) = self.subscriptions.lock() {
guard.insert(channel, true);
}
Ok(())
}
Sources: src/core.rs:255-327, src/commands.rs:252-270
State Tracking and Synchronization
The Centrifugo struct maintains a thread-safe local cache of subscriptions. The get_subscriptions command returns a map of channel names to their boolean subscription status. If the client is detected as disconnected, the local subscription cache is automatically cleared to maintain accuracy.
Sources: src/core.rs:232-253, src/commands.rs:231-240
Event Emission and Handling
Subscription status changes and data reception are communicated back to the frontend through Tauri's event system.
Subscription Events
The core logic maps internal client callbacks to specific Tauri event strings.
| Tauri Event | Description | Data Structure |
|---|---|---|
centrifugo:subscribing | Attempting to join a channel | ChannelStatus { channel: string } |
centrifugo:subscribed | Successfully joined channel | ChannelStatus { channel: string } |
centrifugo:unsubscribed | Left a channel | ChannelStatus { channel: string } |
centrifugo:publication | Message received on a channel | PublicationData { channel, data } |
Sources: src/core.rs:168-198, src/models.rs:141-164, guest-js/index.ts:199-219
Frontend Listeners
The JavaScript API provides specific helper functions to listen for these events. These functions wrap the Tauri listen API and provide type-safe callbacks.
// guest-js/index.ts:246-258
export const onChannelMessage = async (channel: string, callback: (data: any) => void): Promise<UnlistenFn> =>
await onCentrifugoEvent('publication', (pubData: TauriEventWrapper<PublicationData>) => {
if (pubData.payload.channel === channel) {
try {
const decodedData = utils.decodeJson(pubData.payload.data)
callback(decodedData)
} catch (error) {
callback(pubData.payload.data)
}
}
})
Sources: guest-js/index.ts:246-258, README.md:139-166
Security and Permissions
Access to subscription management commands is controlled via Tauri's permission system. By default, these commands are blocked and must be explicitly enabled in the application's capability configuration.
Available Permissions
The plugin defines several permission scopes related to subscriptions in the ACL schema:
allow-add-subscription: Enables joining new channels.allow-remove-subscription: Enables leaving channels.allow-get-subscriptions: Enables querying current active channels.centrifugo:default: A pre-configured set that includes all subscription management commands.
Sources: permissions/schemas/schema.json:200-240, README.md:272-285
Summary
Channel Subscription Management is a core feature of the tauri-plugin-centrifugo that enables real-time, topic-based communication. By leveraging a thread-safe Rust core and a typed TypeScript API, the system provides reliable mechanisms for establishing initial subscriptions, managing dynamic channel updates, and handling incoming data via a robust event system. The implementation ensures state consistency between the frontend and the server while maintaining secure access through Tauri's permission model.