SHARE
TWEET

Untitled

a guest Jan 21st, 2019 98 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import * as WebSocket from 'ws'
  2.  
  3.  
  4. // -------------------------------------------------------
  5. //
  6. // Binding
  7. //
  8. // Message sent immediately on socket connection. The
  9. // binding message contains the client sockets address
  10. // (or socket identifier) and webrtc connection info.
  11. //
  12. // -------------------------------------------------------
  13. export interface Binding {
  14.   type: 'binding'
  15.   address: string
  16.   configuration: RTCConfiguration
  17. }
  18.  
  19. // -------------------------------------------------------
  20. //
  21. // Forward
  22. //
  23. // Message sent from one user to another through via the
  24. // server. The forwarded message is the primary exchange
  25. // type for webrtc negotiation where data T is understood
  26. // by negotiating clients.
  27. //
  28. // -------------------------------------------------------
  29. export interface Forward<T = any> {
  30.   type: 'forward'
  31.   from: string
  32.   to:   string
  33.   data: T
  34. }
  35.  
  36. // -------------------------------------------------------
  37. //
  38. // Address
  39. //
  40. // Simple address allocator. Fakes IPv4 looking
  41. // addresses. Is used by the server to allocate
  42. // unique addresses to sockets on connection.
  43. //
  44. // -------------------------------------------------------
  45. export class Address {
  46.   private index: number = 0
  47.   public next(): string {
  48.     this.index += 1
  49.     const bounds  = [256, 256, 256, 256]
  50.     const address = bounds.reduce<[number[], number]>(
  51.       (state, rank, index) => {
  52.         state[0][index] = Math.floor((this.index / state[1]) % rank)
  53.         state[1] *= rank
  54.         return state
  55.       },
  56.       [Array.from({ length: bounds.length }), 1]
  57.     )[0]
  58.     return address.join('.')
  59.   }
  60. }
  61.  
  62.  
  63. // -------------------------------------------------------
  64. //
  65. // Server
  66. //
  67. // Simple smoke webrtc signalling server. Implements the
  68. // smoke signalling protocol for connecting clients in a
  69. // smoke network.
  70. //
  71. // -------------------------------------------------------
  72.  
  73. export class Server {
  74.   private server!: WebSocket.Server
  75.   private sockets: Map<string, WebSocket>
  76.   private address: Address
  77.  
  78.   constructor(private configuration: RTCConfiguration) {
  79.     this.sockets   = new Map<string, WebSocket>()
  80.     this.address = new Address()
  81.   }
  82.  
  83.   /** Handles incoming connections */
  84.   private onConnection(socket: WebSocket) {
  85.     const configuration = this.configuration
  86.     const address = this.address.next()
  87.     const type = 'binding'
  88.     socket.send(JSON.stringify({ type, address, configuration } as Binding))
  89.  
  90.     socket.on('message', data => this.onMessage(address, data))
  91.     socket.on('error', error => this.onError(address, error))
  92.     socket.on('close', () => this.onClose(address))
  93.     this.sockets.set(address, socket)
  94.   }
  95.  
  96.   /** Handles an incoming message from the given address. */
  97.   private onMessage(address: string, data: WebSocket.Data) {
  98.     try {
  99.       const message = JSON.parse(data as string) as Forward
  100.       if (message.type === 'forward') {
  101.         this.onForward(address, message)
  102.       }
  103.     } catch (error) {
  104.       const socket = this.sockets.get(address)!
  105.       socket.close(1003, 'protocol violation')
  106.       this.sockets.delete(address)
  107.     }
  108.   }
  109.   /** Handles an incoming forward request. */
  110.   private onForward(address: string, forward: Forward) {
  111.     if (!this.sockets.has(forward.to)) {
  112.       return
  113.     }
  114.     const socket = this.sockets.get(forward.to)!
  115.     const type = 'forward'
  116.     const from = address
  117.     const to = forward.to
  118.     const data = forward.data
  119.     socket.send(JSON.stringify({ type, from, to, data } as Forward))
  120.   }
  121.  
  122.   /** Handles the socket keepalive. */
  123.   private onKeepAlive() {
  124.     for (const key in this.sockets.keys()) {
  125.       const socket = this.sockets.get(key)!
  126.       socket.ping()
  127.     }
  128.   }
  129.  
  130.   /** Handles socket on error events. */
  131.   private onError(address: string, error: Error) {
  132.     console.error(address, error)
  133.   }
  134.  
  135.   /** Handles socket on close events. */
  136.   private onClose(address: string) {
  137.     this.sockets.delete(address)
  138.   }
  139.  
  140.   /** Starts this server listening on the given port. */
  141.   public listen(port: number) {
  142.     this.server = new WebSocket.Server({ port })
  143.     this.server.on('connection', socket => this.onConnection(socket))
  144.     setInterval(() => this.onKeepAlive(), 16000)
  145.   }
  146. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top