Use nanoevents typing where possible

(this also fixes the use of a generic function type, where Nanoevents explciitly provides a cleaner type alias)
This commit is contained in:
modeco80 2024-03-12 00:10:24 -04:00
parent 3b4891c0a7
commit 4561eb1f63
2 changed files with 54 additions and 14 deletions

View File

@ -10,6 +10,7 @@ import "simple-keyboard/build/css/index.css";
import VoteStatus from "./protocol/VoteStatus.js"; import VoteStatus from "./protocol/VoteStatus.js";
import * as bootstrap from "bootstrap"; import * as bootstrap from "bootstrap";
import MuteState from "./protocol/MuteState.js"; import MuteState from "./protocol/MuteState.js";
import { Unsubscribe } from "nanoevents";
// Elements // Elements
const w = window as any; const w = window as any;
@ -321,7 +322,7 @@ function openVM(vm : VM) {
VM = new CollabVMClient(vm.url); VM = new CollabVMClient(vm.url);
// Register event listeners // Register event listeners
// An array to keep track of all listeners, and remove them when the VM is closed. Might not be necessary, but it's good practice. // An array to keep track of all listeners, and remove them when the VM is closed. Might not be necessary, but it's good practice.
var listeners : (() => void)[] = []; var listeners : Unsubscribe[] = [];
listeners.push(VM!.on('chat', (username, message) => chatMessage(username, message))); listeners.push(VM!.on('chat', (username, message) => chatMessage(username, message)));
listeners.push(VM!.on('adduser', (user) => addUser(user))); listeners.push(VM!.on('adduser', (user) => addUser(user)));
listeners.push(VM!.on('remuser', (user) => remUser(user))); listeners.push(VM!.on('remuser', (user) => remUser(user)));

View File

@ -18,6 +18,40 @@ interface ToStringable {
/// A type for strings, or things that can (in a valid manner) be turned into strings /// A type for strings, or things that can (in a valid manner) be turned into strings
type StringLike = string | ToStringable; type StringLike = string | ToStringable;
export interface CollabVMClientEvents {
open: () => void;
close: () => void;
message: (...args: string[]) => void;
// Protocol stuff
chat: (username: string, message: string) => void;
adduser: (user: User) => void;
remuser: (user: User) => void;
renamestatus: (status: 'taken' | 'invalid' | 'blacklisted') => void;
turn: (status: TurnStatus) => void;
rename: (oldUsername: string, newUsername: string, selfRename: boolean) => void;
vote: (status: VoteStatus) => void;
voteend: () => void;
votecd: (coolDownTime: number) => void;
badpw: () => void;
login: (rank: Rank, perms: Permissions) => void;
}
// types for private emitter
interface CollabVMClientPrivateEvents {
list: (listEntries: string[]) => void;
connect: (connectedToVM: boolean) => void;
ip: (username: string, ip: string) => void;
qemu: (qemuResponse: string) => void;
}
export default class CollabVMClient { export default class CollabVMClient {
// Fields // Fields
private socket : WebSocket; private socket : WebSocket;
@ -33,15 +67,15 @@ export default class CollabVMClient {
private voteStatus : VoteStatus | null = null; private voteStatus : VoteStatus | null = null;
private node : string | null = null; private node : string | null = null;
// events that are used internally and not exposed // events that are used internally and not exposed
private emitter : Emitter<DefaultEvents>; private internalEmitter : Emitter<CollabVMClientPrivateEvents>;
// public events // public events
private publicEmitter : Emitter<DefaultEvents>; private publicEmitter : Emitter<CollabVMClientEvents>;
constructor(url : string) { constructor(url : string) {
// Save the URL // Save the URL
this.url = url; this.url = url;
// Create the events // Create the events
this.emitter = createNanoEvents(); this.internalEmitter = createNanoEvents();
this.publicEmitter = createNanoEvents(); this.publicEmitter = createNanoEvents();
// Create the canvas // Create the canvas
this.canvas = document.createElement('canvas'); this.canvas = document.createElement('canvas');
@ -148,12 +182,12 @@ export default class CollabVMClient {
} }
case "list": { case "list": {
// pass msgarr to the emitter for processing by list() // pass msgarr to the emitter for processing by list()
this.emitter.emit('list', msgArr.slice(1)); this.internalEmitter.emit('list', msgArr.slice(1));
break; break;
} }
case "connect": { case "connect": {
this.connectedToVM = msgArr[1] === "1"; this.connectedToVM = msgArr[1] === "1";
this.emitter.emit('connect', this.connectedToVM); this.internalEmitter.emit('connect', this.connectedToVM);
break; break;
} }
case "size": { case "size": {
@ -228,7 +262,7 @@ export default class CollabVMClient {
if (_user) { if (_user) {
_user.username = msgArr[3]; _user.username = msgArr[3];
} }
this.publicEmitter.emit('rename', oldusername, msgArr[3], selfrename); this.publicEmitter.emit('rename', oldusername!, msgArr[3], selfrename);
break; break;
} }
case "turn": { case "turn": {
@ -313,12 +347,12 @@ export default class CollabVMClient {
} }
case "19": { case "19": {
// IP // IP
this.emitter.emit('ip', msgArr[2], msgArr[3]); this.internalEmitter.emit('ip', msgArr[2], msgArr[3]);
break; break;
} }
case "2": { case "2": {
// QEMU // QEMU
this.emitter.emit('qemu', msgArr[2]); this.internalEmitter.emit('qemu', msgArr[2]);
break; break;
} }
} }
@ -341,7 +375,7 @@ export default class CollabVMClient {
// Get a list of all VMs // Get a list of all VMs
list() : Promise<VM[]> { list() : Promise<VM[]> {
return new Promise((res, rej) => { return new Promise((res, rej) => {
var u = this.emitter.on('list', (list : string[]) => { var u = this.onInternal('list', (list : string[]) => {
u(); u();
var vms : VM[] = []; var vms : VM[] = [];
for (var i = 0; i < list.length; i += 3) { for (var i = 0; i < list.length; i += 3) {
@ -363,7 +397,7 @@ export default class CollabVMClient {
// Connect to a node // Connect to a node
connect(id : string, username : string | null = null) : Promise<boolean> { connect(id : string, username : string | null = null) : Promise<boolean> {
return new Promise(res => { return new Promise(res => {
var u = this.emitter.on('connect', (success : boolean) => { var u = this.onInternal('connect', (success : boolean) => {
u(); u();
res(success); res(success);
}); });
@ -481,7 +515,7 @@ export default class CollabVMClient {
getip(user : string) { getip(user : string) {
if (this.users.find(u => u.username === user) === undefined) return false; if (this.users.find(u => u.username === user) === undefined) return false;
return new Promise<string>(res => { return new Promise<string>(res => {
var u = this.emitter.on('ip', (username : string, ip : string) => { var u = this.onInternal('ip', (username : string, ip : string) => {
if (username !== user) return; if (username !== user) return;
u(); u();
res(ip); res(ip);
@ -493,7 +527,7 @@ export default class CollabVMClient {
// QEMU Monitor // QEMU Monitor
qemuMonitor(cmd : string) { qemuMonitor(cmd : string) {
return new Promise<string>(res => { return new Promise<string>(res => {
var u = this.emitter.on('qemu', output => { var u = this.onInternal('qemu', output => {
u(); u();
res(output); res(output);
}) })
@ -526,6 +560,11 @@ export default class CollabVMClient {
this.send("admin", AdminOpcode.HideScreen, hidden ? "1" : "0"); this.send("admin", AdminOpcode.HideScreen, hidden ? "1" : "0");
} }
private onInternal<E extends keyof CollabVMClientPrivateEvents>(event: E, callback: CollabVMClientPrivateEvents[E]) {
on = (event : string | number, cb: (...args: any) => void) => this.publicEmitter.on(event, cb); return this.internalEmitter.on(event, callback)
}
on<E extends keyof CollabVMClientEvents>(event: E, callback: CollabVMClientEvents[E]) {
return this.publicEmitter.on(event, callback)
}
} }