mirror of
https://github.com/chirpstack/chirpstack.git
synced 2025-04-13 14:13:01 +00:00
Integrate Buffer class into JS codec runtime.
This commit is contained in:
parent
a656b9f3a1
commit
5b1d70cdbf
Cargo.lock
chirpstack
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -2905,6 +2905,12 @@ version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "relative-path"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4e112eddc95bbf25365df3b5414354ad2fe7ee465eddb9965a515faf8c3b6d9"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
@ -2985,6 +2991,7 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6da4f2b300a58f9fb368bb68b21e288586e503cc0e0c3c3f94af9b28a717e2c"
|
||||
dependencies = [
|
||||
"relative-path",
|
||||
"rquickjs-sys",
|
||||
]
|
||||
|
||||
|
@ -89,7 +89,7 @@ paho-mqtt = { version = "0.9", features = ["vendored-ssl"] }
|
||||
hex = "0.4"
|
||||
|
||||
# Codecs
|
||||
rquickjs = { version = "0.1.5", features = ["bindgen"] }
|
||||
rquickjs = { version = "0.1.5", features = ["bindgen", "loader", "array-buffer"] }
|
||||
|
||||
# Misc
|
||||
lazy_static = "1.4"
|
||||
|
@ -7,6 +7,10 @@ use rquickjs::IntoJs;
|
||||
use super::convert;
|
||||
use crate::config;
|
||||
|
||||
mod vendor_base64_js;
|
||||
mod vendor_buffer;
|
||||
mod vendor_ieee754;
|
||||
|
||||
pub async fn decode(
|
||||
f_port: u8,
|
||||
variables: &HashMap<String, String>,
|
||||
@ -16,13 +20,25 @@ pub async fn decode(
|
||||
let conf = config::get();
|
||||
let max_run_ts = SystemTime::now() + conf.codec.js.max_execution_time;
|
||||
|
||||
let resolver = rquickjs::BuiltinResolver::default()
|
||||
.with_module("base64-js")
|
||||
.with_module("ieee754")
|
||||
.with_module("buffer");
|
||||
let loader = rquickjs::BuiltinLoader::default()
|
||||
.with_module("base64-js", vendor_base64_js::SCRIPT)
|
||||
.with_module("ieee754", vendor_ieee754::SCRIPT)
|
||||
.with_module("buffer", vendor_buffer::SCRIPT);
|
||||
|
||||
let rt = rquickjs::Runtime::new()?;
|
||||
rt.set_interrupt_handler(Some(Box::new(move || SystemTime::now() > max_run_ts)));
|
||||
rt.set_loader(resolver, loader);
|
||||
|
||||
let ctx = rquickjs::Context::full(&rt)?;
|
||||
|
||||
let script = format!(
|
||||
r#"
|
||||
import {{ Buffer }} from "buffer";
|
||||
|
||||
{}
|
||||
|
||||
export {{ decodeUplink }};
|
||||
@ -61,14 +77,27 @@ pub async fn encode(
|
||||
let conf = config::get();
|
||||
let max_run_ts = SystemTime::now() + conf.codec.js.max_execution_time;
|
||||
|
||||
let resolver = rquickjs::BuiltinResolver::default()
|
||||
.with_module("base64-js")
|
||||
.with_module("ieee754")
|
||||
.with_module("buffer");
|
||||
let loader = rquickjs::BuiltinLoader::default()
|
||||
.with_module("base64-js", vendor_base64_js::SCRIPT)
|
||||
.with_module("ieee754", vendor_ieee754::SCRIPT)
|
||||
.with_module("buffer", vendor_buffer::SCRIPT);
|
||||
|
||||
let rt = rquickjs::Runtime::new()?;
|
||||
rt.set_interrupt_handler(Some(Box::new(move || SystemTime::now() > max_run_ts)));
|
||||
rt.set_loader(resolver, loader);
|
||||
|
||||
let ctx = rquickjs::Context::full(&rt)?;
|
||||
|
||||
let script = format!(
|
||||
r#"
|
||||
import {{ Buffer }} from "buffer";
|
||||
|
||||
{}
|
||||
|
||||
export {{ encodeDownlink }};
|
||||
"#,
|
||||
encode_config,
|
||||
@ -113,10 +142,13 @@ pub mod test {
|
||||
pub async fn test_decode() {
|
||||
let decoder = r#"
|
||||
function decodeUplink(input) {
|
||||
var buff = new Buffer(input.bytes);
|
||||
|
||||
return {
|
||||
object: {
|
||||
f_port: input.fPort,
|
||||
variables: input.variables,
|
||||
data_hex: buff.toString('hex'),
|
||||
data: input.bytes
|
||||
}
|
||||
};
|
||||
@ -159,6 +191,12 @@ pub mod test {
|
||||
)),
|
||||
},
|
||||
),
|
||||
(
|
||||
"data_hex".to_string(),
|
||||
pbjson_types::Value {
|
||||
kind: Some(pbjson_types::value::Kind::StringValue("010203".to_string())),
|
||||
},
|
||||
),
|
||||
(
|
||||
"data".to_string(),
|
||||
pbjson_types::Value {
|
155
chirpstack/src/codec/js/vendor_base64_js.rs
Normal file
155
chirpstack/src/codec/js/vendor_base64_js.rs
Normal file
@ -0,0 +1,155 @@
|
||||
// base64-js does basic base64 encoding/decoding in pure JS.
|
||||
//
|
||||
// License: MIT
|
||||
// Source: https://github.com/beatgammit/base64-js
|
||||
|
||||
pub const SCRIPT: &str = r#"
|
||||
'use strict'
|
||||
|
||||
export { byteLength, toByteArray, fromByteArray };
|
||||
|
||||
var lookup = []
|
||||
var revLookup = []
|
||||
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
|
||||
|
||||
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
for (var i = 0, len = code.length; i < len; ++i) {
|
||||
lookup[i] = code[i]
|
||||
revLookup[code.charCodeAt(i)] = i
|
||||
}
|
||||
|
||||
// Support decoding URL-safe base64 strings, as Node.js does.
|
||||
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
|
||||
revLookup['-'.charCodeAt(0)] = 62
|
||||
revLookup['_'.charCodeAt(0)] = 63
|
||||
|
||||
function getLens (b64) {
|
||||
var len = b64.length
|
||||
|
||||
if (len % 4 > 0) {
|
||||
throw new Error('Invalid string. Length must be a multiple of 4')
|
||||
}
|
||||
|
||||
// Trim off extra bytes after placeholder bytes are found
|
||||
// See: https://github.com/beatgammit/base64-js/issues/42
|
||||
var validLen = b64.indexOf('=')
|
||||
if (validLen === -1) validLen = len
|
||||
|
||||
var placeHoldersLen = validLen === len
|
||||
? 0
|
||||
: 4 - (validLen % 4)
|
||||
|
||||
return [validLen, placeHoldersLen]
|
||||
}
|
||||
|
||||
// base64 is 4/3 + up to two characters of the original data
|
||||
function byteLength (b64) {
|
||||
var lens = getLens(b64)
|
||||
var validLen = lens[0]
|
||||
var placeHoldersLen = lens[1]
|
||||
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
||||
}
|
||||
|
||||
function _byteLength (b64, validLen, placeHoldersLen) {
|
||||
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
||||
}
|
||||
|
||||
function toByteArray (b64) {
|
||||
var tmp
|
||||
var lens = getLens(b64)
|
||||
var validLen = lens[0]
|
||||
var placeHoldersLen = lens[1]
|
||||
|
||||
var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
|
||||
|
||||
var curByte = 0
|
||||
|
||||
// if there are placeholders, only get up to the last complete 4 chars
|
||||
var len = placeHoldersLen > 0
|
||||
? validLen - 4
|
||||
: validLen
|
||||
|
||||
var i
|
||||
for (i = 0; i < len; i += 4) {
|
||||
tmp =
|
||||
(revLookup[b64.charCodeAt(i)] << 18) |
|
||||
(revLookup[b64.charCodeAt(i + 1)] << 12) |
|
||||
(revLookup[b64.charCodeAt(i + 2)] << 6) |
|
||||
revLookup[b64.charCodeAt(i + 3)]
|
||||
arr[curByte++] = (tmp >> 16) & 0xFF
|
||||
arr[curByte++] = (tmp >> 8) & 0xFF
|
||||
arr[curByte++] = tmp & 0xFF
|
||||
}
|
||||
|
||||
if (placeHoldersLen === 2) {
|
||||
tmp =
|
||||
(revLookup[b64.charCodeAt(i)] << 2) |
|
||||
(revLookup[b64.charCodeAt(i + 1)] >> 4)
|
||||
arr[curByte++] = tmp & 0xFF
|
||||
}
|
||||
|
||||
if (placeHoldersLen === 1) {
|
||||
tmp =
|
||||
(revLookup[b64.charCodeAt(i)] << 10) |
|
||||
(revLookup[b64.charCodeAt(i + 1)] << 4) |
|
||||
(revLookup[b64.charCodeAt(i + 2)] >> 2)
|
||||
arr[curByte++] = (tmp >> 8) & 0xFF
|
||||
arr[curByte++] = tmp & 0xFF
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
function tripletToBase64 (num) {
|
||||
return lookup[num >> 18 & 0x3F] +
|
||||
lookup[num >> 12 & 0x3F] +
|
||||
lookup[num >> 6 & 0x3F] +
|
||||
lookup[num & 0x3F]
|
||||
}
|
||||
|
||||
function encodeChunk (uint8, start, end) {
|
||||
var tmp
|
||||
var output = []
|
||||
for (var i = start; i < end; i += 3) {
|
||||
tmp =
|
||||
((uint8[i] << 16) & 0xFF0000) +
|
||||
((uint8[i + 1] << 8) & 0xFF00) +
|
||||
(uint8[i + 2] & 0xFF)
|
||||
output.push(tripletToBase64(tmp))
|
||||
}
|
||||
return output.join('')
|
||||
}
|
||||
|
||||
function fromByteArray (uint8) {
|
||||
var tmp
|
||||
var len = uint8.length
|
||||
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
|
||||
var parts = []
|
||||
var maxChunkLength = 16383 // must be multiple of 3
|
||||
|
||||
// go through the array every three bytes, we'll deal with trailing stuff later
|
||||
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
|
||||
parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
|
||||
}
|
||||
|
||||
// pad the end with zeros, but make sure to not forget the extra bytes
|
||||
if (extraBytes === 1) {
|
||||
tmp = uint8[len - 1]
|
||||
parts.push(
|
||||
lookup[tmp >> 2] +
|
||||
lookup[(tmp << 4) & 0x3F] +
|
||||
'=='
|
||||
)
|
||||
} else if (extraBytes === 2) {
|
||||
tmp = (uint8[len - 2] << 8) + uint8[len - 1]
|
||||
parts.push(
|
||||
lookup[tmp >> 10] +
|
||||
lookup[(tmp >> 4) & 0x3F] +
|
||||
lookup[(tmp << 2) & 0x3F] +
|
||||
'='
|
||||
)
|
||||
}
|
||||
|
||||
return parts.join('')
|
||||
}
|
||||
"#;
|
2119
chirpstack/src/codec/js/vendor_buffer.rs
Normal file
2119
chirpstack/src/codec/js/vendor_buffer.rs
Normal file
File diff suppressed because it is too large
Load Diff
110
chirpstack/src/codec/js/vendor_ieee754.rs
Normal file
110
chirpstack/src/codec/js/vendor_ieee754.rs
Normal file
@ -0,0 +1,110 @@
|
||||
// Read/write IEEE754 floating point numbers from/to a Buffer or array-like object.
|
||||
//
|
||||
// License: BSD (3 clause)
|
||||
// Source: https://github.com/feross/ieee754
|
||||
|
||||
pub const SCRIPT: &str = r#"
|
||||
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
||||
export function read(buffer, offset, isLE, mLen, nBytes) {
|
||||
let e, m
|
||||
const eLen = (nBytes * 8) - mLen - 1
|
||||
const eMax = (1 << eLen) - 1
|
||||
const eBias = eMax >> 1
|
||||
let nBits = -7
|
||||
let i = isLE ? (nBytes - 1) : 0
|
||||
const d = isLE ? -1 : 1
|
||||
let s = buffer[offset + i]
|
||||
|
||||
i += d
|
||||
|
||||
e = s & ((1 << (-nBits)) - 1)
|
||||
s >>= (-nBits)
|
||||
nBits += eLen
|
||||
while (nBits > 0) {
|
||||
e = (e * 256) + buffer[offset + i]
|
||||
i += d
|
||||
nBits -= 8
|
||||
}
|
||||
|
||||
m = e & ((1 << (-nBits)) - 1)
|
||||
e >>= (-nBits)
|
||||
nBits += mLen
|
||||
while (nBits > 0) {
|
||||
m = (m * 256) + buffer[offset + i]
|
||||
i += d
|
||||
nBits -= 8
|
||||
}
|
||||
|
||||
if (e === 0) {
|
||||
e = 1 - eBias
|
||||
} else if (e === eMax) {
|
||||
return m ? NaN : ((s ? -1 : 1) * Infinity)
|
||||
} else {
|
||||
m = m + Math.pow(2, mLen)
|
||||
e = e - eBias
|
||||
}
|
||||
return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
|
||||
}
|
||||
|
||||
export function write(buffer, value, offset, isLE, mLen, nBytes) {
|
||||
let e, m, c
|
||||
let eLen = (nBytes * 8) - mLen - 1
|
||||
const eMax = (1 << eLen) - 1
|
||||
const eBias = eMax >> 1
|
||||
const rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
|
||||
let i = isLE ? 0 : (nBytes - 1)
|
||||
const d = isLE ? 1 : -1
|
||||
const s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
|
||||
|
||||
value = Math.abs(value)
|
||||
|
||||
if (isNaN(value) || value === Infinity) {
|
||||
m = isNaN(value) ? 1 : 0
|
||||
e = eMax
|
||||
} else {
|
||||
e = Math.floor(Math.log(value) / Math.LN2)
|
||||
if (value * (c = Math.pow(2, -e)) < 1) {
|
||||
e--
|
||||
c *= 2
|
||||
}
|
||||
if (e + eBias >= 1) {
|
||||
value += rt / c
|
||||
} else {
|
||||
value += rt * Math.pow(2, 1 - eBias)
|
||||
}
|
||||
if (value * c >= 2) {
|
||||
e++
|
||||
c /= 2
|
||||
}
|
||||
|
||||
if (e + eBias >= eMax) {
|
||||
m = 0
|
||||
e = eMax
|
||||
} else if (e + eBias >= 1) {
|
||||
m = ((value * c) - 1) * Math.pow(2, mLen)
|
||||
e = e + eBias
|
||||
} else {
|
||||
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
|
||||
e = 0
|
||||
}
|
||||
}
|
||||
|
||||
while (mLen >= 8) {
|
||||
buffer[offset + i] = m & 0xff
|
||||
i += d
|
||||
m /= 256
|
||||
mLen -= 8
|
||||
}
|
||||
|
||||
e = (e << mLen) | m
|
||||
eLen += mLen
|
||||
while (eLen > 0) {
|
||||
buffer[offset + i] = e & 0xff
|
||||
i += d
|
||||
e /= 256
|
||||
eLen -= 8
|
||||
}
|
||||
|
||||
buffer[offset + i - d] |= s * 128
|
||||
}
|
||||
"#;
|
Loading…
x
Reference in New Issue
Block a user