Improve scalability and documentation
This commit is contained in:
parent
569eab5880
commit
79f730b9c6
26 changed files with 465 additions and 162 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 NGnius
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
83
backend/Cargo.lock
generated
83
backend/Cargo.lock
generated
|
@ -88,6 +88,42 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "3.2.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"clap_derive",
|
||||||
|
"clap_lex",
|
||||||
|
"indexmap",
|
||||||
|
"once_cell",
|
||||||
|
"textwrap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "3.2.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -264,6 +300,12 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
|
@ -372,6 +414,7 @@ name = "kaylon"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"clap",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -484,6 +527,12 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -528,6 +577,30 @@ version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.40"
|
version = "1.0.40"
|
||||||
|
@ -749,6 +822,12 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.31"
|
version = "1.0.31"
|
||||||
|
@ -984,6 +1063,8 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usdpl-back"
|
name = "usdpl-back"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ca96dac4ee471e9534940f99cb36f5212cbfaf4e7779eb3ba970d3c511d9583"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -997,6 +1078,8 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usdpl-core"
|
name = "usdpl-core"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "862153581fac266458521f49e5906a71c1eee1665cb4c7d71e9586bd34b45394"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
[package]
|
[package]
|
||||||
name = "kaylon" # TODO replace with plugin name (also in build.sh)
|
name = "kaylon"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
authors = ["NGnius <ngniusness@gmail.com>"]
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
description = "Better than the Borg"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/NGnius/kaylon"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
usdpl-back = { version = "0.7.0", features = ["decky"], path = "../../usdpl-rs/usdpl-back" }
|
usdpl-back = { version = "0.7.0", features = ["decky"]}
|
||||||
|
|
||||||
|
clap = { version = "3.2", features = ["derive", "std"], default-features = false }
|
||||||
|
|
||||||
# async
|
# async
|
||||||
tokio = { version = "*", features = ["sync", "time"] }
|
tokio = { version = "*", features = ["time"] }
|
||||||
async-trait = "0.1.57"
|
async-trait = "0.1.57"
|
||||||
|
|
||||||
# json
|
# json
|
||||||
|
|
|
@ -4,6 +4,7 @@ use super::ApiParameterType;
|
||||||
|
|
||||||
use crate::runtime::{QueueAction, QueueItem};
|
use crate::runtime::{QueueAction, QueueItem};
|
||||||
|
|
||||||
|
/// API web method to retrieve AboutConfig from the back-end, as described in the config file
|
||||||
pub fn get_about(sender: Sender<QueueItem>) -> impl Fn(ApiParameterType) -> ApiParameterType {
|
pub fn get_about(sender: Sender<QueueItem>) -> impl Fn(ApiParameterType) -> ApiParameterType {
|
||||||
let sender = Mutex::new(sender);
|
let sender = Mutex::new(sender);
|
||||||
move |_| {
|
move |_| {
|
||||||
|
|
19
backend/src/api/async_utils.rs
Normal file
19
backend/src/api/async_utils.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use std::sync::mpsc::{TryRecvError, Receiver};
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
/// Receive on a blocking channel in an async manner (by polling conservatively)
|
||||||
|
pub async fn channel_recv<T>(rx: Receiver<T>) -> Result<T, TryRecvError> {
|
||||||
|
let sleep_duration = std::time::Duration::from_millis(10);
|
||||||
|
let receiver = Mutex::new(rx);
|
||||||
|
loop {
|
||||||
|
let received = receiver.lock().unwrap().try_recv();
|
||||||
|
match received {
|
||||||
|
Err(TryRecvError::Disconnected) => {
|
||||||
|
return Err(TryRecvError::Disconnected);
|
||||||
|
},
|
||||||
|
Err(_) => {},
|
||||||
|
Ok(x) => return Ok(x),
|
||||||
|
}
|
||||||
|
tokio::time::sleep(sleep_duration).await;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,12 @@ use std::sync::{Mutex, mpsc::{Sender, channel, self}};
|
||||||
use usdpl_back::core::serdes::Primitive;
|
use usdpl_back::core::serdes::Primitive;
|
||||||
use usdpl_back::AsyncCallable;
|
use usdpl_back::AsyncCallable;
|
||||||
|
|
||||||
use super::ApiParameterType;
|
use super::{ApiParameterType, ApiDisplayResult};
|
||||||
|
|
||||||
use crate::runtime::{QueueAction, QueueItem};
|
use crate::runtime::{QueueAction, QueueItem};
|
||||||
|
|
||||||
|
/// API web method to retrieve the latest display result for an element,
|
||||||
|
// or wait for the next display result if no display result is cached
|
||||||
pub struct GetDisplayEndpoint {
|
pub struct GetDisplayEndpoint {
|
||||||
//sender: tokio::sync::mpsc::Sender<SetCallbackAsync>,
|
//sender: tokio::sync::mpsc::Sender<SetCallbackAsync>,
|
||||||
//receiver: Mutex<Option<tokio::sync::mpsc::Receiver<SetCallbackAsync>>>,
|
//receiver: Mutex<Option<tokio::sync::mpsc::Receiver<SetCallbackAsync>>>,
|
||||||
|
@ -40,33 +42,31 @@ impl AsyncCallable for GetDisplayEndpoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if let Ok(_) = send_result {
|
match send_result {
|
||||||
|
Ok(_) => {
|
||||||
// TODO: don't poll for response
|
// TODO: don't poll for response
|
||||||
log::info!("waiting for display for item #{}", index);
|
log::info!("waiting for display for item #{}", index);
|
||||||
let sleep_duration = std::time::Duration::from_millis(10);
|
match super::async_utils::channel_recv(receiver).await {
|
||||||
let receiver = Mutex::new(receiver);
|
|
||||||
loop {
|
|
||||||
let received = receiver.lock().unwrap().try_recv();
|
|
||||||
match received {
|
|
||||||
Err(mpsc::TryRecvError::Disconnected) => {
|
Err(mpsc::TryRecvError::Disconnected) => {
|
||||||
log::info!("Failed to response for get_display for #{}", index);
|
let msg = format!("Failed to response for get_display for #{}", index);
|
||||||
return vec![Primitive::Empty];
|
log::warn!("{}", msg);
|
||||||
|
return vec![ApiDisplayResult::failure(msg, "receiving channel disconnected").to_primitive()];
|
||||||
},
|
},
|
||||||
Err(_) => {},
|
Err(_) => return vec![], // impossible
|
||||||
Ok(x) => {
|
Ok(x) => {
|
||||||
log::debug!("got display for item #{}", index);
|
log::debug!("got display for item #{}", index);
|
||||||
return vec![x];
|
return vec![ApiDisplayResult::success(x).to_primitive()];
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
tokio::time::sleep(sleep_duration).await;
|
},
|
||||||
|
Err(_e) => {
|
||||||
|
let msg = format!("Failed to get_display for #{}", index);
|
||||||
|
log::warn!("{}", msg);
|
||||||
|
vec![ApiDisplayResult::failure(msg, "sending channel disconnected").to_primitive()]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::info!("Failed to get_display for #{}", index);
|
vec![ApiDisplayResult::failure("Failed to get param 0", "invalid call parameters").to_primitive()]
|
||||||
vec![Primitive::Empty]
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
vec![Primitive::Empty]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use super::ApiParameterType;
|
||||||
|
|
||||||
use crate::runtime::{QueueAction, QueueItem};
|
use crate::runtime::{QueueAction, QueueItem};
|
||||||
|
|
||||||
|
/// API web method to retrieve all ElementConfig items from the back-end, as described in the config file
|
||||||
pub fn get_items(sender: Sender<QueueItem>) -> impl Fn(ApiParameterType) -> ApiParameterType {
|
pub fn get_items(sender: Sender<QueueItem>) -> impl Fn(ApiParameterType) -> ApiParameterType {
|
||||||
let sender = Mutex::new(sender);
|
let sender = Mutex::new(sender);
|
||||||
move |_| {
|
move |_| {
|
|
@ -1,13 +1,16 @@
|
||||||
mod about;
|
mod about;
|
||||||
|
pub(crate) mod async_utils;
|
||||||
mod get_display;
|
mod get_display;
|
||||||
mod get_item;
|
mod get_items;
|
||||||
mod on_update;
|
mod on_update;
|
||||||
mod reload;
|
mod reload;
|
||||||
|
mod types;
|
||||||
|
|
||||||
pub use about::get_about;
|
pub use about::get_about;
|
||||||
pub use get_display::GetDisplayEndpoint;
|
pub use get_display::GetDisplayEndpoint;
|
||||||
pub use get_item::get_items;
|
pub use get_items::get_items;
|
||||||
pub use on_update::on_update;
|
pub use on_update::on_update;
|
||||||
pub use reload::reload;
|
pub use reload::reload;
|
||||||
|
pub(super) use types::*;
|
||||||
|
|
||||||
pub(super) type ApiParameterType = Vec<usdpl_back::core::serdes::Primitive>;
|
pub(super) type ApiParameterType = Vec<usdpl_back::core::serdes::Primitive>;
|
||||||
|
|
|
@ -6,6 +6,7 @@ use super::ApiParameterType;
|
||||||
|
|
||||||
use crate::runtime::{QueueAction, QueueItem};
|
use crate::runtime::{QueueAction, QueueItem};
|
||||||
|
|
||||||
|
/// API web method to notify the back-end of an update event (e.g. click, slider slide, toggle)
|
||||||
pub fn on_update(sender: Sender<QueueItem>) -> impl Fn(ApiParameterType) -> ApiParameterType {
|
pub fn on_update(sender: Sender<QueueItem>) -> impl Fn(ApiParameterType) -> ApiParameterType {
|
||||||
let sender = Mutex::new(sender);
|
let sender = Mutex::new(sender);
|
||||||
move |mut params: ApiParameterType| {
|
move |mut params: ApiParameterType| {
|
||||||
|
|
70
backend/src/api/types.rs
Normal file
70
backend/src/api/types.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use serde_json::Value;
|
||||||
|
use usdpl_back::core::serdes::Primitive;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
#[serde(tag = "element")]
|
||||||
|
pub enum ApiDisplayResult {
|
||||||
|
#[serde(rename = "value")]
|
||||||
|
Value(ApiValue),
|
||||||
|
#[serde(rename = "error")]
|
||||||
|
Error(ApiError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApiDisplayResult {
|
||||||
|
pub fn dump(&self) -> String {
|
||||||
|
serde_json::to_string(self).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_primitive(self) -> Primitive {
|
||||||
|
Primitive::Json(self.dump())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn success(primitive: Primitive) -> Self {
|
||||||
|
Self::Value(ApiValue::new(primitive))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn failure<S: Into<String>, D: core::fmt::Display>(msg: S, err: D) -> Self {
|
||||||
|
Self::Error(ApiError::new(msg, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ApiValue {
|
||||||
|
pub value: Value,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApiValue {
|
||||||
|
pub fn new(primitive: Primitive) -> Self {
|
||||||
|
let val = match primitive {
|
||||||
|
Primitive::Empty => Value::Null,
|
||||||
|
Primitive::String(s) => Value::String(s),
|
||||||
|
Primitive::F32(x) => x.into(),
|
||||||
|
Primitive::F64(x) => x.into(),
|
||||||
|
Primitive::U32(x) => Value::Number(x.into()),
|
||||||
|
Primitive::U64(x) => Value::Number(x.into()),
|
||||||
|
Primitive::I32(x) => Value::Number(x.into()),
|
||||||
|
Primitive::I64(x) => Value::Number(x.into()),
|
||||||
|
Primitive::Bool(x) => Value::Bool(x),
|
||||||
|
Primitive::Json(x) => serde_json::from_str(&x).unwrap_or(Value::Null),
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
value: val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ApiError {
|
||||||
|
pub message: String,
|
||||||
|
pub exception: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApiError {
|
||||||
|
pub fn new<S: Into<String>, D: core::fmt::Display>(msg: S, err: D) -> Self {
|
||||||
|
Self {
|
||||||
|
message: msg.into(),
|
||||||
|
exception: err.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
backend/src/cli.rs
Normal file
19
backend/src/cli.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[clap(author, version, about, long_about = None)]
|
||||||
|
pub struct CliArgs {
|
||||||
|
/// Path to config file
|
||||||
|
#[clap(long)]
|
||||||
|
pub config: Option<std::path::PathBuf>,
|
||||||
|
|
||||||
|
/// Path to log file
|
||||||
|
#[clap(long)]
|
||||||
|
pub log: Option<std::path::PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CliArgs {
|
||||||
|
pub fn cli() -> Self {
|
||||||
|
Self::parse()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
mod api;
|
mod api;
|
||||||
|
mod cli;
|
||||||
mod config;
|
mod config;
|
||||||
mod consts;
|
mod consts;
|
||||||
mod runtime;
|
mod runtime;
|
||||||
|
@ -9,16 +10,19 @@ use usdpl_back::Instance;
|
||||||
use usdpl_back::core::serdes::Primitive;
|
use usdpl_back::core::serdes::Primitive;
|
||||||
|
|
||||||
fn main() -> Result<(), ()> {
|
fn main() -> Result<(), ()> {
|
||||||
let log_filepath = format!("/tmp/{}.log", consts::PACKAGE_NAME);
|
let cli_args = cli::CliArgs::cli();
|
||||||
|
let log_filepath = cli_args.log.unwrap_or_else(|| format!("/tmp/{}.log", consts::PACKAGE_NAME).into());
|
||||||
WriteLogger::init(
|
WriteLogger::init(
|
||||||
#[cfg(debug_assertions)]{LevelFilter::Debug},
|
#[cfg(debug_assertions)]{LevelFilter::Debug},
|
||||||
#[cfg(not(debug_assertions))]{LevelFilter::Info},
|
#[cfg(not(debug_assertions))]{LevelFilter::Info},
|
||||||
Default::default(),
|
Default::default(),
|
||||||
std::fs::File::create(&log_filepath).unwrap()
|
std::fs::File::create(log_filepath).unwrap()
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let kaylon_conf = config::BaseConfig::load(consts::FILEPATH);
|
let filepath = cli_args.config.unwrap_or(consts::FILEPATH.into());
|
||||||
let (executor, sender) = runtime::RuntimeExecutor::new(kaylon_conf);
|
|
||||||
|
let kaylon_conf = config::BaseConfig::load(&filepath);
|
||||||
|
let (executor, sender) = runtime::RuntimeExecutor::new(kaylon_conf, filepath);
|
||||||
|
|
||||||
log::info!("Starting back-end ({} v{})", consts::PACKAGE_NAME, consts::PACKAGE_VERSION);
|
log::info!("Starting back-end ({} v{})", consts::PACKAGE_NAME, consts::PACKAGE_VERSION);
|
||||||
println!("Starting back-end ({} v{})", consts::PACKAGE_NAME, consts::PACKAGE_VERSION);
|
println!("Starting back-end ({} v{})", consts::PACKAGE_NAME, consts::PACKAGE_VERSION);
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::config::{ElementConfig, ActionConfig};
|
||||||
|
|
||||||
pub type ActError = String;
|
pub type ActError = String;
|
||||||
|
|
||||||
|
/// Something capable of performing an action.
|
||||||
pub trait Act: Sized {
|
pub trait Act: Sized {
|
||||||
type Param;
|
type Param;
|
||||||
type Config: ?Sized;
|
type Config: ?Sized;
|
||||||
|
@ -12,6 +13,7 @@ pub trait Act: Sized {
|
||||||
fn run(self) -> Self::Return;
|
fn run(self) -> Self::Return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Action performer for a regular element
|
||||||
pub struct Actor {
|
pub struct Actor {
|
||||||
actor_type: ActorType,
|
actor_type: ActorType,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
|
|
@ -7,6 +7,7 @@ use super::{Act, ActError};
|
||||||
|
|
||||||
const VALUE_ENV_VAR: &str = "KAYLON_VALUE";
|
const VALUE_ENV_VAR: &str = "KAYLON_VALUE";
|
||||||
|
|
||||||
|
/// Runs a CLI command in Bash
|
||||||
pub struct CommandActor {
|
pub struct CommandActor {
|
||||||
shell: String,
|
shell: String,
|
||||||
run: String,
|
run: String,
|
||||||
|
|
|
@ -4,6 +4,7 @@ use usdpl_back::core::serdes::Primitive;
|
||||||
|
|
||||||
use crate::config::{AboutConfig, ElementConfig};
|
use crate::config::{AboutConfig, ElementConfig};
|
||||||
|
|
||||||
|
/// An API operation for the executor to perform
|
||||||
pub enum QueueAction {
|
pub enum QueueAction {
|
||||||
GetAbout {
|
GetAbout {
|
||||||
respond_to: Sender<AboutConfig>,
|
respond_to: Sender<AboutConfig>,
|
||||||
|
@ -21,6 +22,7 @@ pub enum QueueAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wrapper for an executor command
|
||||||
pub struct QueueItem {
|
pub struct QueueItem {
|
||||||
pub action: QueueAction,
|
pub action: QueueAction,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
use std::sync::mpsc::{self, Receiver, Sender};
|
||||||
|
|
||||||
use crate::config::{BaseConfig, ElementConfig};
|
use crate::config::{BaseConfig, ElementConfig};
|
||||||
|
@ -7,15 +8,17 @@ use super::{ResultRouter, RouterCommand};
|
||||||
|
|
||||||
pub struct RuntimeExecutor {
|
pub struct RuntimeExecutor {
|
||||||
config_data: BaseConfig,
|
config_data: BaseConfig,
|
||||||
tasks_receiver: Receiver<QueueItem>
|
tasks_receiver: Receiver<QueueItem>,
|
||||||
|
config_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RuntimeExecutor {
|
impl RuntimeExecutor {
|
||||||
pub fn new(conf: BaseConfig) -> (Self, Sender<QueueItem>) {
|
pub fn new<P: AsRef<Path>>(conf: BaseConfig, path: P) -> (Self, Sender<QueueItem>) {
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
(Self {
|
(Self {
|
||||||
config_data: conf,
|
config_data: conf,
|
||||||
tasks_receiver: rx,
|
tasks_receiver: rx,
|
||||||
|
config_path: path.as_ref().to_path_buf(),
|
||||||
}, tx)
|
}, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +39,7 @@ impl RuntimeExecutor {
|
||||||
ExecutorState {
|
ExecutorState {
|
||||||
result_handler: ExecutorState::build_router(self.config_data.items().len()),
|
result_handler: ExecutorState::build_router(self.config_data.items().len()),
|
||||||
config_data: self.config_data,
|
config_data: self.config_data,
|
||||||
|
config_path: self.config_path,
|
||||||
},
|
},
|
||||||
self.tasks_receiver
|
self.tasks_receiver
|
||||||
)
|
)
|
||||||
|
@ -45,15 +49,19 @@ impl RuntimeExecutor {
|
||||||
struct ExecutorState {
|
struct ExecutorState {
|
||||||
config_data: BaseConfig,
|
config_data: BaseConfig,
|
||||||
result_handler: Sender<RouterCommand>,
|
result_handler: Sender<RouterCommand>,
|
||||||
|
config_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecutorState {
|
impl ExecutorState {
|
||||||
fn handle_item(&mut self, item: QueueItem) {
|
fn handle_item(&mut self, item: QueueItem) {
|
||||||
match item.action {
|
match item.action {
|
||||||
QueueAction::GetAbout { respond_to } => {
|
QueueAction::GetAbout { respond_to } => {
|
||||||
|
// retrieve about information from (in-memory) config file
|
||||||
respond_to.send(self.config_data.get_about().clone()).unwrap_or(());
|
respond_to.send(self.config_data.get_about().clone()).unwrap_or(());
|
||||||
},
|
},
|
||||||
QueueAction::DoUpdate { index, value } => {
|
QueueAction::DoUpdate { index, value } => {
|
||||||
|
// trigger update event for element
|
||||||
|
// i.e. on_click, on_toggle, etc. action
|
||||||
if let Some(item) = self.config_data.get_item(index) {
|
if let Some(item) = self.config_data.get_item(index) {
|
||||||
match super::Actor::build(item, (index, value)) {
|
match super::Actor::build(item, (index, value)) {
|
||||||
Ok(act) => {
|
Ok(act) => {
|
||||||
|
@ -73,23 +81,30 @@ impl ExecutorState {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
QueueAction::DoReload { respond_to } => {
|
QueueAction::DoReload { respond_to } => {
|
||||||
self.config_data = BaseConfig::load(crate::consts::FILEPATH);
|
// reload config file from storage
|
||||||
|
self.config_data = BaseConfig::load(&self.config_path);
|
||||||
self.populate_router();
|
self.populate_router();
|
||||||
respond_to.send(self.config_data.items().clone()).unwrap_or(());
|
respond_to.send(self.config_data.items().clone()).unwrap_or(());
|
||||||
},
|
},
|
||||||
QueueAction::SetCallback { index, respond_to } => {
|
QueueAction::SetCallback { index, respond_to } => {
|
||||||
|
// register a callback with the ResultRouter for an element's action
|
||||||
|
// the next time that action is performed, the result will be sent through the callback
|
||||||
if let Some(elem) = self.config_data.get_item(index) {
|
if let Some(elem) = self.config_data.get_item(index) {
|
||||||
let display_of = match elem {
|
let display_of = match elem {
|
||||||
ElementConfig::ResultDisplay(c) => c.result_of,
|
ElementConfig::ResultDisplay(c) => c.result_of,
|
||||||
_ => index,
|
_ => index,
|
||||||
};
|
};
|
||||||
if let Err(_) = self.result_handler.send(
|
if let Err(e) = self.result_handler.send(
|
||||||
RouterCommand::AddSender {
|
RouterCommand::AddSender {
|
||||||
index: display_of,
|
index: display_of,
|
||||||
sender: respond_to,
|
sender: respond_to,
|
||||||
}) {
|
}) {
|
||||||
log::warn!("Failed to send to ResultRouter, rebuilding router");
|
log::warn!("Failed to send to ResultRouter, rebuilding router");
|
||||||
self.result_handler = ExecutorState::build_router(self.config_data.items().len());
|
self.result_handler = ExecutorState::build_router(self.config_data.items().len());
|
||||||
|
if let Err(_) = self.result_handler.send(e.0) {
|
||||||
|
// don't retry if another error occurs
|
||||||
|
log::error!("Failed to send to ResultRouter again, did not SetCallback for item #{}", index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use usdpl_back::core::serdes::Primitive;
|
||||||
use crate::config::ReadingConfig;
|
use crate::config::ReadingConfig;
|
||||||
use super::{Act, ActError, ActorType, RouterCommand};
|
use super::{Act, ActError, ActorType, RouterCommand};
|
||||||
|
|
||||||
|
/// Runs an action periodically
|
||||||
pub struct PeriodicActor {
|
pub struct PeriodicActor {
|
||||||
config: ReadingConfig,
|
config: ReadingConfig,
|
||||||
result_handler: Sender<RouterCommand>,
|
result_handler: Sender<RouterCommand>,
|
||||||
|
|
|
@ -20,9 +20,13 @@ pub enum RouterCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ResultRouter {
|
pub struct ResultRouter {
|
||||||
|
/// receiver for new router commands to perform
|
||||||
comm: Receiver<RouterCommand>,
|
comm: Receiver<RouterCommand>,
|
||||||
|
/// active callbacks; more than one sender may listen for a result
|
||||||
senders: Vec<[Option<Sender<Primitive>>; MAX_HANDLERS_PER_ITEM]>,
|
senders: Vec<[Option<Sender<Primitive>>; MAX_HANDLERS_PER_ITEM]>,
|
||||||
|
/// cache of sender, for Act paradigm
|
||||||
comm_tx: Option<Sender<RouterCommand>>,
|
comm_tx: Option<Sender<RouterCommand>>,
|
||||||
|
/// cache of unheard results
|
||||||
cache: Vec<Option<Primitive>>,
|
cache: Vec<Option<Primitive>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,16 +66,21 @@ impl Act for ResultRouter {
|
||||||
for command in self.comm.iter() {
|
for command in self.comm.iter() {
|
||||||
match command {
|
match command {
|
||||||
RouterCommand::AddSender { index, sender } => {
|
RouterCommand::AddSender { index, sender } => {
|
||||||
|
// register result listener
|
||||||
log::debug!("Handling AddSender for item #{}", index);
|
log::debug!("Handling AddSender for item #{}", index);
|
||||||
if let Some(senders) = self.senders.get_mut(index) {
|
if let Some(senders) = self.senders.get_mut(index) {
|
||||||
// send cached value, if available
|
// send cached value, if available.
|
||||||
|
// This avoids race conditions from a result being received before
|
||||||
|
// a listener has been registered. This is especially an issue during
|
||||||
|
// program start, when actions run immediately and listeners come from
|
||||||
|
// the slow front-end (web request in the browser)
|
||||||
if self.cache[index].is_some() {
|
if self.cache[index].is_some() {
|
||||||
log::debug!("Routing cached result for item #{}", index);
|
log::debug!("Routing cached result for item #{}", index);
|
||||||
let result = self.cache[index].take().unwrap();
|
let result = self.cache[index].take().unwrap();
|
||||||
match sender.send(result) {
|
match sender.send(result) {
|
||||||
Ok(_) => {},
|
Ok(_) => {},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.cache[index] = Some(e.0);
|
self.cache[index] = Some(e.0); // re-cache if send fails
|
||||||
log::debug!("ResultRouter ignoring AddSender since sending cached value failed");
|
log::debug!("ResultRouter ignoring AddSender since sending cached value failed");
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
|
@ -94,9 +103,11 @@ impl Act for ResultRouter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RouterCommand::HandleResult {index, result} => {
|
RouterCommand::HandleResult {index, result} => {
|
||||||
|
// send a result to all (relevant) listeners
|
||||||
log::debug!("Handling HandleResult for item #{}", index);
|
log::debug!("Handling HandleResult for item #{}", index);
|
||||||
if let Some(senders) = self.senders.get_mut(index) {
|
if let Some(senders) = self.senders.get_mut(index) {
|
||||||
if Self::all_senders_none(senders) {
|
if Self::all_senders_none(senders) {
|
||||||
|
// cache result if it won't be heard
|
||||||
self.cache[index] = Some(result);
|
self.cache[index] = Some(result);
|
||||||
log::debug!("Cached result for item #{}", index);
|
log::debug!("Cached result for item #{}", index);
|
||||||
} else {
|
} else {
|
||||||
|
|
79
kaylon.json
79
kaylon.json
|
@ -1,47 +1,62 @@
|
||||||
{
|
{
|
||||||
"api-version": "v0.0.0",
|
"api-version": "v0.0.0",
|
||||||
"items": [
|
"items": [
|
||||||
|
{
|
||||||
|
"element": "result-display",
|
||||||
|
"title": "Best Kaylon",
|
||||||
|
"result_of": 1
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"element": "button",
|
"element": "button",
|
||||||
"title": "Test Button",
|
"title": "Tell Me!",
|
||||||
"on_click": {
|
"on_click": {
|
||||||
"action": "command",
|
"action": "command",
|
||||||
"run": "echo 'hello button'"
|
"run": "echo ISAAC"
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"element": "toggle",
|
|
||||||
"title": "Test Toggle",
|
|
||||||
"description": "Toggle description",
|
|
||||||
"on_toggle": {
|
|
||||||
"action": "command",
|
|
||||||
"run": "echo 'hello toggle ${KAYLON_VALUE}'"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"element": "slider",
|
|
||||||
"title": "Test Slider",
|
|
||||||
"min": 0,
|
|
||||||
"max": 3,
|
|
||||||
"notches": null,
|
|
||||||
"on_set": {
|
|
||||||
"action": "command",
|
|
||||||
"run": "echo 'hello slider'"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"element": "reading",
|
|
||||||
"title": "Test Reading",
|
|
||||||
"period_ms": 10000,
|
|
||||||
"on_period": {
|
|
||||||
"action": "command",
|
|
||||||
"run": "echo 'hello reading'"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"element": "result-display",
|
"element": "result-display",
|
||||||
"title": "Test Result",
|
"title": "Smartest Kaylon",
|
||||||
"result_of": 1
|
"result_of": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"element": "toggle",
|
||||||
|
"title": "Switch",
|
||||||
|
"description": "Toggle me!",
|
||||||
|
"on_toggle": {
|
||||||
|
"action": "command",
|
||||||
|
"run": "echo \"Toggle is now ${KAYLON_VALUE}\""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"element": "result-display",
|
||||||
|
"title": "",
|
||||||
|
"result_of": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"element": "slider",
|
||||||
|
"title": "Slider",
|
||||||
|
"min": 0,
|
||||||
|
"max": 10,
|
||||||
|
"notches": null,
|
||||||
|
"on_set": {
|
||||||
|
"action": "command",
|
||||||
|
"run": "echo \"Slider is now ${KAYLON_VALUE}\""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"element": "result-display",
|
||||||
|
"title": "",
|
||||||
|
"result_of": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"element": "reading",
|
||||||
|
"title": "Fan Speed",
|
||||||
|
"period_ms": 1000,
|
||||||
|
"on_period": {
|
||||||
|
"action": "command",
|
||||||
|
"run": "cat /sys/class/hwmon/hwmon5/fan1_input"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"about": {
|
"about": {
|
||||||
|
|
2
main.py
2
main.py
|
@ -11,6 +11,6 @@ class Plugin:
|
||||||
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
||||||
async def _main(self):
|
async def _main(self):
|
||||||
# startup
|
# startup
|
||||||
#self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend"])
|
#self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend", "--config", ""])
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
171
package-lock.json
generated
171
package-lock.json
generated
|
@ -9,7 +9,7 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "GPL-2.0-or-later",
|
"license": "GPL-2.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"decky-frontend-lib": "^1.0.1",
|
"decky-frontend-lib": "*",
|
||||||
"react-icons": "^4.3.1",
|
"react-icons": "^4.3.1",
|
||||||
"usdpl-front": "file:./src/usdpl_front"
|
"usdpl-front": "file:./src/usdpl_front"
|
||||||
},
|
},
|
||||||
|
@ -77,9 +77,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.14",
|
"version": "0.3.15",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
|
||||||
"integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
|
"integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.0.3",
|
"@jridgewell/resolve-uri": "^3.0.3",
|
||||||
|
@ -153,9 +153,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-typescript": {
|
"node_modules/@rollup/plugin-typescript": {
|
||||||
"version": "8.3.4",
|
"version": "8.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz",
|
||||||
"integrity": "sha512-wt7JnYE9antX6BOXtsxGoeVSu4dZfw0dU3xykfOQ4hC3EddxRbVG/K0xiY1Wup7QOHJcjLYXWAn0Kx9Z1SBHHg==",
|
"integrity": "sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/pluginutils": "^3.1.0",
|
"@rollup/pluginutils": "^3.1.0",
|
||||||
|
@ -199,9 +199,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/eslint": {
|
"node_modules/@types/eslint": {
|
||||||
"version": "8.4.5",
|
"version": "8.4.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz",
|
||||||
"integrity": "sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ==",
|
"integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "*",
|
"@types/estree": "*",
|
||||||
|
@ -231,9 +231,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "18.6.4",
|
"version": "18.7.17",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.17.tgz",
|
||||||
"integrity": "sha512-I4BD3L+6AWiUobfxZ49DlU43gtI+FTHSv9pE2Zekg6KjMpre4ByusaljW3vYSLJrvQ1ck1hUaeVu8HVlY3vzHg==",
|
"integrity": "sha512-0UyfUnt02zIuqp7yC8RYtDkp/vo8bFaQ13KkSEvUAohPOAlnVNbj5Fi3fgPSuwzakS+EvvnnZ4x9y7i6ASaSPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/prop-types": {
|
"node_modules/@types/prop-types": {
|
||||||
|
@ -539,9 +539,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001374",
|
"version": "1.0.30001397",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001374.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001397.tgz",
|
||||||
"integrity": "sha512-mWvzatRx3w+j5wx/mpFN5v5twlPrabG8NqX2c6e45LCpymdoGqNvRkRutFUqpRTXKFQFNQJasvK0YT7suW6/Hw==",
|
"integrity": "sha512-SW9N2TbCdLf0eiNDRrrQXx2sOkaakNZbCjgNpPyMJJbiOrU5QzMIrXOVMRM1myBXTD5iTkdrtU/EguCrBocHlA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -588,9 +588,12 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/decky-frontend-lib": {
|
"node_modules/decky-frontend-lib": {
|
||||||
"version": "1.3.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/decky-frontend-lib/-/decky-frontend-lib-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/decky-frontend-lib/-/decky-frontend-lib-3.0.0.tgz",
|
||||||
"integrity": "sha512-j3MfgfSlAE1TUZ5BCmwh01GLFUZsCkDH/FRfTWGYbaJ+49sy6WM9u/1hFHTuX43lK9ZM4BABvweKjsi2AnzsMw=="
|
"integrity": "sha512-ZqJ9ii7QoYWHFfkU8hV82IHi3+McZDmE4wS22duXpgRI8r5BBMiZItw6tYkc24ZtsJIVso83FFt7adcEBqBwJA==",
|
||||||
|
"dependencies": {
|
||||||
|
"minimist": "^1.2.6"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/deepmerge": {
|
"node_modules/deepmerge": {
|
||||||
"version": "4.2.2",
|
"version": "4.2.2",
|
||||||
|
@ -602,9 +605,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.211",
|
"version": "1.4.248",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.211.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.248.tgz",
|
||||||
"integrity": "sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A==",
|
"integrity": "sha512-qShjzEYpa57NnhbW2K+g+Fl+eNoDvQ7I+2MRwWnU6Z6F0HhXekzsECCLv+y2OJUsRodjqoSfwHkIX42VUFtUzg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/enhanced-resolve": {
|
"node_modules/enhanced-resolve": {
|
||||||
|
@ -955,8 +958,7 @@
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/neo-async": {
|
"node_modules/neo-async": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
|
@ -1080,9 +1082,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "2.77.2",
|
"version": "2.79.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.0.tgz",
|
||||||
"integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==",
|
"integrity": "sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
|
@ -1264,9 +1266,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.14.2",
|
"version": "5.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz",
|
||||||
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
|
"integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.2",
|
"@jridgewell/source-map": "^0.3.2",
|
||||||
|
@ -1282,16 +1284,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser-webpack-plugin": {
|
"node_modules/terser-webpack-plugin": {
|
||||||
"version": "5.3.3",
|
"version": "5.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz",
|
||||||
"integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==",
|
"integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/trace-mapping": "^0.3.7",
|
"@jridgewell/trace-mapping": "^0.3.14",
|
||||||
"jest-worker": "^27.4.5",
|
"jest-worker": "^27.4.5",
|
||||||
"schema-utils": "^3.1.1",
|
"schema-utils": "^3.1.1",
|
||||||
"serialize-javascript": "^6.0.0",
|
"serialize-javascript": "^6.0.0",
|
||||||
"terser": "^5.7.2"
|
"terser": "^5.14.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10.13.0"
|
"node": ">= 10.13.0"
|
||||||
|
@ -1322,9 +1324,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "4.7.4",
|
"version": "4.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz",
|
||||||
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
|
"integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
|
@ -1335,9 +1337,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.8.tgz",
|
||||||
"integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==",
|
"integrity": "sha512-GHg7C4M7oJSJYW/ED/5QOJ7nL/E0lwTOBGsOorA7jqHr8ExUhPfwAotIAmdSw/LWv3SMLSNpzTAgeLG9zaZKTA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -1461,11 +1463,8 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"src/usdpl_front": {
|
"src/usdpl_front": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.2",
|
||||||
"license": "GPL-3.0-only"
|
"license": "GPL-3.0-only"
|
||||||
},
|
|
||||||
"src/usdpl-front": {
|
|
||||||
"extraneous": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1509,9 +1508,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@jridgewell/trace-mapping": {
|
"@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.14",
|
"version": "0.3.15",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
|
||||||
"integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
|
"integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jridgewell/resolve-uri": "^3.0.3",
|
"@jridgewell/resolve-uri": "^3.0.3",
|
||||||
|
@ -1567,9 +1566,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@rollup/plugin-typescript": {
|
"@rollup/plugin-typescript": {
|
||||||
"version": "8.3.4",
|
"version": "8.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.5.0.tgz",
|
||||||
"integrity": "sha512-wt7JnYE9antX6BOXtsxGoeVSu4dZfw0dU3xykfOQ4hC3EddxRbVG/K0xiY1Wup7QOHJcjLYXWAn0Kx9Z1SBHHg==",
|
"integrity": "sha512-wMv1/scv0m/rXx21wD2IsBbJFba8wGF3ErJIr6IKRfRj49S85Lszbxb4DCo8iILpluTjk2GAAu9CoZt4G3ppgQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@rollup/pluginutils": "^3.1.0",
|
"@rollup/pluginutils": "^3.1.0",
|
||||||
|
@ -1596,9 +1595,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/eslint": {
|
"@types/eslint": {
|
||||||
"version": "8.4.5",
|
"version": "8.4.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz",
|
||||||
"integrity": "sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ==",
|
"integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/estree": "*",
|
"@types/estree": "*",
|
||||||
|
@ -1628,9 +1627,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "18.6.4",
|
"version": "18.7.17",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.17.tgz",
|
||||||
"integrity": "sha512-I4BD3L+6AWiUobfxZ49DlU43gtI+FTHSv9pE2Zekg6KjMpre4ByusaljW3vYSLJrvQ1ck1hUaeVu8HVlY3vzHg==",
|
"integrity": "sha512-0UyfUnt02zIuqp7yC8RYtDkp/vo8bFaQ13KkSEvUAohPOAlnVNbj5Fi3fgPSuwzakS+EvvnnZ4x9y7i6ASaSPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/prop-types": {
|
"@types/prop-types": {
|
||||||
|
@ -1900,9 +1899,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001374",
|
"version": "1.0.30001397",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001374.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001397.tgz",
|
||||||
"integrity": "sha512-mWvzatRx3w+j5wx/mpFN5v5twlPrabG8NqX2c6e45LCpymdoGqNvRkRutFUqpRTXKFQFNQJasvK0YT7suW6/Hw==",
|
"integrity": "sha512-SW9N2TbCdLf0eiNDRrrQXx2sOkaakNZbCjgNpPyMJJbiOrU5QzMIrXOVMRM1myBXTD5iTkdrtU/EguCrBocHlA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"chrome-trace-event": {
|
"chrome-trace-event": {
|
||||||
|
@ -1936,9 +1935,12 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"decky-frontend-lib": {
|
"decky-frontend-lib": {
|
||||||
"version": "1.3.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/decky-frontend-lib/-/decky-frontend-lib-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/decky-frontend-lib/-/decky-frontend-lib-3.0.0.tgz",
|
||||||
"integrity": "sha512-j3MfgfSlAE1TUZ5BCmwh01GLFUZsCkDH/FRfTWGYbaJ+49sy6WM9u/1hFHTuX43lK9ZM4BABvweKjsi2AnzsMw=="
|
"integrity": "sha512-ZqJ9ii7QoYWHFfkU8hV82IHi3+McZDmE4wS22duXpgRI8r5BBMiZItw6tYkc24ZtsJIVso83FFt7adcEBqBwJA==",
|
||||||
|
"requires": {
|
||||||
|
"minimist": "^1.2.6"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"deepmerge": {
|
"deepmerge": {
|
||||||
"version": "4.2.2",
|
"version": "4.2.2",
|
||||||
|
@ -1947,9 +1949,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.4.211",
|
"version": "1.4.248",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.211.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.248.tgz",
|
||||||
"integrity": "sha512-BZSbMpyFQU0KBJ1JG26XGeFI3i4op+qOYGxftmZXFZoHkhLgsSv4DHDJfl8ogII3hIuzGt51PaZ195OVu0yJ9A==",
|
"integrity": "sha512-qShjzEYpa57NnhbW2K+g+Fl+eNoDvQ7I+2MRwWnU6Z6F0HhXekzsECCLv+y2OJUsRodjqoSfwHkIX42VUFtUzg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"enhanced-resolve": {
|
"enhanced-resolve": {
|
||||||
|
@ -2232,8 +2234,7 @@
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"neo-async": {
|
"neo-async": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
|
@ -2331,9 +2332,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rollup": {
|
"rollup": {
|
||||||
"version": "2.77.2",
|
"version": "2.79.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.0.tgz",
|
||||||
"integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==",
|
"integrity": "sha512-x4KsrCgwQ7ZJPcFA/SUu6QVcYlO7uRLfLAy0DSA4NS2eG8japdbpM50ToH7z4iObodRYOJ0soneF0iaQRJ6zhA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
|
@ -2457,9 +2458,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"version": "5.14.2",
|
"version": "5.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.15.0.tgz",
|
||||||
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
|
"integrity": "sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jridgewell/source-map": "^0.3.2",
|
"@jridgewell/source-map": "^0.3.2",
|
||||||
|
@ -2469,16 +2470,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"terser-webpack-plugin": {
|
"terser-webpack-plugin": {
|
||||||
"version": "5.3.3",
|
"version": "5.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz",
|
||||||
"integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==",
|
"integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jridgewell/trace-mapping": "^0.3.7",
|
"@jridgewell/trace-mapping": "^0.3.14",
|
||||||
"jest-worker": "^27.4.5",
|
"jest-worker": "^27.4.5",
|
||||||
"schema-utils": "^3.1.1",
|
"schema-utils": "^3.1.1",
|
||||||
"serialize-javascript": "^6.0.0",
|
"serialize-javascript": "^6.0.0",
|
||||||
"terser": "^5.7.2"
|
"terser": "^5.14.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tslib": {
|
"tslib": {
|
||||||
|
@ -2488,15 +2489,15 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.7.4",
|
"version": "4.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz",
|
||||||
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
|
"integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"update-browserslist-db": {
|
"update-browserslist-db": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.8.tgz",
|
||||||
"integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==",
|
"integrity": "sha512-GHg7C4M7oJSJYW/ED/5QOJ7nL/E0lwTOBGsOorA7jqHr8ExUhPfwAotIAmdSw/LWv3SMLSNpzTAgeLG9zaZKTA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"escalade": "^3.1.1",
|
"escalade": "^3.1.1",
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"name": "Kaylon",
|
"name": "Kaylon",
|
||||||
"author": "NGnius",
|
"author": "NGnius",
|
||||||
"flags": ["debug", "_root"],
|
"flags": ["_debug", "_root"],
|
||||||
"publish": {
|
"publish": {
|
||||||
"tags": ["template", "root"],
|
"tags": ["automation", "cli"],
|
||||||
"description": "Better than the Borg",
|
"description": "Better than the Borg",
|
||||||
"image": ""
|
"image": ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,19 @@ export type CResultDisplay = {
|
||||||
|
|
||||||
export type CElement = CButton | CToggle | CSlider | CReading | CResultDisplay;
|
export type CElement = CButton | CToggle | CSlider | CReading | CResultDisplay;
|
||||||
|
|
||||||
|
export type CErrorResult = {
|
||||||
|
element: string; // "error"
|
||||||
|
message: string;
|
||||||
|
exception: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CValueResult = {
|
||||||
|
element: string; // "value"
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CDisplayResponse = CValueResult | CErrorResult;
|
||||||
|
|
||||||
export async function getElements(): Promise<CElement[]> {
|
export async function getElements(): Promise<CElement[]> {
|
||||||
return (await call_backend("get_items", []))[0];
|
return (await call_backend("get_items", []))[0];
|
||||||
}
|
}
|
||||||
|
@ -74,7 +87,7 @@ export async function onUpdate(index: number, value: any): Promise<any> {
|
||||||
return (await call_backend("on_update", [index, value]))[0];
|
return (await call_backend("on_update", [index, value]))[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getDisplay(index: number): Promise<string | null> {
|
export async function getDisplay(index: number): Promise<CDisplayResponse> {
|
||||||
return (await call_backend("get_display", [index]))[0];
|
return (await call_backend("get_display", [index]))[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,26 @@ let about: backend.CAbout | null = null;
|
||||||
let update = () => {};
|
let update = () => {};
|
||||||
|
|
||||||
function displayCallback(index: number) {
|
function displayCallback(index: number) {
|
||||||
return (newVal: any) => {
|
return (newVal: backend.CDisplayResponse) => {
|
||||||
set_value(DISPLAY_KEY + index.toString(), newVal);
|
if (newVal != null) {
|
||||||
|
switch (newVal.element) {
|
||||||
|
case "value":
|
||||||
|
let val = newVal as backend.CValueResult;
|
||||||
|
console.log("KAYLON: Got display for " + index.toString(), val);
|
||||||
|
set_value(DISPLAY_KEY + index.toString(), val.value);
|
||||||
|
break;
|
||||||
|
case "error":
|
||||||
|
let err = newVal as backend.CErrorResult;
|
||||||
|
console.warn("KAYLON: Got display error for " + index.toString(), err);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error("KAYLON: Got invalid display response for " + index.toString(), newVal);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("KAYLON: Ignoring null display result for " + index.toString());
|
||||||
|
}
|
||||||
backend.resolve(backend.getDisplay(index), displayCallback(index));
|
backend.resolve(backend.getDisplay(index), displayCallback(index));
|
||||||
console.log("Got display for " + index.toString(), newVal);
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Reference in a new issue