cvm-rs: merge guac and jpeg libs together into one
doesn't really need to be two seperate libraries. also preperation for other funnies the build script has been replaced with a much saner justfile which uses much saner "yarn workspace" invocations instead of blindly cding all over the place
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -10,9 +10,5 @@ cvmts/attic
|
|||||||
**/dist/
|
**/dist/
|
||||||
|
|
||||||
# Guac-rs
|
# Guac-rs
|
||||||
guac-rs/target
|
cvm-rs/target
|
||||||
guac-rs/index.node
|
cvm-rs/index.node
|
||||||
|
|
||||||
# jpegturbo-rs
|
|
||||||
jpegturbo-rs/target
|
|
||||||
jpegturbo-rs/index.node
|
|
||||||
|
|||||||
8
Justfile
Normal file
8
Justfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
all:
|
||||||
|
yarn workspace @cvmts/cvm-rs run build
|
||||||
|
yarn workspace @cvmts/shared run build
|
||||||
|
yarn workspace @cvmts/qemu run build
|
||||||
|
yarn workspace @cvmts/cvmts run build
|
||||||
|
|
||||||
|
pkg:
|
||||||
|
yarn
|
||||||
@@ -7,9 +7,9 @@ This is a drop-in replacement for the dying CollabVM 1.2.11. Currently in beta
|
|||||||
**TODO**: These instructions are not finished for the refactor branch.
|
**TODO**: These instructions are not finished for the refactor branch.
|
||||||
|
|
||||||
1. Copy config.example.toml to config.toml, and fill out fields
|
1. Copy config.example.toml to config.toml, and fill out fields
|
||||||
2. Install dependencies: `npm i`
|
2. Install dependencies: `yarn`
|
||||||
3. Build it: `npm run build`
|
3. Build it: `yarn build`
|
||||||
4. Run it: `npm run serve`
|
4. Run it: `yarn serve`
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
### When I try to access the admin panel, the server crashes!
|
### When I try to access the admin panel, the server crashes!
|
||||||
|
|||||||
20
jpegturbo-rs/Cargo.lock → cvm-rs/Cargo.lock
generated
20
jpegturbo-rs/Cargo.lock → cvm-rs/Cargo.lock
generated
@@ -59,6 +59,16 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cvm-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"neon",
|
||||||
|
"once_cell",
|
||||||
|
"tokio",
|
||||||
|
"turbojpeg-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@@ -82,16 +92,6 @@ version = "0.3.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jpegturbo-rs"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"neon",
|
|
||||||
"once_cell",
|
|
||||||
"tokio",
|
|
||||||
"turbojpeg-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.155"
|
version = "0.2.155"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "jpegturbo-rs"
|
name = "cvm-rs"
|
||||||
description = "Rust powered JPEGTurbo sex"
|
description = "Rust utility library for cvmts. Runs all the high performance code"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
exclude = ["index.node"]
|
exclude = ["index.node"]
|
||||||
@@ -10,6 +10,8 @@ crate-type = ["cdylib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
neon = "1"
|
neon = "1"
|
||||||
|
|
||||||
|
# Required for JPEG
|
||||||
once_cell = "1.19.0"
|
once_cell = "1.19.0"
|
||||||
tokio = { version = "1.38.0", features = [ "rt", "rt-multi-thread" ] }
|
tokio = { version = "1.38.0", features = [ "rt", "rt-multi-thread" ] }
|
||||||
turbojpeg-sys = "1.0.0"
|
turbojpeg-sys = "1.0.0"
|
||||||
84
cvm-rs/index.d.ts
vendored
Normal file
84
cvm-rs/index.d.ts
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
|
||||||
|
// Guacamole Codec
|
||||||
|
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
|
||||||
|
|
||||||
|
// 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>;
|
||||||
|
|
||||||
|
// TODO: Version that can downscale?
|
||||||
|
|
||||||
|
|
||||||
|
/* remoting API?
|
||||||
|
|
||||||
|
js side api:
|
||||||
|
|
||||||
|
class RemotingClient extends EventEmitter {
|
||||||
|
constructor(uri: string)
|
||||||
|
|
||||||
|
Connect(): Promise<void> - connects to server.
|
||||||
|
|
||||||
|
Disconnect(): void - disconnects from a server.
|
||||||
|
|
||||||
|
get FullScreen(): Buffer - gets the full screen JPEG at a specific moment. This should only be called once
|
||||||
|
during some user-specific setup (for example: when a new user connects)
|
||||||
|
|
||||||
|
get Thumbnail(): Buffer - gets JPEG thumbnail.
|
||||||
|
|
||||||
|
KeyEvent(key: number, pressed: boolean) - sends a key event to the server.
|
||||||
|
MouseEvent(x: number, y: number, buttons: MouseButtonMask) - sends a mouse event (the button mask is semi-standardized for remoting,
|
||||||
|
the mask can be converted if not applicable for a given protocol)
|
||||||
|
|
||||||
|
// explicit property setter APIs, maybe expose the semi-internal remotingSetProperty API if required?
|
||||||
|
set JpegQuality(q: number) - sets JPEG quality
|
||||||
|
|
||||||
|
// events:
|
||||||
|
|
||||||
|
on('open', cb: () => void) - on open
|
||||||
|
|
||||||
|
//on('firstupdate', cb: (rect: RectWithJpeg) => void) - the first update of a resize is given here
|
||||||
|
// doesn't really matter
|
||||||
|
|
||||||
|
on('resize', cb: (size: Size) => void) - when the server resizes we do too.
|
||||||
|
|
||||||
|
on('update', cb: (rects: Array<RectWithJpeg>) => void) - gives screen frame update as jpeg rects
|
||||||
|
(pre-batched using existing batcher or a new invention or something)
|
||||||
|
on('close', cb: () => void) - on close
|
||||||
|
|
||||||
|
on('cursor', cb: (b: CursorBitmap) => void) - cursor bitmap changed (always rgba8888)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
binding side API:
|
||||||
|
|
||||||
|
remotingNew("vnc://abc.def:1234") - creates a new remoting client which will use the given protocol in the URI
|
||||||
|
xxx for callbacks (they will get migrated to eventemitter or something on the JS side so it's more "idiomatic", depending on performance.
|
||||||
|
In all honesty however, remoting will take care of all the performance sensitive tasks, so it probably won't matter at all)
|
||||||
|
|
||||||
|
remotingConnect(client) -> promise<void> (throws rejection) - disconnects
|
||||||
|
remotingDisconnect(client) - disconnects
|
||||||
|
remotingGetBuffer(client) -> Buffer - gets the buffer used for the screen
|
||||||
|
|
||||||
|
remotingSetProperty(client, propertyId, propertyValue) - sets property (e.g: jpeg quality)
|
||||||
|
e.g: server uri could be set after client creation
|
||||||
|
with remotingSetProperty(boxedClient, remoting.propertyServerUri, "vnc://another-server.org::2920")
|
||||||
|
|
||||||
|
remotingGetThumbnail(client) - gets thumbnail, this is updated by remoting at about 5 fps
|
||||||
|
|
||||||
|
remotingKeyEvent(client, key, pressed) - key event
|
||||||
|
remotingMouseEvent(client, x, y, buttons) - mouse event
|
||||||
|
|
||||||
|
on the rust side a boxed client will contain an inner boxed `dyn RemotingProtocolClient` which will contain protocol specific dispatch,
|
||||||
|
upon parsing a remoting URI we will create a given client (e.g, for `vnc://` we'd make the VNC one)
|
||||||
|
*/
|
||||||
@@ -2,5 +2,5 @@
|
|||||||
import { createRequire } from 'module';
|
import { createRequire } from 'module';
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
export let {jpegEncode} = require('./index.node');
|
export let {guacDecode, guacEncode, jpegEncode} = require('./index.node');
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@cvmts/guac-rs",
|
"name": "@cvmts/cvm-rs",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"packageManager": "yarn@4.1.1",
|
"packageManager": "yarn@4.1.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
mod guac;
|
|
||||||
|
|
||||||
use neon::prelude::*;
|
use neon::prelude::*;
|
||||||
|
use crate::guac;
|
||||||
|
|
||||||
fn guac_decode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsArray> {
|
fn guac_decode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsArray> {
|
||||||
let input = cx.argument::<JsString>(0)?.value(cx);
|
let input = cx.argument::<JsString>(0)?.value(cx);
|
||||||
@@ -40,17 +39,10 @@ fn guac_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsString>
|
|||||||
Ok(cx.string(guac::encode_instruction(&elements)))
|
Ok(cx.string(guac::encode_instruction(&elements)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guac_decode(mut cx: FunctionContext) -> JsResult<JsArray> {
|
pub fn guac_decode(mut cx: FunctionContext) -> JsResult<JsArray> {
|
||||||
guac_decode_impl(&mut cx)
|
guac_decode_impl(&mut cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guac_encode(mut cx: FunctionContext) -> JsResult<JsString> {
|
pub fn guac_encode(mut cx: FunctionContext) -> JsResult<JsString> {
|
||||||
guac_encode_impl(&mut cx)
|
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(())
|
|
||||||
}
|
|
||||||
@@ -8,8 +8,10 @@ use tokio::runtime::Runtime;
|
|||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
mod jpeg_compressor;
|
use crate::jpeg_compressor::*;
|
||||||
|
|
||||||
|
/// Gives a static Tokio runtime. We should replace this with
|
||||||
|
/// rayon or something, but for now tokio works.
|
||||||
fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> {
|
fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> {
|
||||||
static RUNTIME: OnceCell<Runtime> = OnceCell::new();
|
static RUNTIME: OnceCell<Runtime> = OnceCell::new();
|
||||||
|
|
||||||
@@ -19,7 +21,7 @@ fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static COMPRESSOR: RefCell<jpeg_compressor::JpegCompressor> = RefCell::new(jpeg_compressor::JpegCompressor::new());
|
static COMPRESSOR: RefCell<JpegCompressor> = RefCell::new(JpegCompressor::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn jpeg_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsPromise> {
|
fn jpeg_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsPromise> {
|
||||||
@@ -52,7 +54,7 @@ fn jpeg_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsPromise>
|
|||||||
let clone = Arc::clone(©);
|
let clone = Arc::clone(©);
|
||||||
let locked = clone.lock().unwrap();
|
let locked = clone.lock().unwrap();
|
||||||
|
|
||||||
let image: jpeg_compressor::Image = jpeg_compressor::Image {
|
let image: Image = Image {
|
||||||
buffer: locked.as_slice(),
|
buffer: locked.as_slice(),
|
||||||
width: width as u32,
|
width: width as u32,
|
||||||
height: height as u32,
|
height: height as u32,
|
||||||
@@ -80,12 +82,6 @@ fn jpeg_encode_impl<'a>(cx: &mut FunctionContext<'a>) -> JsResult<'a, JsPromise>
|
|||||||
Ok(promise)
|
Ok(promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn jpeg_encode(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
pub fn jpeg_encode(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
jpeg_encode_impl(&mut cx)
|
jpeg_encode_impl(&mut cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[neon::main]
|
|
||||||
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
|
||||||
cx.export_function("jpegEncode", jpeg_encode)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
19
cvm-rs/src/lib.rs
Normal file
19
cvm-rs/src/lib.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
mod guac;
|
||||||
|
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
|
||||||
|
cx.export_function("jpegEncode", jpeg_js::jpeg_encode)?;
|
||||||
|
|
||||||
|
cx.export_function("guacDecode", guac_js::guac_decode)?;
|
||||||
|
cx.export_function("guacEncode", guac_js::guac_encode)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -11,8 +11,7 @@
|
|||||||
"author": "Elijah R, modeco80",
|
"author": "Elijah R, modeco80",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cvmts/guac-rs": "*",
|
"@cvmts/cvm-rs": "*",
|
||||||
"@cvmts/jpegturbo-rs": "*",
|
|
||||||
"@cvmts/qemu": "*",
|
"@cvmts/qemu": "*",
|
||||||
"execa": "^8.0.1",
|
"execa": "^8.0.1",
|
||||||
"mnemonist": "^0.39.5",
|
"mnemonist": "^0.39.5",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import IConfig from './IConfig.js';
|
import IConfig from './IConfig.js';
|
||||||
import * as Utilities from './Utilities.js';
|
import * as Utilities from './Utilities.js';
|
||||||
import { User, Rank } from './User.js';
|
import { User, Rank } from './User.js';
|
||||||
import * as guac from '@cvmts/guac-rs';
|
import * as cvm from '@cvmts/cvm-rs';
|
||||||
// I hate that you have to do it like this
|
// I hate that you have to do it like this
|
||||||
import CircularBuffer from 'mnemonist/circular-buffer.js';
|
import CircularBuffer from 'mnemonist/circular-buffer.js';
|
||||||
import Queue from 'mnemonist/queue.js';
|
import Queue from 'mnemonist/queue.js';
|
||||||
@@ -142,7 +142,7 @@ export default class CollabVMServer {
|
|||||||
user.socket.on('msg', (msg: string) => this.onMessage(user, msg));
|
user.socket.on('msg', (msg: string) => this.onMessage(user, msg));
|
||||||
user.socket.on('disconnect', () => this.connectionClosed(user));
|
user.socket.on('disconnect', () => this.connectionClosed(user));
|
||||||
if (this.Config.auth.enabled) {
|
if (this.Config.auth.enabled) {
|
||||||
user.sendMsg(guac.guacEncode('auth', this.Config.auth.apiEndpoint));
|
user.sendMsg(cvm.guacEncode('auth', this.Config.auth.apiEndpoint));
|
||||||
}
|
}
|
||||||
user.sendMsg(this.getAdduserMsg());
|
user.sendMsg(this.getAdduserMsg());
|
||||||
}
|
}
|
||||||
@@ -171,25 +171,25 @@ export default class CollabVMServer {
|
|||||||
if (hadturn) this.nextTurn();
|
if (hadturn) this.nextTurn();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('remuser', '1', user.username!)));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('remuser', '1', user.username!)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onMessage(client: User, message: string) {
|
private async onMessage(client: User, message: string) {
|
||||||
try {
|
try {
|
||||||
var msgArr = guac.guacDecode(message);
|
var msgArr = cvm.guacDecode(message);
|
||||||
if (msgArr.length < 1) return;
|
if (msgArr.length < 1) return;
|
||||||
switch (msgArr[0]) {
|
switch (msgArr[0]) {
|
||||||
case 'login':
|
case 'login':
|
||||||
if (msgArr.length !== 2 || !this.Config.auth.enabled) return;
|
if (msgArr.length !== 2 || !this.Config.auth.enabled) return;
|
||||||
if (!client.connectedToNode) {
|
if (!client.connectedToNode) {
|
||||||
client.sendMsg(guac.guacEncode('login', '0', 'You must connect to the VM before logging in.'));
|
client.sendMsg(cvm.guacEncode('login', '0', 'You must connect to the VM before logging in.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let res = await this.auth!.Authenticate(msgArr[1], client);
|
let res = await this.auth!.Authenticate(msgArr[1], client);
|
||||||
if (res.clientSuccess) {
|
if (res.clientSuccess) {
|
||||||
this.logger.Info(`${client.IP.address} logged in as ${res.username}`);
|
this.logger.Info(`${client.IP.address} logged in as ${res.username}`);
|
||||||
client.sendMsg(guac.guacEncode('login', '1'));
|
client.sendMsg(cvm.guacEncode('login', '1'));
|
||||||
let old = this.clients.find((c) => c.username === res.username);
|
let old = this.clients.find((c) => c.username === res.username);
|
||||||
if (old) {
|
if (old) {
|
||||||
// kick() doesnt wait until the user is actually removed from the list and itd be anal to make it do that
|
// kick() doesnt wait until the user is actually removed from the list and itd be anal to make it do that
|
||||||
@@ -202,13 +202,13 @@ export default class CollabVMServer {
|
|||||||
// Set rank
|
// Set rank
|
||||||
client.rank = res.rank;
|
client.rank = res.rank;
|
||||||
if (client.rank === Rank.Admin) {
|
if (client.rank === Rank.Admin) {
|
||||||
client.sendMsg(guac.guacEncode('admin', '0', '1'));
|
client.sendMsg(cvm.guacEncode('admin', '0', '1'));
|
||||||
} else if (client.rank === Rank.Moderator) {
|
} else if (client.rank === Rank.Moderator) {
|
||||||
client.sendMsg(guac.guacEncode('admin', '0', '3', this.ModPerms.toString()));
|
client.sendMsg(cvm.guacEncode('admin', '0', '3', this.ModPerms.toString()));
|
||||||
}
|
}
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('adduser', '1', client.username!, client.rank.toString())));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('adduser', '1', client.username!, client.rank.toString())));
|
||||||
} else {
|
} else {
|
||||||
client.sendMsg(guac.guacEncode('login', '0', res.error!));
|
client.sendMsg(cvm.guacEncode('login', '0', res.error!));
|
||||||
if (res.error === 'You are banned') {
|
if (res.error === 'You are banned') {
|
||||||
client.kick();
|
client.kick();
|
||||||
}
|
}
|
||||||
@@ -216,28 +216,28 @@ export default class CollabVMServer {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.Error(`Error authenticating client ${client.IP.address}: ${(err as Error).message}`);
|
this.logger.Error(`Error authenticating client ${client.IP.address}: ${(err as Error).message}`);
|
||||||
// for now?
|
// for now?
|
||||||
client.sendMsg(guac.guacEncode('login', '0', 'There was an internal error while authenticating. Please let a staff member know as soon as possible'));
|
client.sendMsg(cvm.guacEncode('login', '0', 'There was an internal error while authenticating. Please let a staff member know as soon as possible'));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'list':
|
case 'list':
|
||||||
client.sendMsg(guac.guacEncode('list', this.Config.collabvm.node, this.Config.collabvm.displayname, this.screenHidden ? this.screenHiddenThumb : await this.getThumbnail()));
|
client.sendMsg(cvm.guacEncode('list', this.Config.collabvm.node, this.Config.collabvm.displayname, this.screenHidden ? this.screenHiddenThumb : await this.getThumbnail()));
|
||||||
break;
|
break;
|
||||||
case 'connect':
|
case 'connect':
|
||||||
if (!client.username || msgArr.length !== 2 || msgArr[1] !== this.Config.collabvm.node) {
|
if (!client.username || msgArr.length !== 2 || msgArr[1] !== this.Config.collabvm.node) {
|
||||||
client.sendMsg(guac.guacEncode('connect', '0'));
|
client.sendMsg(cvm.guacEncode('connect', '0'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
client.connectedToNode = true;
|
client.connectedToNode = true;
|
||||||
client.sendMsg(guac.guacEncode('connect', '1', '1', this.VM.SnapshotsSupported() ? '1' : '0', '0'));
|
client.sendMsg(cvm.guacEncode('connect', '1', '1', this.VM.SnapshotsSupported() ? '1' : '0', '0'));
|
||||||
if (this.ChatHistory.size !== 0) client.sendMsg(this.getChatHistoryMsg());
|
if (this.ChatHistory.size !== 0) client.sendMsg(this.getChatHistoryMsg());
|
||||||
if (this.Config.collabvm.motd) client.sendMsg(guac.guacEncode('chat', '', this.Config.collabvm.motd));
|
if (this.Config.collabvm.motd) client.sendMsg(cvm.guacEncode('chat', '', this.Config.collabvm.motd));
|
||||||
if (this.screenHidden) {
|
if (this.screenHidden) {
|
||||||
client.sendMsg(guac.guacEncode('size', '0', '1024', '768'));
|
client.sendMsg(cvm.guacEncode('size', '0', '1024', '768'));
|
||||||
client.sendMsg(guac.guacEncode('png', '0', '0', '0', '0', this.screenHiddenImg));
|
client.sendMsg(cvm.guacEncode('png', '0', '0', '0', '0', this.screenHiddenImg));
|
||||||
} else {
|
} else {
|
||||||
await this.SendFullScreenWithSize(client);
|
await this.SendFullScreenWithSize(client);
|
||||||
}
|
}
|
||||||
client.sendMsg(guac.guacEncode('sync', Date.now().toString()));
|
client.sendMsg(cvm.guacEncode('sync', Date.now().toString()));
|
||||||
if (this.voteInProgress) this.sendVoteUpdate(client);
|
if (this.voteInProgress) this.sendVoteUpdate(client);
|
||||||
this.sendTurnUpdate(client);
|
this.sendTurnUpdate(client);
|
||||||
break;
|
break;
|
||||||
@@ -245,7 +245,7 @@ export default class CollabVMServer {
|
|||||||
if (client.connectedToNode) return;
|
if (client.connectedToNode) return;
|
||||||
if (client.username || msgArr.length !== 3 || msgArr[1] !== this.Config.collabvm.node) {
|
if (client.username || msgArr.length !== 3 || msgArr[1] !== this.Config.collabvm.node) {
|
||||||
// The use of connect here is intentional.
|
// The use of connect here is intentional.
|
||||||
client.sendMsg(guac.guacEncode('connect', '0'));
|
client.sendMsg(cvm.guacEncode('connect', '0'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,22 +257,22 @@ export default class CollabVMServer {
|
|||||||
client.viewMode = 1;
|
client.viewMode = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
client.sendMsg(guac.guacEncode('connect', '0'));
|
client.sendMsg(cvm.guacEncode('connect', '0'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
client.sendMsg(guac.guacEncode('connect', '1', '1', this.VM.SnapshotsSupported() ? '1' : '0', '0'));
|
client.sendMsg(cvm.guacEncode('connect', '1', '1', this.VM.SnapshotsSupported() ? '1' : '0', '0'));
|
||||||
if (this.ChatHistory.size !== 0) client.sendMsg(this.getChatHistoryMsg());
|
if (this.ChatHistory.size !== 0) client.sendMsg(this.getChatHistoryMsg());
|
||||||
if (this.Config.collabvm.motd) client.sendMsg(guac.guacEncode('chat', '', this.Config.collabvm.motd));
|
if (this.Config.collabvm.motd) client.sendMsg(cvm.guacEncode('chat', '', this.Config.collabvm.motd));
|
||||||
|
|
||||||
if (client.viewMode == 1) {
|
if (client.viewMode == 1) {
|
||||||
if (this.screenHidden) {
|
if (this.screenHidden) {
|
||||||
client.sendMsg(guac.guacEncode('size', '0', '1024', '768'));
|
client.sendMsg(cvm.guacEncode('size', '0', '1024', '768'));
|
||||||
client.sendMsg(guac.guacEncode('png', '0', '0', '0', '0', this.screenHiddenImg));
|
client.sendMsg(cvm.guacEncode('png', '0', '0', '0', '0', this.screenHiddenImg));
|
||||||
} else {
|
} else {
|
||||||
await this.SendFullScreenWithSize(client);
|
await this.SendFullScreenWithSize(client);
|
||||||
}
|
}
|
||||||
client.sendMsg(guac.guacEncode('sync', Date.now().toString()));
|
client.sendMsg(cvm.guacEncode('sync', Date.now().toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.voteInProgress) this.sendVoteUpdate(client);
|
if (this.voteInProgress) this.sendVoteUpdate(client);
|
||||||
@@ -282,12 +282,12 @@ export default class CollabVMServer {
|
|||||||
if (!client.RenameRateLimit.request()) return;
|
if (!client.RenameRateLimit.request()) return;
|
||||||
if (client.connectedToNode && client.IP.muted) return;
|
if (client.connectedToNode && client.IP.muted) return;
|
||||||
if (this.Config.auth.enabled && client.rank !== Rank.Unregistered) {
|
if (this.Config.auth.enabled && client.rank !== Rank.Unregistered) {
|
||||||
client.sendMsg(guac.guacEncode('chat', '', 'Go to your account settings to change your username.'));
|
client.sendMsg(cvm.guacEncode('chat', '', 'Go to your account settings to change your username.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.Config.auth.enabled && msgArr[1] !== undefined) {
|
if (this.Config.auth.enabled && msgArr[1] !== undefined) {
|
||||||
// Don't send system message to a user without a username since it was likely an automated attempt by the webapp
|
// Don't send system message to a user without a username since it was likely an automated attempt by the webapp
|
||||||
if (client.username) client.sendMsg(guac.guacEncode('chat', '', 'You need to log in to do that.'));
|
if (client.username) client.sendMsg(cvm.guacEncode('chat', '', 'You need to log in to do that.'));
|
||||||
if (client.rank !== Rank.Unregistered) return;
|
if (client.rank !== Rank.Unregistered) return;
|
||||||
this.renameUser(client, undefined);
|
this.renameUser(client, undefined);
|
||||||
return;
|
return;
|
||||||
@@ -299,7 +299,7 @@ export default class CollabVMServer {
|
|||||||
if (client.IP.muted) return;
|
if (client.IP.muted) return;
|
||||||
if (msgArr.length !== 2) return;
|
if (msgArr.length !== 2) return;
|
||||||
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.chat) {
|
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.chat) {
|
||||||
client.sendMsg(guac.guacEncode('chat', '', 'You need to login to do that.'));
|
client.sendMsg(cvm.guacEncode('chat', '', 'You need to login to do that.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var msg = Utilities.HTMLSanitize(msgArr[1]);
|
var msg = Utilities.HTMLSanitize(msgArr[1]);
|
||||||
@@ -307,14 +307,14 @@ export default class CollabVMServer {
|
|||||||
if (msg.length > this.Config.collabvm.maxChatLength) msg = msg.substring(0, this.Config.collabvm.maxChatLength);
|
if (msg.length > this.Config.collabvm.maxChatLength) msg = msg.substring(0, this.Config.collabvm.maxChatLength);
|
||||||
if (msg.trim().length < 1) return;
|
if (msg.trim().length < 1) return;
|
||||||
|
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('chat', client.username!, msg)));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('chat', client.username!, msg)));
|
||||||
this.ChatHistory.push({ user: client.username, msg: msg });
|
this.ChatHistory.push({ user: client.username, msg: msg });
|
||||||
client.onMsgSent();
|
client.onMsgSent();
|
||||||
break;
|
break;
|
||||||
case 'turn':
|
case 'turn':
|
||||||
if ((!this.turnsAllowed || this.Config.collabvm.turnwhitelist) && client.rank !== Rank.Admin && client.rank !== Rank.Moderator && client.rank !== Rank.Turn) return;
|
if ((!this.turnsAllowed || this.Config.collabvm.turnwhitelist) && client.rank !== Rank.Admin && client.rank !== Rank.Moderator && client.rank !== Rank.Turn) return;
|
||||||
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.turn) {
|
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.turn) {
|
||||||
client.sendMsg(guac.guacEncode('chat', '', 'You need to login to do that.'));
|
client.sendMsg(cvm.guacEncode('chat', '', 'You need to login to do that.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!client.TurnRateLimit.request()) return;
|
if (!client.TurnRateLimit.request()) return;
|
||||||
@@ -384,33 +384,33 @@ export default class CollabVMServer {
|
|||||||
case '1':
|
case '1':
|
||||||
if (!this.voteInProgress) {
|
if (!this.voteInProgress) {
|
||||||
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.callForReset) {
|
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.callForReset) {
|
||||||
client.sendMsg(guac.guacEncode('chat', '', 'You need to login to do that.'));
|
client.sendMsg(cvm.guacEncode('chat', '', 'You need to login to do that.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.voteCooldown !== 0) {
|
if (this.voteCooldown !== 0) {
|
||||||
client.sendMsg(guac.guacEncode('vote', '3', this.voteCooldown.toString()));
|
client.sendMsg(cvm.guacEncode('vote', '3', this.voteCooldown.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.startVote();
|
this.startVote();
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('chat', '', `${client.username} has started a vote to reset the VM.`)));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('chat', '', `${client.username} has started a vote to reset the VM.`)));
|
||||||
}
|
}
|
||||||
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.vote) {
|
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.vote) {
|
||||||
client.sendMsg(guac.guacEncode('chat', '', 'You need to login to do that.'));
|
client.sendMsg(cvm.guacEncode('chat', '', 'You need to login to do that.'));
|
||||||
return;
|
return;
|
||||||
} else if (client.IP.vote !== true) {
|
} else if (client.IP.vote !== true) {
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('chat', '', `${client.username} has voted yes.`)));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('chat', '', `${client.username} has voted yes.`)));
|
||||||
}
|
}
|
||||||
client.IP.vote = true;
|
client.IP.vote = true;
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
if (!this.voteInProgress) return;
|
if (!this.voteInProgress) return;
|
||||||
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.vote) {
|
if (this.Config.auth.enabled && client.rank === Rank.Unregistered && !this.Config.auth.guestPermissions.vote) {
|
||||||
client.sendMsg(guac.guacEncode('chat', '', 'You need to login to do that.'));
|
client.sendMsg(cvm.guacEncode('chat', '', 'You need to login to do that.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (client.IP.vote !== false) {
|
if (client.IP.vote !== false) {
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('chat', '', `${client.username} has voted no.`)));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('chat', '', `${client.username} has voted no.`)));
|
||||||
}
|
}
|
||||||
client.IP.vote = false;
|
client.IP.vote = false;
|
||||||
break;
|
break;
|
||||||
@@ -423,7 +423,7 @@ export default class CollabVMServer {
|
|||||||
case '2':
|
case '2':
|
||||||
// Login
|
// Login
|
||||||
if (this.Config.auth.enabled) {
|
if (this.Config.auth.enabled) {
|
||||||
client.sendMsg(guac.guacEncode('chat', '', 'This server does not support staff passwords. Please log in to become staff.'));
|
client.sendMsg(cvm.guacEncode('chat', '', 'This server does not support staff passwords. Please log in to become staff.'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!client.LoginRateLimit.request() || !client.username) return;
|
if (!client.LoginRateLimit.request() || !client.username) return;
|
||||||
@@ -434,37 +434,37 @@ export default class CollabVMServer {
|
|||||||
sha256.destroy();
|
sha256.destroy();
|
||||||
if (pwdHash === this.Config.collabvm.adminpass) {
|
if (pwdHash === this.Config.collabvm.adminpass) {
|
||||||
client.rank = Rank.Admin;
|
client.rank = Rank.Admin;
|
||||||
client.sendMsg(guac.guacEncode('admin', '0', '1'));
|
client.sendMsg(cvm.guacEncode('admin', '0', '1'));
|
||||||
} else if (this.Config.collabvm.moderatorEnabled && pwdHash === this.Config.collabvm.modpass) {
|
} else if (this.Config.collabvm.moderatorEnabled && pwdHash === this.Config.collabvm.modpass) {
|
||||||
client.rank = Rank.Moderator;
|
client.rank = Rank.Moderator;
|
||||||
client.sendMsg(guac.guacEncode('admin', '0', '3', this.ModPerms.toString()));
|
client.sendMsg(cvm.guacEncode('admin', '0', '3', this.ModPerms.toString()));
|
||||||
} else if (this.Config.collabvm.turnwhitelist && pwdHash === this.Config.collabvm.turnpass) {
|
} else if (this.Config.collabvm.turnwhitelist && pwdHash === this.Config.collabvm.turnpass) {
|
||||||
client.rank = Rank.Turn;
|
client.rank = Rank.Turn;
|
||||||
client.sendMsg(guac.guacEncode('chat', '', 'You may now take turns.'));
|
client.sendMsg(cvm.guacEncode('chat', '', 'You may now take turns.'));
|
||||||
} else {
|
} else {
|
||||||
client.sendMsg(guac.guacEncode('admin', '0', '0'));
|
client.sendMsg(cvm.guacEncode('admin', '0', '0'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.screenHidden) {
|
if (this.screenHidden) {
|
||||||
await this.SendFullScreenWithSize(client);
|
await this.SendFullScreenWithSize(client);
|
||||||
|
|
||||||
client.sendMsg(guac.guacEncode('sync', Date.now().toString()));
|
client.sendMsg(cvm.guacEncode('sync', Date.now().toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('adduser', '1', client.username!, client.rank.toString())));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('adduser', '1', client.username!, client.rank.toString())));
|
||||||
break;
|
break;
|
||||||
case '5':
|
case '5':
|
||||||
// QEMU Monitor
|
// QEMU Monitor
|
||||||
if (client.rank !== Rank.Admin) return;
|
if (client.rank !== Rank.Admin) return;
|
||||||
/* Surely there could be rudimentary processing to convert some qemu monitor syntax to [XYZ hypervisor] if possible
|
/* Surely there could be rudimentary processing to convert some qemu monitor syntax to [XYZ hypervisor] if possible
|
||||||
if (!(this.VM instanceof QEMUVM)) {
|
if (!(this.VM instanceof QEMUVM)) {
|
||||||
client.sendMsg(guac.guacEncode("admin", "2", "This is not a QEMU VM and therefore QEMU monitor commands cannot be run."));
|
client.sendMsg(cvm.guacEncode("admin", "2", "This is not a QEMU VM and therefore QEMU monitor commands cannot be run."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (msgArr.length !== 4 || msgArr[2] !== this.Config.collabvm.node) return;
|
if (msgArr.length !== 4 || msgArr[2] !== this.Config.collabvm.node) return;
|
||||||
var output = await this.VM.MonitorCommand(msgArr[3]);
|
var output = await this.VM.MonitorCommand(msgArr[3]);
|
||||||
client.sendMsg(guac.guacEncode('admin', '2', String(output)));
|
client.sendMsg(cvm.guacEncode('admin', '2', String(output)));
|
||||||
break;
|
break;
|
||||||
case '8':
|
case '8':
|
||||||
// Restore
|
// Restore
|
||||||
@@ -541,7 +541,7 @@ export default class CollabVMServer {
|
|||||||
// Rename user
|
// Rename user
|
||||||
if (client.rank !== Rank.Admin && (client.rank !== Rank.Moderator || !this.Config.collabvm.moderatorPermissions.rename)) return;
|
if (client.rank !== Rank.Admin && (client.rank !== Rank.Moderator || !this.Config.collabvm.moderatorPermissions.rename)) return;
|
||||||
if (this.Config.auth.enabled) {
|
if (this.Config.auth.enabled) {
|
||||||
client.sendMsg(guac.guacEncode('chat', '', 'Cannot rename users on a server that uses authentication.'));
|
client.sendMsg(cvm.guacEncode('chat', '', 'Cannot rename users on a server that uses authentication.'));
|
||||||
}
|
}
|
||||||
if (msgArr.length !== 4) return;
|
if (msgArr.length !== 4) return;
|
||||||
var user = this.clients.find((c) => c.username === msgArr[2]);
|
var user = this.clients.find((c) => c.username === msgArr[2]);
|
||||||
@@ -554,7 +554,7 @@ export default class CollabVMServer {
|
|||||||
if (msgArr.length !== 3) return;
|
if (msgArr.length !== 3) return;
|
||||||
var user = this.clients.find((c) => c.username === msgArr[2]);
|
var user = this.clients.find((c) => c.username === msgArr[2]);
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
client.sendMsg(guac.guacEncode('admin', '19', msgArr[2], user.IP.address));
|
client.sendMsg(cvm.guacEncode('admin', '19', msgArr[2], user.IP.address));
|
||||||
break;
|
break;
|
||||||
case '20':
|
case '20':
|
||||||
// Steal turn
|
// Steal turn
|
||||||
@@ -567,14 +567,14 @@ export default class CollabVMServer {
|
|||||||
if (msgArr.length !== 3) return;
|
if (msgArr.length !== 3) return;
|
||||||
switch (client.rank) {
|
switch (client.rank) {
|
||||||
case Rank.Admin:
|
case Rank.Admin:
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('chat', client.username!, msgArr[2])));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('chat', client.username!, msgArr[2])));
|
||||||
|
|
||||||
this.ChatHistory.push({ user: client.username!, msg: msgArr[2] });
|
this.ChatHistory.push({ user: client.username!, msg: msgArr[2] });
|
||||||
break;
|
break;
|
||||||
case Rank.Moderator:
|
case Rank.Moderator:
|
||||||
this.clients.filter((c) => c.rank !== Rank.Admin).forEach((c) => c.sendMsg(guac.guacEncode('chat', client.username!, msgArr[2])));
|
this.clients.filter((c) => c.rank !== Rank.Admin).forEach((c) => c.sendMsg(cvm.guacEncode('chat', client.username!, msgArr[2])));
|
||||||
|
|
||||||
this.clients.filter((c) => c.rank === Rank.Admin).forEach((c) => c.sendMsg(guac.guacEncode('chat', client.username!, Utilities.HTMLSanitize(msgArr[2]))));
|
this.clients.filter((c) => c.rank === Rank.Admin).forEach((c) => c.sendMsg(cvm.guacEncode('chat', client.username!, Utilities.HTMLSanitize(msgArr[2]))));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -609,9 +609,9 @@ export default class CollabVMServer {
|
|||||||
this.clients
|
this.clients
|
||||||
.filter((c) => c.rank == Rank.Unregistered)
|
.filter((c) => c.rank == Rank.Unregistered)
|
||||||
.forEach((client) => {
|
.forEach((client) => {
|
||||||
client.sendMsg(guac.guacEncode('size', '0', '1024', '768'));
|
client.sendMsg(cvm.guacEncode('size', '0', '1024', '768'));
|
||||||
client.sendMsg(guac.guacEncode('png', '0', '0', '0', '0', this.screenHiddenImg));
|
client.sendMsg(cvm.guacEncode('png', '0', '0', '0', '0', this.screenHiddenImg));
|
||||||
client.sendMsg(guac.guacEncode('sync', Date.now().toString()));
|
client.sendMsg(cvm.guacEncode('sync', Date.now().toString()));
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case '1':
|
case '1':
|
||||||
@@ -626,16 +626,16 @@ export default class CollabVMServer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.clients.forEach(async (client) => {
|
this.clients.forEach(async (client) => {
|
||||||
client.sendMsg(guac.guacEncode('size', '0', displaySize.width.toString(), displaySize.height.toString()));
|
client.sendMsg(cvm.guacEncode('size', '0', displaySize.width.toString(), displaySize.height.toString()));
|
||||||
client.sendMsg(guac.guacEncode('png', '0', '0', '0', '0', encoded));
|
client.sendMsg(cvm.guacEncode('png', '0', '0', '0', '0', encoded));
|
||||||
client.sendMsg(guac.guacEncode('sync', Date.now().toString()));
|
client.sendMsg(cvm.guacEncode('sync', Date.now().toString()));
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '25':
|
case '25':
|
||||||
if (client.rank !== Rank.Admin || msgArr.length !== 3) return;
|
if (client.rank !== Rank.Admin || msgArr.length !== 3) return;
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('chat', '', msgArr[2])));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('chat', '', msgArr[2])));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -665,7 +665,7 @@ export default class CollabVMServer {
|
|||||||
} else {
|
} else {
|
||||||
newName = newName.trim();
|
newName = newName.trim();
|
||||||
if (hadName && newName === oldname) {
|
if (hadName && newName === oldname) {
|
||||||
client.sendMsg(guac.guacEncode('rename', '0', '0', client.username!, client.rank.toString()));
|
client.sendMsg(cvm.guacEncode('rename', '0', '0', client.username!, client.rank.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.getUsernameList().indexOf(newName) !== -1) {
|
if (this.getUsernameList().indexOf(newName) !== -1) {
|
||||||
@@ -682,13 +682,13 @@ export default class CollabVMServer {
|
|||||||
} else client.username = newName;
|
} else client.username = newName;
|
||||||
}
|
}
|
||||||
|
|
||||||
client.sendMsg(guac.guacEncode('rename', '0', status, client.username!, client.rank.toString()));
|
client.sendMsg(cvm.guacEncode('rename', '0', status, client.username!, client.rank.toString()));
|
||||||
if (hadName) {
|
if (hadName) {
|
||||||
this.logger.Info(`Rename ${client.IP.address} from ${oldname} to ${client.username}`);
|
this.logger.Info(`Rename ${client.IP.address} from ${oldname} to ${client.username}`);
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('rename', '1', oldname, client.username!, client.rank.toString())));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('rename', '1', oldname, client.username!, client.rank.toString())));
|
||||||
} else {
|
} else {
|
||||||
this.logger.Info(`Rename ${client.IP.address} to ${client.username}`);
|
this.logger.Info(`Rename ${client.IP.address} to ${client.username}`);
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('adduser', '1', client.username!, client.rank.toString())));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('adduser', '1', client.username!, client.rank.toString())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,13 +696,13 @@ export default class CollabVMServer {
|
|||||||
var arr: string[] = ['adduser', this.clients.filter((c) => c.username).length.toString()];
|
var arr: string[] = ['adduser', this.clients.filter((c) => c.username).length.toString()];
|
||||||
|
|
||||||
this.clients.filter((c) => c.username).forEach((c) => arr.push(c.username!, c.rank.toString()));
|
this.clients.filter((c) => c.username).forEach((c) => arr.push(c.username!, c.rank.toString()));
|
||||||
return guac.guacEncode(...arr);
|
return cvm.guacEncode(...arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
getChatHistoryMsg(): string {
|
getChatHistoryMsg(): string {
|
||||||
var arr: string[] = ['chat'];
|
var arr: string[] = ['chat'];
|
||||||
this.ChatHistory.forEach((c) => arr.push(c.user, c.msg));
|
this.ChatHistory.forEach((c) => arr.push(c.user, c.msg));
|
||||||
return guac.guacEncode(...arr);
|
return cvm.guacEncode(...arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendTurnUpdate(client?: User) {
|
private sendTurnUpdate(client?: User) {
|
||||||
@@ -715,7 +715,7 @@ export default class CollabVMServer {
|
|||||||
this.TurnQueue.forEach((c) => arr.push(c.username));
|
this.TurnQueue.forEach((c) => arr.push(c.username));
|
||||||
var currentTurningUser = this.TurnQueue.peek();
|
var currentTurningUser = this.TurnQueue.peek();
|
||||||
if (client) {
|
if (client) {
|
||||||
client.sendMsg(guac.guacEncode(...arr));
|
client.sendMsg(cvm.guacEncode(...arr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.clients
|
this.clients
|
||||||
@@ -725,12 +725,12 @@ export default class CollabVMServer {
|
|||||||
var time;
|
var time;
|
||||||
if (this.indefiniteTurn === null) time = this.TurnTime * 1000 + (turnQueueArr.indexOf(c) - 1) * this.Config.collabvm.turnTime * 1000;
|
if (this.indefiniteTurn === null) time = this.TurnTime * 1000 + (turnQueueArr.indexOf(c) - 1) * this.Config.collabvm.turnTime * 1000;
|
||||||
else time = 9999999999;
|
else time = 9999999999;
|
||||||
c.sendMsg(guac.guacEncode(...arr, time.toString()));
|
c.sendMsg(cvm.guacEncode(...arr, time.toString()));
|
||||||
} else {
|
} else {
|
||||||
c.sendMsg(guac.guacEncode(...arr));
|
c.sendMsg(cvm.guacEncode(...arr));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (currentTurningUser) currentTurningUser.sendMsg(guac.guacEncode(...arr));
|
if (currentTurningUser) currentTurningUser.sendMsg(cvm.guacEncode(...arr));
|
||||||
}
|
}
|
||||||
private nextTurn() {
|
private nextTurn() {
|
||||||
clearInterval(this.TurnInterval);
|
clearInterval(this.TurnInterval);
|
||||||
@@ -777,8 +777,8 @@ export default class CollabVMServer {
|
|||||||
.filter((c) => c.connectedToNode || c.viewMode == 1)
|
.filter((c) => c.connectedToNode || c.viewMode == 1)
|
||||||
.forEach((c) => {
|
.forEach((c) => {
|
||||||
if (this.screenHidden && c.rank == Rank.Unregistered) return;
|
if (this.screenHidden && c.rank == Rank.Unregistered) return;
|
||||||
c.sendMsg(guac.guacEncode('png', '0', '0', rect.x.toString(), rect.y.toString(), encodedb64));
|
c.sendMsg(cvm.guacEncode('png', '0', '0', rect.x.toString(), rect.y.toString(), encodedb64));
|
||||||
c.sendMsg(guac.guacEncode('sync', Date.now().toString()));
|
c.sendMsg(cvm.guacEncode('sync', Date.now().toString()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -787,7 +787,7 @@ export default class CollabVMServer {
|
|||||||
.filter((c) => c.connectedToNode || c.viewMode == 1)
|
.filter((c) => c.connectedToNode || c.viewMode == 1)
|
||||||
.forEach((c) => {
|
.forEach((c) => {
|
||||||
if (this.screenHidden && c.rank == Rank.Unregistered) return;
|
if (this.screenHidden && c.rank == Rank.Unregistered) return;
|
||||||
c.sendMsg(guac.guacEncode('size', '0', size.width.toString(), size.height.toString()));
|
c.sendMsg(cvm.guacEncode('size', '0', size.width.toString(), size.height.toString()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,8 +802,8 @@ export default class CollabVMServer {
|
|||||||
height: displaySize.height
|
height: displaySize.height
|
||||||
});
|
});
|
||||||
|
|
||||||
client.sendMsg(guac.guacEncode('size', '0', displaySize.width.toString(), displaySize.height.toString()));
|
client.sendMsg(cvm.guacEncode('size', '0', displaySize.width.toString(), displaySize.height.toString()));
|
||||||
client.sendMsg(guac.guacEncode('png', '0', '0', '0', '0', encoded));
|
client.sendMsg(cvm.guacEncode('png', '0', '0', '0', '0', encoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async MakeRectData(rect: Rect) {
|
private async MakeRectData(rect: Rect) {
|
||||||
@@ -828,7 +828,7 @@ export default class CollabVMServer {
|
|||||||
startVote() {
|
startVote() {
|
||||||
if (this.voteInProgress) return;
|
if (this.voteInProgress) return;
|
||||||
this.voteInProgress = true;
|
this.voteInProgress = true;
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('vote', '0')));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('vote', '0')));
|
||||||
this.voteTime = this.Config.collabvm.voteTime;
|
this.voteTime = this.Config.collabvm.voteTime;
|
||||||
this.voteInterval = setInterval(() => {
|
this.voteInterval = setInterval(() => {
|
||||||
this.voteTime--;
|
this.voteTime--;
|
||||||
@@ -843,12 +843,12 @@ export default class CollabVMServer {
|
|||||||
this.voteInProgress = false;
|
this.voteInProgress = false;
|
||||||
clearInterval(this.voteInterval);
|
clearInterval(this.voteInterval);
|
||||||
var count = this.getVoteCounts();
|
var count = this.getVoteCounts();
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('vote', '2')));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('vote', '2')));
|
||||||
if (result === true || (result === undefined && count.yes >= count.no)) {
|
if (result === true || (result === undefined && count.yes >= count.no)) {
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('chat', '', 'The vote to reset the VM has won.')));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('chat', '', 'The vote to reset the VM has won.')));
|
||||||
this.VM.Reset();
|
this.VM.Reset();
|
||||||
} else {
|
} else {
|
||||||
this.clients.forEach((c) => c.sendMsg(guac.guacEncode('chat', '', 'The vote to reset the VM has lost.')));
|
this.clients.forEach((c) => c.sendMsg(cvm.guacEncode('chat', '', 'The vote to reset the VM has lost.')));
|
||||||
}
|
}
|
||||||
this.clients.forEach((c) => {
|
this.clients.forEach((c) => {
|
||||||
c.IP.vote = null;
|
c.IP.vote = null;
|
||||||
@@ -863,7 +863,7 @@ export default class CollabVMServer {
|
|||||||
sendVoteUpdate(client?: User) {
|
sendVoteUpdate(client?: User) {
|
||||||
if (!this.voteInProgress) return;
|
if (!this.voteInProgress) return;
|
||||||
var count = this.getVoteCounts();
|
var count = this.getVoteCounts();
|
||||||
var msg = guac.guacEncode('vote', '1', (this.voteTime * 1000).toString(), count.yes.toString(), count.no.toString());
|
var msg = cvm.guacEncode('vote', '1', (this.voteTime * 1000).toString(), count.yes.toString(), count.no.toString());
|
||||||
if (client) client.sendMsg(msg);
|
if (client) client.sendMsg(msg);
|
||||||
else this.clients.forEach((c) => c.sendMsg(msg));
|
else this.clients.forEach((c) => c.sendMsg(msg));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Size, Rect } from '@cvmts/shared';
|
import { Size, Rect } from '@cvmts/shared';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import * as jpeg from '@cvmts/jpegturbo-rs';
|
import * as cvm from '@cvmts/cvm-rs';
|
||||||
|
|
||||||
// A good balance. TODO: Configurable?
|
// A good balance. TODO: Configurable?
|
||||||
let gJpegQuality = 35;
|
let gJpegQuality = 35;
|
||||||
@@ -28,7 +28,7 @@ export class JPEGEncoder {
|
|||||||
|
|
||||||
static async Encode(canvas: Buffer, displaySize: Size, rect: Rect): Promise<Buffer> {
|
static async Encode(canvas: Buffer, displaySize: Size, rect: Rect): Promise<Buffer> {
|
||||||
let offset = (rect.y * displaySize.width + rect.x) * 4;
|
let offset = (rect.y * displaySize.width + rect.x) * 4;
|
||||||
return jpeg.jpegEncode({
|
return cvm.jpegEncode({
|
||||||
width: rect.width,
|
width: rect.width,
|
||||||
height: rect.height,
|
height: rect.height,
|
||||||
stride: displaySize.width,
|
stride: displaySize.width,
|
||||||
@@ -42,7 +42,7 @@ export class JPEGEncoder {
|
|||||||
.raw()
|
.raw()
|
||||||
.toBuffer({ resolveWithObject: true });
|
.toBuffer({ resolveWithObject: true });
|
||||||
|
|
||||||
return jpeg.jpegEncode({
|
return cvm.jpegEncode({
|
||||||
width: kThumbnailSize.width,
|
width: kThumbnailSize.width,
|
||||||
height: kThumbnailSize.height,
|
height: kThumbnailSize.height,
|
||||||
stride: kThumbnailSize.width,
|
stride: kThumbnailSize.width,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as Utilities from './Utilities.js';
|
import * as Utilities from './Utilities.js';
|
||||||
import * as guac from '@cvmts/guac-rs';
|
import * as cvm from '@cvmts/cvm-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';
|
||||||
@@ -95,7 +95,7 @@ export class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
closeConnection() {
|
closeConnection() {
|
||||||
this.socket.send(guac.guacEncode('disconnect'));
|
this.socket.send(cvm.guacEncode('disconnect'));
|
||||||
this.socket.close();
|
this.socket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ export class User {
|
|||||||
|
|
||||||
mute(permanent: boolean) {
|
mute(permanent: boolean) {
|
||||||
this.IP.muted = true;
|
this.IP.muted = true;
|
||||||
this.sendMsg(guac.guacEncode('chat', '', `You have been muted${permanent ? '' : ` for ${this.Config.collabvm.tempMuteTime} seconds`}.`));
|
this.sendMsg(cvm.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);
|
||||||
@@ -124,7 +124,7 @@ export class User {
|
|||||||
unmute() {
|
unmute() {
|
||||||
clearTimeout(this.IP.tempMuteExpireTimeout);
|
clearTimeout(this.IP.tempMuteExpireTimeout);
|
||||||
this.IP.muted = false;
|
this.IP.muted = false;
|
||||||
this.sendMsg(guac.guacEncode('chat', '', 'You are no longer muted.'));
|
this.sendMsg(cvm.guacEncode('chat', '', 'You are no longer muted.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private banCmdArgs(arg: string): string {
|
private banCmdArgs(arg: string): string {
|
||||||
|
|||||||
@@ -49,7 +49,14 @@ export default class WSClient extends EventEmitter implements NetworkClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
close(): void {
|
close(): void {
|
||||||
|
if(this.isOpen()) {
|
||||||
|
// While this seems counterintutive, do note that the WebSocket protocol
|
||||||
|
// *sends* a data frame whilist closing a connection. Therefore, if the other end
|
||||||
|
// has forcibly hung up (closed) their connection, the best way to handle that
|
||||||
|
// is to just let the inner TCP socket propegate that, which `ws` will do for us.
|
||||||
|
// Otherwise, we'll try to send data to a closed client then SIGPIPE.
|
||||||
this.socket.close();
|
this.socket.close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
209
guac-rs/Cargo.lock
generated
209
guac-rs/Cargo.lock
generated
@@ -1,209 +0,0 @@
|
|||||||
# 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"
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "guac-rs"
|
|
||||||
description = "Rust guacamole decoding :)"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
exclude = ["index.node"]
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
crate-type = ["cdylib"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
neon = "1"
|
|
||||||
3
guac-rs/index.d.ts
vendored
3
guac-rs/index.d.ts
vendored
@@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
export function guacDecode(input: string): string[];
|
|
||||||
export function guacEncode(...items: string[]): string;
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
// *sigh*
|
|
||||||
import { createRequire } from 'module';
|
|
||||||
const require = createRequire(import.meta.url);
|
|
||||||
|
|
||||||
export let {guacDecode, guacEncode} = require('./index.node');
|
|
||||||
|
|
||||||
15
jpegturbo-rs/index.d.ts
vendored
15
jpegturbo-rs/index.d.ts
vendored
@@ -1,15 +0,0 @@
|
|||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
// 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>;
|
|
||||||
|
|
||||||
// TODO: Version that can downscale?
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@cvmts/jpegturbo-rs",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,7 @@
|
|||||||
"name": "cvmts-repo",
|
"name": "cvmts-repo",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"shared",
|
"shared",
|
||||||
"guac-rs",
|
"cvm-rs",
|
||||||
"jpegturbo-rs",
|
|
||||||
"nodejs-rfb",
|
"nodejs-rfb",
|
||||||
"qemu",
|
"qemu",
|
||||||
"cvmts"
|
"cvmts"
|
||||||
@@ -19,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
"packageManager": "yarn@4.1.1",
|
"packageManager": "yarn@4.1.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn && cd nodejs-rfb && yarn && yarn build && cd ../shared && yarn build && cd ../qemu && yarn build && cd ../cvmts && yarn build",
|
"build": "just",
|
||||||
"serve": "node cvmts/dist/index.js"
|
"serve": "node cvmts/dist/index.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
yarn.lock
27
yarn.lock
@@ -47,12 +47,19 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"@cvmts/cvm-rs@npm:*, @cvmts/cvm-rs@workspace:cvm-rs":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@cvmts/cvm-rs@workspace:cvm-rs"
|
||||||
|
dependencies:
|
||||||
|
cargo-cp-artifact: "npm:^0.1"
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@cvmts/cvmts@workspace:cvmts":
|
"@cvmts/cvmts@workspace:cvmts":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@cvmts/cvmts@workspace:cvmts"
|
resolution: "@cvmts/cvmts@workspace:cvmts"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cvmts/guac-rs": "npm:*"
|
"@cvmts/cvm-rs": "npm:*"
|
||||||
"@cvmts/jpegturbo-rs": "npm:*"
|
|
||||||
"@cvmts/qemu": "npm:*"
|
"@cvmts/qemu": "npm:*"
|
||||||
"@types/node": "npm:^20.12.5"
|
"@types/node": "npm:^20.12.5"
|
||||||
"@types/ws": "npm:^8.5.5"
|
"@types/ws": "npm:^8.5.5"
|
||||||
@@ -66,22 +73,6 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@cvmts/guac-rs@npm:*, @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/jpegturbo-rs@npm:*, @cvmts/jpegturbo-rs@workspace:jpegturbo-rs":
|
|
||||||
version: 0.0.0-use.local
|
|
||||||
resolution: "@cvmts/jpegturbo-rs@workspace:jpegturbo-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"
|
||||||
|
|||||||
Reference in New Issue
Block a user