init
This commit is contained in:
commit
d013ffebbb
7 changed files with 1490 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/target
|
||||||
|
/.cargo
|
||||||
|
*.old.*
|
1173
Cargo.lock
generated
Normal file
1173
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "quad-ws"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
websocket = "0.27.0"
|
118
js/quad-ws.js
Normal file
118
js/quad-ws.js
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a WebSocket connection and its state.
|
||||||
|
* @typedef {Object} WebSocketConnection
|
||||||
|
* @property {WebSocket} socket - The WebSocket instance.
|
||||||
|
* @property {number} state - The state of the WebSocket connection. Possible values:
|
||||||
|
* - 0: Connection is in the CONNECTING state.
|
||||||
|
* - 1: Connection is in the OPEN state.
|
||||||
|
* - 2: Connection is in the CLOSING state.
|
||||||
|
* - 3: Connection is in the CLOSED state.
|
||||||
|
* @property {Array} received - An array to store received data or messages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of WebSocketConnection.
|
||||||
|
* @type {{[key: number]: WebSocketConnection}}
|
||||||
|
*/
|
||||||
|
|
||||||
|
let ws = {};
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
const WS_NOT_EXISTING = -1;
|
||||||
|
const WS_CREATING = 0;
|
||||||
|
const WS_OPEN = 1;
|
||||||
|
const WS_CLOSED = 2;
|
||||||
|
|
||||||
|
function ws_open(ptr, len) {
|
||||||
|
let url = UTF8ToString(ptr, len);
|
||||||
|
let id = i++;
|
||||||
|
let conn;
|
||||||
|
try {
|
||||||
|
conn = {
|
||||||
|
socket: new WebSocket(url),
|
||||||
|
state: 0,
|
||||||
|
received: []
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.socket.onopen = (s, e) => {
|
||||||
|
conn.state = WS_OPEN;
|
||||||
|
};
|
||||||
|
conn.socket.onmessage = (s, e) => {
|
||||||
|
conn.received.push(new Uint8Array(e.data.arraybuffer()));
|
||||||
|
};
|
||||||
|
conn.socket.onerror = (s, e) => {
|
||||||
|
conn.state = WS_CLOSED;
|
||||||
|
};
|
||||||
|
conn.socket.onclose = (s, e) => {
|
||||||
|
conn.state = WS_CLOSED;
|
||||||
|
delete ws[id];
|
||||||
|
ws[id] = undefined;
|
||||||
|
};
|
||||||
|
ws[id] = conn;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ws_write(id, ptr, len) {
|
||||||
|
let data = new Uint8Array(wasm_memory.buffer, ptr, len);
|
||||||
|
/*let data = new Uint8Array(len);
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
data[i] = data_in[i];
|
||||||
|
}*/
|
||||||
|
if (ws[id] != null) {
|
||||||
|
ws[id].socket.send(data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function ws_available(id) {
|
||||||
|
if (ws[id].received.length == 0) return -1;
|
||||||
|
return ws[id].received[0].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ws_read(id, ptr, max_length) {
|
||||||
|
let file = ws[id].received.pop();
|
||||||
|
var dest = new Uint8Array(wasm_memory.buffer, ptr, max_length);
|
||||||
|
for (let i = 0; i < file.length && i < max_length; i++) {
|
||||||
|
dest[i] = file[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ws_state(id) {
|
||||||
|
return ws[id]?.state ?? WS_NOT_EXISTING;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ws_close(id) {
|
||||||
|
if (ws[id] == null) return;
|
||||||
|
ws[id].socket.close();
|
||||||
|
ws[id].state = WS_CLOSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
function register_plugin(importObject) {
|
||||||
|
importObject.env.ws_open = ws_open;
|
||||||
|
importObject.env.ws_write = ws_write;
|
||||||
|
importObject.env.ws_read = ws_read;
|
||||||
|
importObject.env.ws_available = ws_available;
|
||||||
|
importObject.env.ws_state = ws_state;
|
||||||
|
importObject.env.ws_close = ws_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
miniquad_add_plugin({ register_plugin, version: "0.0.1", name: "miniquad_websocket" });
|
||||||
|
|
||||||
|
/*
|
||||||
|
var socket = new WebSocket("ws://127.0.0.1:7878");
|
||||||
|
socket.onmessage = function (event) {
|
||||||
|
var received = document.getElementById("received");
|
||||||
|
var br = document.createElement("BR");
|
||||||
|
console.log(event.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
function send(data) {
|
||||||
|
|
||||||
|
socket.send(data);
|
||||||
|
}
|
||||||
|
*/
|
29
src/lib.rs
Normal file
29
src/lib.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub mod wasm;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
use wasm::*;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub mod pc;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use pc::*;
|
||||||
|
|
||||||
|
pub struct QuadWs {
|
||||||
|
channel: WsChannnel,
|
||||||
|
}
|
||||||
|
impl QuadWs {
|
||||||
|
pub fn new(url: String) -> Self {
|
||||||
|
Self {
|
||||||
|
channel: ws_open_rust(url).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn write(&mut self) -> bool {
|
||||||
|
ws_write_rust(&mut self.channel, vec![])
|
||||||
|
}
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
ws_close_rust(&mut self.channel)
|
||||||
|
}
|
||||||
|
pub fn read(&mut self) -> Option<Vec<u8>>{
|
||||||
|
ws_read_rust(&mut self.channel)
|
||||||
|
}
|
||||||
|
}
|
116
src/pc.rs
Normal file
116
src/pc.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
use std::net::TcpStream;
|
||||||
|
|
||||||
|
use websocket::{native_tls::TlsStream, sync::Client, ClientBuilder, OwnedMessage, WebSocketError};
|
||||||
|
|
||||||
|
enum WsClient {
|
||||||
|
None,
|
||||||
|
Insecure(Client<TcpStream>),
|
||||||
|
Secure(Client<TlsStream<TcpStream>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WsConnection {
|
||||||
|
client: WsClient,
|
||||||
|
_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type WsChannnel = WsConnection;
|
||||||
|
|
||||||
|
pub fn ws_open_rust(url: String) -> Option<WsChannnel> {
|
||||||
|
let secure = url.starts_with("wss");
|
||||||
|
let builder = ClientBuilder::new("ws://127.0.0.1:7878");
|
||||||
|
if builder.is_err() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut builder = builder.expect("Failed to expect none err");
|
||||||
|
|
||||||
|
if secure {
|
||||||
|
let connector = builder.connect_secure(None);
|
||||||
|
if connector.is_err() {
|
||||||
|
return Some(WsConnection {
|
||||||
|
client: WsClient::None,
|
||||||
|
_url: url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let client = connector.expect("Failed to expect none err");
|
||||||
|
client.set_nonblocking(true).unwrap();
|
||||||
|
return Some(WsConnection {
|
||||||
|
client: WsClient::Secure(client),
|
||||||
|
_url: url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let connector = builder.connect_insecure();
|
||||||
|
if connector.is_err() {
|
||||||
|
return Some(WsConnection {
|
||||||
|
client: WsClient::None,
|
||||||
|
_url: url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let client = connector.expect("Failed to expect none err");
|
||||||
|
client.set_nonblocking(true).unwrap();
|
||||||
|
return Some(WsConnection {
|
||||||
|
client: WsClient::Insecure(client),
|
||||||
|
_url: url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ws_write_raw(socket: &mut WsChannnel, data: OwnedMessage) -> bool {
|
||||||
|
match &mut socket.client {
|
||||||
|
WsClient::None => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WsClient::Insecure(client) => {
|
||||||
|
return client.send_message(&data).is_ok();
|
||||||
|
}
|
||||||
|
WsClient::Secure(client) => {
|
||||||
|
return client.send_message(&data).is_ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ws_write_rust(socket: &mut WsChannnel, data: Vec<u8>) -> bool {
|
||||||
|
ws_write_raw(socket, OwnedMessage::Binary(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ws_read_rust(socket: &mut WsChannnel) -> Option<Vec<u8>> {
|
||||||
|
let message: Result<OwnedMessage, WebSocketError> = match socket.client {
|
||||||
|
WsClient::None => Err(WebSocketError::NoDataAvailable),
|
||||||
|
WsClient::Insecure(ref mut client) => client.recv_message(),
|
||||||
|
WsClient::Secure(ref mut client) => client.recv_message(),
|
||||||
|
};
|
||||||
|
match message {
|
||||||
|
Ok(message) => match message {
|
||||||
|
websocket::OwnedMessage::Text(_) => {}
|
||||||
|
websocket::OwnedMessage::Binary(data) => {
|
||||||
|
return Some(data);
|
||||||
|
}
|
||||||
|
websocket::OwnedMessage::Close(_) => {
|
||||||
|
socket.client = WsClient::None;
|
||||||
|
}
|
||||||
|
websocket::OwnedMessage::Ping(ping) => {
|
||||||
|
let message = OwnedMessage::Pong(ping);
|
||||||
|
ws_write_raw(socket, message);
|
||||||
|
}
|
||||||
|
websocket::OwnedMessage::Pong(_data) => {}
|
||||||
|
},
|
||||||
|
Err(ref e) => match e {
|
||||||
|
WebSocketError::IoError(err) => if err.kind() == std::io::ErrorKind::WouldBlock {},
|
||||||
|
WebSocketError::NoDataAvailable => {
|
||||||
|
socket.client = WsClient::None;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ws_close_rust(socket: &WsChannnel) {
|
||||||
|
match &socket.client {
|
||||||
|
WsClient::None => {}
|
||||||
|
WsClient::Insecure(client) => {
|
||||||
|
client.shutdown().unwrap();
|
||||||
|
}
|
||||||
|
WsClient::Secure(client) => {
|
||||||
|
client.shutdown().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
src/wasm.rs
Normal file
42
src/wasm.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
pub type WsChannnel = i32;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn ws_open(ptr: *const i8, len: u32) -> WsChannnel;
|
||||||
|
fn ws_write(id: WsChannnel, ptr: *const u8, len: u32) -> bool;
|
||||||
|
fn ws_read(id: WsChannnel, ptr: *const u8, len: u32);
|
||||||
|
fn ws_available(id: WsChannnel) -> i32;
|
||||||
|
fn ws_state(id: WsChannnel) -> i32;
|
||||||
|
fn ws_close(id: WsChannnel);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ws_open_rust(url: String) -> Result<WsChannnel, _> {
|
||||||
|
let url = CString::new(url).unwrap();
|
||||||
|
let socket_id = unsafe { ws_open(url.as_ptr(), url.as_bytes().len() as u32) };
|
||||||
|
if socket_id < 0 {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
Ok(socket_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ws_write_rust(socket: WsChannnel, data: Vec<u8>) -> bool {
|
||||||
|
let buf = data.as_slice();
|
||||||
|
let succ = unsafe { ws_write(socket, buf.as_ptr(), buf.len() as u32) };
|
||||||
|
succ
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ws_read_rust(socket: WsChannnel) -> Option<Vec<u8>> {
|
||||||
|
let available = unsafe { ws_available(socket) };
|
||||||
|
if available < 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut buffer = vec![0; available as usize];
|
||||||
|
unsafe { ws_read(socket, buffer.as_mut_ptr(), available as u32) };
|
||||||
|
return Some(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ws_close_rust(socket: WsChannnel) {
|
||||||
|
unsafe { ws_close(socket) };
|
||||||
|
}
|
Loading…
Reference in a new issue