cvmts: replace guacamole decoder with a node native module written in rust
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -7,4 +7,8 @@ config.toml
|
|||||||
cvmts/attic
|
cvmts/attic
|
||||||
|
|
||||||
/dist
|
/dist
|
||||||
**/dist/
|
**/dist/
|
||||||
|
|
||||||
|
# Guac-rs
|
||||||
|
guac-rs/target
|
||||||
|
guac-rs/index.node
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@computernewb/jpeg-turbo": "*",
|
"@computernewb/jpeg-turbo": "*",
|
||||||
|
"@cvmts/guac-rs": "*",
|
||||||
"@cvmts/qemu": "*",
|
"@cvmts/qemu": "*",
|
||||||
"execa": "^8.0.1",
|
"execa": "^8.0.1",
|
||||||
"mnemonist": "^0.39.5",
|
"mnemonist": "^0.39.5",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
import * as Utilities from './Utilities.js';
|
import * as Utilities from './Utilities.js';
|
||||||
import * as guacutils from './guacutils.js';
|
import * as guac from '@cvmts/guac-rs';
|
||||||
import { IPData } from './IPData.js';
|
import { IPData } from './IPData.js';
|
||||||
import IConfig from './IConfig.js';
|
import IConfig from './IConfig.js';
|
||||||
import RateLimiter from './RateLimiter.js';
|
import RateLimiter from './RateLimiter.js';
|
||||||
@@ -89,7 +89,7 @@ export class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
closeConnection() {
|
closeConnection() {
|
||||||
this.socket.send(guacutils.encode('disconnect'));
|
this.socket.send(guac.guacEncode('disconnect'));
|
||||||
this.socket.close();
|
this.socket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ export class User {
|
|||||||
|
|
||||||
mute(permanent: boolean) {
|
mute(permanent: boolean) {
|
||||||
this.IP.muted = true;
|
this.IP.muted = true;
|
||||||
this.sendMsg(guacutils.encode('chat', '', `You have been muted${permanent ? '' : ` for ${this.Config.collabvm.tempMuteTime} seconds`}.`));
|
this.sendMsg(guac.guacEncode('chat', '', `You have been muted${permanent ? '' : ` for ${this.Config.collabvm.tempMuteTime} seconds`}.`));
|
||||||
if (!permanent) {
|
if (!permanent) {
|
||||||
clearTimeout(this.IP.tempMuteExpireTimeout);
|
clearTimeout(this.IP.tempMuteExpireTimeout);
|
||||||
this.IP.tempMuteExpireTimeout = setTimeout(() => this.unmute(), this.Config.collabvm.tempMuteTime * 1000);
|
this.IP.tempMuteExpireTimeout = setTimeout(() => this.unmute(), this.Config.collabvm.tempMuteTime * 1000);
|
||||||
@@ -118,7 +118,7 @@ export class User {
|
|||||||
unmute() {
|
unmute() {
|
||||||
clearTimeout(this.IP.tempMuteExpireTimeout);
|
clearTimeout(this.IP.tempMuteExpireTimeout);
|
||||||
this.IP.muted = false;
|
this.IP.muted = false;
|
||||||
this.sendMsg(guacutils.encode('chat', '', 'You are no longer muted.'));
|
this.sendMsg(guac.guacEncode('chat', '', 'You are no longer muted.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private banCmdArgs(arg: string): string {
|
private banCmdArgs(arg: string): string {
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
export function decode(string: string): string[] {
|
|
||||||
let pos = -1;
|
|
||||||
let sections = [];
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
let len = string.indexOf('.', pos + 1);
|
|
||||||
|
|
||||||
if (len === -1) break;
|
|
||||||
|
|
||||||
pos = parseInt(string.slice(pos + 1, len)) + len + 1;
|
|
||||||
|
|
||||||
// don't allow funky protocol length
|
|
||||||
if (pos > string.length) return [];
|
|
||||||
|
|
||||||
sections.push(string.slice(len + 1, pos));
|
|
||||||
|
|
||||||
const sep = string.slice(pos, pos + 1);
|
|
||||||
|
|
||||||
if (sep === ',') continue;
|
|
||||||
else if (sep === ';') break;
|
|
||||||
// Invalid data.
|
|
||||||
else return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return sections;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function encode(...string: string[]): string {
|
|
||||||
let command = '';
|
|
||||||
|
|
||||||
for (var i = 0; i < string.length; i++) {
|
|
||||||
let current = string[i];
|
|
||||||
command += current.toString().length + '.' + current;
|
|
||||||
command += i < string.length - 1 ? ',' : ';';
|
|
||||||
}
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
209
guac-rs/Cargo.lock
generated
Normal file
209
guac-rs/Cargo.lock
generated
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "guac-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"neon",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.155"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "neon"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d75440242411c87dc39847b0e33e961ec1f10326a9d8ecf9c1ea64a3b3c13dc"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"libloading",
|
||||||
|
"neon-macros",
|
||||||
|
"once_cell",
|
||||||
|
"semver",
|
||||||
|
"send_wrapper",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "neon-macros"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6813fde79b646e47e7ad75f480aa80ef76a5d9599e2717407961531169ee38b"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"syn-mid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.85"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "send_wrapper"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.66"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn-mid"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5dc35bb08dd1ca3dfb09dce91fd2d13294d6711c88897d9a9d60acf39bce049"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||||
13
guac-rs/Cargo.toml
Normal file
13
guac-rs/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "guac-rs"
|
||||||
|
description = "Rust guacamole decoding :)"
|
||||||
|
version = "0.1.0"
|
||||||
|
license = "MIT"
|
||||||
|
edition = "2021"
|
||||||
|
exclude = ["index.node"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
neon = "1"
|
||||||
3
guac-rs/index.d.ts
vendored
Normal file
3
guac-rs/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
export function guacDecode(input: string): string[];
|
||||||
|
export function guacEncode(...items: string[]): string;
|
||||||
6
guac-rs/index.js
Normal file
6
guac-rs/index.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// *sigh*
|
||||||
|
import { createRequire } from 'module';
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
|
export let {guacDecode, guacEncode} = require('./index.node');
|
||||||
|
|
||||||
15
guac-rs/package.json
Normal file
15
guac-rs/package.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "@cvmts/guac-rs",
|
||||||
|
"packageManager": "yarn@4.1.1",
|
||||||
|
"type": "module",
|
||||||
|
"main": "index.js",
|
||||||
|
"types": "index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "cargo-cp-artifact -nc index.node -- cargo build --release --message-format=json-render-diagnostics",
|
||||||
|
"install": "yarn build",
|
||||||
|
"test": "cargo test"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"cargo-cp-artifact": "^0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
193
guac-rs/src/guac.rs
Normal file
193
guac-rs/src/guac.rs
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
// type of a guac message
|
||||||
|
pub type Elements = Vec<String>;
|
||||||
|
|
||||||
|
// FIXME: thiserror, please.
|
||||||
|
|
||||||
|
/// Errors during decoding
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum DecodeError {
|
||||||
|
/// Invalid guacamole instruction format
|
||||||
|
InvalidFormat,
|
||||||
|
|
||||||
|
/// Instruction is too long for the current decode policy.
|
||||||
|
InstructionTooLong,
|
||||||
|
|
||||||
|
/// Element is too long for the current decode policy.
|
||||||
|
ElementTooLong,
|
||||||
|
|
||||||
|
/// Invalid element size.
|
||||||
|
ElementSizeInvalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DecodeResult<T> = std::result::Result<T, DecodeError>;
|
||||||
|
|
||||||
|
impl fmt::Display for DecodeError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::InvalidFormat => write!(f, "Invalid Guacamole instruction while decoding"),
|
||||||
|
Self::InstructionTooLong => write!(f, "Instruction too long for current decode policy"),
|
||||||
|
Self::ElementTooLong => write!(f, "Element too long for current decode policy"),
|
||||||
|
Self::ElementSizeInvalid => write!(f, "Element size is invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this decode policy abstraction would in theory be useful,
|
||||||
|
// but idk how to do this kind of thing in rust very well
|
||||||
|
|
||||||
|
pub struct StaticDecodePolicy<const INST_SIZE: usize, const ELEM_SIZE: usize>();
|
||||||
|
|
||||||
|
impl<const INST_SIZE: usize, const ELEM_SIZE: usize> StaticDecodePolicy<INST_SIZE, ELEM_SIZE> {
|
||||||
|
fn max_instruction_size(&self) -> usize {
|
||||||
|
INST_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_element_size(&self) -> usize {
|
||||||
|
ELEM_SIZE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The default decode policy.
|
||||||
|
pub type DefaultDecodePolicy = StaticDecodePolicy<12288, 4096>;
|
||||||
|
|
||||||
|
|
||||||
|
/// Encodes elements into a Guacamole instruction
|
||||||
|
pub fn encode_instruction(elements: &Elements) -> String {
|
||||||
|
let mut str = String::new();
|
||||||
|
|
||||||
|
for elem in elements.iter() {
|
||||||
|
str.push_str(&format!("{}.{},", elem.len(), elem));
|
||||||
|
}
|
||||||
|
|
||||||
|
// hacky, but whatever
|
||||||
|
str.pop();
|
||||||
|
str.push(';');
|
||||||
|
|
||||||
|
str
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a Guacamole instruction to individual elements
|
||||||
|
pub fn decode_instruction(element_string: &String) -> DecodeResult<Elements> {
|
||||||
|
let policy = DefaultDecodePolicy {};
|
||||||
|
|
||||||
|
let mut vec: Elements = Vec::new();
|
||||||
|
let mut current_position: usize = 0;
|
||||||
|
|
||||||
|
// Instruction is too long. Don't even bother
|
||||||
|
if policy.max_instruction_size() < element_string.len() {
|
||||||
|
return Err(DecodeError::InstructionTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
let chars = element_string.chars().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut element_size: usize = 0;
|
||||||
|
|
||||||
|
// Scan the integer value in by hand. This is mostly because
|
||||||
|
// I'm stupid, and the Rust integer parsing routines (seemingly)
|
||||||
|
// require a substring (or a slice, but, if you can generate a slice,
|
||||||
|
// you can also just scan the value in by hand.)
|
||||||
|
//
|
||||||
|
// We bound this anyways and do quite the checks, so even though it's not great,
|
||||||
|
// it should be generally fine (TM).
|
||||||
|
loop {
|
||||||
|
let c = chars[current_position];
|
||||||
|
|
||||||
|
if c >= '0' && c <= '9' {
|
||||||
|
element_size = element_size * 10 + (c as usize) - ('0' as usize);
|
||||||
|
} else {
|
||||||
|
if c == '.' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(DecodeError::InvalidFormat);
|
||||||
|
}
|
||||||
|
current_position += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eat the '.' seperating the size and the element data;
|
||||||
|
// our integer scanning ensures we only get here in the case that this is actually the '.'
|
||||||
|
// character.
|
||||||
|
current_position += 1;
|
||||||
|
|
||||||
|
// Make sure the element size doesn't overflow the decode policy
|
||||||
|
// or the size of the whole instruction.
|
||||||
|
|
||||||
|
if element_size >= policy.max_element_size() {
|
||||||
|
return Err(DecodeError::ElementTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
if element_size >= element_string.len() {
|
||||||
|
return Err(DecodeError::ElementSizeInvalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cutoff elements or something
|
||||||
|
if current_position + element_size > chars.len()-1 {
|
||||||
|
//println!("? {current_position} a {}", chars.len());
|
||||||
|
return Err(DecodeError::InvalidFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
let element = chars
|
||||||
|
.iter()
|
||||||
|
.skip(current_position)
|
||||||
|
.take(element_size)
|
||||||
|
.collect::<String>();
|
||||||
|
|
||||||
|
current_position += element_size;
|
||||||
|
|
||||||
|
vec.push(element);
|
||||||
|
|
||||||
|
// make sure seperator is proper
|
||||||
|
match chars[current_position] {
|
||||||
|
',' => {}
|
||||||
|
';' => break,
|
||||||
|
_ => return Err(DecodeError::InvalidFormat),
|
||||||
|
}
|
||||||
|
|
||||||
|
// eat the ','
|
||||||
|
current_position += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_basic() {
|
||||||
|
let test = String::from("7.connect,3.vm1;");
|
||||||
|
let res = decode_instruction(&test);
|
||||||
|
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(res.unwrap(), vec!["connect", "vm1"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_errors() {
|
||||||
|
let test = String::from("700.connect,3.vm1;");
|
||||||
|
let res = decode_instruction(&test);
|
||||||
|
|
||||||
|
eprintln!("Error for: {}", res.clone().unwrap_err());
|
||||||
|
|
||||||
|
assert!(res.is_err())
|
||||||
|
}
|
||||||
|
|
||||||
|
// generally just test that the codec even works
|
||||||
|
// (we can decode a instruction we created)
|
||||||
|
#[test]
|
||||||
|
fn general_codec_works() {
|
||||||
|
let vec = vec![String::from("connect"), String::from("vm1")];
|
||||||
|
let test = encode_instruction(&vec);
|
||||||
|
|
||||||
|
assert_eq!(test, "7.connect,3.vm1;");
|
||||||
|
|
||||||
|
let res = decode_instruction(&test);
|
||||||
|
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(res.unwrap(), vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
80
guac-rs/src/lib.rs
Normal file
80
guac-rs/src/lib.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
mod guac;
|
||||||
|
|
||||||
|
use neon::prelude::*;
|
||||||
|
|
||||||
|
fn guac_decode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsArray> {
|
||||||
|
let input = cx.argument::<JsString>(0)?.value(cx);
|
||||||
|
|
||||||
|
match guac::decode_instruction(&input) {
|
||||||
|
Ok(data) => {
|
||||||
|
let array = JsArray::new(cx, data.len());
|
||||||
|
|
||||||
|
let conv = data.iter()
|
||||||
|
.map(|v| {
|
||||||
|
cx.string(v)
|
||||||
|
})
|
||||||
|
.collect::<Vec<Handle<JsString>>>();
|
||||||
|
|
||||||
|
for (i, str) in conv.iter().enumerate() {
|
||||||
|
array.set(cx, i as u32, *str)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(e) => {
|
||||||
|
let err = cx.string(format!("Error decoding guacamole: {}", e));
|
||||||
|
return cx.throw(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn guac_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsString> {
|
||||||
|
|
||||||
|
let mut elements: Vec<String> = Vec::with_capacity(cx.len());
|
||||||
|
|
||||||
|
// Capture varadic arguments
|
||||||
|
for i in 0..cx.len() {
|
||||||
|
let input = cx.argument::<JsString>(i)?.value(cx);
|
||||||
|
elements.push(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// old array stuff
|
||||||
|
/*
|
||||||
|
let input = cx.argument::<JsArray>(0)?;
|
||||||
|
let raw_elements = input.to_vec(cx)?;
|
||||||
|
|
||||||
|
// bleh
|
||||||
|
let vecres: Result<Vec<_>, _> = raw_elements
|
||||||
|
.iter()
|
||||||
|
.map(|item| match item.to_string(cx) {
|
||||||
|
Ok(s) => {
|
||||||
|
return Ok(s.value(cx));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let vec = vecres?;
|
||||||
|
*/
|
||||||
|
|
||||||
|
Ok(cx.string(guac::encode_instruction(&elements)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn guac_decode(mut cx: FunctionContext) -> JsResult<JsArray> {
|
||||||
|
guac_decode_impl(&mut cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn guac_encode(mut cx: FunctionContext) -> JsResult<JsString> {
|
||||||
|
guac_encode_impl(&mut cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[neon::main]
|
||||||
|
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||||
|
cx.export_function("guacDecode", guac_decode)?;
|
||||||
|
cx.export_function("guacEncode", guac_encode)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
"name": "cvmts-repo",
|
"name": "cvmts-repo",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"shared",
|
"shared",
|
||||||
|
"guac-rs",
|
||||||
"jpeg-turbo",
|
"jpeg-turbo",
|
||||||
"nodejs-rfb",
|
"nodejs-rfb",
|
||||||
"qemu",
|
"qemu",
|
||||||
|
|||||||
17
yarn.lock
17
yarn.lock
@@ -75,6 +75,14 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"@cvmts/guac-rs@workspace:guac-rs":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@cvmts/guac-rs@workspace:guac-rs"
|
||||||
|
dependencies:
|
||||||
|
cargo-cp-artifact: "npm:^0.1"
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@cvmts/qemu@npm:*, @cvmts/qemu@workspace:qemu":
|
"@cvmts/qemu@npm:*, @cvmts/qemu@workspace:qemu":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@cvmts/qemu@workspace:qemu"
|
resolution: "@cvmts/qemu@workspace:qemu"
|
||||||
@@ -1772,6 +1780,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"cargo-cp-artifact@npm:^0.1":
|
||||||
|
version: 0.1.9
|
||||||
|
resolution: "cargo-cp-artifact@npm:0.1.9"
|
||||||
|
bin:
|
||||||
|
cargo-cp-artifact: bin/cargo-cp-artifact.js
|
||||||
|
checksum: 10c0/60eb1845917cfb021920fcf600a72379890b385396f9c69107face3b16b347960b66cd3d82cc169c6ac8b1212cf0706584125bc36fbc08353b033310c17ca0a6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"chalk@npm:^2.4.2":
|
"chalk@npm:^2.4.2":
|
||||||
version: 2.4.2
|
version: 2.4.2
|
||||||
resolution: "chalk@npm:2.4.2"
|
resolution: "chalk@npm:2.4.2"
|
||||||
|
|||||||
Reference in New Issue
Block a user