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}