Hi,
Is it possible to write asynchronous functions in the custom ADR?
All the examples I see are fully synchronous, but I want to make HTTP requests to delegate some calculations to a separate engine, is it possible?
Thank you
Hi,
Is it possible to write asynchronous functions in the custom ADR?
All the examples I see are fully synchronous, but I want to make HTTP requests to delegate some calculations to a separate engine, is it possible?
Thank you
So, answering to myself here.
QuickJS does not provide any reasonable way to send HTTP requests.
It needs a native module that provides that (qjs-net or write your own).
Native modules can be imported using ES6 imports:
import * as net from 'net.so'; // Would load `qjs-net`
In Chirpstack that does not work, because Chirpstack (using rquickjs) runs the JS as a script and not a module so that syntax is not available. Instead, this syntax must be used:[1]
const net = await import('./net.so');
Which doesn’t work either I believe because Chirpstack uses a Context and a Runtime that are not async capable: AsyncContext and AsyncRuntime would allow that to be called. It’s is not clear to me though because Chirpstack does not return a detailed error message when a script fails, like the codecs do[2] as it doesn’t catch from the ADR script.
In any case, doing ADR is not mandatory for our case but Chirpstack doesn’t provide any gRPC interface for configuring device parameters like channel masks, tx power, data rate and so on, so we can’t find any way to replace the ADR system with an augmented one that can take smarter decisions.
Just if anyone was interested.
I tried importing an external module changing Chirpstack’s code but in the end the easiest way was to implement support for HTTP requests from Rust itself and expose that to the JS.
What I didn’t manage to do is to make them Asyncronous, because that requires more changes.
I installed ureq and using that exposed an HTTP request module I wrote, and that’s perfectly available from JavaScript, and I can delegate the ADR calculus to a more powerful system.
I didn’t manage to make this work with reqwest, which is already included in Chirpstack.
It’s pretty ugly stuff, but it works:
--- a/chirpstack/src/adr/plugin.rs
+++ b/chirpstack/src/adr/plugin.rs
@@ -13,6 +13,22 @@ pub struct Plugin {
name: String,
}
+#[rquickjs::module(rename_vars = "camelCase")]
+mod http {
+ #[rquickjs::function]
+ pub fn get(url: String) -> Result<String, rquickjs::Error> {
+ // TODO: improve me
+ let body: String = ureq::get(url)
+ .header("Example-Header", "header value")
+ .call()
+ .map_err(|e| rquickjs::Error::Exception)?
+ .body_mut()
+ .read_to_string()
+ .map_err(|e| rquickjs::Error::Exception)?;
+ Ok(body)
+ }
+}
+
impl Plugin {
pub fn new(file_path: &str) -> Result<Self> {
let rt = rquickjs::Runtime::new()?;
@@ -20,6 +36,7 @@ impl Plugin {
let script = fs::read_to_string(file_path).context("Read ADR plugin")?;
let (id, name) = ctx.with::<_, Result<(String, String)>>(|ctx| {
+ rquickjs::Module::declare_def::<js_http, _>(ctx.clone(), "http").unwrap();
let m = rquickjs::Module::declare(ctx.clone(), "script", script.clone())
.catch(&ctx)
.map_err(|e| anyhow!("Declare script: JS error: {}", e))?;
@@ -73,6 +90,7 @@ impl Handler for Plugin {
let ctx = rquickjs::Context::full(&rt)?;
ctx.with::<_, Result<Response>>(|ctx| {
+ rquickjs::Module::declare_def::<js_http, _>(ctx.clone(), "http").unwrap();
let m = rquickjs::Module::declare(ctx.clone(), "script", self.script.clone())
.catch(&ctx)
.map_err(|e| anyhow!("Declare script: JS error: {}", e))?;
And about this… I sent a PR
That’s incorrect. It can work, but it needs Loaders and Resolvers for the modules you want to load. If there are none configured, it won’t load anything, it’s not because Chirpstack loads things as scripts, it loads them as Modules, actually.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.