From ff7eafd5bdd831113a380cb565ab0702a52fc213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Fri, 6 Nov 2020 23:27:07 +0100 Subject: [PATCH] add messages handler. --- src/components/canvas.vue | 10 +- src/internal/messages.ts | 240 ++++++++++++++++++++++++++++++++++++++ src/types/events.ts | 87 ++++++++++++++ src/types/messages.ts | 183 +++++++++++++++++++++++++++++ src/types/structs.ts | 26 +++++ 5 files changed, 545 insertions(+), 1 deletion(-) create mode 100644 src/internal/messages.ts create mode 100644 src/types/events.ts create mode 100644 src/types/messages.ts create mode 100644 src/types/structs.ts diff --git a/src/components/canvas.vue b/src/components/canvas.vue index 6654fb0e..6c94edcf 100644 --- a/src/components/canvas.vue +++ b/src/components/canvas.vue @@ -46,6 +46,7 @@ import { NekoWebSocket } from '~/internal/websocket' import { NekoWebRTC } from '~/internal/webrtc' + import { NekoMessages } from '~/internal/messages' import NekoState from '~/types/state' import Overlay from './overlay.vue' @@ -64,6 +65,7 @@ private observer = new ResizeObserver(this.onResize.bind(this)) private websocket = new NekoWebSocket() private webrtc = new NekoWebRTC() + private messages = new NekoMessages() private state = { id: null, @@ -134,7 +136,13 @@ } break default: - console.log(event, payload) + // @ts-ignore + if (typeof this.messages[event] === 'function') { + // @ts-ignore + this.messages[event](payload) + } else { + console.log(`unhandled websocket event '${event}':`, payload) + } } }) this.websocket.on('connecting', () => { diff --git a/src/internal/messages.ts b/src/internal/messages.ts new file mode 100644 index 00000000..1161200d --- /dev/null +++ b/src/internal/messages.ts @@ -0,0 +1,240 @@ +import Vue from 'vue' +import { Member } from '../types/structs' +import { EVENT } from '../types/events' +import { + DisconnectPayload, + SignalProvidePayload, + MemberListPayload, + MemberDisconnectPayload, + MemberPayload, + ControlPayload, + ControlTargetPayload, + ControlClipboardPayload, + ScreenConfigurationsPayload, + ScreenResolutionPayload, + BroadcastStatusPayload, + AdminPayload, + AdminTargetPayload, +} from '../types/messages' + +export class NekoMessages { + ///////////////////////////// + // System Events + ///////////////////////////// + public [EVENT.SYSTEM.DISCONNECT]({ message }: DisconnectPayload) { + console.log('EVENT.SYSTEM.DISCONNECT') + //this.onDisconnected(new Error(message)) + //this.$vue.$swal({ + // title: this.$vue.$t('connection.disconnected'), + // text: message, + // icon: 'error', + // confirmButtonText: this.$vue.$t('connection.button_confirm') as string, + //}) + } + + ///////////////////////////// + // Member Events + ///////////////////////////// + public [EVENT.MEMBER.LIST]({ members }: MemberListPayload) { + console.log('EVENT.MEMBER.LIST') + //this.$accessor.user.setMembers(members) + } + + public [EVENT.MEMBER.CONNECTED](member: MemberPayload) { + console.log('EVENT.MEMBER.CONNECTED') + //this.$accessor.user.addMember(member) + } + + public [EVENT.MEMBER.DISCONNECTED]({ id }: MemberDisconnectPayload) { + console.log('EVENT.MEMBER.DISCONNECTED') + //const member = this.member(id) + //if (!member) { + // return + //} + // + //this.$accessor.user.delMember(id) + } + + ///////////////////////////// + // Control Events + ///////////////////////////// + public [EVENT.CONTROL.LOCKED]({ id }: ControlPayload) { + console.log('EVENT.CONTROL.LOCKED') + //this.$accessor.remote.setHost(id) + //this.$accessor.remote.changeKeyboard() + // + //const member = this.member(id) + //if (!member) { + // return + //} + // + //if (this.id === id) { + // this.$vue.$notify({ + // group: 'neko', + // type: 'info', + // title: this.$vue.$t('notifications.controls_taken', { name: this.$vue.$t('you') }) as string, + // duration: 5000, + // speed: 1000, + // }) + //} + } + + public [EVENT.CONTROL.RELEASE]({ id }: ControlPayload) { + console.log('EVENT.CONTROL.RELEASE') + //this.$accessor.remote.reset() + //const member = this.member(id) + //if (!member) { + // return + //} + // + //if (this.id === id) { + // this.$vue.$notify({ + // group: 'neko', + // type: 'info', + // title: this.$vue.$t('notifications.controls_released', { name: this.$vue.$t('you') }) as string, + // duration: 5000, + // speed: 1000, + // }) + //} + } + + public [EVENT.CONTROL.REQUEST]({ id }: ControlPayload) { + console.log('EVENT.CONTROL.REQUEST') + //const member = this.member(id) + //if (!member) { + // return + //} + // + //this.$vue.$notify({ + // group: 'neko', + // type: 'info', + // title: this.$vue.$t('notifications.controls_has', { name: member.displayname }) as string, + // text: this.$vue.$t('notifications.controls_has_alt') as string, + // duration: 5000, + // speed: 1000, + //}) + } + + public [EVENT.CONTROL.REQUESTING]({ id }: ControlPayload) { + console.log('EVENT.CONTROL.REQUESTING') + //const member = this.member(id) + //if (!member || member.ignored) { + // return + //} + // + //this.$vue.$notify({ + // group: 'neko', + // type: 'info', + // title: this.$vue.$t('notifications.controls_requesting', { name: member.displayname }) as string, + // duration: 5000, + // speed: 1000, + //}) + } + + public [EVENT.CONTROL.GIVE]({ id, target }: ControlTargetPayload) { + console.log('EVENT.CONTROL.GIVE') + //const member = this.member(target) + //if (!member) { + // return + //} + // + //this.$accessor.remote.setHost(member) + //this.$accessor.remote.changeKeyboard() + } + + public [EVENT.CONTROL.CLIPBOARD]({ text }: ControlClipboardPayload) { + console.log('EVENT.CONTROL.CLIPBOARD') + //this.$accessor.remote.setClipboard(text) + } + + ///////////////////////////// + // Screen Events + ///////////////////////////// + public [EVENT.SCREEN.CONFIGURATIONS]({ configurations }: ScreenConfigurationsPayload) { + console.log('EVENT.SCREEN.CONFIGURATIONS') + //this.$accessor.video.setConfigurations(configurations) + } + + public [EVENT.SCREEN.RESOLUTION]({ id, width, height, rate }: ScreenResolutionPayload) { + console.log('EVENT.SCREEN.RESOLUTION') + //this.$accessor.video.setResolution({ width, height, rate }) + } + + ///////////////////////////// + // Broadcast Events + ///////////////////////////// + public [EVENT.BROADCAST.STATUS](payload: BroadcastStatusPayload) { + console.log('EVENT.BROADCAST.STATUS') + //this.$accessor.settings.broadcastStatus(payload) + } + + ///////////////////////////// + // Admin Events + ///////////////////////////// + public [EVENT.ADMIN.BAN]({ id, target }: AdminTargetPayload) { + console.log('EVENT.ADMIN.BAN') + // TODO + } + + public [EVENT.ADMIN.KICK]({ id, target }: AdminTargetPayload) { + console.log('EVENT.ADMIN.KICK') + // TODO + } + + public [EVENT.ADMIN.MUTE]({ id, target }: AdminTargetPayload) { + console.log('EVENT.ADMIN.MUTE') + //if (!target) { + // return + //} + // + //this.$accessor.user.setMuted({ id: target, muted: true }) + } + + public [EVENT.ADMIN.UNMUTE]({ id, target }: AdminTargetPayload) { + console.log('EVENT.ADMIN.UNMUTE') + //if (!target) { + // return + //} + // + //this.$accessor.user.setMuted({ id: target, muted: false }) + } + + public [EVENT.ADMIN.LOCK]({ id }: AdminPayload) { + console.log('EVENT.ADMIN.LOCK') + //this.$accessor.setLocked(true) + } + + public [EVENT.ADMIN.UNLOCK]({ id }: AdminPayload) { + console.log('EVENT.ADMIN.UNLOCK') + //this.$accessor.setLocked(false) + } + + public [EVENT.ADMIN.CONTROL]({ id, target }: AdminTargetPayload) { + console.log('EVENT.ADMIN.CONTROL') + //this.$accessor.remote.setHost(id) + //this.$accessor.remote.changeKeyboard() + } + + public [EVENT.ADMIN.RELEASE]({ id, target }: AdminTargetPayload) { + console.log('EVENT.ADMIN.RELEASE') + //this.$accessor.remote.reset() + } + + public [EVENT.ADMIN.GIVE]({ id, target }: AdminTargetPayload) { + console.log('EVENT.ADMIN.GIVE') + //if (!target) { + // return + //} + // + //const member = this.member(target) + //if (member) { + // this.$accessor.remote.setHost(member) + // this.$accessor.remote.changeKeyboard() + //} + } + + // Utilities + //public member(id: string): Member | undefined { + // return this.$accessor.user.members[id] + //} +} diff --git a/src/types/events.ts b/src/types/events.ts new file mode 100644 index 00000000..80403da0 --- /dev/null +++ b/src/types/events.ts @@ -0,0 +1,87 @@ +export const EVENT = { + SYSTEM: { + DISCONNECT: 'system/disconnect', + }, + SIGNAL: { + ANSWER: 'signal/answer', + PROVIDE: 'signal/provide', + }, + MEMBER: { + LIST: 'member/list', + CONNECTED: 'member/connected', + DISCONNECTED: 'member/disconnected', + }, + CONTROL: { + LOCKED: 'control/locked', + RELEASE: 'control/release', + REQUEST: 'control/request', + REQUESTING: 'control/requesting', + CLIPBOARD: 'control/clipboard', + GIVE: 'control/give', + KEYBOARD: 'control/keyboard', + }, + SCREEN: { + CONFIGURATIONS: 'screen/configurations', + RESOLUTION: 'screen/resolution', + SET: 'screen/set', + }, + BROADCAST: { + STATUS: 'broadcast/status', + CREATE: 'broadcast/create', + DESTROY: 'broadcast/destroy', + }, + ADMIN: { + BAN: 'admin/ban', + KICK: 'admin/kick', + LOCK: 'admin/lock', + UNLOCK: 'admin/unlock', + MUTE: 'admin/mute', + UNMUTE: 'admin/unmute', + CONTROL: 'admin/control', + RELEASE: 'admin/release', + GIVE: 'admin/give', + }, +} as const + +export type Events = typeof EVENT + +export type WebSocketEvents = + | SystemEvents + | SignalEvents + | MemberEvents + | ControlEvents + | ScreenEvents + | BroadcastEvents + | AdminEvents + +export type SystemEvents = typeof EVENT.SYSTEM.DISCONNECT + +export type SignalEvents = typeof EVENT.SIGNAL.ANSWER | typeof EVENT.SIGNAL.PROVIDE + +export type MemberEvents = typeof EVENT.MEMBER.LIST | typeof EVENT.MEMBER.CONNECTED | typeof EVENT.MEMBER.DISCONNECTED + +export type ControlEvents = + | typeof EVENT.CONTROL.LOCKED + | typeof EVENT.CONTROL.RELEASE + | typeof EVENT.CONTROL.REQUEST + | typeof EVENT.CONTROL.GIVE + | typeof EVENT.CONTROL.CLIPBOARD + | typeof EVENT.CONTROL.KEYBOARD + +export type ScreenEvents = typeof EVENT.SCREEN.CONFIGURATIONS | typeof EVENT.SCREEN.RESOLUTION | typeof EVENT.SCREEN.SET + +export type BroadcastEvents = + | typeof EVENT.BROADCAST.STATUS + | typeof EVENT.BROADCAST.CREATE + | typeof EVENT.BROADCAST.DESTROY + +export type AdminEvents = + | typeof EVENT.ADMIN.BAN + | typeof EVENT.ADMIN.KICK + | typeof EVENT.ADMIN.LOCK + | typeof EVENT.ADMIN.UNLOCK + | typeof EVENT.ADMIN.MUTE + | typeof EVENT.ADMIN.UNMUTE + | typeof EVENT.ADMIN.CONTROL + | typeof EVENT.ADMIN.RELEASE + | typeof EVENT.ADMIN.GIVE diff --git a/src/types/messages.ts b/src/types/messages.ts new file mode 100644 index 00000000..bee8cae2 --- /dev/null +++ b/src/types/messages.ts @@ -0,0 +1,183 @@ +import { + EVENT, + WebSocketEvents, + SystemEvents, + SignalEvents, + MemberEvents, + ControlEvents, + ScreenEvents, + BroadcastEvents, + AdminEvents, +} from './events' + +import { + Member, + ScreenConfigurations, + ScreenResolution +} from './structs' + +export type WebSocketMessages = + | WebSocketMessage + | SignalProvideMessage + | SignalAnswerMessage + | MemberListMessage + | MemberConnectMessage + | MemberDisconnectMessage + | ControlMessage + | ScreenResolutionMessage + | ScreenConfigurationsMessage + +export type WebSocketPayloads = + | SignalProvidePayload + | SignalAnswerPayload + | MemberListPayload + | Member + | ControlPayload + | ControlClipboardPayload + | ControlKeyboardPayload + | ScreenResolutionPayload + | ScreenConfigurationsPayload + | AdminPayload + | BroadcastStatusPayload + | BroadcastCreatePayload + +export interface WebSocketMessage { + event: WebSocketEvents | string +} + +/* + SYSTEM MESSAGES/PAYLOADS +*/ +// system/disconnect +export interface DisconnectMessage extends WebSocketMessage, DisconnectPayload { + event: typeof EVENT.SYSTEM.DISCONNECT +} +export interface DisconnectPayload { + message: string +} + +/* + SIGNAL MESSAGES/PAYLOADS +*/ +// signal/provide +export interface SignalProvideMessage extends WebSocketMessage, SignalProvidePayload { + event: typeof EVENT.SIGNAL.PROVIDE +} +export interface SignalProvidePayload { + id: string + lite: boolean + ice: string[] + sdp: string +} + +// signal/answer +export interface SignalAnswerMessage extends WebSocketMessage, SignalAnswerPayload { + event: typeof EVENT.SIGNAL.ANSWER +} +export interface SignalAnswerPayload { + sdp: string + displayname: string +} + +/* + MEMBER MESSAGES/PAYLOADS +*/ +// member/list +export interface MemberListMessage extends WebSocketMessage, MemberListPayload { + event: typeof EVENT.MEMBER.LIST +} +export interface MemberListPayload { + members: Member[] +} + +// member/connected +export interface MemberConnectMessage extends WebSocketMessage, MemberPayload { + event: typeof EVENT.MEMBER.CONNECTED +} +export type MemberPayload = Member + +// member/disconnected +export interface MemberDisconnectMessage extends WebSocketMessage, MemberPayload { + event: typeof EVENT.MEMBER.DISCONNECTED +} +export interface MemberDisconnectPayload { + id: string +} + +/* + CONTROL MESSAGES/PAYLOADS +*/ +// control/locked & control/release & control/request +export interface ControlMessage extends WebSocketMessage, ControlPayload { + event: ControlEvents +} +export interface ControlPayload { + id: string +} + +export interface ControlTargetPayload { + id: string + target: string +} + +export interface ControlClipboardPayload { + text: string +} + +export interface ControlKeyboardPayload { + layout?: string + capsLock?: boolean + numLock?: boolean + scrollLock?: boolean +} + +/* + SCREEN PAYLOADS +*/ +export interface ScreenResolutionMessage extends WebSocketMessage, ScreenResolutionPayload { + event: ScreenEvents +} + +export interface ScreenResolutionPayload extends ScreenResolution { + id?: string +} + +export interface ScreenConfigurationsMessage extends WebSocketMessage, ScreenConfigurationsPayload { + event: ScreenEvents +} + +export interface ScreenConfigurationsPayload { + configurations: ScreenConfigurations +} + +/* + BROADCAST PAYLOADS +*/ +export interface BroadcastCreatePayload { + url: string +} + +export interface BroadcastStatusPayload { + url: string + isActive: boolean +} + +/* + ADMIN PAYLOADS +*/ +export interface AdminMessage extends WebSocketMessage, AdminPayload { + event: AdminEvents +} + +export interface AdminPayload { + id: string +} + +export interface AdminTargetMessage extends WebSocketMessage, AdminTargetPayload { + event: AdminEvents +} + +export interface AdminTargetPayload { + id: string + target?: string +} diff --git a/src/types/structs.ts b/src/types/structs.ts new file mode 100644 index 00000000..cd601113 --- /dev/null +++ b/src/types/structs.ts @@ -0,0 +1,26 @@ +export interface Member { + id: string + displayname: string + admin: boolean + muted: boolean + connected?: boolean + ignored?: boolean +} + +export interface ScreenConfigurations { + [index: string]: ScreenConfiguration +} + +export interface ScreenConfiguration { + width: number + height: number + rates: { + [index: string]: number + } +} + +export interface ScreenResolution { + width: number + height: number + rate: number +}