dh_demo

DreamHanks demo project
git clone git://git.lair.cx/dh_demo
Log | Files | Refs | README

sockets.ts (2756B)


      1 import { createNanoEvents, Emitter } from 'nanoevents'
      2 import { remove } from 'next/dist/build/webpack/loaders/resolve-url-loader/lib/file-protocol'
      3 
      4 interface SocketEvent {
      5   payload: string
      6 }
      7 
      8 interface EventMap {
      9   [event: string]: (e: SocketEvent) => void
     10 }
     11 
     12 export class SocketClient {
     13   private eventEmitter: Emitter<EventMap>
     14   private socket?: WebSocket
     15 
     16   constructor () {
     17     this.eventEmitter = createNanoEvents()
     18   }
     19 
     20   get isConnected () {
     21     if (typeof WebSocket === 'undefined') {
     22       return false
     23     }
     24     return this.socket?.readyState === WebSocket.OPEN
     25   }
     26 
     27   wait () {
     28     return new Promise<void>((resolve) => {
     29       const check = () => {
     30         if (this.isConnected) {
     31           setTimeout(() => resolve(), 500)
     32           return
     33         }
     34 
     35         setTimeout(check, 100)
     36       }
     37 
     38       check()
     39     })
     40   }
     41 
     42   connect () {
     43     return new Promise<void>((resolve, reject) => {
     44       const self = this
     45 
     46       this.socket = new WebSocket(process.env.NEXT_PUBLIC_WIKI_SOCKET_URL ?? 'ws://localhost:3001/ws')
     47 
     48       function handleClose () {
     49         removePromiseListeners()
     50         reject()
     51       }
     52 
     53       function handleOpen () {
     54         removePromiseListeners()
     55         setTimeout(() => {
     56           resolve()
     57         }, 500)
     58       }
     59 
     60       function removePromiseListeners () {
     61         self.socket?.removeEventListener('open', handleOpen)
     62         self.socket?.removeEventListener('close', handleClose)
     63       }
     64 
     65       this.socket.addEventListener('open', handleOpen)
     66       this.socket.addEventListener('close', handleClose)
     67 
     68       this.socket.addEventListener('message', (event) => {
     69         this.handleMessage(event.data)
     70       })
     71 
     72       this.socket.addEventListener('open', () => {
     73         console.log('SocketClient: connected')
     74       })
     75       this.socket.addEventListener('close', () => {
     76         console.log('SocketClient: disconnected')
     77       })
     78 
     79     })
     80   }
     81 
     82   disconnect () {
     83     this.socket?.close()
     84   }
     85 
     86   public changePath (path: string) {
     87     this.socket?.send(`PATH${path}`)
     88   }
     89 
     90   public on (event: string, callback: (e: SocketEvent) => void) {
     91     return this.eventEmitter.on(event, callback)
     92   }
     93 
     94   private handleMessage (message: string) {
     95     const [command, commandPayload] = this.parseMessage(message)
     96 
     97     if (command === 'EMIT') {
     98       const [eventName, eventArgs] = this.parseEmitArgs(commandPayload)
     99       this.eventEmitter.emit(eventName, { payload: eventArgs })
    100     }
    101   }
    102 
    103   private parseMessage (message: string) {
    104     message = message.trim()
    105     return [message.slice(0, 4), message.slice(4)]
    106   }
    107 
    108   private parseEmitArgs (command: string) {
    109     const index = command.indexOf(' ')
    110     if (index === -1) {
    111       return [command, '']
    112     }
    113     return [command.slice(0, index), command.slice(index + 1)]
    114   }
    115 }