mirror of
https://github.com/MercuryWorkshop/epoxy-tls.git
synced 2025-05-13 06:20:02 -04:00
websockets impl
This commit is contained in:
parent
05d55eada3
commit
4de4f06f30
5 changed files with 186 additions and 38 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -79,6 +79,12 @@ dependencies = [
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.21.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -1543,6 +1549,7 @@ name = "wstcp-client"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-compression",
|
"async-compression",
|
||||||
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"either",
|
"either",
|
||||||
|
@ -1555,6 +1562,7 @@ dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"penguin-mux-wasm",
|
"penguin-mux-wasm",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"rand",
|
||||||
"ring",
|
"ring",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
|
|
|
@ -31,6 +31,8 @@ either = "1.9.0"
|
||||||
tokio-util = { version = "0.7.10", features = ["io"] }
|
tokio-util = { version = "0.7.10", features = ["io"] }
|
||||||
async-compression = { version = "0.4.5", features = ["tokio", "gzip", "brotli"] }
|
async-compression = { version = "0.4.5", features = ["tokio", "gzip", "brotli"] }
|
||||||
fastwebsockets = { version = "0.6.0", features=[]}
|
fastwebsockets = { version = "0.6.0", features=[]}
|
||||||
|
rand = "0.8.5"
|
||||||
|
base64 = "0.21.7"
|
||||||
|
|
||||||
[dependencies.getrandom]
|
[dependencies.getrandom]
|
||||||
features = ["js"]
|
features = ["js"]
|
||||||
|
|
|
@ -6,14 +6,18 @@ rm -rf out/ || true
|
||||||
mkdir out/
|
mkdir out/
|
||||||
|
|
||||||
cargo build --target wasm32-unknown-unknown --release
|
cargo build --target wasm32-unknown-unknown --release
|
||||||
|
echo "[ws] built rust"
|
||||||
wasm-bindgen --weak-refs --no-typescript --target no-modules --out-dir out/ ../target/wasm32-unknown-unknown/release/wstcp_client.wasm
|
wasm-bindgen --weak-refs --no-typescript --target no-modules --out-dir out/ ../target/wasm32-unknown-unknown/release/wstcp_client.wasm
|
||||||
|
echo "[ws] bindgen finished"
|
||||||
|
|
||||||
mv out/wstcp_client_bg.wasm out/wstcp_client_unoptimized.wasm
|
mv out/wstcp_client_bg.wasm out/wstcp_client_unoptimized.wasm
|
||||||
wasm-opt -O4 out/wstcp_client_unoptimized.wasm -o out/wstcp_client_bg.wasm
|
wasm-opt out/wstcp_client_unoptimized.wasm -o out/wstcp_client_bg.wasm
|
||||||
|
echo "[ws] optimized"
|
||||||
|
|
||||||
AUTOGENERATED_SOURCE=$(<"out/wstcp_client.js")
|
AUTOGENERATED_SOURCE=$(<"out/wstcp_client.js")
|
||||||
WASM_BASE64=$(base64 -w0 out/wstcp_client_bg.wasm)
|
WASM_BASE64=$(base64 -w0 out/wstcp_client_bg.wasm)
|
||||||
echo "${AUTOGENERATED_SOURCE//__wbg_init(input) \{/__wbg_init(input) \{input=\'data:application/wasm;base64,$WASM_BASE64\'}" > out/wstcp_client_bundled.js
|
echo "${AUTOGENERATED_SOURCE//__wbg_init(input) \{/__wbg_init(input) \{input=\'data:application/wasm;base64,$WASM_BASE64\'}" > out/wstcp_client_bundled.js
|
||||||
|
|
||||||
cp -r src/web/* out/
|
cp -r src/web/* out/
|
||||||
|
echo "[ws] done!"
|
||||||
(cd out; python3 -m http.server)
|
(cd out; python3 -m http.server)
|
||||||
|
|
16
client/disable-the-fucking-borrow-checker.mjs
Normal file
16
client/disable-the-fucking-borrow-checker.mjs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import binaryen from "binaryen";
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
let fp = path.resolve(__dirname, './wat.wat');
|
||||||
|
const originBuffer = fs.readFileSync(fp).toString();
|
||||||
|
|
||||||
|
// const wasm = binaryen.readBinary(originBuffer);
|
||||||
|
const wast = originBuffer
|
||||||
|
.replace(/\(br_if \$label\$1[\s\n]+?\(i32.eq\n[\s\S\n]+?i32.const -1\)[\s\n]+\)[\s\n]+\)/g, '');
|
||||||
|
// const distBuffer = binaryen.parseText(wast).emitBinary();
|
||||||
|
|
||||||
|
fs.writeFileSync(fp, wast);
|
|
@ -4,13 +4,14 @@ mod utils;
|
||||||
mod tokioio;
|
mod tokioio;
|
||||||
mod wrappers;
|
mod wrappers;
|
||||||
|
|
||||||
|
use base64::{engine::general_purpose::STANDARD, Engine};
|
||||||
use fastwebsockets::{Frame, OpCode, Payload, Role, WebSocket};
|
use fastwebsockets::{Frame, OpCode, Payload, Role, WebSocket};
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokioio::TokioIo;
|
use tokioio::TokioIo;
|
||||||
use utils::{ReplaceErr, UriExt};
|
use utils::{ReplaceErr, UriExt};
|
||||||
use wrappers::{IncomingBody, WsStreamWrapper};
|
use wrappers::{IncomingBody, WsStreamWrapper};
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{io::Read, ptr::null_mut, str::from_utf8, sync::Arc};
|
||||||
|
|
||||||
use async_compression::tokio::bufread as async_comp;
|
use async_compression::tokio::bufread as async_comp;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
@ -114,6 +115,154 @@ async fn start() {
|
||||||
utils::set_panic_hook();
|
utils::set_panic_hook();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct WsWebSocket {
|
||||||
|
onopen: Function,
|
||||||
|
onclose: Function,
|
||||||
|
onerror: Function,
|
||||||
|
onmessage: Function,
|
||||||
|
ws: Option<WebSocket<WsTcpStream>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wtf(iop: *mut WsTcpStream) {
|
||||||
|
let mut t = false;
|
||||||
|
unsafe {
|
||||||
|
let io = &mut *iop;
|
||||||
|
loop {
|
||||||
|
let r = io.read_u8().await;
|
||||||
|
|
||||||
|
if let Ok(u) = r {
|
||||||
|
// log!("{}", u as char);
|
||||||
|
if t && u as char == '\r' {
|
||||||
|
let r = io.read_u8().await;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if u as char == '\n' {
|
||||||
|
t = true;
|
||||||
|
} else {
|
||||||
|
t = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl WsWebSocket {
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new(
|
||||||
|
onopen: Function,
|
||||||
|
onclose: Function,
|
||||||
|
onmessage: Function,
|
||||||
|
onerror: Function,
|
||||||
|
) -> Result<WsWebSocket, JsError> {
|
||||||
|
Ok(Self {
|
||||||
|
onopen,
|
||||||
|
onclose,
|
||||||
|
onerror,
|
||||||
|
onmessage,
|
||||||
|
ws: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub async fn connect(
|
||||||
|
&mut self,
|
||||||
|
tcp: &mut WsTcp,
|
||||||
|
url: String,
|
||||||
|
protocols: Vec<String>,
|
||||||
|
host: String,
|
||||||
|
) -> Result<(), JsError> {
|
||||||
|
self.onopen.call0(&Object::default());
|
||||||
|
let uri = url.parse::<uri::Uri>().replace_err("Failed to parse URL")?;
|
||||||
|
let mut io = tcp.get_http_io(&uri).await?;
|
||||||
|
|
||||||
|
let r: [u8; 16] = rand::random();
|
||||||
|
let key = STANDARD.encode(&r);
|
||||||
|
|
||||||
|
io.write(b"GET / HTTP/1.1\r\n").await;
|
||||||
|
io.write(b"Sec-WebSocket-Version: 13\r\n").await;
|
||||||
|
io.write(format!("Sec-WebSocket-Key: {}\r\n", key).as_bytes())
|
||||||
|
.await;
|
||||||
|
io.write(b"Connection: Upgrade\r\n").await;
|
||||||
|
io.write(b"Upgrade: websocket\r\n").await;
|
||||||
|
io.write(format!("Host: {}\r\n", host).as_bytes()).await;
|
||||||
|
io.write(b"\r\n").await;
|
||||||
|
|
||||||
|
let iop: *mut WsTcpStream = &mut io;
|
||||||
|
wtf(iop).await;
|
||||||
|
|
||||||
|
let mut ws = WebSocket::after_handshake(io, fastwebsockets::Role::Client);
|
||||||
|
ws.set_writev(false);
|
||||||
|
ws.set_auto_close(true);
|
||||||
|
ws.set_auto_pong(true);
|
||||||
|
|
||||||
|
self.ws = Some(ws);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn ptr(&mut self) -> *mut WsWebSocket {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub async fn send(&mut self, payload: String) -> Result<(), JsError> {
|
||||||
|
let Some(ws) = self.ws.as_mut() else {
|
||||||
|
return Err(JsError::new("Tried to send() before handshake!"));
|
||||||
|
};
|
||||||
|
ws.write_frame(Frame::new(
|
||||||
|
true,
|
||||||
|
OpCode::Text,
|
||||||
|
None,
|
||||||
|
Payload::Owned(payload.as_bytes().to_vec()),
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.replace_err("Failed to send WsWebSocket payload")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub async fn recv(&mut self) -> Result<(), JsError> {
|
||||||
|
let Some(ws) = self.ws.as_mut() else {
|
||||||
|
return Err(JsError::new("Tried to recv() before handshake!"));
|
||||||
|
};
|
||||||
|
loop {
|
||||||
|
let Ok(frame) = ws.read_frame().await else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if frame.opcode == OpCode::Text {
|
||||||
|
if let Ok(str) = from_utf8(&frame.payload) {
|
||||||
|
self.onmessage
|
||||||
|
.call1(&JsValue::null(), &jval!(str))
|
||||||
|
.replace_err("missing onmessage handler")?;
|
||||||
|
}
|
||||||
|
} else if frame.opcode == OpCode::Binary {
|
||||||
|
self.onmessage
|
||||||
|
.call1(
|
||||||
|
&JsValue::null(),
|
||||||
|
&jval!(Uint8Array::from(frame.payload.to_vec().as_slice())),
|
||||||
|
)
|
||||||
|
.replace_err("missing onmessage handler")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.onclose
|
||||||
|
.call0(&JsValue::null())
|
||||||
|
.replace_err("missing onclose handler")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub async fn send(pointer: *mut WsWebSocket, payload: String) -> Result<(), JsError> {
|
||||||
|
let tcp = unsafe { &mut *pointer };
|
||||||
|
tcp.send(payload).await
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct WsTcp {
|
pub struct WsTcp {
|
||||||
rustls_config: Arc<rustls::ClientConfig>,
|
rustls_config: Arc<rustls::ClientConfig>,
|
||||||
|
@ -164,6 +313,10 @@ impl WsTcp {
|
||||||
redirect_limit,
|
redirect_limit,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn ptr(&mut self) -> *mut WsTcp {
|
||||||
|
self as *mut Self
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_http_io(&self, url: &Uri) -> Result<WsTcpStream, JsError> {
|
async fn get_http_io(&self, url: &Uri) -> Result<WsTcpStream, JsError> {
|
||||||
let url_host = url.host().replace_err("URL must have a host")?;
|
let url_host = url.host().replace_err("URL must have a host")?;
|
||||||
|
@ -192,41 +345,6 @@ impl WsTcp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub async fn connect_ws(
|
|
||||||
&self,
|
|
||||||
url: String,
|
|
||||||
protocols: Vec<String>,
|
|
||||||
onopen: Function,
|
|
||||||
onclose: Function,
|
|
||||||
onmessage: Function,
|
|
||||||
onerror: Function,
|
|
||||||
host: String,
|
|
||||||
) -> Result<JsValue, JsError> {
|
|
||||||
onopen.call0(&Object::default());
|
|
||||||
let uri = url.parse::<uri::Uri>().replace_err("Failed to parse URL")?;
|
|
||||||
let mut io = self.get_http_io(&uri).await?;
|
|
||||||
|
|
||||||
let mut a = WebSocket::after_handshake(io, fastwebsockets::Role::Client);
|
|
||||||
a.set_writev(false);
|
|
||||||
a.set_auto_close(true);
|
|
||||||
a.set_auto_pong(true);
|
|
||||||
a.write_frame(Frame::new(
|
|
||||||
true,
|
|
||||||
OpCode::Text,
|
|
||||||
None,
|
|
||||||
Payload::Owned(b"aasdfdfhsdfhkadfhsdfkhjasfkajdfhaksjhfkadhfkashdfkhsd".to_vec()),
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
|
|
||||||
// .await
|
|
||||||
// .replace_err("Failed to connect to host")?;
|
|
||||||
|
|
||||||
let closure = Closure::<dyn FnMut(JsValue)>::new(move |data: JsValue| {
|
|
||||||
log!("WaeASDASd");
|
|
||||||
});
|
|
||||||
Ok(closure.into_js_value())
|
|
||||||
}
|
|
||||||
async fn send_req(
|
async fn send_req(
|
||||||
&self,
|
&self,
|
||||||
req: http::Request<HttpBody>,
|
req: http::Request<HttpBody>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue