chore: comment config.example.toml and format code with prettier/cargo
This commit is contained in:
11
cvm-rs/index.d.ts
vendored
11
cvm-rs/index.d.ts
vendored
@@ -5,21 +5,20 @@ export function guacDecode(input: string): string[];
|
||||
export function guacEncode(...items: string[]): string;
|
||||
|
||||
interface JpegInputArgs {
|
||||
width: number,
|
||||
height: number,
|
||||
stride: number, // The width of your input framebuffer OR your image width (if encoding a full image)
|
||||
buffer: Buffer
|
||||
width: number;
|
||||
height: number;
|
||||
stride: number; // The width of your input framebuffer OR your image width (if encoding a full image)
|
||||
buffer: Buffer;
|
||||
|
||||
// TODO: Allow different formats, or export a boxed ffi object which can store a format
|
||||
// (i.e: new JpegEncoder(FORMAT_xxx)).
|
||||
}
|
||||
|
||||
/// Performs JPEG encoding.
|
||||
export function jpegEncode(input: JpegInputArgs) : Promise<Buffer>;
|
||||
export function jpegEncode(input: JpegInputArgs): Promise<Buffer>;
|
||||
|
||||
// TODO: Version that can downscale?
|
||||
|
||||
|
||||
/* remoting API?
|
||||
|
||||
js side api:
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"scripts": {
|
||||
"build": "cargo-cp-artifact -nc index.node -- cargo build --release --message-format=json-render-diagnostics",
|
||||
"install": "yarn build",
|
||||
"test": "cargo test"
|
||||
"test": "cargo test",
|
||||
"format": "cargo fmt"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cargo-cp-artifact": "^0.1"
|
||||
|
||||
@@ -8,30 +8,30 @@ pub type Elements = Vec<String>;
|
||||
/// Errors during decoding
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DecodeError {
|
||||
/// Invalid guacamole instruction format
|
||||
InvalidFormat,
|
||||
/// Invalid guacamole instruction format
|
||||
InvalidFormat,
|
||||
|
||||
/// Instruction is too long for the current decode policy.
|
||||
InstructionTooLong,
|
||||
/// Instruction is too long for the current decode policy.
|
||||
InstructionTooLong,
|
||||
|
||||
/// Element is too long for the current decode policy.
|
||||
ElementTooLong,
|
||||
/// Element is too long for the current decode policy.
|
||||
ElementTooLong,
|
||||
|
||||
/// Invalid element size.
|
||||
ElementSizeInvalid,
|
||||
/// 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")
|
||||
}
|
||||
}
|
||||
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,
|
||||
@@ -40,154 +40,153 @@ impl fmt::Display for DecodeError {
|
||||
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_instruction_size(&self) -> usize {
|
||||
INST_SIZE
|
||||
}
|
||||
|
||||
fn max_element_size(&self) -> usize {
|
||||
ELEM_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();
|
||||
let mut str = String::new();
|
||||
|
||||
for elem in elements.iter() {
|
||||
str.push_str(&format!("{}.{},", elem.len(), elem));
|
||||
}
|
||||
for elem in elements.iter() {
|
||||
str.push_str(&format!("{}.{},", elem.len(), elem));
|
||||
}
|
||||
|
||||
// hacky, but whatever
|
||||
str.pop();
|
||||
str.push(';');
|
||||
// hacky, but whatever
|
||||
str.pop();
|
||||
str.push(';');
|
||||
|
||||
str
|
||||
str
|
||||
}
|
||||
|
||||
/// Decodes a Guacamole instruction to individual elements
|
||||
pub fn decode_instruction(element_string: &String) -> DecodeResult<Elements> {
|
||||
let policy = DefaultDecodePolicy {};
|
||||
let policy = DefaultDecodePolicy {};
|
||||
|
||||
let mut vec: Elements = Vec::new();
|
||||
let mut current_position: usize = 0;
|
||||
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);
|
||||
}
|
||||
// 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<_>>();
|
||||
let chars = element_string.chars().collect::<Vec<_>>();
|
||||
|
||||
loop {
|
||||
let mut element_size: usize = 0;
|
||||
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];
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
// 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.
|
||||
// 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 >= policy.max_element_size() {
|
||||
return Err(DecodeError::ElementTooLong);
|
||||
}
|
||||
|
||||
if element_size >= element_string.len() {
|
||||
return Err(DecodeError::ElementSizeInvalid);
|
||||
}
|
||||
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>();
|
||||
// cutoff elements or something
|
||||
if current_position + element_size > chars.len() - 1 {
|
||||
//println!("? {current_position} a {}", chars.len());
|
||||
return Err(DecodeError::InvalidFormat);
|
||||
}
|
||||
|
||||
current_position += element_size;
|
||||
let element = chars
|
||||
.iter()
|
||||
.skip(current_position)
|
||||
.take(element_size)
|
||||
.collect::<String>();
|
||||
|
||||
vec.push(element);
|
||||
|
||||
// make sure seperator is proper
|
||||
match chars[current_position] {
|
||||
',' => {}
|
||||
';' => break,
|
||||
_ => return Err(DecodeError::InvalidFormat),
|
||||
}
|
||||
current_position += element_size;
|
||||
|
||||
// eat the ','
|
||||
current_position += 1;
|
||||
}
|
||||
vec.push(element);
|
||||
|
||||
Ok(vec)
|
||||
// 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::*;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn decode_basic() {
|
||||
let test = String::from("7.connect,3.vm1;");
|
||||
let res = decode_instruction(&test);
|
||||
#[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"]);
|
||||
}
|
||||
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);
|
||||
#[test]
|
||||
fn decode_errors() {
|
||||
let test = String::from("700.connect,3.vm1;");
|
||||
let res = decode_instruction(&test);
|
||||
|
||||
eprintln!("Error for: {}", res.clone().unwrap_err());
|
||||
eprintln!("Error for: {}", res.clone().unwrap_err());
|
||||
|
||||
assert!(res.is_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);
|
||||
// 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;");
|
||||
assert_eq!(test, "7.connect,3.vm1;");
|
||||
|
||||
let res = decode_instruction(&test);
|
||||
let res = decode_instruction(&test);
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), vec);
|
||||
}
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), vec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use neon::prelude::*;
|
||||
use crate::guac;
|
||||
use neon::prelude::*;
|
||||
|
||||
fn guac_decode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsArray> {
|
||||
let input = cx.argument::<JsString>(0)?.value(cx);
|
||||
|
||||
@@ -61,13 +61,13 @@ impl JpegCompressor {
|
||||
(TJFLAG_NOREALLOC) as i32,
|
||||
);
|
||||
|
||||
// TODO: Result sex so we can actually notify failure
|
||||
// TODO: Result sex so we can actually notify failure
|
||||
if res == -1 {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// Truncate down to the size we're given back
|
||||
vec.truncate(size as usize);
|
||||
// Truncate down to the size we're given back
|
||||
vec.truncate(size as usize);
|
||||
return vec;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ fn jpeg_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsPromise>
|
||||
|
||||
let copy: Arc<Mutex<Vec<u8>>> = Arc::new(Mutex::new(Vec::with_capacity(buf.len())));
|
||||
|
||||
// Copy from the node buffer to our temporary buffer
|
||||
// Copy from the node buffer to our temporary buffer
|
||||
{
|
||||
let mut locked = copy.lock().unwrap();
|
||||
let cap = locked.capacity();
|
||||
@@ -49,8 +49,8 @@ fn jpeg_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsPromise>
|
||||
locked.copy_from_slice(buf);
|
||||
}
|
||||
|
||||
// Spawn off a tokio blocking pool thread that will do the work for us
|
||||
runtime.spawn_blocking(move || {
|
||||
// Spawn off a tokio blocking pool thread that will do the work for us
|
||||
runtime.spawn_blocking(move || {
|
||||
let clone = Arc::clone(©);
|
||||
let locked = clone.lock().unwrap();
|
||||
|
||||
@@ -70,7 +70,7 @@ fn jpeg_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsPromise>
|
||||
b.compress_buffer(&image)
|
||||
});
|
||||
|
||||
// Fulfill the Javascript promise with our encoded buffer
|
||||
// Fulfill the Javascript promise with our encoded buffer
|
||||
deferred.settle_with(&channel, move |mut cx| {
|
||||
let mut buf = cx.buffer(vec.len())?;
|
||||
let slice = buf.as_mut_slice(&mut cx);
|
||||
|
||||
@@ -4,13 +4,11 @@ mod guac_js;
|
||||
mod jpeg_compressor;
|
||||
mod jpeg_js;
|
||||
|
||||
|
||||
use neon::prelude::*;
|
||||
|
||||
|
||||
#[neon::main]
|
||||
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||
// Mostly transitionary, later on API should change
|
||||
// Mostly transitionary, later on API should change
|
||||
cx.export_function("jpegEncode", jpeg_js::jpeg_encode)?;
|
||||
|
||||
cx.export_function("guacDecode", guac_js::guac_decode)?;
|
||||
|
||||
Reference in New Issue
Block a user