trillium_websockets/
websocket_connection.rs1use crate::{Result, Role, WebSocketConfig};
2use async_tungstenite::{
3 WebSocketReceiver, WebSocketSender, WebSocketStream,
4 tungstenite::{self, Message},
5};
6use futures_lite::{Stream, StreamExt, future};
7use futures_sink::Sink;
8use std::{
9 fmt::Debug,
10 net::IpAddr,
11 pin::Pin,
12 sync::Arc,
13 task::{self, Poll},
14};
15use swansong::{Interrupt, Swansong};
16use trillium::{Headers, Method, Transport, TypeSet, Upgrade};
17use trillium_http::{HttpContext, type_set::entry::Entry};
18
19pub struct WebSocketConn {
28 request_headers: Headers,
29 path: String,
30 querystring: String,
31 method: Method,
32 state: TypeSet,
33 peer_ip: Option<IpAddr>,
34 context: Arc<HttpContext>,
35 sink: WebSocketSender<Box<dyn Transport>>,
36 stream: Option<WStream>,
37}
38
39impl Debug for WebSocketConn {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("WebSocketConn")
42 .field("request_headers", &self.request_headers)
43 .field("path", &self.path)
44 .field("querystring", &self.querystring)
45 .field("method", &self.method)
46 .field("state", &self.state)
47 .field("peer_ip", &self.peer_ip)
48 .field("context", &self.context)
49 .field("stream", &self.stream)
50 .finish_non_exhaustive()
51 }
52}
53
54impl WebSocketConn {
55 pub async fn send_string(&mut self, string: String) -> Result<()> {
57 self.send(Message::text(string)).await
58 }
59
60 pub async fn send_bytes(&mut self, bin: Vec<u8>) -> Result<()> {
62 self.send(Message::binary(bin)).await
63 }
64
65 #[cfg(feature = "json")]
66 pub async fn send_json(&mut self, json: &impl serde::Serialize) -> Result<()> {
69 self.send_string(serde_json::to_string(json)?).await
70 }
71
72 pub async fn send(&mut self, message: Message) -> Result<()> {
77 self.feed(message).await?;
78 self.flush().await
79 }
80
81 pub async fn feed(&mut self, message: Message) -> Result<()> {
88 future::poll_fn(|cx| Pin::new(&mut self.sink).poll_ready(cx)).await?;
89 Pin::new(&mut self.sink).start_send(message)?;
90 Ok(())
91 }
92
93 pub async fn flush(&mut self) -> Result<()> {
95 future::poll_fn(|cx| Pin::new(&mut self.sink).poll_flush(cx))
96 .await
97 .map_err(Into::into)
98 }
99
100 #[doc(hidden)]
105 pub async fn new(
106 upgrade: impl Into<Upgrade>,
107 config: Option<WebSocketConfig>,
108 role: Role,
109 ) -> Self {
110 let mut upgrade = upgrade.into();
111 let request_headers = upgrade.take_request_headers();
112 let path = upgrade.path().to_string();
113 let querystring = upgrade.querystring().to_string();
114 let method = upgrade.method();
115 let state = upgrade.take_state();
116 let context = upgrade.context().clone();
117 let peer_ip = upgrade.peer_ip();
118 let (buffer, transport) = upgrade.into_transport();
119
120 let wss = if buffer.is_empty() {
121 WebSocketStream::from_raw_socket(transport, role, config).await
122 } else {
123 WebSocketStream::from_partially_read(transport, buffer, role, config).await
124 };
125
126 let (sink, stream) = wss.split();
127 let stream = Some(WStream {
128 stream: context.swansong().interrupt(stream),
129 });
130
131 Self {
132 request_headers,
133 path,
134 querystring,
135 method,
136 state,
137 peer_ip,
138 sink,
139 stream,
140 context,
141 }
142 }
143
144 pub fn swansong(&self) -> Swansong {
146 self.context.swansong().clone()
147 }
148
149 pub async fn close(&mut self) -> Result<()> {
151 self.send(Message::Close(None)).await
152 }
153
154 pub fn headers(&self) -> &Headers {
156 &self.request_headers
157 }
158
159 pub fn peer_ip(&self) -> Option<IpAddr> {
161 self.peer_ip
162 }
163
164 pub fn set_peer_ip(&mut self, peer_ip: Option<IpAddr>) -> &mut Self {
166 self.peer_ip = peer_ip;
167 self
168 }
169
170 pub fn path(&self) -> &str {
173 &self.path
174 }
175
176 pub fn querystring(&self) -> &str {
179 &self.querystring
180 }
181
182 pub fn method(&self) -> Method {
184 self.method
185 }
186
187 pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {
192 self.state.get()
193 }
194
195 pub fn state_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
197 self.state.get_mut()
198 }
199
200 pub fn insert_state<T: Send + Sync + 'static>(&mut self, state: T) -> Option<T> {
204 self.state.insert(state)
205 }
206
207 pub fn state_entry<T: Send + Sync + 'static>(&mut self) -> Entry<'_, T> {
210 self.state.entry()
211 }
212
213 pub fn take_state<T: Send + Sync + 'static>(&mut self) -> Option<T> {
218 self.state.take()
219 }
220
221 pub(crate) fn poll_flush_sink(
222 &mut self,
223 cx: &mut task::Context<'_>,
224 ) -> Poll<std::result::Result<(), tungstenite::Error>> {
225 Pin::new(&mut self.sink).poll_flush(cx)
226 }
227
228 pub fn take_inbound_stream(&mut self) -> Option<impl Stream<Item = MessageResult> + use<>> {
230 self.stream.take()
231 }
232
233 pub fn inbound_stream(&mut self) -> Option<impl Stream<Item = MessageResult> + '_> {
235 self.stream.as_mut()
236 }
237}
238
239type MessageResult = std::result::Result<Message, tungstenite::Error>;
240
241pub struct WStream {
242 stream: Interrupt<WebSocketReceiver<Box<dyn Transport>>>,
243}
244
245impl Debug for WStream {
246 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
247 f.debug_struct("WStream").finish_non_exhaustive()
248 }
249}
250
251impl Stream for WStream {
252 type Item = MessageResult;
253
254 fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
255 self.stream.poll_next(cx)
256 }
257}
258
259impl AsMut<TypeSet> for WebSocketConn {
260 fn as_mut(&mut self) -> &mut TypeSet {
261 &mut self.state
262 }
263}
264
265impl AsRef<TypeSet> for WebSocketConn {
266 fn as_ref(&self) -> &TypeSet {
267 &self.state
268 }
269}
270
271impl Stream for WebSocketConn {
272 type Item = MessageResult;
273
274 fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
275 let this = &mut *self;
276 let poll = match this.stream.as_mut() {
277 Some(stream) => Pin::new(stream).poll_next(cx),
278 None => Poll::Ready(None),
279 };
280
281 if !matches!(poll, Poll::Ready(Some(_)))
285 && let Poll::Ready(Err(e)) = this.poll_flush_sink(cx)
286 {
287 log::debug!("websocket flush error: {e}");
288 }
289
290 poll
291 }
292}