1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Stateroom is a minimalist framework for developing stateful
//! [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) applications.
//!
//! Stateroom apps implement the [SimpleStateroomService] trait, which provides a way for the
//! app to hook into events when clients connect, disconnect, and send messages. Additionally,
//! Stateroom provides a simple mechanism for invoking events in the future with a timer.
//!
//! A simple chat server looks like this:
//!
//! ```
//! use stateroom::*;
//! use std::collections::HashMap;
//!
//! #[derive(Default)]
//! struct ChatServer {
//! /// The server's only state is a mapping of client ID to username.
//! client_to_nickname: HashMap<ClientId, String>,
//! }
//!
//! impl StateroomService for ChatServer {
//! /// This is called when a user connects.
//! fn connect(&mut self, client: ClientId, ctx: &impl StateroomContext) {
//! let username = format!("client{}", u32::from(client));
//!
//! // Send a welcome message.
//! ctx.send_message(client,
//! format!("Welcome to the chat! Your name is {}. \
//! Send /nick <username> to change it.",
//! &username));
//!
//! // Alert all other connected users to the new user.
//! ctx.send_message(MessageRecipient::Broadcast,
//! format!("{} has joined the chat", &username));
//! }
//!
//! /// This is called when a user disconnects.
//! fn disconnect(&mut self, client: ClientId, ctx: &impl StateroomContext) {
//! let username = self.client_to_nickname.remove(&client).unwrap();
//!
//! // Alert all remaining users that a user has left.
//! ctx.send_message(MessageRecipient::Broadcast,
//! format!("{} has left the chat", &username));
//! }
//!
//! /// This is called when a user sends a message.
//! fn message(&mut self, client: ClientId, message: MessagePayload, ctx: &impl StateroomContext) {
//! let Some(message) = message.text() else {
//! // Ignore binary messages.
//! return;
//! };
//!
//! if let Some(new_nick) = message.strip_prefix("/nick ") {
//! // This message is a /nick command, so process accordingly.
//! let old_nick = self.client_to_nickname.insert(client, new_nick.to_string()).unwrap();
//! ctx.send_message(MessageRecipient::Broadcast,
//! format!("{} is now known as {}", old_nick, new_nick));
//! } else {
//! // Broadcast the message to all connected users, prefixed by the username.
//! let username = self.client_to_nickname.get(&client).unwrap();
//! ctx.send_message(MessageRecipient::Broadcast,
//! format!("{}: {}", username, message));
//! }
//! }
//! }
use ;
pub use ClientId;
pub use MessageRecipient;
pub use ;
/// Provides an interface for a [StateroomService] instance to send messages back to its host environment.
/// A simplified interface for creating a [StateroomService] that can be exposed as a WebAssembly module.
///
/// See module documentation for usage examples.