Improve build scripts and framework to get WASM loaded on Steam Deck
This commit is contained in:
parent
eaf193a1b2
commit
ccd3969185
14 changed files with 291 additions and 93 deletions
|
@ -3,9 +3,16 @@ name = "usdpl-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
|
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "GPL-3.0-only"
|
||||||
|
repository = "https://github.com/NGnius/usdpl-rs"
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
# Tell `rustc` to optimize for small code size.
|
||||||
|
opt-level = "s"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"usdpl-core",
|
"usdpl-core",
|
||||||
|
|
45
build.sh
Executable file
45
build.sh
Executable file
|
@ -0,0 +1,45 @@
|
||||||
|
#!/bin/bash
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
if [ "$1" == "--help" ]; then
|
||||||
|
echo "Usage:
|
||||||
|
$0 [decky|crankshaft|<nothing>]"
|
||||||
|
exit 0
|
||||||
|
elif [ "$1" == "decky" ]; then
|
||||||
|
echo "Building back & front for decky framework"
|
||||||
|
# usdpl-back
|
||||||
|
cd ./usdpl-back
|
||||||
|
./build.sh decky
|
||||||
|
# usdpl-front
|
||||||
|
cd ../usdpl-front
|
||||||
|
./build.sh decky
|
||||||
|
cd ..
|
||||||
|
echo "Built usdpl back & front for decky"
|
||||||
|
elif [ "$1" == "crankshaft" ]; then
|
||||||
|
echo "WARNING: crankshaft is unimplemented"
|
||||||
|
echo "Building back & front for crankshaft framework"
|
||||||
|
# usdpl-back
|
||||||
|
cd ./usdpl-back
|
||||||
|
./build.sh crankshaft
|
||||||
|
# usdpl-front
|
||||||
|
cd ../usdpl-front
|
||||||
|
./build.sh crankshaft
|
||||||
|
cd ..
|
||||||
|
echo "Built usdpl back & front for crankshaft"
|
||||||
|
else
|
||||||
|
echo "Unsupported plugin framework \`$1\`"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARNING: Building for any plugin framework, which may not work for every framework"
|
||||||
|
echo "Building back & front for any framework"
|
||||||
|
# usdpl-back
|
||||||
|
echo "...Running usdpl-back build..."
|
||||||
|
cd ./usdpl-back
|
||||||
|
cargo build --release
|
||||||
|
# usdpl-front
|
||||||
|
echo "...Running usdpl-front build..."
|
||||||
|
cd ../usdpl-front
|
||||||
|
./build.sh crankshaft
|
||||||
|
cd ..
|
||||||
|
echo "Built usdpl back & front for any"
|
||||||
|
fi
|
|
@ -2,8 +2,14 @@
|
||||||
name = "usdpl-back"
|
name = "usdpl-back"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "GPL-3.0-only"
|
||||||
|
repository = "https://github.com/NGnius/usdpl-rs"
|
||||||
|
readme = "../README.md"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
[features]
|
||||||
|
default = []
|
||||||
|
decky = []
|
||||||
|
crankshaft = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
usdpl-core = { version = "0.1.0", path = "../usdpl-core" }
|
usdpl-core = { version = "0.1.0", path = "../usdpl-core" }
|
||||||
|
|
20
usdpl-back/build.sh
Executable file
20
usdpl-back/build.sh
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/bash
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
if [ "$1" == "--help" ]; then
|
||||||
|
echo "Usage:
|
||||||
|
$0 [decky|crankshaft|<nothing>]"
|
||||||
|
exit 0
|
||||||
|
elif [ "$1" == "decky" ]; then
|
||||||
|
echo "Building back-end module for decky framework"
|
||||||
|
cargo build --release --features decky
|
||||||
|
elif [ "$1" == "crankshaft" ]; then
|
||||||
|
echo "WARNING: crankshaft support is unimplemented"
|
||||||
|
cargo build --release --features crankshaft
|
||||||
|
else
|
||||||
|
echo "Unsupported plugin framework \`$1\`"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARNING: Building for any plugin framework, which may not work for every framework"
|
||||||
|
cargo build --release
|
||||||
|
fi
|
|
@ -1,4 +1,4 @@
|
||||||
use std::net::TcpListener;
|
use std::net::{TcpListener, TcpStream};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
@ -8,13 +8,15 @@ use usdpl_core::{RemoteCallResponse, socket};
|
||||||
/// Instance for interacting with the front-end
|
/// Instance for interacting with the front-end
|
||||||
pub struct Instance<'a> {
|
pub struct Instance<'a> {
|
||||||
calls: HashMap<String, &'a mut dyn FnMut(Vec<Primitive>) -> Vec<Primitive>>,
|
calls: HashMap<String, &'a mut dyn FnMut(Vec<Primitive>) -> Vec<Primitive>>,
|
||||||
|
port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Instance<'a> {
|
impl<'a> Instance<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Self {
|
pub fn new(port_usdpl: u16) -> Self {
|
||||||
Instance {
|
Instance {
|
||||||
calls: HashMap::new(),
|
calls: HashMap::new(),
|
||||||
|
port: port_usdpl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,15 +26,7 @@ impl<'a> Instance<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receive and execute callbacks forever
|
fn handle_packet<const ERROR: bool>(&mut self, packet: socket::Packet, buffer: &mut [u8], incoming: &mut TcpStream) -> std::io::Result<()> {
|
||||||
pub fn serve<const ERROR: bool>(&mut self) -> std::io::Result<()> {
|
|
||||||
let listener = TcpListener::bind(socket::socket_addr())?;
|
|
||||||
for incoming in listener.incoming() {
|
|
||||||
let mut incoming = incoming?;
|
|
||||||
let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE];
|
|
||||||
let len = incoming.read(&mut buffer)?;
|
|
||||||
let (obj_maybe, _) = socket::Packet::load(&buffer[..len]);
|
|
||||||
if let Some(packet) = obj_maybe {
|
|
||||||
match packet {
|
match packet {
|
||||||
socket::Packet::Call(obj) => {
|
socket::Packet::Call(obj) => {
|
||||||
if let Some(target_func) = self.calls.get_mut(&obj.function) {
|
if let Some(target_func) = self.calls.get_mut(&obj.function) {
|
||||||
|
@ -42,7 +36,7 @@ impl<'a> Instance<'a> {
|
||||||
id: obj.id,
|
id: obj.id,
|
||||||
response: result,
|
response: result,
|
||||||
});
|
});
|
||||||
let (ok, len) = response.dump(&mut buffer);
|
let (ok, len) = response.dump(buffer);
|
||||||
if !ok && ERROR {
|
if !ok && ERROR {
|
||||||
return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, format!("Cannot dump return value of function `{}`", &obj.function)));
|
return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, format!("Cannot dump return value of function `{}`", &obj.function)));
|
||||||
}
|
}
|
||||||
|
@ -60,8 +54,22 @@ impl<'a> Instance<'a> {
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
socket::Packet::Many(many) => {
|
||||||
|
for packet in many {
|
||||||
|
if let socket::Packet::Many(_) = packet {
|
||||||
|
// drop nested socket packets (prevents DoS and bad practices)
|
||||||
|
if ERROR {
|
||||||
|
return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, format!("Invalid nested Many packet received from {}", incoming.peer_addr()?)));
|
||||||
|
} else {
|
||||||
|
eprintln!("Invalid nested Many packet received from {}", incoming.peer_addr()?);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
self.handle_packet::<ERROR>(packet, buffer, incoming)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let (ok, len) = socket::Packet::Unsupported.dump(&mut buffer);
|
let (ok, len) = socket::Packet::Unsupported.dump(buffer);
|
||||||
if !ok && ERROR {
|
if !ok && ERROR {
|
||||||
return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, format!("Cannot dump unsupported packet")));
|
return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, format!("Cannot dump unsupported packet")));
|
||||||
}
|
}
|
||||||
|
@ -72,6 +80,25 @@ impl<'a> Instance<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serve<const ERROR: bool>(&mut self) -> std::io::Result<()> {
|
||||||
|
let result = self.serve_internal::<ERROR>();
|
||||||
|
//println!("Stopping server due to serve_internal returning a result");
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Receive and execute callbacks forever
|
||||||
|
pub fn serve_internal<const ERROR: bool>(&mut self) -> std::io::Result<()> {
|
||||||
|
let listener = TcpListener::bind(socket::socket_addr(self.port))?;
|
||||||
|
for incoming in listener.incoming() {
|
||||||
|
let mut incoming = incoming?;
|
||||||
|
let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE];
|
||||||
|
let len = incoming.read(&mut buffer)?;
|
||||||
|
let (obj_maybe, _) = socket::Packet::load(&buffer[..len]);
|
||||||
|
if let Some(packet) = obj_maybe {
|
||||||
|
self.handle_packet::<ERROR>(packet, &mut buffer, &mut incoming)?;
|
||||||
} else {
|
} else {
|
||||||
if ERROR {
|
if ERROR {
|
||||||
return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, format!("Invalid packet received from {}", incoming.peer_addr()?)));
|
return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, format!("Invalid packet received from {}", incoming.peer_addr()?)));
|
||||||
|
@ -90,10 +117,12 @@ mod tests {
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
const PORT: u16 = 31337;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serve_full_test() -> std::io::Result<()> {
|
fn serve_full_test() -> std::io::Result<()> {
|
||||||
let _server = std::thread::spawn(|| {
|
let _server = std::thread::spawn(|| {
|
||||||
Instance::new()
|
Instance::new(PORT, PORT + 80)
|
||||||
.register("echo".to_string(), &mut |params| params)
|
.register("echo".to_string(), &mut |params| params)
|
||||||
.register("hello".to_string(), &mut |params| {
|
.register("hello".to_string(), &mut |params| {
|
||||||
if let Some(Primitive::String(name)) = params.get(0) {
|
if let Some(Primitive::String(name)) = params.get(0) {
|
||||||
|
@ -105,7 +134,7 @@ mod tests {
|
||||||
.serve::<true>()
|
.serve::<true>()
|
||||||
});
|
});
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
let mut front = TcpStream::connect(socket::socket_addr()).unwrap();
|
let mut front = TcpStream::connect(socket::socket_addr(PORT)).unwrap();
|
||||||
let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE];
|
let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE];
|
||||||
let call = socket::Packet::Call(usdpl_core::RemoteCall {
|
let call = socket::Packet::Call(usdpl_core::RemoteCall {
|
||||||
id: 42,
|
id: 42,
|
||||||
|
@ -140,13 +169,13 @@ mod tests {
|
||||||
fn serve_err_test() {
|
fn serve_err_test() {
|
||||||
let _client = std::thread::spawn(|| {
|
let _client = std::thread::spawn(|| {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
let mut front = TcpStream::connect(socket::socket_addr()).unwrap();
|
let mut front = TcpStream::connect(socket::socket_addr(PORT+1)).unwrap();
|
||||||
let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE];
|
let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE];
|
||||||
let (_, len) = socket::Packet::Bad.dump(&mut buffer);
|
let (_, len) = socket::Packet::Bad.dump(&mut buffer);
|
||||||
front.write(&buffer[..len]).unwrap();
|
front.write(&buffer[..len]).unwrap();
|
||||||
let _ = front.read(&mut buffer).unwrap();
|
let _ = front.read(&mut buffer).unwrap();
|
||||||
});
|
});
|
||||||
Instance::new()
|
Instance::new(PORT+1, PORT+1+80)
|
||||||
.register("echo".to_string(), &mut |params| params)
|
.register("echo".to_string(), &mut |params| params)
|
||||||
.register("hello".to_string(), &mut |params| {
|
.register("hello".to_string(), &mut |params| {
|
||||||
if let Some(Primitive::String(name)) = params.get(0) {
|
if let Some(Primitive::String(name)) = params.get(0) {
|
||||||
|
@ -163,7 +192,7 @@ mod tests {
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn serve_unsupported_test() {
|
fn serve_unsupported_test() {
|
||||||
let _server = std::thread::spawn(|| {
|
let _server = std::thread::spawn(|| {
|
||||||
Instance::new()
|
Instance::new(PORT+2, PORT+2+80)
|
||||||
.register("echo".to_string(), &mut |params| params)
|
.register("echo".to_string(), &mut |params| params)
|
||||||
.register("hello".to_string(), &mut |params| {
|
.register("hello".to_string(), &mut |params| {
|
||||||
if let Some(Primitive::String(name)) = params.get(0) {
|
if let Some(Primitive::String(name)) = params.get(0) {
|
||||||
|
@ -175,7 +204,7 @@ mod tests {
|
||||||
.serve::<true>()
|
.serve::<true>()
|
||||||
});
|
});
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
let mut front = TcpStream::connect(socket::socket_addr()).unwrap();
|
let mut front = TcpStream::connect(socket::socket_addr(PORT+2)).unwrap();
|
||||||
let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE];
|
let mut buffer = [0u8; socket::PACKET_BUFFER_SIZE];
|
||||||
let (ok, len) = socket::Packet::Unsupported.dump(&mut buffer);
|
let (ok, len) = socket::Packet::Unsupported.dump(&mut buffer);
|
||||||
assert!(ok, "Packet dump failed");
|
assert!(ok, "Packet dump failed");
|
||||||
|
|
|
@ -7,3 +7,7 @@
|
||||||
mod instance;
|
mod instance;
|
||||||
|
|
||||||
pub use instance::Instance;
|
pub use instance::Instance;
|
||||||
|
|
||||||
|
pub mod core {
|
||||||
|
pub use usdpl_core::*;
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
name = "usdpl-core"
|
name = "usdpl-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "GPL-3.0-only"
|
||||||
|
repository = "https://github.com/NGnius/usdpl-rs"
|
||||||
|
readme = "../README.md"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,14 @@ use std::net::{SocketAddrV4, SocketAddr, Ipv4Addr};
|
||||||
use crate::serdes::{Loadable, Dumpable};
|
use crate::serdes::{Loadable, Dumpable};
|
||||||
use crate::{RemoteCall, RemoteCallResponse};
|
use crate::{RemoteCall, RemoteCallResponse};
|
||||||
|
|
||||||
pub const PORT: u16 = 31337;
|
|
||||||
pub const HTTP_PORT: u16 = 31338;
|
|
||||||
pub const HOST_STR: &str = "127.0.0.1";
|
pub const HOST_STR: &str = "127.0.0.1";
|
||||||
pub const HOST: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
|
pub const HOST: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
|
||||||
pub const SOCKET_ADDR_STR: &str = "127.0.0.1:31337";
|
|
||||||
//pub const SOCKET_ADDR: SocketAddr = SocketAddr::V4(SocketAddrV4::new(HOST, PORT));
|
|
||||||
|
|
||||||
pub const PACKET_BUFFER_SIZE: usize = 1024;
|
pub const PACKET_BUFFER_SIZE: usize = 1024;
|
||||||
|
|
||||||
pub fn socket_addr() -> SocketAddr {
|
#[inline]
|
||||||
SocketAddr::V4(SocketAddrV4::new(HOST, PORT))
|
pub fn socket_addr(port: u16) -> SocketAddr {
|
||||||
|
SocketAddr::V4(SocketAddrV4::new(HOST, port))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Packet {
|
pub enum Packet {
|
||||||
|
@ -24,6 +21,7 @@ pub enum Packet {
|
||||||
Message(String),
|
Message(String),
|
||||||
Unsupported,
|
Unsupported,
|
||||||
Bad,
|
Bad,
|
||||||
|
Many(Vec<Packet>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Packet {
|
impl Packet {
|
||||||
|
@ -36,6 +34,7 @@ impl Packet {
|
||||||
Self::Message(_) => 5,
|
Self::Message(_) => 5,
|
||||||
Self::Unsupported => 6,
|
Self::Unsupported => 6,
|
||||||
Self::Bad => 7,
|
Self::Bad => 7,
|
||||||
|
Self::Many(_) => 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +62,10 @@ impl Loadable for Packet {
|
||||||
},
|
},
|
||||||
6 => (Some(Self::Unsupported), 0),
|
6 => (Some(Self::Unsupported), 0),
|
||||||
7 => (None, 0),
|
7 => (None, 0),
|
||||||
|
8 => {
|
||||||
|
let (obj, len) = <_>::load(&buf[1..]);
|
||||||
|
(obj.map(Self::Many), len)
|
||||||
|
}
|
||||||
_ => (None, 0)
|
_ => (None, 0)
|
||||||
};
|
};
|
||||||
result.1 += 1;
|
result.1 += 1;
|
||||||
|
@ -84,6 +87,7 @@ impl Dumpable for Packet {
|
||||||
Self::Message(s) => s.dump(&mut buf[1..]),
|
Self::Message(s) => s.dump(&mut buf[1..]),
|
||||||
Self::Unsupported => (true, 0),
|
Self::Unsupported => (true, 0),
|
||||||
Self::Bad => (false, 0),
|
Self::Bad => (false, 0),
|
||||||
|
Self::Many(v) => v.dump(&mut buf[1..]),
|
||||||
};
|
};
|
||||||
result.1 += 1;
|
result.1 += 1;
|
||||||
result
|
result
|
||||||
|
|
|
@ -4,12 +4,17 @@ description = "WASM front-end library for USDPL"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
|
authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "GPL-3.0-only"
|
||||||
|
repository = "https://github.com/NGnius/usdpl-rs"
|
||||||
|
readme = "../README.md"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["console_error_panic_hook"]
|
default = ["console_error_panic_hook"]
|
||||||
|
decky = []
|
||||||
|
crankshaft = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasm-bindgen = "0.2.63"
|
wasm-bindgen = "0.2.63"
|
||||||
|
@ -35,6 +40,6 @@ usdpl-core = { version = "0.1.0", path = "../usdpl-core" }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasm-bindgen-test = "0.3.13"
|
wasm-bindgen-test = "0.3.13"
|
||||||
|
|
||||||
[profile.release]
|
#[profile.release]
|
||||||
# Tell `rustc` to optimize for small code size.
|
# Tell `rustc` to optimize for small code size.
|
||||||
opt-level = "s"
|
#opt-level = "s"
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
if [ "$1" == "--help" ]; then
|
||||||
|
echo "Usage:
|
||||||
|
$0 [decky|crankshaft|<nothing>]"
|
||||||
|
exit 0
|
||||||
|
elif [ "$1" == "decky" ]; then
|
||||||
|
echo "Building WASM module for decky framework"
|
||||||
|
wasm-pack build --target web --features decky
|
||||||
|
elif [ "$1" == "crankshaft" ]; then
|
||||||
|
echo "WARNING: crankshaft support is unimplemented"
|
||||||
|
wasm-pack build --target web --features crankshaft
|
||||||
|
else
|
||||||
|
echo "Unsupported plugin framework \`$1\`"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARNING: Building for any plugin framework, which may not work for every framework"
|
||||||
|
wasm-pack build --target web
|
||||||
|
fi
|
||||||
|
|
||||||
wasm-pack build --target web
|
python3 ./scripts/generate_embedded_wasm.py
|
||||||
|
|
37
usdpl-front/scripts/generate_embedded_wasm.py
Normal file
37
usdpl-front/scripts/generate_embedded_wasm.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import base64
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("Embedding WASM into udspl.js")
|
||||||
|
# assumption: current working directory (relative to this script) is ../
|
||||||
|
# assumption: release wasm binary at ./pkg/usdpl_bg.wasm
|
||||||
|
with open("./pkg/usdpl_bg.wasm", mode="rb") as infile:
|
||||||
|
with open("./pkg/usdpl.js", mode="ab") as outfile:
|
||||||
|
outfile.write("\n\n// USDPL customization\nconst encoded = \"".encode())
|
||||||
|
encoded = base64.b64encode(infile.read())
|
||||||
|
outfile.write(encoded)
|
||||||
|
outfile.write("\";\n\n".encode())
|
||||||
|
outfile.write(
|
||||||
|
"""function asciiToBinary(str) {
|
||||||
|
if (typeof atob === 'function') {
|
||||||
|
return atob(str)
|
||||||
|
} else {
|
||||||
|
return new Buffer(str, 'base64').toString('binary');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decode() {
|
||||||
|
var binaryString = asciiToBinary(encoded);
|
||||||
|
var bytes = new Uint8Array(binaryString.length);
|
||||||
|
for (var i = 0; i < binaryString.length; i++) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return (async function() {return new Response(bytes.buffer);})();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function init_embedded() {
|
||||||
|
return init(decode())
|
||||||
|
}
|
||||||
|
""".encode())
|
||||||
|
with open("./pkg/usdpl.d.ts", "a") as outfile:
|
||||||
|
outfile.write("\n\n// USDPL customization\nexport function init_embedded();\n")
|
||||||
|
print("Done: Embedded WASM into udspl.js")
|
|
@ -8,8 +8,8 @@ use usdpl_core::socket;
|
||||||
use usdpl_core::serdes::{Dumpable, Loadable};
|
use usdpl_core::serdes::{Dumpable, Loadable};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn send(packet: socket::Packet) -> bool {
|
pub(crate) fn send(packet: socket::Packet, port: u16) -> bool {
|
||||||
let socket = match TcpSocket::new(socket::HOST_STR, socket::PORT) {
|
let socket = match TcpSocket::new(socket::HOST_STR, port) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(_) => return false,
|
Err(_) => return false,
|
||||||
};
|
};
|
||||||
|
@ -30,8 +30,8 @@ pub(crate) fn send(packet: socket::Packet) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn send_native(packet: socket::Packet) -> Option<socket::Packet> {
|
pub(crate) fn send_native(packet: socket::Packet, port: u16) -> Option<socket::Packet> {
|
||||||
let mut socket = match TcpStream::connect(socket::socket_addr()) {
|
let mut socket = match TcpStream::connect(socket::socket_addr(port)) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(_) => return None,
|
Err(_) => return None,
|
||||||
};
|
};
|
||||||
|
|
35
usdpl-front/src/convert.rs
Normal file
35
usdpl-front/src/convert.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
use wasm_bindgen::prelude::JsValue;
|
||||||
|
use js_sys::JSON::{stringify, parse};
|
||||||
|
|
||||||
|
use usdpl_core::serdes::Primitive;
|
||||||
|
|
||||||
|
pub(crate) fn primitive_to_js(primitive: Primitive) -> JsValue {
|
||||||
|
match primitive {
|
||||||
|
Primitive::Empty => JsValue::null(),
|
||||||
|
Primitive::String(s) => JsValue::from_str(&s),
|
||||||
|
Primitive::F32(f)=> JsValue::from_f64(f as _),
|
||||||
|
Primitive::F64(f)=> JsValue::from_f64(f),
|
||||||
|
Primitive::U32(f)=> JsValue::from_f64(f as _),
|
||||||
|
Primitive::U64(f)=> JsValue::from_f64(f as _),
|
||||||
|
Primitive::I32(f)=> JsValue::from_f64(f as _),
|
||||||
|
Primitive::I64(f)=> JsValue::from_f64(f as _),
|
||||||
|
Primitive::Bool(b) => JsValue::from_bool(b),
|
||||||
|
Primitive::Json(s) => parse(&s).ok().unwrap_or(JsValue::from_str(&s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn js_to_primitive(val: JsValue) -> Primitive {
|
||||||
|
if let Some(b) = val.as_bool() {
|
||||||
|
Primitive::Bool(b)
|
||||||
|
} else if let Some(f) = val.as_f64() {
|
||||||
|
Primitive::F64(f)
|
||||||
|
} else if let Some(s) = val.as_string() {
|
||||||
|
Primitive::String(s)
|
||||||
|
} else if val.is_null() || val.is_undefined() {
|
||||||
|
Primitive::Empty
|
||||||
|
} else if let Ok(s) = stringify(&val) {
|
||||||
|
Primitive::Json(s.as_string().unwrap())
|
||||||
|
} else {
|
||||||
|
Primitive::Empty
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,12 +5,13 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
mod connection;
|
mod connection;
|
||||||
|
mod convert;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use js_sys::JSON::{stringify, parse};
|
|
||||||
|
|
||||||
use usdpl_core::{socket::Packet, RemoteCall, serdes::Primitive};
|
use usdpl_core::{socket::Packet, RemoteCall};
|
||||||
const REMOTE_CALL_ID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
const REMOTE_CALL_ID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
||||||
|
const REMOTE_PORT: std::sync::atomic::AtomicU16 = std::sync::atomic::AtomicU16::new(31337);
|
||||||
|
|
||||||
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global allocator.
|
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global allocator.
|
||||||
#[cfg(feature = "wee_alloc")]
|
#[cfg(feature = "wee_alloc")]
|
||||||
|
@ -24,16 +25,22 @@ extern {
|
||||||
|
|
||||||
/// Initialize the front-end library
|
/// Initialize the front-end library
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn init() -> bool {
|
pub fn init_usdpl(port: u16) -> bool {
|
||||||
#[cfg(feature = "console_error_panic_hook")]
|
#[cfg(feature = "console_error_panic_hook")]
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
|
REMOTE_PORT.store(port, std::sync::atomic::Ordering::Relaxed);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the targeted plugin framework, or "any" if unknown
|
/// Get the targeted plugin framework, or "any" if unknown
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn target() -> String {
|
pub fn target() -> String {
|
||||||
"any".to_string()
|
#[cfg(all(feature = "decky", not(any(feature = "crankshaft"))))]
|
||||||
|
{"decky".to_string()}
|
||||||
|
#[cfg(all(feature = "crankshaft", not(any(feature = "decky"))))]
|
||||||
|
{"crankshaft".to_string()}
|
||||||
|
#[cfg(not(any(feature = "decky", feature = "crankshaft")))]
|
||||||
|
{"any".to_string()}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call a function on the back-end.
|
/// Call a function on the back-end.
|
||||||
|
@ -43,42 +50,19 @@ pub fn call_backend(name: String, parameters: Vec<JsValue>) -> Option<Vec<JsValu
|
||||||
let next_id = REMOTE_CALL_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
let next_id = REMOTE_CALL_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
let mut params = Vec::with_capacity(parameters.len());
|
let mut params = Vec::with_capacity(parameters.len());
|
||||||
for val in parameters {
|
for val in parameters {
|
||||||
if let Some(b) = val.as_bool() {
|
params.push(convert::js_to_primitive(val));
|
||||||
params.push(Primitive::Bool(b));
|
|
||||||
} else if let Some(f) = val.as_f64() {
|
|
||||||
params.push(Primitive::F64(f));
|
|
||||||
} else if let Some(s) = val.as_string() {
|
|
||||||
params.push(Primitive::String(s));
|
|
||||||
} else if val.is_null() || val.is_undefined() {
|
|
||||||
params.push(Primitive::Empty);
|
|
||||||
} else if let Ok(s) = stringify(&val) {
|
|
||||||
params.push(Primitive::Json(s.as_string().unwrap()));
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let results = match connection::send_native(Packet::Call(RemoteCall {
|
let results = match connection::send_native(Packet::Call(RemoteCall {
|
||||||
id: next_id,
|
id: next_id,
|
||||||
function: name,
|
function: name,
|
||||||
parameters: params,
|
parameters: params,
|
||||||
})) {
|
}), REMOTE_PORT.load(std::sync::atomic::Ordering::Relaxed)) {
|
||||||
Some(Packet::CallResponse(resp)) => resp,
|
Some(Packet::CallResponse(resp)) => resp,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let mut js_results = Vec::with_capacity(results.response.len());
|
let mut js_results = Vec::with_capacity(results.response.len());
|
||||||
for val in results.response {
|
for val in results.response {
|
||||||
let js_val = match val {
|
let js_val = convert::primitive_to_js(val);
|
||||||
Primitive::Empty => JsValue::null(),
|
|
||||||
Primitive::String(s) => JsValue::from_str(&s),
|
|
||||||
Primitive::F32(f)=> JsValue::from_f64(f as _),
|
|
||||||
Primitive::F64(f)=> JsValue::from_f64(f),
|
|
||||||
Primitive::U32(f)=> JsValue::from_f64(f as _),
|
|
||||||
Primitive::U64(f)=> JsValue::from_f64(f as _),
|
|
||||||
Primitive::I32(f)=> JsValue::from_f64(f as _),
|
|
||||||
Primitive::I64(f)=> JsValue::from_f64(f as _),
|
|
||||||
Primitive::Bool(b) => JsValue::from_bool(b),
|
|
||||||
Primitive::Json(s) => parse(&s).ok().unwrap_or(JsValue::from_str(&s)),
|
|
||||||
};
|
|
||||||
js_results.push(js_val);
|
js_results.push(js_val);
|
||||||
}
|
}
|
||||||
Some(js_results)
|
Some(js_results)
|
||||||
|
|
Loading…
Reference in a new issue