Skip to main content

trillium_channels/
channel_handler.rs

1use crate::{ChannelConn, ChannelEvent};
2use std::future::Future;
3
4/// # Trait for you to implement in order to define a [`Channel`](crate::Channel).
5///
6/// ## Example
7///
8/// This simple example represents a simple chat server that's
9/// compatible with the [phoenix chat
10/// example](https://github.com/chrismccord/phoenix_chat_example) -- see
11/// channels/examples/channels.rs in this repo for a runnable example.
12///
13/// The only behavior we need to implement:
14///
15/// allow users to join the lobby channel
16/// broadcast to all users when a new user has joined the lobby
17/// broadcast all messages sent to the lobby channel to all users
18/// subscribed to the lobby channel.
19///
20/// ```
21/// use trillium_channels::{ChannelConn, ChannelEvent, ChannelHandler, channel};
22///
23/// struct ChatChannel;
24/// impl ChannelHandler for ChatChannel {
25///     async fn join_channel(&self, conn: ChannelConn<'_>, event: ChannelEvent) {
26///         match event.topic() {
27///             "rooms:lobby" => {
28///                 conn.allow_join(&event, &()).await;
29///                 conn.broadcast(("rooms:lobby", "user:entered"));
30///             }
31///
32///             _ => {}
33///         }
34///     }
35///
36///     async fn incoming_message(&self, conn: ChannelConn<'_>, event: ChannelEvent) {
37///         match (event.topic(), event.event()) {
38///             ("rooms:lobby", "new:msg") => conn.broadcast(event),
39///             _ => {}
40///         }
41///     }
42/// }
43///
44/// // fn main() {
45/// //    trillium_smol::run(channel(ChatChannel));
46/// // }
47/// ```
48#[allow(unused_variables)]
49pub trait ChannelHandler: Sized + Send + Sync + 'static {
50    /// `connect` is called once when each websocket client is connected. The default implementation
51    /// does nothing.
52    fn connect(&self, conn: ChannelConn<'_>) -> impl Future<Output = ()> + Send {
53        async {}
54    }
55
56    /// `join_channel` is called when a websocket client sends a
57    /// `phx_join` event. There is no default implementation to ensure
58    /// that you implement the appropriate access control logic for your
59    /// application. If you want clients to be able to connect to any
60    /// channel they request, use this definition:
61    ///
62    /// ```
63    /// # use trillium_channels::{ChannelEvent, ChannelConn, ChannelHandler};
64    /// # struct MyChannel; impl ChannelHandler for MyChannel {
65    /// async fn join_channel(&self, conn: ChannelConn<'_>, event: ChannelEvent) {
66    ///     conn.allow_join(&event, &()).await;
67    /// }
68    /// # }
69    /// ```
70    fn join_channel(
71        &self,
72        conn: ChannelConn<'_>,
73        event: ChannelEvent,
74    ) -> impl Future<Output = ()> + Send;
75
76    /// `leave_channel` is called when a websocket client sends a
77    /// `phx_leave` event. The default implementation is to allow the user
78    /// to leave that channel.
79    fn leave_channel(
80        &self,
81        conn: ChannelConn<'_>,
82        event: ChannelEvent,
83    ) -> impl Future<Output = ()> + Send {
84        async move { conn.allow_leave(&event, &()).await }
85    }
86
87    /// `incoming_message` is called once for each [`ChannelEvent`] sent
88    /// from a client. The default implementation does nothing.
89    fn incoming_message(
90        &self,
91        conn: ChannelConn<'_>,
92        event: ChannelEvent,
93    ) -> impl Future<Output = ()> + Send {
94        async {}
95    }
96
97    /// `disconnect` is called when the websocket client ceases to be
98    /// connected, either gracefully or abruptly.
99    fn disconnect(&self, conn: ChannelConn<'_>) -> impl Future<Output = ()> + Send {
100        async {}
101    }
102}
103
104impl ChannelHandler for () {
105    async fn join_channel(&self, _conn: ChannelConn<'_>, _event: ChannelEvent) {}
106}