-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(dgw): Allow video-streamer to properly send code 1000 on stream
finishes
- Loading branch information
1 parent
f891342
commit dfe4cd9
Showing
4 changed files
with
107 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,91 @@ | ||
use std::{borrow::Cow, pin::Pin}; | ||
|
||
use axum::extract::ws::{self, WebSocket}; | ||
use futures::{SinkExt as _, StreamExt as _}; | ||
use futures::{sink::With, Sink, SinkExt as _, Stream, StreamExt as _}; | ||
use tokio::io::{AsyncRead, AsyncWrite}; | ||
use transport::CloseStream; | ||
|
||
pub fn websocket_compat(ws: WebSocket) -> impl AsyncRead + AsyncWrite + Unpin + Send + 'static { | ||
pub fn websocket_compat(ws: WebSocket) -> impl AsyncRead + AsyncWrite + CloseStream + Unpin + Send + 'static { | ||
let ws_compat = ws | ||
.map(|item| { | ||
item.map(|msg| match msg { | ||
ws::Message::Text(s) => transport::WsMessage::Payload(s.into_bytes()), | ||
ws::Message::Binary(data) => transport::WsMessage::Payload(data), | ||
ws::Message::Ping(_) | ws::Message::Pong(_) => transport::WsMessage::Ignored, | ||
ws::Message::Close(_) => transport::WsMessage::Close, | ||
}) | ||
}) | ||
.with(|item| futures::future::ready(Ok::<_, axum::Error>(ws::Message::Binary(item)))); | ||
|
||
transport::WsStream::new(ws_compat) | ||
.map(map_ws_message as fn(Result<ws::Message, axum::Error>) -> Result<transport::WsMessage, axum::Error>) | ||
.with(with_binary as fn(Vec<u8>) -> futures::future::Ready<Result<ws::Message, axum::Error>>); | ||
|
||
let res = transport::WsStream::new(CloseableWebSocket(ws_compat)); | ||
|
||
res | ||
} | ||
|
||
impl Stream for CloseableWebSocket { | ||
type Item = Result<transport::WsMessage, axum::Error>; | ||
|
||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Option<Self::Item>> { | ||
self.0.poll_next_unpin(cx) | ||
} | ||
} | ||
|
||
impl Sink<Vec<u8>> for CloseableWebSocket { | ||
type Error = axum::Error; | ||
|
||
fn poll_ready( | ||
mut self: Pin<&mut Self>, | ||
cx: &mut std::task::Context<'_>, | ||
) -> std::task::Poll<Result<(), Self::Error>> { | ||
self.0.poll_ready_unpin(cx) | ||
} | ||
|
||
fn start_send(mut self: Pin<&mut Self>, item: Vec<u8>) -> Result<(), Self::Error> { | ||
self.0.start_send_unpin(item) | ||
} | ||
|
||
fn poll_flush( | ||
mut self: Pin<&mut Self>, | ||
cx: &mut std::task::Context<'_>, | ||
) -> std::task::Poll<Result<(), Self::Error>> { | ||
self.0.poll_flush_unpin(cx) | ||
} | ||
|
||
fn poll_close( | ||
mut self: Pin<&mut Self>, | ||
cx: &mut std::task::Context<'_>, | ||
) -> std::task::Poll<Result<(), Self::Error>> { | ||
self.0.poll_close_unpin(cx) | ||
} | ||
} | ||
|
||
pub struct CloseableWebSocket(WithExplicit); | ||
|
||
impl CloseStream for CloseableWebSocket { | ||
async fn close_stream(&mut self) { | ||
warn!("Closing WebSocket stream"); | ||
let res = self | ||
.0 | ||
.get_mut() | ||
.send(ws::Message::Close(Some(ws::CloseFrame { | ||
code: 1000, | ||
reason: Cow::Borrowed("EOF"), | ||
}))) | ||
.await; | ||
warn!(?res, "WebSocket stream closed"); | ||
} | ||
} | ||
|
||
type WithExplicit = With< | ||
futures::stream::Map<WebSocket, fn(Result<ws::Message, axum::Error>) -> Result<transport::WsMessage, axum::Error>>, | ||
ws::Message, | ||
Vec<u8>, | ||
futures::future::Ready<Result<ws::Message, axum::Error>>, | ||
fn(Vec<u8>) -> futures::future::Ready<Result<ws::Message, axum::Error>>, | ||
>; | ||
|
||
fn map_ws_message(item: Result<ws::Message, axum::Error>) -> Result<transport::WsMessage, axum::Error> { | ||
item.map(|msg| match msg { | ||
ws::Message::Text(s) => transport::WsMessage::Payload(s.into_bytes()), | ||
ws::Message::Binary(data) => transport::WsMessage::Payload(data), | ||
ws::Message::Ping(_) | ws::Message::Pong(_) => transport::WsMessage::Ignored, | ||
ws::Message::Close(_) => transport::WsMessage::Close, | ||
}) | ||
} | ||
|
||
fn with_binary(item: Vec<u8>) -> futures::future::Ready<Result<ws::Message, axum::Error>> { | ||
futures::future::ready(Ok::<_, axum::Error>(ws::Message::Binary(item))) | ||
} |