2020-12-30 08:50:49 +13:00
|
|
|
import Vue from 'vue'
|
|
|
|
import * as EVENT from '../types/events'
|
|
|
|
import * as message from '../types/messages'
|
|
|
|
|
|
|
|
import EventEmitter from 'eventemitter3'
|
2021-01-16 05:17:49 +13:00
|
|
|
import { Logger } from '../utils/logger'
|
2021-06-18 10:31:03 +12:00
|
|
|
import { NekoConnection } from './connection'
|
2020-12-30 08:50:49 +13:00
|
|
|
import NekoState from '../types/state'
|
|
|
|
|
|
|
|
export interface NekoEvents {
|
2021-02-01 02:25:17 +13:00
|
|
|
// connection events
|
2021-07-12 08:38:48 +12:00
|
|
|
['connection.status']: (status: 'connected' | 'connecting' | 'disconnected') => void
|
2021-08-11 05:15:44 +12:00
|
|
|
['connection.type']: (status: 'fallback' | 'webrtc' | 'none') => void
|
2021-04-19 08:49:41 +12:00
|
|
|
['connection.webrtc.sdp']: (type: 'local' | 'remote', data: string) => void
|
|
|
|
['connection.webrtc.sdp.candidate']: (type: 'local' | 'remote', data: RTCIceCandidateInit) => void
|
2021-07-27 09:59:41 +12:00
|
|
|
['connection.closed']: (error?: Error) => void
|
2021-02-01 02:25:17 +13:00
|
|
|
|
|
|
|
// drag and drop events
|
2021-01-09 09:36:59 +13:00
|
|
|
['upload.drop.started']: () => void
|
|
|
|
['upload.drop.progress']: (progressEvent: ProgressEvent) => void
|
2021-09-02 05:05:44 +12:00
|
|
|
['upload.drop.finished']: (error?: Error) => void
|
2021-02-01 02:25:17 +13:00
|
|
|
|
|
|
|
// upload dialog events
|
|
|
|
['upload.dialog.requested']: () => void
|
|
|
|
['upload.dialog.overlay']: (id: string) => void
|
|
|
|
['upload.dialog.closed']: () => void
|
|
|
|
|
|
|
|
// custom messages events
|
|
|
|
['receive.unicast']: (sender: string, subject: string, body: any) => void
|
|
|
|
['receive.broadcast']: (sender: string, subject: string, body: any) => void
|
|
|
|
|
2021-03-14 12:08:52 +13:00
|
|
|
// session events
|
|
|
|
['session.created']: (id: string) => void
|
|
|
|
['session.deleted']: (id: string) => void
|
|
|
|
['session.updated']: (id: string) => void
|
2021-02-01 02:25:17 +13:00
|
|
|
|
|
|
|
// room events
|
2021-07-18 00:08:25 +12:00
|
|
|
['room.control.host']: (hasHost: boolean, hostID?: string) => void
|
2021-02-01 02:25:17 +13:00
|
|
|
['room.screen.updated']: (width: number, height: number, rate: number) => void
|
|
|
|
['room.clipboard.updated']: (text: string) => void
|
2021-07-18 00:08:25 +12:00
|
|
|
['room.broadcast.status']: (isActive: boolean, url?: string) => void
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
export class NekoMessages extends EventEmitter<NekoEvents> {
|
2021-09-13 04:05:16 +12:00
|
|
|
private _localLog: Logger
|
|
|
|
private _remoteLog: Logger
|
2020-12-30 08:50:49 +13:00
|
|
|
|
2021-10-04 11:22:11 +13:00
|
|
|
// eslint-disable-next-line
|
|
|
|
constructor(
|
|
|
|
private readonly _connection: NekoConnection,
|
|
|
|
private readonly _state: NekoState,
|
|
|
|
) {
|
2020-12-30 08:50:49 +13:00
|
|
|
super()
|
|
|
|
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog = new Logger('messages')
|
2021-10-04 11:22:11 +13:00
|
|
|
this._remoteLog = _connection.getLogger('messages')
|
2021-03-25 23:31:49 +13:00
|
|
|
|
2021-06-18 10:31:03 +12:00
|
|
|
this._connection.websocket.on('message', async (event: string, payload: any) => {
|
2020-12-30 08:50:49 +13:00
|
|
|
// @ts-ignore
|
|
|
|
if (typeof this[event] === 'function') {
|
2021-09-10 09:23:34 +12:00
|
|
|
try {
|
|
|
|
// @ts-ignore
|
|
|
|
this[event](payload)
|
|
|
|
} catch (error: any) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._remoteLog.error(`error while processing websocket event`, { event, error })
|
2021-09-10 09:23:34 +12:00
|
|
|
}
|
2020-12-30 08:50:49 +13:00
|
|
|
} else {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._remoteLog.warn(`unhandled websocket event`, { event, payload })
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
})
|
2021-06-18 10:31:03 +12:00
|
|
|
|
|
|
|
this._connection.webrtc.on('candidate', (candidate: RTCIceCandidateInit) => {
|
|
|
|
this._connection.websocket.send(EVENT.SIGNAL_CANDIDATE, candidate)
|
|
|
|
this.emit('connection.webrtc.sdp.candidate', 'local', candidate)
|
|
|
|
})
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////
|
|
|
|
// System Events
|
|
|
|
/////////////////////////////
|
|
|
|
|
|
|
|
protected [EVENT.SYSTEM_INIT](conf: message.SystemInit) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SYSTEM_INIT`)
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.set(this._state, 'session_id', conf.session_id)
|
|
|
|
Vue.set(this._state.control, 'implicit_hosting', conf.implicit_hosting)
|
2021-07-15 00:30:55 +12:00
|
|
|
Vue.set(this._state.connection, 'screencast', conf.screencast_enabled)
|
2021-05-01 02:06:13 +12:00
|
|
|
Vue.set(this._state.connection.webrtc, 'videos', conf.webrtc.videos)
|
2020-12-30 08:50:49 +13:00
|
|
|
|
2021-03-14 12:08:52 +13:00
|
|
|
for (const id in conf.sessions) {
|
|
|
|
this[EVENT.SESSION_CREATED](conf.sessions[id])
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
this[EVENT.SCREEN_UPDATED](conf.screen_size)
|
|
|
|
this[EVENT.CONTROL_HOST](conf.control_host)
|
|
|
|
}
|
|
|
|
|
|
|
|
protected [EVENT.SYSTEM_ADMIN]({ screen_sizes_list, broadcast_status }: message.SystemAdmin) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SYSTEM_ADMIN`)
|
2020-12-30 08:50:49 +13:00
|
|
|
|
|
|
|
const list = screen_sizes_list.sort((a, b) => {
|
|
|
|
if (b.width === a.width && b.height == a.height) {
|
|
|
|
return b.rate - a.rate
|
|
|
|
} else if (b.width === a.width) {
|
|
|
|
return b.height - a.height
|
|
|
|
}
|
|
|
|
return b.width - a.width
|
|
|
|
})
|
|
|
|
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.set(this._state.screen, 'configurations', list)
|
2020-12-30 08:50:49 +13:00
|
|
|
|
|
|
|
this[EVENT.BORADCAST_STATUS](broadcast_status)
|
|
|
|
}
|
|
|
|
|
|
|
|
protected [EVENT.SYSTEM_DISCONNECT]({ message }: message.SystemDisconnect) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SYSTEM_DISCONNECT`)
|
2021-07-27 09:59:41 +12:00
|
|
|
this._connection.close(new Error(message))
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////
|
|
|
|
// Signal Events
|
|
|
|
/////////////////////////////
|
|
|
|
|
2021-06-18 10:31:03 +12:00
|
|
|
protected async [EVENT.SIGNAL_PROVIDE]({ sdp: remoteSdp, video, iceservers }: message.SignalProvide) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SIGNAL_PROVIDE`)
|
2021-06-18 10:31:03 +12:00
|
|
|
this.emit('connection.webrtc.sdp', 'remote', remoteSdp)
|
|
|
|
|
|
|
|
const localSdp = await this._connection.webrtc.connect(remoteSdp, iceservers)
|
|
|
|
this._connection.websocket.send(EVENT.SIGNAL_ANSWER, {
|
|
|
|
sdp: localSdp,
|
|
|
|
})
|
|
|
|
|
|
|
|
this.emit('connection.webrtc.sdp', 'local', localSdp)
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.set(this._state.connection.webrtc, 'video', video)
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
2021-09-09 10:03:19 +12:00
|
|
|
protected async [EVENT.SIGNAL_RESTART]({ sdp }: message.SignalAnswer) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SIGNAL_RESTART`)
|
2021-06-28 08:07:42 +12:00
|
|
|
this.emit('connection.webrtc.sdp', 'remote', sdp)
|
|
|
|
|
|
|
|
const localSdp = await this._connection.webrtc.offer(sdp)
|
|
|
|
this._connection.websocket.send(EVENT.SIGNAL_ANSWER, {
|
|
|
|
sdp: localSdp,
|
|
|
|
})
|
|
|
|
|
|
|
|
this.emit('connection.webrtc.sdp', 'local', localSdp)
|
|
|
|
}
|
|
|
|
|
2021-09-09 10:03:19 +12:00
|
|
|
protected [EVENT.SIGNAL_CANDIDATE](candidate: message.SignalCandidate) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SIGNAL_CANDIDATE`)
|
2021-06-18 10:31:03 +12:00
|
|
|
this._connection.webrtc.setCandidate(candidate)
|
2021-04-19 08:49:41 +12:00
|
|
|
this.emit('connection.webrtc.sdp.candidate', 'remote', candidate)
|
2021-02-03 08:27:23 +13:00
|
|
|
}
|
|
|
|
|
2021-06-18 10:31:03 +12:00
|
|
|
protected [EVENT.SIGNAL_VIDEO]({ video }: message.SignalVideo) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SIGNAL_VIDEO`, { video })
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.set(this._state.connection.webrtc, 'video', video)
|
2021-02-08 05:28:15 +13:00
|
|
|
}
|
|
|
|
|
2020-12-30 08:50:49 +13:00
|
|
|
/////////////////////////////
|
2021-03-14 12:08:52 +13:00
|
|
|
// Session Events
|
2020-12-30 08:50:49 +13:00
|
|
|
/////////////////////////////
|
|
|
|
|
2021-03-14 12:08:52 +13:00
|
|
|
protected [EVENT.SESSION_CREATED]({ id, ...data }: message.SessionData) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SESSION_CREATED`, { id })
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.set(this._state.sessions, id, data)
|
2021-03-14 12:08:52 +13:00
|
|
|
this.emit('session.created', id)
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
2021-03-14 12:08:52 +13:00
|
|
|
protected [EVENT.SESSION_DELETED]({ id }: message.SessionID) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SESSION_DELETED`, { id })
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.delete(this._state.sessions, id)
|
2021-03-14 12:08:52 +13:00
|
|
|
this.emit('session.deleted', id)
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
2021-03-14 11:48:16 +13:00
|
|
|
protected [EVENT.SESSION_PROFILE]({ id, ...profile }: message.MemberProfile) {
|
2021-09-27 02:13:42 +13:00
|
|
|
if (id in this._state.sessions) {
|
|
|
|
this._localLog.debug(`EVENT.SESSION_PROFILE`, { id })
|
|
|
|
Vue.set(this._state.sessions[id], 'profile', profile)
|
|
|
|
this.emit('session.updated', id)
|
|
|
|
}
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
2021-03-14 11:48:16 +13:00
|
|
|
protected [EVENT.SESSION_STATE]({ id, ...state }: message.SessionState) {
|
2021-09-27 02:13:42 +13:00
|
|
|
if (id in this._state.sessions) {
|
|
|
|
this._localLog.debug(`EVENT.SESSION_STATE`, { id })
|
|
|
|
Vue.set(this._state.sessions[id], 'state', state)
|
|
|
|
this.emit('session.updated', id)
|
|
|
|
}
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
2021-10-27 05:02:01 +13:00
|
|
|
protected [EVENT.SESSION_CURSORS](cursors: message.SessionCursor[]) {
|
|
|
|
// TODO: State retention logic.
|
|
|
|
Vue.set(this._state, 'cursors', cursors)
|
|
|
|
}
|
|
|
|
|
2020-12-30 08:50:49 +13:00
|
|
|
/////////////////////////////
|
|
|
|
// Control Events
|
|
|
|
/////////////////////////////
|
|
|
|
|
|
|
|
protected [EVENT.CONTROL_HOST]({ has_host, host_id }: message.ControlHost) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.CONTROL_HOST`)
|
2020-12-30 08:50:49 +13:00
|
|
|
|
|
|
|
if (has_host && host_id) {
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.set(this._state.control, 'host_id', host_id)
|
2020-12-30 08:50:49 +13:00
|
|
|
} else {
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.set(this._state.control, 'host_id', null)
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
2021-02-01 02:25:17 +13:00
|
|
|
this.emit('room.control.host', has_host, host_id)
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////
|
|
|
|
// Screen Events
|
|
|
|
/////////////////////////////
|
|
|
|
|
|
|
|
protected [EVENT.SCREEN_UPDATED]({ width, height, rate }: message.ScreenSize) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SCREEN_UPDATED`)
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.set(this._state.screen, 'size', { width, height, rate })
|
2021-02-01 02:25:17 +13:00
|
|
|
this.emit('room.screen.updated', width, height, rate)
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
2021-02-12 07:03:31 +13:00
|
|
|
|
2020-12-30 08:50:49 +13:00
|
|
|
/////////////////////////////
|
|
|
|
// Clipboard Events
|
|
|
|
/////////////////////////////
|
|
|
|
|
|
|
|
protected [EVENT.CLIPBOARD_UPDATED]({ text }: message.ClipboardData) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.CLIPBOARD_UPDATED`)
|
2021-04-25 07:06:42 +12:00
|
|
|
Vue.set(this._state.control, 'clipboard', { text })
|
2021-02-01 02:25:17 +13:00
|
|
|
this.emit('room.clipboard.updated', text)
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////
|
|
|
|
// Broadcast Events
|
|
|
|
/////////////////////////////
|
|
|
|
|
2021-09-09 10:03:19 +12:00
|
|
|
protected [EVENT.BORADCAST_STATUS]({ url, is_active }: message.BroadcastStatus) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.BORADCAST_STATUS`)
|
2020-12-30 08:50:49 +13:00
|
|
|
// TODO: Handle.
|
2021-02-01 02:25:17 +13:00
|
|
|
this.emit('room.broadcast.status', is_active, url)
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|
2021-01-21 11:59:32 +13:00
|
|
|
|
2021-01-29 04:08:17 +13:00
|
|
|
/////////////////////////////
|
|
|
|
// Send Events
|
|
|
|
/////////////////////////////
|
|
|
|
|
|
|
|
protected [EVENT.SEND_UNICAST]({ sender, subject, body }: message.SendMessage) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.SEND_UNICAST`)
|
2021-01-29 04:08:17 +13:00
|
|
|
this.emit('receive.unicast', sender, subject, body)
|
|
|
|
}
|
|
|
|
|
|
|
|
protected [EVENT.SEND_BROADCAST]({ sender, subject, body }: message.SendMessage) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.BORADCAST_STATUS`)
|
2021-01-29 04:08:17 +13:00
|
|
|
this.emit('receive.broadcast', sender, subject, body)
|
|
|
|
}
|
|
|
|
|
2021-01-21 11:59:32 +13:00
|
|
|
/////////////////////////////
|
|
|
|
// FileChooserDialog Events
|
|
|
|
/////////////////////////////
|
|
|
|
|
2021-03-14 12:08:52 +13:00
|
|
|
protected [EVENT.FILE_CHOOSER_DIALOG_OPENED]({ id }: message.SessionID) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.FILE_CHOOSER_DIALOG_OPENED`)
|
2021-01-21 11:59:32 +13:00
|
|
|
|
2021-04-25 07:06:42 +12:00
|
|
|
if (id == this._state.session_id) {
|
2021-02-01 02:25:17 +13:00
|
|
|
this.emit('upload.dialog.requested')
|
2021-01-21 11:59:32 +13:00
|
|
|
} else {
|
2021-02-01 02:25:17 +13:00
|
|
|
this.emit('upload.dialog.overlay', id)
|
2021-01-21 11:59:32 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-14 12:08:52 +13:00
|
|
|
protected [EVENT.FILE_CHOOSER_DIALOG_CLOSED]({ id }: message.SessionID) {
|
2021-09-13 04:05:16 +12:00
|
|
|
this._localLog.debug(`EVENT.FILE_CHOOSER_DIALOG_CLOSED`)
|
2021-02-01 02:25:17 +13:00
|
|
|
this.emit('upload.dialog.closed')
|
2021-01-21 11:59:32 +13:00
|
|
|
}
|
2020-12-30 08:50:49 +13:00
|
|
|
}
|