netkitty
Version:
Network tools kit
100 lines (85 loc) • 3.29 kB
text/typescript
import EventEmitter from 'events'
import {MessageConnection} from 'socket-ipc'
import {PipeMessage, PipeMessageType} from './PipeMessage'
import {PipeMessageHandler} from './PipeMessageHandler'
import {SocketDownError} from '../../errors/SocketDownError'
export interface IPipeClientSocketOptions {
id: string
connection: MessageConnection
actions: Record<string, (...args: any[]) => Promise<any>>
}
export class PipeClientSocket extends EventEmitter {
readonly #id: string
readonly #connection: MessageConnection
#connected: boolean
protected readonly pipeMessageHandler: PipeMessageHandler
public readonly actions: Record<string, (...args: any[]) => Promise<any>> = {}
/**
* ClientId
*/
public get id(): string {
return this.#id
}
/**
* Is client socket connected
*/
public get connected(): boolean {
return this.#connected
}
constructor(options: IPipeClientSocketOptions) {
super()
this.#id = options.id
this.#connection = options.connection
this.actions = options.actions ? options.actions : {}
this.#connected = true
this.#connection
.on('error', (err: Error): boolean => this.emit('error', err))
.once('close', (): void => {
this.#connected = false
this.emit('disconnect')
this.removeAllListeners()
})
this.pipeMessageHandler = new PipeMessageHandler(this, this.#connection)
}
/**
* Invoke client side action
* @param act
* @param args
*/
public async invoke(act: string, ...args: any[]): Promise<any> {
return new Promise((resolve, reject): void => {
const pipeMessage: PipeMessage = new PipeMessage()
pipeMessage.type = PipeMessageType.REQUEST
pipeMessage.payload = [act, ...args]
this.once(pipeMessage.messageId, (resultOrError: any | Error): void => resultOrError instanceof Error ? reject(resultOrError) : resolve(resultOrError))
if (!this.connected) {
this.removeAllListeners(pipeMessage.messageId)
return reject(new SocketDownError('Socket is down'))
}
this.#connection.send(pipeMessage.serialize())
})
}
/**
* Notify event to pipe client
* @param event
* @param args
*/
public notify(event: string, ...args: any[]): void {
const pipeMessage: PipeMessage = new PipeMessage()
pipeMessage.type = PipeMessageType.EVENT
pipeMessage.payload = [event, ...args]
if (this.connected) this.#connection.send(pipeMessage.serialize())
}
public on(eventName: 'disconnect', listener: () => void): this
public on(eventName: string, listener: (...args: any) => void): this
public on(eventName: string, listener: (...args: any) => void): this {
super.on(eventName, listener)
return this
}
public once(eventName: 'disconnect', listener: () => void): this
public once(eventName: string, listener: (...args: any) => void): this
public once(eventName: string, listener: (...args: any) => void): this {
super.once(eventName, listener)
return this
}
}