flake
This commit is contained in:
parent
3fb51b7723
commit
e24674642c
3 changed files with 198 additions and 12 deletions
96
flake.lock
generated
Normal file
96
flake.lock
generated
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1781577229,
|
||||
"narHash": "sha256-lrp67w8AulE9Ks53n27I45ADSzbOCn4H+CNW1Ck8B+8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "567a49d1913ce81ac6e9582e3553dd90a955875f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1744536153,
|
||||
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1782357464,
|
||||
"narHash": "sha256-mXgoT1qDHCdSfF9IvhMtEEFNy9dxrmUfSViwP7RpzOQ=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "77a8263847fb02dc49dbe377278ef6b952f1c6bb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use mtp_codec::{
|
||||
CommunicationType, CommunicationTypeId, CommunicationValue, DataType, DataTypeId, DataValue,
|
||||
CommunicationType, CommunicationValue, DataType, DataTypeId, DataValue,
|
||||
};
|
||||
use mtp_type_map::communication_type_name;
|
||||
use mtp_crypto::{
|
||||
ChaCha20Poly1305, Ed25519Signer, Keyring, SigAlgorithm,
|
||||
derive_encryption_key,
|
||||
|
|
@ -134,6 +135,77 @@ pub fn parse_auth_response(response: &[u8]) -> Result<JsValue, JsValue> {
|
|||
Ok(obj.into())
|
||||
}
|
||||
|
||||
/// Build a request frame with the given communication type name, request ID, and JSON data.
|
||||
///
|
||||
/// - `comm_type`: communication type name (e.g. "get_model", "rank_models") or PascalCase
|
||||
/// - `id`: request ID for response correlation
|
||||
/// - `json_data`: JSON-stringified request payload
|
||||
#[wasm_bindgen]
|
||||
pub fn build_request_frame(comm_type: &str, id: u32, json_data: &str) -> Result<Vec<u8>, JsValue> {
|
||||
let comm_type_enum = CommunicationType::from_name(comm_type)
|
||||
.or_else(|| {
|
||||
let pascal = comm_type
|
||||
.split('_')
|
||||
.map(|s| {
|
||||
let mut c = s.chars();
|
||||
match c.next() {
|
||||
None => String::new(),
|
||||
Some(f) => f.to_uppercase().to_string() + c.as_str(),
|
||||
}
|
||||
})
|
||||
.collect::<String>();
|
||||
CommunicationType::from_name(&pascal)
|
||||
})
|
||||
.ok_or_else(|| js_error(&format!("unknown communication type: {}", comm_type)))?;
|
||||
|
||||
let frame = CommunicationValue::new(comm_type_enum)
|
||||
.with_id(id)
|
||||
.add_data(DataTypeId(32), DataValue::Str(json_data.to_string()))
|
||||
.to_bytes();
|
||||
|
||||
Ok(frame)
|
||||
}
|
||||
|
||||
/// Parse a response frame into a JSON string containing `_id`, `_type`, and data fields.
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_response_frame(frame: &[u8]) -> Result<String, JsValue> {
|
||||
let comm = CommunicationValue::from_bytes(frame)
|
||||
.map_err(|e| js_error(&format!("parse failed: {}", e)))?;
|
||||
|
||||
let obj = js_sys::Object::new();
|
||||
|
||||
let _ = js_sys::Reflect::set(&obj, &JsValue::from_str("_id"), &JsValue::from(comm.get_id()));
|
||||
|
||||
let type_name = communication_type_name(comm.get_type().0).unwrap_or("Unknown");
|
||||
let _ = js_sys::Reflect::set(
|
||||
&obj,
|
||||
&JsValue::from_str("_type"),
|
||||
&JsValue::from_str(&type_name),
|
||||
);
|
||||
|
||||
if let DataValue::Str(s) = comm.get_data(DataTypeId(32)) {
|
||||
if let Ok(parsed) = js_sys::JSON::parse(s) {
|
||||
let parsed_obj: &js_sys::Object = parsed.unchecked_ref();
|
||||
let entries = js_sys::Object::entries(parsed_obj);
|
||||
let len = entries.length();
|
||||
for i in 0..len {
|
||||
let entry = js_sys::Array::get(&entries, i);
|
||||
if let Some(entry_arr) = entry.dyn_ref::<js_sys::Array>() {
|
||||
if let Some(key) = entry_arr.get(0).as_string() {
|
||||
let val = entry_arr.get(1);
|
||||
let _ = js_sys::Reflect::set(&obj, &JsValue::from_str(&key), &val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let stringified = js_sys::JSON::stringify(&obj)
|
||||
.map_err(|_| js_error("JSON stringify failed"))?;
|
||||
stringified.as_string()
|
||||
.ok_or_else(|| js_error("JSON stringify result not a string"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod tests {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,26 @@ use web_sys::{WebTransport, WebTransportHash, WebTransportOptions};
|
|||
|
||||
use crate::error::js_error;
|
||||
|
||||
/// Given a `SendStream` (old API with `.writable` or new API where stream IS a WritableStream),
|
||||
/// return the object to call `.getWriter()` on.
|
||||
fn resolve_stream_writable(send_stream: &JsValue) -> Result<JsValue, JsValue> {
|
||||
let writable = js_sys::Reflect::get(send_stream, &JsValue::from_str("writable"));
|
||||
match writable {
|
||||
Ok(val) if !val.is_undefined() && !val.is_null() => Ok(val),
|
||||
_ => Ok(send_stream.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a `ReceiveStream` (old API with `.readable` or new API where stream IS a ReadableStream),
|
||||
/// return the object to call `.getReader()` on.
|
||||
fn resolve_stream_readable(recv_stream: &JsValue) -> Result<JsValue, JsValue> {
|
||||
let readable = js_sys::Reflect::get(recv_stream, &JsValue::from_str("readable"));
|
||||
match readable {
|
||||
Ok(val) if !val.is_undefined() && !val.is_null() => Ok(val),
|
||||
_ => Ok(recv_stream.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WasmTransport {
|
||||
inner: WebTransport,
|
||||
|
|
@ -50,14 +70,13 @@ impl WasmTransport {
|
|||
let stream_promise = self.inner.create_unidirectional_stream();
|
||||
let stream = JsFuture::from(stream_promise).await?;
|
||||
|
||||
let writable = js_sys::Reflect::get(&stream, &JsValue::from_str("writable"))
|
||||
.map_err(|_| js_error("missing writable"))?;
|
||||
let writable_or_stream = resolve_stream_writable(&stream)?;
|
||||
|
||||
let writer_val = js_sys::Reflect::get(&writable, &JsValue::from_str("getWriter"))
|
||||
let writer_val = js_sys::Reflect::get(&writable_or_stream, &JsValue::from_str("getWriter"))
|
||||
.map_err(|_| js_error("missing getWriter"))?
|
||||
.dyn_into::<js_sys::Function>()
|
||||
.map_err(|_| js_error("getWriter not a function"))?
|
||||
.call0(&writable)
|
||||
.call0(&writable_or_stream)
|
||||
.map_err(|_| js_error("getWriter call failed"))?;
|
||||
|
||||
let len = frame.len() as u32;
|
||||
|
|
@ -123,14 +142,13 @@ impl WasmTransport {
|
|||
let recv_stream = js_sys::Reflect::get(&result, &JsValue::from_str("value"))
|
||||
.map_err(|_| js_error("missing value"))?;
|
||||
|
||||
let readable = js_sys::Reflect::get(&recv_stream, &JsValue::from_str("readable"))
|
||||
.map_err(|_| js_error("missing readable"))?;
|
||||
let readable_or_stream = resolve_stream_readable(&recv_stream)?;
|
||||
|
||||
let stream_reader_fn = js_sys::Reflect::get(&readable, &JsValue::from_str("getReader"))
|
||||
let stream_reader_fn = js_sys::Reflect::get(&readable_or_stream, &JsValue::from_str("getReader"))
|
||||
.map_err(|_| js_error("missing stream getReader"))?
|
||||
.dyn_into::<js_sys::Function>()
|
||||
.map_err(|_| js_error("stream getReader not a function"))?;
|
||||
let stream_reader = stream_reader_fn.call0(&readable)
|
||||
let stream_reader = stream_reader_fn.call0(&readable_or_stream)
|
||||
.map_err(|_| js_error("stream getReader call failed"))?;
|
||||
|
||||
let mut chunks: Vec<Vec<u8>> = Vec::new();
|
||||
|
|
@ -228,16 +246,16 @@ impl WasmTransport {
|
|||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let readable = match js_sys::Reflect::get(&recv_stream, &JsValue::from_str("readable")) {
|
||||
let readable_or_stream = match resolve_stream_readable(&recv_stream) {
|
||||
Ok(v) => v,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let stream_reader_fn = match js_sys::Reflect::get(&readable, &JsValue::from_str("getReader")) {
|
||||
let stream_reader_fn = match js_sys::Reflect::get(&readable_or_stream, &JsValue::from_str("getReader")) {
|
||||
Ok(f) => f.dyn_into::<js_sys::Function>().unwrap(),
|
||||
Err(_) => continue,
|
||||
};
|
||||
let stream_reader = match stream_reader_fn.call0(&readable) {
|
||||
let stream_reader = match stream_reader_fn.call0(&readable_or_stream) {
|
||||
Ok(v) => v,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue