Abstract the VM, so that we can use other hypervisors in the future
This commit is contained in:
@@ -8,8 +8,9 @@ import BatchRects from "./RectBatcher.js";
|
|||||||
import { createCanvas, Canvas, CanvasRenderingContext2D, createImageData } from "canvas";
|
import { createCanvas, Canvas, CanvasRenderingContext2D, createImageData } from "canvas";
|
||||||
import { Mutex } from "async-mutex";
|
import { Mutex } from "async-mutex";
|
||||||
import log from "./log.js";
|
import log from "./log.js";
|
||||||
|
import VM from "./VM.js";
|
||||||
|
|
||||||
export default class QEMUVM extends EventEmitter {
|
export default class QEMUVM extends VM {
|
||||||
vnc? : rfb.RfbClient;
|
vnc? : rfb.RfbClient;
|
||||||
vncPort : number;
|
vncPort : number;
|
||||||
framebuffer : Canvas;
|
framebuffer : Canvas;
|
||||||
@@ -116,7 +117,7 @@ export default class QEMUVM extends EventEmitter {
|
|||||||
this.vnc.on("resize", (s) => this.onVNCSize(s));
|
this.vnc.on("resize", (s) => this.onVNCSize(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
getSize() {
|
public getSize() {
|
||||||
if (!this.vnc) return {height:0,width:0};
|
if (!this.vnc) return {height:0,width:0};
|
||||||
return {height: this.vnc.height, width: this.vnc.width}
|
return {height: this.vnc.height, width: this.vnc.width}
|
||||||
}
|
}
|
||||||
@@ -240,4 +241,16 @@ export default class QEMUVM extends EventEmitter {
|
|||||||
res();
|
res();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public pointerEvent(x: number, y: number, mask: number) {
|
||||||
|
if (!this.vnc) throw new Error("VNC was not instantiated.");
|
||||||
|
this.vnc.pointerEvent(x, y, mask);
|
||||||
|
}
|
||||||
|
public acceptingInput(): boolean {
|
||||||
|
return this.vncOpen;
|
||||||
|
}
|
||||||
|
public keyEvent(keysym: number, down: boolean): void {
|
||||||
|
if (!this.vnc) throw new Error("VNC was not instantiated.");
|
||||||
|
this.vnc.keyEvent(keysym, down ? 1 : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/VM.ts
Normal file
12
src/VM.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Canvas } from "canvas";
|
||||||
|
import EventEmitter from "events";
|
||||||
|
|
||||||
|
export default abstract class VM extends EventEmitter {
|
||||||
|
public abstract getSize() : {height:number;width:number;};
|
||||||
|
public abstract get framebuffer() : Canvas;
|
||||||
|
public abstract pointerEvent(x : number, y : number, mask : number) : void;
|
||||||
|
public abstract acceptingInput() : boolean;
|
||||||
|
public abstract keyEvent(keysym : number, down : boolean) : void;
|
||||||
|
public abstract Restore() : void;
|
||||||
|
public abstract Reboot() : Promise<void>;
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import QEMUVM from './QEMUVM.js';
|
|||||||
import { Canvas, createCanvas, CanvasRenderingContext2D } from 'canvas';
|
import { Canvas, createCanvas, CanvasRenderingContext2D } from 'canvas';
|
||||||
import { IPData } from './IPData.js';
|
import { IPData } from './IPData.js';
|
||||||
import log from './log.js';
|
import log from './log.js';
|
||||||
|
import VM from './VM.js';
|
||||||
|
|
||||||
export default class WSServer {
|
export default class WSServer {
|
||||||
private Config : IConfig;
|
private Config : IConfig;
|
||||||
@@ -44,8 +45,8 @@ export default class WSServer {
|
|||||||
// Indefinite turn
|
// Indefinite turn
|
||||||
private indefiniteTurn : User | null;
|
private indefiniteTurn : User | null;
|
||||||
private ModPerms : number;
|
private ModPerms : number;
|
||||||
private VM : QEMUVM;
|
private VM : VM;
|
||||||
constructor(config : IConfig, vm : QEMUVM) {
|
constructor(config : IConfig, vm : VM) {
|
||||||
this.ChatHistory = new CircularBuffer<{user:string,msg:string}>(Array, 5);
|
this.ChatHistory = new CircularBuffer<{user:string,msg:string}>(Array, 5);
|
||||||
this.TurnQueue = new Queue<User>();
|
this.TurnQueue = new Queue<User>();
|
||||||
this.TurnTime = 0;
|
this.TurnTime = 0;
|
||||||
@@ -254,22 +255,20 @@ export default class WSServer {
|
|||||||
break;
|
break;
|
||||||
case "mouse":
|
case "mouse":
|
||||||
if (this.TurnQueue.peek() !== client && client.rank !== Rank.Admin) return;
|
if (this.TurnQueue.peek() !== client && client.rank !== Rank.Admin) return;
|
||||||
if (!this.VM.vncOpen) return;
|
if (!this.VM.acceptingInput()) return;
|
||||||
if (!this.VM.vnc) throw new Error("VNC Client was undefined");
|
|
||||||
var x = parseInt(msgArr[1]);
|
var x = parseInt(msgArr[1]);
|
||||||
var y = parseInt(msgArr[2]);
|
var y = parseInt(msgArr[2]);
|
||||||
var mask = parseInt(msgArr[3]);
|
var mask = parseInt(msgArr[3]);
|
||||||
if (x === undefined || y === undefined || mask === undefined) return;
|
if (x === undefined || y === undefined || mask === undefined) return;
|
||||||
this.VM.vnc.pointerEvent(x, y, mask);
|
this.VM.pointerEvent(x, y, mask);
|
||||||
break;
|
break;
|
||||||
case "key":
|
case "key":
|
||||||
if (this.TurnQueue.peek() !== client && client.rank !== Rank.Admin) return;
|
if (this.TurnQueue.peek() !== client && client.rank !== Rank.Admin) return;
|
||||||
if (!this.VM.vncOpen) return;
|
if (!this.VM.acceptingInput()) return;
|
||||||
if (!this.VM.vnc) throw new Error("VNC Client was undefined");
|
|
||||||
var keysym = parseInt(msgArr[1]);
|
var keysym = parseInt(msgArr[1]);
|
||||||
var down = parseInt(msgArr[2]);
|
var down = parseInt(msgArr[2]);
|
||||||
if (keysym === undefined || (down !== 0 && down !== 1)) return;
|
if (keysym === undefined || (down !== 0 && down !== 1)) return;
|
||||||
this.VM.vnc.keyEvent(keysym, down);
|
this.VM.keyEvent(keysym, down === 1 ? true : false);
|
||||||
break;
|
break;
|
||||||
case "vote":
|
case "vote":
|
||||||
if (!this.Config.vm.snapshots) return;
|
if (!this.Config.vm.snapshots) return;
|
||||||
@@ -327,6 +326,10 @@ export default class WSServer {
|
|||||||
case "5":
|
case "5":
|
||||||
// QEMU Monitor
|
// QEMU Monitor
|
||||||
if (client.rank !== Rank.Admin) return;
|
if (client.rank !== Rank.Admin) return;
|
||||||
|
if (!(this.VM instanceof QEMUVM)) {
|
||||||
|
client.sendMsg(guacutils.encode("admin", "2", "This is not a QEMU VM and therefore QEMU monitor commands cannot be run."));
|
||||||
|
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.qmpClient.runMonitorCmd(msgArr[3]);
|
var output = await this.VM.qmpClient.runMonitorCmd(msgArr[3]);
|
||||||
client.sendMsg(guacutils.encode("admin", "2", String(output)));
|
client.sendMsg(guacutils.encode("admin", "2", String(output)));
|
||||||
|
|||||||
Reference in New Issue
Block a user