UNPKG

wasdtv

Version:

WASD.tv API client

153 lines (134 loc) 4.24 kB
import io from 'socket.io-client' import EventEmitter from 'events' import { Wasd } from '../types/api' import { SocketError } from '../core/error' export default class SocketClient extends EventEmitter { private heartbeat = 25 public socketio!: SocketIOClient.Socket private _subs: (keyof Wasd.EventMap)[] = [] private _originalOn = EventEmitter.prototype.on private _originalOff = EventEmitter.prototype.off constructor(private jwt: Wasd.JWT) { super() try { this.socketio = io('wss://chat.wasd.tv', { path: '/socket.io', transports: ['websocket'], query: { EIO: 3, }, }) } catch (err) { this.errorHandler(err as Error) } } private connect(cb?: CallableFunction): void { try { this.socketio = io('wss://chat.wasd.tv', { path: '/socket.io', transports: ['websocket'], query: { EIO: 3, }, }) } catch (err) { this.errorHandler(err as Error) } this.listen(cb) } public join(stream_id: number, channel_id: number): void { if (this.socketio?.connected) { this.socketio.emit('join', { streamId: stream_id, channelId: channel_id, jwt: this.jwt, excludeStickers: true, }) } else { this.connect(() => { this.join(stream_id, channel_id) }) } } public leave(stream_id: number): void { if (this.socketio?.connected) { this.socketio.emit('leave', { streamId: stream_id, }) } else { this.connect(() => { this.leave(stream_id) }) } } public sendMessage(stream_id: number, message: string, channel_id: number, streamer_id: number): void { if (this.socketio?.connected) { this.socketio.emit('message', { channelId: channel_id, hash: this.messageHash(), jwt: this.jwt, message: message, streamId: stream_id, streamerId: streamer_id, }) } else { throw new SocketError('Socket is not connected at this moment. Use this method only after "joined" event.') } } public sendSticker(stream_id: number, sticker_id: number, channel_id: number, streamer_id: number): void { if (this.socketio?.connected) { this.socketio.emit('sticker', { channel_id: channel_id, hash: this.messageHash(), sticker_id: sticker_id, stream_id: stream_id, streamer_id: streamer_id, }) } else { throw new SocketError('Socket is not connected at this moment. Use this method only after "joined" event.') } } private messageHash(length = 25): string { let result = '' const characters = 'abcdefghijklmnopqrstuvwxyz0123456789' const charactersLength = characters.length for (let i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * charactersLength)) } return result } private listen(cb?: CallableFunction): void { this.socketio.on('connect', () => { this.ping() if (cb !== undefined) { cb() } this.emit('connect', null) console.log('connected') this._subs.forEach((event) => { this.socketio.on(event, (ctx: Wasd.EventMap[typeof event]) => { this.emit(event, ctx) }) }) }) } public on<T extends Wasd.EventMap, V extends keyof Wasd.EventMap>(event: V, listener: (ctx: Pick<T, V>[V]) => void): this { this._subs.push(event) return this._originalOn(event, listener) as this } public off<T extends Wasd.EventMap, V extends keyof Wasd.EventMap>(event: V, listener: (ctx: Pick<T, V>[V]) => void): this { this._subs = this._subs.filter((e) => e !== event) return this._originalOff(event, listener) as this } private ping(): void { setTimeout(() => { if (this.socketio.connected) { this.socketio.send(2) this.ping() } }, this.heartbeat * 1000) } private errorHandler(err: Error): void { throw new SocketError(`${err.name}: ${err.message}`) } }