Upgrade backend & wasm to USDPL next
This commit is contained in:
parent
b52441f1ad
commit
c88402e580
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -44,6 +44,7 @@ yalc.lock
|
|||
/backend-rs/target
|
||||
backend
|
||||
/bin/backend
|
||||
/src/rust/target
|
||||
|
||||
# packaged teasers
|
||||
*.zip
|
||||
|
|
1267
backend-rs/Cargo.lock
generated
1267
backend-rs/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,17 +1,24 @@
|
|||
[package]
|
||||
name = "fantastic-rs"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
usdpl-back = { version = "0.10", features = ["blocking"]}
|
||||
usdpl-back = { version = "0.11", features = ["blocking"], path = "../../usdpl-rs/usdpl-back"}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
nrpc = "0.6"
|
||||
prost = "0.11"
|
||||
tokio = { version = "1", features = ["sync"] }
|
||||
|
||||
# logging
|
||||
log = "0.4"
|
||||
simplelog = "0.12"
|
||||
|
||||
[build-dependencies]
|
||||
usdpl-build = { version = "0.11", path = "../../usdpl-rs/usdpl-build" }
|
||||
|
||||
[profile.release]
|
||||
debug = false
|
||||
strip = true
|
||||
|
|
9
backend-rs/build.rs
Normal file
9
backend-rs/build.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
fn main() {
|
||||
//println!("CWD: {}", std::env::current_dir().unwrap().display());
|
||||
usdpl_build::back::build([
|
||||
format!("{}/protos/fantastic.proto", std::env::current_dir().unwrap().display())
|
||||
].into_iter(),
|
||||
[
|
||||
format!("{}/protos/", std::env::current_dir().unwrap().display())
|
||||
].into_iter())
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
#cargo build --release --target x86_64-unknown-linux-musl
|
||||
cargo build --target x86_64-unknown-linux-musl
|
||||
#cargo build --target x86_64-unknown-linux-musl
|
||||
#cross build --release
|
||||
cargo build
|
||||
|
||||
mkdir -p ../bin
|
||||
#cp ./target/x86_64-unknown-linux-musl/release/fantastic-rs ../bin/backend
|
||||
cp ./target/x86_64-unknown-linux-musl/debug/fantastic-rs ../bin/backend
|
||||
#cp ./target/release/fantastic-rs ../bin/backend
|
||||
#cp --preserve=mode ./target/x86_64-unknown-linux-musl/release/fantastic-rs ../bin/backend
|
||||
#cp --preserve=mode ./target/x86_64-unknown-linux-musl/debug/fantastic-rs ../bin/backend
|
||||
#cp --preserve=mode ./target/release/fantastic-rs ../bin/backend
|
||||
cp --preserve=mode ./target/debug/fantastic-rs ../bin/backend
|
||||
|
||||
|
|
136
backend-rs/protos/fantastic.proto
Normal file
136
backend-rs/protos/fantastic.proto
Normal file
|
@ -0,0 +1,136 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package fantastic;
|
||||
|
||||
// The most amazing fan service
|
||||
service Fan {
|
||||
// Send back the exact same message as received
|
||||
rpc echo (EchoMessage) returns (EchoMessage);
|
||||
|
||||
// Hello world
|
||||
rpc hello (NameMessage) returns (HelloResponse);
|
||||
|
||||
// Fantastic version info
|
||||
rpc version (Empty) returns (VersionMessage);
|
||||
|
||||
// Fantastic version number string
|
||||
rpc version_str (Empty) returns (VersionDisplayMessage);
|
||||
|
||||
// Rust name (fantastic)
|
||||
rpc name (Empty) returns (NameMessage);
|
||||
|
||||
// Get fan speed
|
||||
rpc get_fan_rpm (Empty) returns (RpmMessage);
|
||||
|
||||
// Get system temperature
|
||||
rpc get_temperature (Empty) returns (TemperatureMessage);
|
||||
|
||||
// Set custom fan control enabled
|
||||
rpc set_enable (EnablementMessage) returns (EnablementMessage);
|
||||
|
||||
// Get custon fan control status
|
||||
rpc get_enable (Empty) returns (EnablementMessage);
|
||||
|
||||
// Set fan control interpolation
|
||||
rpc set_interpolate (EnablementMessage) returns (EnablementMessage);
|
||||
|
||||
// Get fan control interpolation
|
||||
rpc get_interpolate (Empty) returns (EnablementMessage);
|
||||
|
||||
// Get fan control curve
|
||||
rpc get_curve_x (Empty) returns (CurveMessageX);
|
||||
|
||||
// Get fan control curve
|
||||
rpc get_curve_y (Empty) returns (CurveMessageY);
|
||||
|
||||
// Add a new point to the fan curve
|
||||
rpc add_curve_point (GraphPoint) returns (Empty);
|
||||
|
||||
// Remove a point from the fan curve
|
||||
rpc remove_curve_point (IndexMessage) returns (Empty);
|
||||
|
||||
/*
|
||||
.register("echo", api::echo)
|
||||
.register("hello", api::hello)
|
||||
.register("version", api::version)
|
||||
.register("name", api::name)
|
||||
.register("get_fan_rpm", api::get_fan_rpm)
|
||||
.register("get_temperature", api::get_temperature)
|
||||
.register("set_enable", api::set_enable_gen(&runtime))
|
||||
.register("get_enable", api::get_enable_gen(&runtime))
|
||||
.register("set_interpolate", api::set_interpolate_gen(&runtime))
|
||||
.register("get_interpolate", api::get_interpolate_gen(&runtime))
|
||||
.register("get_curve", api::get_curve_gen(&runtime))
|
||||
.register("add_curve_point", api::add_curve_point_gen(&runtime))
|
||||
.register("remove_curve_point", api::remove_curve_point_gen(&runtime))
|
||||
*/
|
||||
}
|
||||
|
||||
// The request and response message for Echo
|
||||
message EchoMessage {
|
||||
string msg = 1;
|
||||
}
|
||||
|
||||
message NameMessage {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message HelloResponse {
|
||||
string phrase = 1;
|
||||
}
|
||||
|
||||
message Empty {
|
||||
bool ok = 1;
|
||||
}
|
||||
|
||||
message VersionMessage {
|
||||
int32 major = 1;
|
||||
int32 minor = 2;
|
||||
int32 patch = 3;
|
||||
//string display = 4;
|
||||
}
|
||||
|
||||
message VersionDisplayMessage {
|
||||
string display = 1;
|
||||
}
|
||||
|
||||
message VersionStr {
|
||||
string version_str = 1;
|
||||
}
|
||||
|
||||
message RpmMessage {
|
||||
uint64 rpm = 1;
|
||||
}
|
||||
|
||||
message TemperatureMessage {
|
||||
double temperature = 1;
|
||||
}
|
||||
|
||||
message EnablementMessage {
|
||||
bool is_enabled = 1;
|
||||
}
|
||||
|
||||
message GraphPoint {
|
||||
double x = 1;
|
||||
double y = 2;
|
||||
}
|
||||
|
||||
/*message CurveMessage {
|
||||
//repeated GraphPoint points = 1;
|
||||
repeated double x = 1;
|
||||
repeated double y = 2;
|
||||
}*/
|
||||
|
||||
message CurveMessageX {
|
||||
//repeated GraphPoint points = 1;
|
||||
repeated double x = 1;
|
||||
}
|
||||
|
||||
message CurveMessageY {
|
||||
//repeated GraphPoint points = 1;
|
||||
repeated double y = 2;
|
||||
}
|
||||
|
||||
message IndexMessage {
|
||||
uint64 index = 1;
|
||||
}
|
|
@ -1,259 +1,183 @@
|
|||
use usdpl_back::core::serdes::Primitive;
|
||||
use crate::services::fantastic::*;
|
||||
|
||||
use super::control::ControlRuntime;
|
||||
use super::json::GraphPointJson;
|
||||
|
||||
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
pub const NAME: &'static str = env!("CARGO_PKG_NAME");
|
||||
|
||||
pub fn hello(params: Vec<Primitive>) -> Vec<Primitive> {
|
||||
if let Some(Primitive::String(name)) = params.get(0) {
|
||||
vec![Primitive::String(format!("Hello {}", name))]
|
||||
} else {
|
||||
vec![]
|
||||
pub struct FanService {
|
||||
ctrl: ControlRuntime,
|
||||
}
|
||||
|
||||
impl FanService {
|
||||
pub fn new(runtime: ControlRuntime) -> Self {
|
||||
runtime.run();
|
||||
Self {
|
||||
ctrl: runtime,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn echo(params: Vec<Primitive>) -> Vec<Primitive> {
|
||||
params
|
||||
}
|
||||
|
||||
pub fn version(_: Vec<Primitive>) -> Vec<Primitive> {
|
||||
vec![VERSION.into()]
|
||||
}
|
||||
|
||||
pub fn name(_: Vec<Primitive>) -> Vec<Primitive> {
|
||||
vec![NAME.into()]
|
||||
}
|
||||
|
||||
pub fn get_fan_rpm(_: Vec<Primitive>) -> Vec<Primitive> {
|
||||
#[usdpl_back::nrpc::_helpers::async_trait::async_trait]
|
||||
impl IFan for FanService {
|
||||
async fn echo(
|
||||
&mut self,
|
||||
input: EchoMessage,
|
||||
) -> Result<EchoMessage, Box<dyn std::error::Error>> {
|
||||
Ok(input)
|
||||
}
|
||||
async fn hello(
|
||||
&mut self,
|
||||
input: NameMessage,
|
||||
) -> Result<HelloResponse, Box<dyn std::error::Error>> {
|
||||
Ok(HelloResponse {
|
||||
phrase: format!("Hello {}", input.name)
|
||||
})
|
||||
}
|
||||
async fn version(
|
||||
&mut self,
|
||||
_input: Empty,
|
||||
) -> Result<VersionMessage, Box<dyn std::error::Error>> {
|
||||
Ok(
|
||||
VersionMessage {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
//display: VERSION.to_string(),
|
||||
}
|
||||
)
|
||||
}
|
||||
async fn version_str(
|
||||
&mut self,
|
||||
_input: Empty,
|
||||
) -> Result<VersionDisplayMessage, Box<dyn std::error::Error>> {
|
||||
Ok(
|
||||
VersionDisplayMessage {
|
||||
display: VERSION.to_owned(),
|
||||
}
|
||||
)
|
||||
}
|
||||
async fn name(
|
||||
&mut self,
|
||||
_input: Empty,
|
||||
) -> Result<NameMessage, Box<dyn std::error::Error>> {
|
||||
Ok(
|
||||
NameMessage {
|
||||
name: NAME.to_string(),
|
||||
}
|
||||
)
|
||||
}
|
||||
async fn get_fan_rpm(
|
||||
&mut self,
|
||||
_input: Empty,
|
||||
) -> Result<RpmMessage, Box<dyn std::error::Error>> {
|
||||
if let Some(rpm) = crate::sys::read_fan() {
|
||||
log::debug!("get_fan_rpm() success: {}", rpm);
|
||||
vec![rpm.into()]
|
||||
Ok(RpmMessage { rpm })
|
||||
} else {
|
||||
log::error!("get_fan_rpm failed to read fan speed");
|
||||
Vec::new()
|
||||
Err("Failed to read fan speed".into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_temperature(_: Vec<Primitive>) -> Vec<Primitive> {
|
||||
}
|
||||
async fn get_temperature(
|
||||
&mut self,
|
||||
_input: Empty,
|
||||
) -> Result<TemperatureMessage, Box<dyn std::error::Error>>{
|
||||
if let Some(temperature) = crate::sys::read_thermal_zone(0) {
|
||||
let real_temp = temperature as f64 / 1000.0;
|
||||
log::debug!("get_temperature() success: {}", real_temp);
|
||||
vec![real_temp.into()]
|
||||
Ok(TemperatureMessage { temperature: real_temp })
|
||||
} else {
|
||||
log::error!("get_fan_rpm failed to read fan speed");
|
||||
Vec::new()
|
||||
Err("get_temperature failed to read thermal zone 0".into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_enable_gen(runtime: &ControlRuntime) -> impl Fn(Vec<Primitive>) -> Vec<Primitive> {
|
||||
let runtime_settings = runtime.settings_clone();
|
||||
let runtime_state = runtime.state_clone();
|
||||
move |params| {
|
||||
if let Some(Primitive::Bool(enabled)) = params.get(0) {
|
||||
let mut settings = match runtime_settings.write() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("set_enable failed to acquire settings write lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
if settings.enable != *enabled {
|
||||
settings.enable = *enabled;
|
||||
let mut state = match runtime_state.write() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("set_enable failed to acquire state write lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
async fn set_enable(
|
||||
&mut self,
|
||||
input: EnablementMessage,
|
||||
) -> Result<EnablementMessage, Box<dyn std::error::Error>>{
|
||||
let mut settings = self.ctrl.settings().write().await;
|
||||
if settings.enable != input.is_enabled {
|
||||
let mut state = self.ctrl.state().write().await;
|
||||
settings.enable = input.is_enabled;
|
||||
state.dirty = true;
|
||||
log::debug!("set_enable({}) success", enabled);
|
||||
}
|
||||
vec![(*enabled).into()]
|
||||
} else {
|
||||
Vec::new()
|
||||
log::debug!("set_enable({}) success", input.is_enabled);
|
||||
Ok(input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_enable_gen(runtime: &ControlRuntime) -> impl Fn(Vec<Primitive>) -> Vec<Primitive> {
|
||||
let runtime_settings = runtime.settings_clone();
|
||||
move |_| {
|
||||
let lock = match runtime_settings.read() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("get_enable failed to acquire settings read lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
async fn get_enable(
|
||||
&mut self,
|
||||
_input: Empty,
|
||||
) -> Result<EnablementMessage, Box<dyn std::error::Error>>{
|
||||
let is_enabled = self.ctrl.settings().read().await.enable;
|
||||
log::debug!("get_enable() success");
|
||||
vec![lock.enable.into()]
|
||||
Ok(EnablementMessage { is_enabled })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_interpolate_gen(runtime: &ControlRuntime) -> impl Fn(Vec<Primitive>) -> Vec<Primitive> {
|
||||
let runtime_settings = runtime.settings_clone();
|
||||
let runtime_state = runtime.state_clone();
|
||||
move |params| {
|
||||
if let Some(Primitive::Bool(enabled)) = params.get(0) {
|
||||
let mut settings = match runtime_settings.write() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("set_enable failed to acquire settings write lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
if settings.interpolate != *enabled {
|
||||
settings.interpolate = *enabled;
|
||||
let mut state = match runtime_state.write() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("set_interpolate failed to acquire state write lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
async fn set_interpolate(
|
||||
&mut self,
|
||||
input: EnablementMessage,
|
||||
) -> Result<EnablementMessage, Box<dyn std::error::Error>>{
|
||||
let mut settings = self.ctrl.settings().write().await;
|
||||
if settings.interpolate != input.is_enabled {
|
||||
let mut state = self.ctrl.state().write().await;
|
||||
settings.interpolate = input.is_enabled;
|
||||
state.dirty = true;
|
||||
log::debug!("set_interpolate({}) success", enabled);
|
||||
}
|
||||
vec![(*enabled).into()]
|
||||
} else {
|
||||
Vec::new()
|
||||
log::debug!("set_interpolate({}) success", input.is_enabled);
|
||||
Ok(input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_interpolate_gen(runtime: &ControlRuntime) -> impl Fn(Vec<Primitive>) -> Vec<Primitive> {
|
||||
let runtime_settings = runtime.settings_clone();
|
||||
move |_| {
|
||||
let lock = match runtime_settings.read() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("get_interpolate failed to acquire settings read lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
async fn get_interpolate(
|
||||
&mut self,
|
||||
_input: Empty,
|
||||
) -> Result<EnablementMessage, Box<dyn std::error::Error>>{
|
||||
let is_enabled = self.ctrl.settings().read().await.interpolate;
|
||||
log::debug!("get_interpolate() success");
|
||||
vec![lock.interpolate.into()]
|
||||
Ok(EnablementMessage { is_enabled })
|
||||
}
|
||||
}
|
||||
|
||||
fn curve_to_json(curve: &Vec<super::datastructs::GraphPoint>) -> serde_json::Result<String> {
|
||||
let mut curve_points = Vec::<GraphPointJson>::with_capacity(curve.len());
|
||||
for point in curve.iter() {
|
||||
curve_points.push(point.clone().into());
|
||||
async fn get_curve_x(
|
||||
&mut self,
|
||||
_input: Empty,
|
||||
) -> Result<CurveMessageX, Box<dyn std::error::Error>>{
|
||||
let settings = self.ctrl.settings().read().await;
|
||||
let x = settings.curve.iter().map(|p| p.x).collect();
|
||||
log::debug!("get_curve_x() success");
|
||||
Ok(CurveMessageX { x })
|
||||
}
|
||||
serde_json::to_string(&curve_points)
|
||||
}
|
||||
|
||||
pub fn get_curve_gen(runtime: &ControlRuntime) -> impl Fn(Vec<Primitive>) -> Vec<Primitive> {
|
||||
let runtime_settings = runtime.settings_clone();
|
||||
move |_| {
|
||||
let lock = match runtime_settings.read() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("get_curve failed to acquire settings read lock: {}", e);
|
||||
return vec![];
|
||||
async fn get_curve_y(
|
||||
&mut self,
|
||||
_input: Empty,
|
||||
) -> Result<CurveMessageY, Box<dyn std::error::Error>>{
|
||||
let settings = self.ctrl.settings().read().await;
|
||||
let y = settings.curve.iter().map(|p| p.y).collect();
|
||||
log::debug!("get_curve_x() success");
|
||||
Ok(CurveMessageY { y })
|
||||
}
|
||||
};
|
||||
let json_str = match curve_to_json(&lock.curve) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("get_curve failed to serialize points: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
log::debug!("get_curve() success");
|
||||
vec![Primitive::Json(json_str)]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_curve_point_gen(runtime: &ControlRuntime) -> impl Fn(Vec<Primitive>) -> Vec<Primitive> {
|
||||
let runtime_settings = runtime.settings_clone();
|
||||
let runtime_state = runtime.state_clone();
|
||||
move |params| {
|
||||
if let Some(Primitive::Json(json_str)) = params.get(0) {
|
||||
let mut settings = match runtime_settings.write() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("add_curve_point failed to acquire settings write lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
let new_point: GraphPointJson = match serde_json::from_str(&json_str) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("add_curve_point failed deserialize point json: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
let version = settings.version;
|
||||
settings.curve.push(super::datastructs::GraphPoint::from_json(new_point, version));
|
||||
async fn add_curve_point(
|
||||
&mut self,
|
||||
point: GraphPoint,
|
||||
) -> Result<Empty, Box<dyn std::error::Error>>{
|
||||
let mut settings = self.ctrl.settings().write().await;
|
||||
settings.curve.push(super::datastructs::GraphPoint {
|
||||
x: point.x,
|
||||
y: point.y
|
||||
});
|
||||
settings.sort_curve();
|
||||
let mut state = match runtime_state.write() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("add_curve_point failed to acquire state write lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
let mut state = self.ctrl.state().write().await;
|
||||
state.dirty = true;
|
||||
let json_str = match curve_to_json(&settings.curve) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("add_curve_point failed to serialize points: {}", e);
|
||||
return vec![];
|
||||
Ok(Empty { ok: true })
|
||||
}
|
||||
};
|
||||
log::debug!("add_curve_point({}) success", json_str);
|
||||
vec![Primitive::Json(json_str)]
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_curve_point_gen(runtime: &ControlRuntime) -> impl Fn(Vec<Primitive>) -> Vec<Primitive> {
|
||||
let runtime_settings = runtime.settings_clone();
|
||||
let runtime_state = runtime.state_clone();
|
||||
move |params| {
|
||||
if let Some(Primitive::F64(index)) = params.get(0) {
|
||||
let mut settings = match runtime_settings.write() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("remove_curve_point failed to acquire settings write lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
let rounded = index.round();
|
||||
if rounded >= 0.0 && rounded < settings.curve.len() as _ {
|
||||
let index = rounded as usize;
|
||||
settings.curve.swap_remove(index);
|
||||
async fn remove_curve_point(
|
||||
&mut self,
|
||||
input: IndexMessage,
|
||||
) -> Result<Empty, Box<dyn std::error::Error>>{
|
||||
let mut settings = self.ctrl.settings().write().await;
|
||||
let i = input.index as usize;
|
||||
if settings.curve.len() < i {
|
||||
settings.curve.swap_remove(i);
|
||||
settings.sort_curve();
|
||||
let mut state = match runtime_state.write() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("remove_curve_point failed to acquire state write lock: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
let mut state = self.ctrl.state().write().await;
|
||||
state.dirty = true;
|
||||
let json_str = match curve_to_json(&settings.curve) {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("remove_curve_point failed to serialize points: {}", e);
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
log::debug!("remove_curve_point({}) success", json_str);
|
||||
vec![Primitive::Json(json_str)]
|
||||
Ok(Empty { ok: true })
|
||||
} else {
|
||||
log::error!("remove_curve_point received index out of bounds: {} indexing array of length {}", index, settings.curve.len());
|
||||
return vec![];
|
||||
}
|
||||
} else {
|
||||
Vec::new()
|
||||
Ok(Empty { ok: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Fan control
|
||||
|
||||
use std::sync::{RwLock, Arc};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
@ -33,6 +34,14 @@ impl ControlRuntime {
|
|||
self.state.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn settings(&self) -> &'_ RwLock<Settings> {
|
||||
&self.settings
|
||||
}
|
||||
|
||||
pub(crate) fn state(&self) -> &'_ RwLock<State> {
|
||||
&self.state
|
||||
}
|
||||
|
||||
pub fn run(&self) -> thread::JoinHandle<()> {
|
||||
let runtime_settings = self.settings_clone();
|
||||
let runtime_state = self.state_clone();
|
||||
|
@ -44,20 +53,8 @@ impl ControlRuntime {
|
|||
// resumed from sleep; do fan re-init
|
||||
log::debug!("Detected resume from sleep, overriding fan again");
|
||||
{
|
||||
let state = match runtime_state.read() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("runtime failed to acquire state read lock: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let settings = match runtime_settings.read() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("runtime failed to acquire settings read lock: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let state = runtime_state.blocking_read();
|
||||
let settings = runtime_settings.blocking_read();
|
||||
if settings.enable {
|
||||
Self::on_set_enable(&settings, &state);
|
||||
}
|
||||
|
@ -65,46 +62,22 @@ impl ControlRuntime {
|
|||
}
|
||||
start_time = Instant::now();
|
||||
{ // save to file
|
||||
let state = match runtime_state.read() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("runtime failed to acquire state read lock: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let state = runtime_state.blocking_read();
|
||||
if state.dirty {
|
||||
// save settings to file
|
||||
let settings = match runtime_settings.read() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("runtime failed to acquire settings read lock: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let settings = runtime_settings.blocking_read();
|
||||
let settings_json: SettingsJson = settings.clone().into();
|
||||
if let Err(e) = settings_json.save(settings_path(&state.home)) {
|
||||
log::error!("SettingsJson.save({}) error: {}", settings_path(&state.home).display(), e);
|
||||
}
|
||||
Self::on_set_enable(&settings, &state);
|
||||
drop(state);
|
||||
let mut state = match runtime_state.write() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("runtime failed to acquire state write lock: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let mut state = runtime_state.blocking_write();
|
||||
state.dirty = false;
|
||||
}
|
||||
}
|
||||
{ // fan control
|
||||
let settings = match runtime_settings.read() {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
log::error!("runtime failed to acquire settings read lock: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let settings = runtime_settings.blocking_read();
|
||||
if settings.enable {
|
||||
Self::enforce_jupiter_status(true);
|
||||
Self::do_fan_control(&settings);
|
||||
|
|
|
@ -6,7 +6,13 @@ mod sys;
|
|||
|
||||
use simplelog::{WriteLogger, LevelFilter};
|
||||
|
||||
use usdpl_back::Instance;
|
||||
#[allow(missing_docs)]
|
||||
#[allow(dead_code)]
|
||||
pub mod services {
|
||||
include!(concat!(env!("OUT_DIR"), "/mod.rs"));
|
||||
}
|
||||
|
||||
use services::fantastic::FanServer;
|
||||
|
||||
const PORT: u16 = 44444;
|
||||
|
||||
|
@ -20,9 +26,14 @@ fn main() -> Result<(), ()> {
|
|||
|
||||
log::info!("Starting back-end ({} v{})", api::NAME, api::VERSION);
|
||||
println!("Starting back-end ({} v{})", api::NAME, api::VERSION);
|
||||
let runtime = control::ControlRuntime::new();
|
||||
runtime.run();
|
||||
Instance::new(PORT)
|
||||
usdpl_back::Server::new(PORT)
|
||||
.register(FanServer::new(
|
||||
api::FanService::new(control::ControlRuntime::new())
|
||||
))
|
||||
.run_blocking()
|
||||
.unwrap();
|
||||
Ok(())
|
||||
/*Instance::new(PORT)
|
||||
.register("echo", api::echo)
|
||||
.register("hello", api::hello)
|
||||
.register("version", api::version)
|
||||
|
@ -36,7 +47,7 @@ fn main() -> Result<(), ()> {
|
|||
.register("get_curve", api::get_curve_gen(&runtime))
|
||||
.register("add_curve_point", api::add_curve_point_gen(&runtime))
|
||||
.register("remove_curve_point", api::remove_curve_point_gen(&runtime))
|
||||
.run_blocking()
|
||||
.run_blocking()*/
|
||||
//Ok(())
|
||||
//println!("Hello, world!");
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
"dependencies": {
|
||||
"decky-frontend-lib": "~3.19.1",
|
||||
"react-icons": "^4.7.1",
|
||||
"usdpl-front": "file:src/usdpl"
|
||||
"fantastic-wasm": "file:src/rust/pkg"
|
||||
},
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
|
|
1069
src/rust/Cargo.lock
generated
Normal file
1069
src/rust/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
19
src/rust/Cargo.toml
Normal file
19
src/rust/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "fantastic-wasm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
usdpl-front = { version = "0.11", path = "../../../usdpl-rs/usdpl-front"}
|
||||
nrpc = "0.6"
|
||||
prost = "0.11"
|
||||
|
||||
[build-dependencies]
|
||||
usdpl-build = { version = "0.11", path = "../../../usdpl-rs/usdpl-build" }
|
||||
|
||||
[features]
|
||||
debug = ["usdpl-front/debug"]
|
||||
decky = ["usdpl-front/decky"]
|
15
src/rust/build.rs
Normal file
15
src/rust/build.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
fn main() {
|
||||
println!("CWD: {}", std::env::current_dir().unwrap().display());
|
||||
usdpl_build::front::build(
|
||||
[format!(
|
||||
"{}/../../backend-rs/protos/fantastic.proto",
|
||||
std::env::current_dir().unwrap().display()
|
||||
)]
|
||||
.into_iter(),
|
||||
[format!(
|
||||
"{}/../../backend-rs/protos/",
|
||||
std::env::current_dir().unwrap().display()
|
||||
)]
|
||||
.into_iter(),
|
||||
)
|
||||
}
|
19
src/rust/build.sh
Executable file
19
src/rust/build.sh
Executable file
|
@ -0,0 +1,19 @@
|
|||
#!/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"
|
||||
RUSTFLAGS="--cfg aes_compact" wasm-pack build --target web --features decky,$2
|
||||
else
|
||||
echo "Unsupported plugin framework \`$1\`"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "WARNING: Building for any plugin framework, which may not work for every framework"
|
||||
RUSTFLAGS="--cfg aes_compact" wasm-pack build --target web --features debug,$2
|
||||
fi
|
||||
|
||||
python3 ./scripts/generate_embedded_wasm.py
|
45
src/rust/scripts/generate_embedded_wasm.py
Normal file
45
src/rust/scripts/generate_embedded_wasm.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
import base64
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Embedding WASM into udspl_front.js")
|
||||
# assumption: current working directory (relative to this script) is ../
|
||||
# assumption: release wasm binary at ./pkg/usdpl_bg.wasm
|
||||
with open("./pkg/fantastic_wasm_bg.wasm", mode="rb") as infile:
|
||||
with open("./pkg/fantastic_wasm.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, {
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
headers: {
|
||||
'Content-Type': 'application/wasm'
|
||||
}
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
export function init_embedded() {
|
||||
return init(decode())
|
||||
}
|
||||
""".encode())
|
||||
with open("./pkg/usdpl_front.d.ts", "a") as outfile:
|
||||
outfile.write("\n\n// USDPL customization\nexport function init_embedded();\n")
|
||||
print("Done: Embedded WASM into udspl_front.js")
|
5
src/rust/src/lib.rs
Normal file
5
src/rust/src/lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
#[allow(missing_docs)]
|
||||
#[allow(dead_code)]
|
||||
pub mod services {
|
||||
include!(concat!(env!("OUT_DIR"), "/mod.rs"));
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
[![Crates.io](https://img.shields.io/crates/v/usdpl-front?style=flat-square)](https://crates.io/crates/usdpl-front)
|
||||
|
||||
# usdpl-front-front
|
||||
|
||||
Front-end library to be called from Javascript.
|
||||
Targets WASM.
|
||||
|
||||
In true Javascript tradition, this part of the library does not support error handling.
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"name": "usdpl-front",
|
||||
"collaborators": [
|
||||
"NGnius (Graham) <ngniusness@gmail.com>"
|
||||
],
|
||||
"description": "Universal Steam Deck Plugin Library front-end designed for WASM",
|
||||
"version": "0.10.0",
|
||||
"license": "GPL-3.0-only",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/NGnius/usdpl-rs"
|
||||
},
|
||||
"files": [
|
||||
"usdpl_front_bg.wasm",
|
||||
"usdpl_front.js",
|
||||
"usdpl_front.d.ts"
|
||||
],
|
||||
"module": "usdpl_front.js",
|
||||
"types": "usdpl_front.d.ts",
|
||||
"sideEffects": false
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
git clone https://github.com/NGnius/usdpl-rs usdpl-rs
|
||||
cd usdpl-rs/usdpl-front/
|
||||
|
||||
./build.sh $1 $2
|
||||
|
||||
cd ../..
|
||||
|
||||
cp -f ./usdpl-rs/usdpl-front/pkg/* ./
|
||||
#rm ./.gitignore
|
||||
|
||||
rm -rf ./usdpl-rs
|
105
src/usdpl/usdpl_front.d.ts
vendored
105
src/usdpl/usdpl_front.d.ts
vendored
|
@ -1,105 +0,0 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Initialize the front-end library
|
||||
* @param {number} port
|
||||
*/
|
||||
export function init_usdpl(port: number): void;
|
||||
/**
|
||||
* Get the targeted plugin framework, or "any" if unknown
|
||||
* @returns {string}
|
||||
*/
|
||||
export function target_usdpl(): string;
|
||||
/**
|
||||
* Get the UDSPL front-end version
|
||||
* @returns {string}
|
||||
*/
|
||||
export function version_usdpl(): string;
|
||||
/**
|
||||
* Get the targeted plugin framework, or "any" if unknown
|
||||
* @param {string} key
|
||||
* @param {any} value
|
||||
* @returns {any}
|
||||
*/
|
||||
export function set_value(key: string, value: any): any;
|
||||
/**
|
||||
* Get the targeted plugin framework, or "any" if unknown
|
||||
* @param {string} key
|
||||
* @returns {any}
|
||||
*/
|
||||
export function get_value(key: string): any;
|
||||
/**
|
||||
* Call a function on the back-end.
|
||||
* Returns null (None) if this fails for any reason.
|
||||
* @param {string} name
|
||||
* @param {any[]} parameters
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export function call_backend(name: string, parameters: any[]): Promise<any>;
|
||||
/**
|
||||
* Initialize translation strings for the front-end
|
||||
* @param {string} locale
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export function init_tr(locale: string): Promise<void>;
|
||||
/**
|
||||
* Translate a phrase, equivalent to tr_n(msg_id, 0)
|
||||
* @param {string} msg_id
|
||||
* @returns {string}
|
||||
*/
|
||||
export function tr(msg_id: string): string;
|
||||
/**
|
||||
* Translate a phrase, retrieving the plural form for `n` items
|
||||
* @param {string} msg_id
|
||||
* @param {number} n
|
||||
* @returns {string}
|
||||
*/
|
||||
export function tr_n(msg_id: string, n: number): string;
|
||||
|
||||
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
export interface InitOutput {
|
||||
readonly memory: WebAssembly.Memory;
|
||||
readonly init_usdpl: (a: number) => void;
|
||||
readonly target_usdpl: (a: number) => void;
|
||||
readonly version_usdpl: (a: number) => void;
|
||||
readonly set_value: (a: number, b: number, c: number) => number;
|
||||
readonly get_value: (a: number, b: number) => number;
|
||||
readonly call_backend: (a: number, b: number, c: number, d: number) => number;
|
||||
readonly init_tr: (a: number, b: number) => number;
|
||||
readonly tr: (a: number, b: number, c: number) => void;
|
||||
readonly tr_n: (a: number, b: number, c: number, d: number) => void;
|
||||
readonly __wbindgen_export_0: (a: number) => number;
|
||||
readonly __wbindgen_export_1: (a: number, b: number, c: number) => number;
|
||||
readonly __wbindgen_export_2: WebAssembly.Table;
|
||||
readonly __wbindgen_export_3: (a: number, b: number, c: number) => void;
|
||||
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
||||
readonly __wbindgen_export_4: (a: number, b: number) => void;
|
||||
readonly __wbindgen_export_5: (a: number) => void;
|
||||
readonly __wbindgen_export_6: (a: number, b: number, c: number, d: number) => void;
|
||||
}
|
||||
|
||||
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
||||
/**
|
||||
* Instantiates the given `module`, which can either be bytes or
|
||||
* a precompiled `WebAssembly.Module`.
|
||||
*
|
||||
* @param {SyncInitInput} module
|
||||
*
|
||||
* @returns {InitOutput}
|
||||
*/
|
||||
export function initSync(module: SyncInitInput): InitOutput;
|
||||
|
||||
/**
|
||||
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
||||
* for everything else, calls `WebAssembly.instantiate` directly.
|
||||
*
|
||||
* @param {InitInput | Promise<InitInput>} module_or_path
|
||||
*
|
||||
* @returns {Promise<InitOutput>}
|
||||
*/
|
||||
export default function init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;
|
||||
|
||||
|
||||
// USDPL customization
|
||||
export function init_embedded();
|
File diff suppressed because one or more lines are too long
Binary file not shown.
20
src/usdpl/usdpl_front_bg.wasm.d.ts
vendored
20
src/usdpl/usdpl_front_bg.wasm.d.ts
vendored
|
@ -1,20 +0,0 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export const memory: WebAssembly.Memory;
|
||||
export function init_usdpl(a: number): void;
|
||||
export function target_usdpl(a: number): void;
|
||||
export function version_usdpl(a: number): void;
|
||||
export function set_value(a: number, b: number, c: number): number;
|
||||
export function get_value(a: number, b: number): number;
|
||||
export function call_backend(a: number, b: number, c: number, d: number): number;
|
||||
export function init_tr(a: number, b: number): number;
|
||||
export function tr(a: number, b: number, c: number): void;
|
||||
export function tr_n(a: number, b: number, c: number, d: number): void;
|
||||
export function __wbindgen_export_0(a: number): number;
|
||||
export function __wbindgen_export_1(a: number, b: number, c: number): number;
|
||||
export const __wbindgen_export_2: WebAssembly.Table;
|
||||
export function __wbindgen_export_3(a: number, b: number, c: number): void;
|
||||
export function __wbindgen_add_to_stack_pointer(a: number): number;
|
||||
export function __wbindgen_export_4(a: number, b: number): void;
|
||||
export function __wbindgen_export_5(a: number): void;
|
||||
export function __wbindgen_export_6(a: number, b: number, c: number, d: number): void;
|
Loading…
Reference in a new issue