2024-08-21 07:10:58 -04:00
|
|
|
import { Rank, User } from './User';
|
|
|
|
|
|
|
|
|
|
// We should probably put this in the binproto repository or something
|
2024-08-22 03:50:04 -04:00
|
|
|
export enum ProtocolUpgradeCapability {
|
|
|
|
|
BinRects = 'bin'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export enum ProtocolRenameStatus {
|
|
|
|
|
Ok = 0,
|
|
|
|
|
UsernameTaken = 1,
|
|
|
|
|
UsernameInvalid = 2,
|
|
|
|
|
UsernameNotAllowed = 3
|
2024-08-21 07:10:58 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ScreenRect {
|
|
|
|
|
x: number;
|
|
|
|
|
y: number;
|
|
|
|
|
data: Buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ListEntry {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
thumbnail: Buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProtocolChatHistory {
|
|
|
|
|
user: string;
|
|
|
|
|
msg: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProtocolAddUser {
|
|
|
|
|
username: string;
|
|
|
|
|
rank: Rank;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 03:50:04 -04:00
|
|
|
export interface ProtocolFlag {
|
|
|
|
|
username: string;
|
|
|
|
|
countryCode: string;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-21 07:10:58 -04:00
|
|
|
// Protocol handlers. This is implemented by a layer that wants to listen to CollabVM protocol messages.
|
|
|
|
|
export interface IProtocolHandlers {
|
|
|
|
|
onNop(user: User): void;
|
|
|
|
|
|
|
|
|
|
onNoFlag(user: User): void;
|
|
|
|
|
|
|
|
|
|
// Called when the client requests a capability upgrade
|
|
|
|
|
onCapabilityUpgrade(user: User, capability: Array<String>): boolean;
|
|
|
|
|
|
|
|
|
|
onLogin(user: User, token: string): void;
|
|
|
|
|
|
|
|
|
|
// Called on turn request
|
|
|
|
|
onTurnRequest(user: User, forfeit: boolean): void;
|
|
|
|
|
|
|
|
|
|
onVote(user: User, choice: number): void;
|
|
|
|
|
|
|
|
|
|
onList(user: User): void;
|
|
|
|
|
onConnect(user: User, node: string): void;
|
|
|
|
|
onView(user: User, node: string, viewMode: number): void;
|
|
|
|
|
|
2024-08-21 20:15:14 -04:00
|
|
|
// Admin handlers
|
2024-08-21 07:10:58 -04:00
|
|
|
onAdminLogin(user: User, password: string): void;
|
|
|
|
|
onAdminMonitor(user: User, node: string, command: string): void;
|
2024-08-21 20:15:14 -04:00
|
|
|
onAdminRestore(user: User, node: string): void;
|
|
|
|
|
onAdminReboot(user: User, node: string): void;
|
|
|
|
|
onAdminBanUser(user: User, username: string): void;
|
|
|
|
|
onAdminForceVote(user: User, choice: number): void;
|
|
|
|
|
onAdminMuteUser(user: User, username: string, temporary: boolean): void;
|
|
|
|
|
onAdminKickUser(user: User, username: string): void;
|
|
|
|
|
onAdminEndTurn(user: User, username: string): void;
|
|
|
|
|
onAdminClearQueue(user: User, node: string): void;
|
|
|
|
|
onAdminRename(user: User, target: string, newName: string): void;
|
|
|
|
|
onAdminGetIP(user: User, username: string): void;
|
|
|
|
|
onAdminBypassTurn(user: User): void;
|
|
|
|
|
onAdminRawMessage(user: User, message: string): void;
|
|
|
|
|
onAdminToggleTurns(user: User, enabled: boolean): void;
|
|
|
|
|
onAdminIndefiniteTurn(user: User): void;
|
|
|
|
|
onAdminHideScreen(user: User, show: boolean): void;
|
|
|
|
|
onAdminSystemMessage(user: User, message: string): void;
|
|
|
|
|
|
|
|
|
|
onRename(user: User, newName: string | undefined): void;
|
2024-08-21 07:10:58 -04:00
|
|
|
onChat(user: User, message: string): void;
|
|
|
|
|
|
|
|
|
|
onKey(user: User, keysym: number, pressed: boolean): void;
|
|
|
|
|
onMouse(user: User, x: number, y: number, buttonMask: number): void;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 03:50:04 -04:00
|
|
|
// Abstracts away all of the protocol details from the CollabVM server,
|
|
|
|
|
// allowing it to be protocol-independent (as long as the client and server
|
|
|
|
|
// are able to speak the same protocol.)
|
2024-08-21 07:10:58 -04:00
|
|
|
export interface IProtocol {
|
2024-08-21 22:26:36 -04:00
|
|
|
// don't implement this yourself, extend from ProtocolBase
|
2024-08-21 07:10:58 -04:00
|
|
|
init(u: User): void;
|
2024-08-21 22:18:11 -04:00
|
|
|
dispose(): void;
|
2024-08-21 07:10:58 -04:00
|
|
|
|
|
|
|
|
// Sets handler object.
|
|
|
|
|
setHandler(handlers: IProtocolHandlers): void;
|
|
|
|
|
|
2024-08-21 22:26:36 -04:00
|
|
|
// Protocol implementation stuff
|
|
|
|
|
|
2024-08-22 03:50:04 -04:00
|
|
|
// Parses a single message and fires the given handler with deserialized arguments.
|
2024-08-21 07:10:58 -04:00
|
|
|
// This function does not catch any thrown errors; it is the caller's responsibility
|
|
|
|
|
// to handle errors. It should, however, catch invalid parameters without failing.
|
2024-08-22 03:50:04 -04:00
|
|
|
//
|
|
|
|
|
// This function will perform conversion to text if it is required.
|
2024-08-21 07:10:58 -04:00
|
|
|
processMessage(buffer: Buffer): boolean;
|
|
|
|
|
|
|
|
|
|
// Senders
|
|
|
|
|
|
|
|
|
|
sendNop(): void;
|
|
|
|
|
sendSync(now: number): void;
|
|
|
|
|
|
|
|
|
|
sendAuth(authServer: string): void;
|
|
|
|
|
|
2024-08-22 03:50:04 -04:00
|
|
|
sendCapabilities(caps: ProtocolUpgradeCapability[]): void;
|
|
|
|
|
|
2024-08-21 07:10:58 -04:00
|
|
|
sendConnectFailResponse(): void;
|
|
|
|
|
sendConnectOKResponse(votes: boolean): void;
|
|
|
|
|
|
|
|
|
|
sendLoginResponse(ok: boolean, message: string | undefined): void;
|
|
|
|
|
|
2024-08-21 22:18:11 -04:00
|
|
|
sendAdminLoginResponse(ok: boolean, modPerms: number | undefined): void;
|
|
|
|
|
sendAdminMonitorResponse(output: string): void;
|
|
|
|
|
sendAdminIPResponse(username: string, ip: string): void;
|
|
|
|
|
|
2024-08-21 07:10:58 -04:00
|
|
|
sendChatMessage(username: '' | string, message: string): void;
|
|
|
|
|
sendChatHistoryMessage(history: ProtocolChatHistory[]): void;
|
|
|
|
|
|
|
|
|
|
sendAddUser(users: ProtocolAddUser[]): void;
|
|
|
|
|
sendRemUser(users: string[]): void;
|
2024-08-22 03:50:04 -04:00
|
|
|
sendFlag(flag: ProtocolFlag[]): void;
|
2024-08-21 07:10:58 -04:00
|
|
|
|
2024-08-22 03:50:04 -04:00
|
|
|
sendSelfRename(status: ProtocolRenameStatus, newUsername: string, rank: Rank): void;
|
|
|
|
|
sendRename(oldUsername: string, newUsername: string, rank: Rank): void;
|
|
|
|
|
|
2024-08-21 07:10:58 -04:00
|
|
|
sendListResponse(list: ListEntry[]): void;
|
|
|
|
|
|
2024-08-21 22:36:22 -04:00
|
|
|
sendVoteStarted(): void;
|
|
|
|
|
sendVoteStats(msLeft: number, nrYes: number, nrNo: number): void;
|
|
|
|
|
sendVoteEnded(): void;
|
|
|
|
|
sendVoteCooldown(ms: number): void;
|
|
|
|
|
|
2024-08-21 07:10:58 -04:00
|
|
|
sendScreenResize(width: number, height: number): void;
|
|
|
|
|
|
|
|
|
|
// Sends a rectangle update to the user.
|
|
|
|
|
sendScreenUpdate(rect: ScreenRect): void;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 03:50:04 -04:00
|
|
|
// Base mixin for all concrete protocols to use. Inherit from this!
|
2024-08-21 22:26:36 -04:00
|
|
|
export class ProtocolBase {
|
|
|
|
|
protected handlers: IProtocolHandlers | null = null;
|
|
|
|
|
protected user: User | null = null;
|
|
|
|
|
|
|
|
|
|
init(u: User): void {
|
|
|
|
|
this.user = u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dispose(): void {
|
|
|
|
|
this.user = null;
|
|
|
|
|
this.handlers = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setHandler(handlers: IProtocolHandlers): void {
|
|
|
|
|
this.handlers = handlers;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 03:50:04 -04:00
|
|
|
// The protocol manager. Holds protocol factories, and provides the ability
|
|
|
|
|
// to create a protocol by name. Avoids direct dependency on a given list of protocols,
|
|
|
|
|
// and allows (relatively simple) expansion.
|
2024-08-21 07:10:58 -04:00
|
|
|
export class ProtocolManager {
|
|
|
|
|
private protocols = new Map<String, () => IProtocol>();
|
|
|
|
|
|
|
|
|
|
// Registers a protocol with the given name.
|
|
|
|
|
registerProtocol(name: string, protocolFactory: () => IProtocol) {
|
|
|
|
|
if (!this.protocols.has(name)) this.protocols.set(name, protocolFactory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Creates an instance of a given protocol for a user.
|
|
|
|
|
createProtocol(name: string, user: User): IProtocol {
|
|
|
|
|
if (!this.protocols.has(name)) throw new Error(`ProtocolManager does not have protocol \"${name}\"`);
|
|
|
|
|
|
|
|
|
|
let factory = this.protocols.get(name)!;
|
|
|
|
|
let proto = factory();
|
|
|
|
|
proto.init(user);
|
|
|
|
|
return proto;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Global protocol manager
|
|
|
|
|
export let TheProtocolManager = new ProtocolManager();
|