Compare commits

...

4 Commits

  1. 26
      Cargo.toml
  2. 48
      README.md
  3. 2
      examples/server-custom-accept.rs
  4. 26
      src/async_std.rs
  5. 10
      src/async_tls.rs
  6. 2
      src/compat.rs
  7. 10
      src/gio.rs
  8. 12
      src/handshake.rs
  9. 30
      src/lib.rs
  10. 10
      src/tokio.rs
  11. 4
      src/tokio/async_tls.rs
  12. 10
      src/tokio/dummy_tls.rs
  13. 8
      src/tokio/native_tls.rs
  14. 8
      src/tokio/openssl.rs
  15. 10
      src/tokio/rustls.rs
  16. 2
      tests/communication.rs

@ -1,12 +1,12 @@
[package] [package]
name = "async-tungstenite" name = "ng-async-tungstenite"
description = "Async binding for Tungstenite, the Lightweight stream-based WebSocket implementation" description = "fork of async-tungstenite for NextGraph.org"
categories = ["web-programming::websocket", "network-programming", "asynchronous", "concurrency"] categories = []
keywords = ["websocket", "io", "web", "tokio", "async-std"] keywords = ["websocket", "io", "web", "tokio", "async-std"]
authors = ["Sebastian Dröge <sebastian@centricular.com>"] authors = ["Sebastian Dröge <sebastian@centricular.com>", "Niko PLP <niko@nextgraph.org>"]
license = "MIT" license = "MIT"
homepage = "https://github.com/sdroege/async-tungstenite" homepage = "https://git.nextgraph.org/NextGraph/async-tungstenite"
repository = "https://github.com/sdroege/async-tungstenite" repository = "https://git.nextgraph.org/NextGraph/async-tungstenite"
documentation = "https://docs.rs/async-tungstenite" documentation = "https://docs.rs/async-tungstenite"
version = "0.22.2" version = "0.22.2"
edition = "2018" edition = "2018"
@ -16,20 +16,20 @@ rust-version = "1.64"
[features] [features]
default = ["handshake"] default = ["handshake"]
handshake = ["tungstenite/handshake"] handshake = ["ng-tungstenite/handshake"]
async-std-runtime = ["async-std", "handshake"] async-std-runtime = ["async-std", "handshake"]
tokio-runtime = ["tokio", "handshake"] tokio-runtime = ["tokio", "handshake"]
gio-runtime = ["gio", "glib", "handshake"] gio-runtime = ["gio", "glib", "handshake"]
async-tls = ["real-async-tls", "handshake"] async-tls = ["real-async-tls", "handshake"]
async-native-tls = ["async-std-runtime", "real-async-native-tls", "tungstenite/native-tls"] async-native-tls = ["async-std-runtime", "real-async-native-tls", "ng-tungstenite/native-tls"]
tokio-native-tls = ["tokio-runtime", "real-tokio-native-tls", "real-native-tls", "tungstenite/native-tls"] tokio-native-tls = ["tokio-runtime", "real-tokio-native-tls", "real-native-tls", "ng-tungstenite/native-tls"]
tokio-rustls-manual-roots = ["__rustls-tls"] tokio-rustls-manual-roots = ["__rustls-tls"]
tokio-rustls-webpki-roots = ["__rustls-tls", "webpki-roots"] tokio-rustls-webpki-roots = ["__rustls-tls", "webpki-roots"]
tokio-rustls-native-certs = ["__rustls-tls", "rustls-native-certs"] tokio-rustls-native-certs = ["__rustls-tls", "rustls-native-certs"]
tokio-openssl = ["tokio-runtime", "real-tokio-openssl", "openssl"] tokio-openssl = ["tokio-runtime", "real-tokio-openssl", "openssl"]
verbose-logging = [] verbose-logging = []
__rustls-tls = ["tokio-runtime", "real-tokio-rustls", "tungstenite/__rustls-tls"] __rustls-tls = ["tokio-runtime", "real-tokio-rustls", "ng-tungstenite/__rustls-tls"]
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["async-std-runtime", "tokio-runtime", "gio-runtime", "async-tls", "async-native-tls", "tokio-native-tls"] features = ["async-std-runtime", "tokio-runtime", "gio-runtime", "async-tls", "async-native-tls", "tokio-native-tls"]
@ -40,9 +40,11 @@ futures-util = { version = "0.3", default-features = false, features = ["sink",
futures-io = { version = "0.3", default-features = false, features = ["std"] } futures-io = { version = "0.3", default-features = false, features = ["std"] }
pin-project-lite = "0.2" pin-project-lite = "0.2"
[dependencies.tungstenite] [dependencies.ng-tungstenite]
version = "0.19" git = "https://git.nextgraph.org/NextGraph/tungstenite-rs.git"
branch = "nextgraph"
default-features = false default-features = false
version = "0.19.0"
[dependencies.async-std] [dependencies.async-std]
optional = true optional = true

@ -1,4 +1,6 @@
# async-tungstenite # ng-async-tungstenite
fork of https://github.com/sdroege/async-tungstenite for the needs of NextGraph.org
Asynchronous WebSockets for [async-std](https://async.rs), Asynchronous WebSockets for [async-std](https://async.rs),
[tokio](https://tokio.rs), [gio](https://gtk-rs.org) and any `std` [tokio](https://tokio.rs), [gio](https://gtk-rs.org) and any `std`
@ -31,28 +33,28 @@ can use it with non-blocking/asynchronous `TcpStream`s from and couple it
together with other crates from the async stack. In addition, optional together with other crates from the async stack. In addition, optional
integration with various other crates can be enabled via feature flags integration with various other crates can be enabled via feature flags
* `async-tls`: Enables the `async_tls` module, which provides integration - `async-tls`: Enables the `async_tls` module, which provides integration
with the [async-tls](https://crates.io/crates/async-tls) TLS stack and can with the [async-tls](https://crates.io/crates/async-tls) TLS stack and can
be used independent of any async runtime. be used independent of any async runtime.
* `async-std-runtime`: Enables the `async_std` module, which provides - `async-std-runtime`: Enables the `async_std` module, which provides
integration with the [async-std](https://async.rs) runtime. integration with the [async-std](https://async.rs) runtime.
* `async-native-tls`: Enables the additional functions in the `async_std` - `async-native-tls`: Enables the additional functions in the `async_std`
module to implement TLS via module to implement TLS via
[async-native-tls](https://crates.io/crates/async-native-tls). [async-native-tls](https://crates.io/crates/async-native-tls).
* `tokio-runtime`: Enables the `tokio` module, which provides integration - `tokio-runtime`: Enables the `tokio` module, which provides integration
with the [tokio](https://tokio.rs) runtime. with the [tokio](https://tokio.rs) runtime.
* `tokio-native-tls`: Enables the additional functions in the `tokio` module to - `tokio-native-tls`: Enables the additional functions in the `tokio` module to
implement TLS via [tokio-native-tls](https://crates.io/crates/tokio-native-tls). implement TLS via [tokio-native-tls](https://crates.io/crates/tokio-native-tls).
* `tokio-rustls-native-certs`: Enables the additional functions in the `tokio` - `tokio-rustls-native-certs`: Enables the additional functions in the `tokio`
module to implement TLS via [tokio-rustls](https://crates.io/crates/tokio-rustls) module to implement TLS via [tokio-rustls](https://crates.io/crates/tokio-rustls)
and uses native system certificates found with and uses native system certificates found with
[rustls-native-certs](https://github.com/rustls/rustls-native-certs). [rustls-native-certs](https://github.com/rustls/rustls-native-certs).
* `tokio-rustls-webpki-roots`: Enables the additional functions in the `tokio` - `tokio-rustls-webpki-roots`: Enables the additional functions in the `tokio`
module to implement TLS via [tokio-rustls](https://crates.io/crates/tokio-rustls) module to implement TLS via [tokio-rustls](https://crates.io/crates/tokio-rustls)
and uses the certificates [webpki-roots](https://github.com/rustls/webpki-roots) and uses the certificates [webpki-roots](https://github.com/rustls/webpki-roots)
provides. provides.
* `gio-runtime`: Enables the `gio` module, which provides integration with - `gio-runtime`: Enables the `gio` module, which provides integration with
the [gio](https://gtk-rs.org) runtime. the [gio](https://gtk-rs.org) runtime.
## Messages vs Streaming ## Messages vs Streaming

@ -40,7 +40,7 @@ use futures_channel::mpsc::{unbounded, UnboundedSender};
use futures_util::{future, pin_mut, stream::TryStreamExt, StreamExt}; use futures_util::{future, pin_mut, stream::TryStreamExt, StreamExt};
use async_tungstenite::{tokio::TokioAdapter, WebSocketStream}; use async_tungstenite::{tokio::TokioAdapter, WebSocketStream};
use tungstenite::{ use ng_tungstenite::{
handshake::derive_accept_key, handshake::derive_accept_key,
protocol::{Message, Role}, protocol::{Message, Role},
}; };

@ -1,8 +1,8 @@
//! `async-std` integration. //! `async-std` integration.
use tungstenite::client::IntoClientRequest; use ng_tungstenite::client::IntoClientRequest;
use tungstenite::handshake::client::{Request, Response}; use ng_tungstenite::handshake::client::{Request, Response};
use tungstenite::protocol::WebSocketConfig; use ng_tungstenite::protocol::WebSocketConfig;
use tungstenite::Error; use ng_tungstenite::Error;
use async_std::net::TcpStream; use async_std::net::TcpStream;
@ -17,10 +17,10 @@ pub(crate) mod async_native_tls {
use async_native_tls::TlsStream; use async_native_tls::TlsStream;
use real_async_native_tls as async_native_tls; use real_async_native_tls as async_native_tls;
use tungstenite::client::uri_mode; use ng_tungstenite::client::uri_mode;
use tungstenite::handshake::client::Request; use ng_tungstenite::handshake::client::Request;
use tungstenite::stream::Mode; use ng_tungstenite::stream::Mode;
use tungstenite::Error; use ng_tungstenite::Error;
use futures_io::{AsyncRead, AsyncWrite}; use futures_io::{AsyncRead, AsyncWrite};
@ -95,10 +95,10 @@ pub(crate) mod async_native_tls {
pub(crate) mod dummy_tls { pub(crate) mod dummy_tls {
use futures_io::{AsyncRead, AsyncWrite}; use futures_io::{AsyncRead, AsyncWrite};
use tungstenite::client::{uri_mode, IntoClientRequest}; use ng_tungstenite::client::{uri_mode, IntoClientRequest};
use tungstenite::handshake::client::Request; use ng_tungstenite::handshake::client::Request;
use tungstenite::stream::Mode; use ng_tungstenite::stream::Mode;
use tungstenite::Error; use ng_tungstenite::Error;
use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream}; use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream};
@ -117,7 +117,7 @@ pub(crate) mod dummy_tls {
match mode { match mode {
Mode::Plain => Ok(socket), Mode::Plain => Ok(socket),
Mode::Tls => Err(Error::Url( Mode::Tls => Err(Error::Url(
tungstenite::error::UrlError::TlsFeatureNotEnabled, ng_tungstenite::error::UrlError::TlsFeatureNotEnabled,
)), )),
} }
} }

@ -1,8 +1,8 @@
//! `async-tls` integration. //! `async-tls` integration.
use tungstenite::client::{uri_mode, IntoClientRequest}; use ng_tungstenite::client::{uri_mode, IntoClientRequest};
use tungstenite::handshake::client::{Request, Response}; use ng_tungstenite::handshake::client::{Request, Response};
use tungstenite::protocol::WebSocketConfig; use ng_tungstenite::protocol::WebSocketConfig;
use tungstenite::Error; use ng_tungstenite::Error;
use futures_io::{AsyncRead, AsyncWrite}; use futures_io::{AsyncRead, AsyncWrite};
@ -12,7 +12,7 @@ use async_tls::client::TlsStream;
use async_tls::TlsConnector as AsyncTlsConnector; use async_tls::TlsConnector as AsyncTlsConnector;
use real_async_tls as async_tls; use real_async_tls as async_tls;
use tungstenite::stream::Mode; use ng_tungstenite::stream::Mode;
use crate::domain; use crate::domain;
use crate::stream::Stream as StreamSwitcher; use crate::stream::Stream as StreamSwitcher;

@ -6,8 +6,8 @@ use std::task::{Context, Poll};
use futures_io::{AsyncRead, AsyncWrite}; use futures_io::{AsyncRead, AsyncWrite};
use futures_util::task; use futures_util::task;
use ng_tungstenite::Error as WsError;
use std::sync::Arc; use std::sync::Arc;
use tungstenite::Error as WsError;
pub(crate) enum ContextWaker { pub(crate) enum ContextWaker {
Read, Read,

@ -1,5 +1,5 @@
//! `gio` integration. //! `gio` integration.
use tungstenite::Error; use ng_tungstenite::Error;
use std::io; use std::io;
@ -7,10 +7,10 @@ use gio::prelude::*;
use futures_io::{AsyncRead, AsyncWrite}; use futures_io::{AsyncRead, AsyncWrite};
use tungstenite::client::{uri_mode, IntoClientRequest}; use ng_tungstenite::client::{uri_mode, IntoClientRequest};
use tungstenite::handshake::client::Request; use ng_tungstenite::handshake::client::Request;
use tungstenite::handshake::server::{Callback, NoCallback}; use ng_tungstenite::handshake::server::{Callback, NoCallback};
use tungstenite::stream::Mode; use ng_tungstenite::stream::Mode;
use crate::{client_async_with_config, domain, port, Response, WebSocketConfig, WebSocketStream}; use crate::{client_async_with_config, domain, port, Response, WebSocketConfig, WebSocketStream};

@ -5,19 +5,19 @@ use crate::WebSocketStream;
use futures_io::{AsyncRead, AsyncWrite}; use futures_io::{AsyncRead, AsyncWrite};
#[allow(unused_imports)] #[allow(unused_imports)]
use log::*; use log::*;
use std::future::Future; use ng_tungstenite::WebSocket;
use std::io::{Read, Write};
use std::pin::Pin;
use std::task::{Context, Poll};
use tungstenite::WebSocket;
#[cfg(feature = "handshake")] #[cfg(feature = "handshake")]
use tungstenite::{ use ng_tungstenite::{
handshake::{ handshake::{
client::Response, server::Callback, HandshakeError as Error, HandshakeRole, client::Response, server::Callback, HandshakeError as Error, HandshakeRole,
MidHandshake as WsHandshake, MidHandshake as WsHandshake,
}, },
ClientHandshake, ServerHandshake, ClientHandshake, ServerHandshake,
}; };
use std::future::Future;
use std::io::{Read, Write};
use std::pin::Pin;
use std::task::{Context, Poll};
pub(crate) async fn without_handshake<F, S>(stream: S, f: F) -> WebSocketStream<S> pub(crate) async fn without_handshake<F, S>(stream: S, f: F) -> WebSocketStream<S>
where where

@ -42,7 +42,7 @@
unused_import_braces unused_import_braces
)] )]
pub use tungstenite; pub use ng_tungstenite as tungstenite;
mod compat; mod compat;
mod handshake; mod handshake;
@ -71,7 +71,7 @@ use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
#[cfg(feature = "handshake")] #[cfg(feature = "handshake")]
use tungstenite::{ use ng_tungstenite::{
client::IntoClientRequest, client::IntoClientRequest,
handshake::{ handshake::{
client::{ClientHandshake, Response}, client::{ClientHandshake, Response},
@ -79,7 +79,7 @@ use tungstenite::{
HandshakeError, HandshakeError,
}, },
}; };
use tungstenite::{ use ng_tungstenite::{
error::Error as WsError, error::Error as WsError,
protocol::{Message, Role, WebSocket, WebSocketConfig}, protocol::{Message, Role, WebSocket, WebSocketConfig},
}; };
@ -93,7 +93,7 @@ pub mod gio;
#[cfg(feature = "tokio-runtime")] #[cfg(feature = "tokio-runtime")]
pub mod tokio; pub mod tokio;
use tungstenite::protocol::CloseFrame; use ng_tungstenite::protocol::CloseFrame;
/// Creates a WebSocket handshake from a request and a stream. /// Creates a WebSocket handshake from a request and a stream.
/// For convenience, the user may call this with a url string, a URL, /// For convenience, the user may call this with a url string, a URL,
@ -204,7 +204,7 @@ where
C: Callback + Unpin, C: Callback + Unpin,
{ {
let f = handshake::server_handshake(stream, move |allow_std| { let f = handshake::server_handshake(stream, move |allow_std| {
tungstenite::accept_hdr_with_config(allow_std, callback, config) ng_tungstenite::accept_hdr_with_config(allow_std, callback, config)
}); });
f.await.map_err(|e| match e { f.await.map_err(|e| match e {
HandshakeError::Failure(e) => e, HandshakeError::Failure(e) => e,
@ -436,8 +436,8 @@ where
/// Get a domain from an URL. /// Get a domain from an URL.
#[inline] #[inline]
pub(crate) fn domain( pub(crate) fn domain(
request: &tungstenite::handshake::client::Request, request: &ng_tungstenite::handshake::client::Request,
) -> Result<String, tungstenite::Error> { ) -> Result<String, ng_tungstenite::Error> {
request request
.uri() .uri()
.host() .host()
@ -455,8 +455,8 @@ pub(crate) fn domain(
host.to_owned() host.to_owned()
}) })
.ok_or(tungstenite::Error::Url( .ok_or(ng_tungstenite::Error::Url(
tungstenite::error::UrlError::NoHostName, ng_tungstenite::error::UrlError::NoHostName,
)) ))
} }
@ -468,8 +468,8 @@ pub(crate) fn domain(
/// Get the port from an URL. /// Get the port from an URL.
#[inline] #[inline]
pub(crate) fn port( pub(crate) fn port(
request: &tungstenite::handshake::client::Request, request: &ng_tungstenite::handshake::client::Request,
) -> Result<u16, tungstenite::Error> { ) -> Result<u16, ng_tungstenite::Error> {
request request
.uri() .uri()
.port_u16() .port_u16()
@ -478,8 +478,8 @@ pub(crate) fn port(
Some("ws") => Some(80), Some("ws") => Some(80),
_ => None, _ => None,
}) })
.ok_or(tungstenite::Error::Url( .ok_or(ng_tungstenite::Error::Url(
tungstenite::error::UrlError::UnsupportedUrlScheme, ng_tungstenite::error::UrlError::UnsupportedUrlScheme,
)) ))
} }
@ -493,7 +493,7 @@ mod tests {
))] ))]
#[test] #[test]
fn domain_strips_ipv6_brackets() { fn domain_strips_ipv6_brackets() {
use tungstenite::client::IntoClientRequest; use ng_tungstenite::client::IntoClientRequest;
let request = "ws://[::1]:80".into_client_request().unwrap(); let request = "ws://[::1]:80".into_client_request().unwrap();
assert_eq!(crate::domain(&request).unwrap(), "::1"); assert_eq!(crate::domain(&request).unwrap(), "::1");
@ -502,7 +502,7 @@ mod tests {
#[cfg(feature = "handshake")] #[cfg(feature = "handshake")]
#[test] #[test]
fn requests_cannot_contain_invalid_uris() { fn requests_cannot_contain_invalid_uris() {
use tungstenite::client::IntoClientRequest; use ng_tungstenite::client::IntoClientRequest;
assert!("ws://[".into_client_request().is_err()); assert!("ws://[".into_client_request().is_err());
assert!("ws://[blabla/bla".into_client_request().is_err()); assert!("ws://[blabla/bla".into_client_request().is_err());

@ -1,9 +1,9 @@
//! `tokio` integration. //! `tokio` integration.
use tungstenite::client::IntoClientRequest; use ng_tungstenite::client::IntoClientRequest;
use tungstenite::handshake::client::{Request, Response}; use ng_tungstenite::handshake::client::{Request, Response};
use tungstenite::handshake::server::{Callback, NoCallback}; use ng_tungstenite::handshake::server::{Callback, NoCallback};
use tungstenite::protocol::WebSocketConfig; use ng_tungstenite::protocol::WebSocketConfig;
use tungstenite::Error; use ng_tungstenite::Error;
use tokio::net::TcpStream; use tokio::net::TcpStream;

@ -1,8 +1,8 @@
use real_async_tls::client::TlsStream; use real_async_tls::client::TlsStream;
use real_async_tls::TlsConnector; use real_async_tls::TlsConnector;
use tungstenite::client::IntoClientRequest; use ng_tungstenite::client::IntoClientRequest;
use tungstenite::Error; use ng_tungstenite::Error;
use crate::stream::Stream as StreamSwitcher; use crate::stream::Stream as StreamSwitcher;
use crate::{Response, WebSocketConfig, WebSocketStream}; use crate::{Response, WebSocketConfig, WebSocketStream};

@ -1,7 +1,7 @@
use tungstenite::client::{uri_mode, IntoClientRequest}; use ng_tungstenite::client::{uri_mode, IntoClientRequest};
use tungstenite::handshake::client::Request; use ng_tungstenite::handshake::client::Request;
use tungstenite::stream::Mode; use ng_tungstenite::stream::Mode;
use tungstenite::Error; use ng_tungstenite::Error;
use super::TokioAdapter; use super::TokioAdapter;
@ -23,7 +23,7 @@ where
match mode { match mode {
Mode::Plain => Ok(TokioAdapter::new(socket)), Mode::Plain => Ok(TokioAdapter::new(socket)),
Mode::Tls => Err(Error::Url( Mode::Tls => Err(Error::Url(
tungstenite::error::UrlError::TlsFeatureNotEnabled, ng_tungstenite::error::UrlError::TlsFeatureNotEnabled,
)), )),
} }
} }

@ -1,10 +1,10 @@
use real_tokio_native_tls::TlsConnector as AsyncTlsConnector; use real_tokio_native_tls::TlsConnector as AsyncTlsConnector;
use real_tokio_native_tls::TlsStream; use real_tokio_native_tls::TlsStream;
use tungstenite::client::{uri_mode, IntoClientRequest}; use ng_tungstenite::client::{uri_mode, IntoClientRequest};
use tungstenite::handshake::client::Request; use ng_tungstenite::handshake::client::Request;
use tungstenite::stream::Mode; use ng_tungstenite::stream::Mode;
use tungstenite::Error; use ng_tungstenite::Error;
use crate::stream::Stream as StreamSwitcher; use crate::stream::Stream as StreamSwitcher;
use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream}; use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream};

@ -1,10 +1,10 @@
use openssl::ssl::{ConnectConfiguration, SslConnector, SslMethod}; use openssl::ssl::{ConnectConfiguration, SslConnector, SslMethod};
use real_tokio_openssl::SslStream as TlsStream; use real_tokio_openssl::SslStream as TlsStream;
use tungstenite::client::{uri_mode, IntoClientRequest}; use ng_tungstenite::client::{uri_mode, IntoClientRequest};
use tungstenite::handshake::client::Request; use ng_tungstenite::handshake::client::Request;
use tungstenite::stream::Mode; use ng_tungstenite::stream::Mode;
use tungstenite::Error; use ng_tungstenite::Error;
use crate::stream::Stream as StreamSwitcher; use crate::stream::Stream as StreamSwitcher;
use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream}; use crate::{client_async_with_config, domain, Response, WebSocketConfig, WebSocketStream};

@ -1,11 +1,11 @@
use real_tokio_rustls::rustls::{ClientConfig, RootCertStore, ServerName}; use real_tokio_rustls::rustls::{ClientConfig, RootCertStore, ServerName};
use real_tokio_rustls::{client::TlsStream, TlsConnector}; use real_tokio_rustls::{client::TlsStream, TlsConnector};
use tungstenite::client::{uri_mode, IntoClientRequest}; use ng_tungstenite::client::{uri_mode, IntoClientRequest};
use tungstenite::error::TlsError; use ng_tungstenite::error::TlsError;
use tungstenite::handshake::client::Request; use ng_tungstenite::handshake::client::Request;
use tungstenite::stream::Mode; use ng_tungstenite::stream::Mode;
use tungstenite::Error; use ng_tungstenite::Error;
use std::convert::TryFrom; use std::convert::TryFrom;

@ -5,7 +5,7 @@ use async_std::task;
use async_tungstenite::{accept_async, client_async, WebSocketStream}; use async_tungstenite::{accept_async, client_async, WebSocketStream};
use futures::prelude::*; use futures::prelude::*;
use log::*; use log::*;
use tungstenite::Message; use ng_tungstenite::Message;
async fn run_connection<S>( async fn run_connection<S>(
connection: WebSocketStream<S>, connection: WebSocketStream<S>,

Loading…
Cancel
Save