Jelajahi Sumber

Add basic websocket functionality

Alan Colon 7 tahun lalu
induk
melakukan
f7789080ca
6 mengubah file dengan 89 tambahan dan 2 penghapusan
  1. 11 1
      lib/app.js
  2. 14 0
      lib/server.js
  3. 2 1
      package.json
  4. 41 0
      src/client.js
  5. 9 0
      src/index.js
  6. 12 0
      yarn.lock

+ 11 - 1
lib/app.js

@@ -2,6 +2,8 @@ const http = require('http')
 const express = require('express')
 const express = require('express')
 const morgan = require('morgan')
 const morgan = require('morgan')
 const bodyParser = require('body-parser')
 const bodyParser = require('body-parser')
+const WebSocket = require('ws')
+const EventEmitter = require('events')
 const chalk = require('chalk')
 const chalk = require('chalk')
 const config = require('../config')
 const config = require('../config')
 
 
@@ -11,6 +13,7 @@ app.use(morgan('combined'))
 app.use(bodyParser.json())
 app.use(bodyParser.json())
 app.use(express.static('dist'))
 app.use(express.static('dist'))
 
 
+app.ws = new EventEmitter()
 app.listen = (port = config.port || (app.settings.env === 'production' ? 80 : 3000)) => new Promise((resolve, reject) => {
 app.listen = (port = config.port || (app.settings.env === 'production' ? 80 : 3000)) => new Promise((resolve, reject) => {
   app.server = http.createServer(app)
   app.server = http.createServer(app)
   app.server.once('error', (err) => {
   app.server.once('error', (err) => {
@@ -22,7 +25,14 @@ app.listen = (port = config.port || (app.settings.env === 'production' ? 80 : 30
     }
     }
   })
   })
   app.server.listen(port, () => {
   app.server.listen(port, () => {
-    console.log(`Server running at ${chalk.underline(chalk.blueBright(`http://localhost:${app.server.address().port}`))}`)
+    app.wss = new WebSocket.Server({ server: app.server })
+    app.wss.on('connection', (...args) => app.ws.emit('connection', ...args))
+    app.wss.on('message', (...args) => app.ws.emit('message', ...args))
+    app.wss.on('close', (...args) => app.ws.emit('close', ...args))
+    app.wss.on('error', (...args) => app.ws.emit('error', ...args))
+    app.server.port = app.server.address().port
+    console.log(`Server running at ${chalk.underline(chalk.blueBright(`http://localhost:${app.server.port}`))}`)
+    resolve()
   })
   })
 })
 })
 
 

+ 14 - 0
lib/server.js

@@ -2,6 +2,20 @@ const app = require('./app')
 
 
 /* TODO: Add handlers */
 /* TODO: Add handlers */
 
 
+const connections = []
+
+app.ws.on('connection', ws => {
+  connections.push(ws)
+  ws.on('close', () => {
+    connections.splice(connections.indexOf(ws), 1)
+  })
+  ws.on('message', message => {
+    console.log(message)
+    /* TODO: Add logic */
+  })
+  ws.send('Hello Client')
+})
+
 app.listen().catch((err) => {
 app.listen().catch((err) => {
   console.log(err.toString())
   console.log(err.toString())
   process.exit(1)
   process.exit(1)

+ 2 - 1
package.json

@@ -34,6 +34,7 @@
     "body-parser": "^1.18.3",
     "body-parser": "^1.18.3",
     "chalk": "^2.4.2",
     "chalk": "^2.4.2",
     "express": "^4.16.4",
     "express": "^4.16.4",
-    "morgan": "^1.9.1"
+    "morgan": "^1.9.1",
+    "ws": "^6.1.2"
   }
   }
 }
 }

+ 41 - 0
src/client.js

@@ -0,0 +1,41 @@
+const client = new EventTarget()
+const delay = 1000
+const protocol = `ws${location.protocol.substr(4)}`
+const path = location.pathname.split('/').slice(0, -1).join('/')
+const url = `${protocol}//${location.host}${path}`
+
+let _connect = null
+
+const connect = () => {
+  if (_connect == null) {
+    _connect = new Promise(resolve => {
+      const ws = new WebSocket(url)
+      window.ws = ws
+      let connected = false
+      const retry = () => resolve(new Promise(resolve => setTimeout(resolve, delay)).then(connect))
+      const dispatch = evt => client.dispatchEvent(new evt.constructor(evt.type, evt))
+      ws.addEventListener('open', evt => {
+        connected = true
+        dispatch(evt)
+        resolve(ws)
+      })
+      ws.addEventListener('close', evt => {
+        _connect = null
+        dispatch(evt)
+        retry()
+      })
+      ws.addEventListener('message', evt => dispatch(evt))
+      ws.addEventListener('error', evt => {
+        if (!connected) retry()
+        dispatch(evt)
+      })
+    })
+  }
+  return _connect
+}
+
+const send = message => connect().then(ws => ws.send(message))
+
+client.connect = connect
+client.send = send
+module.exports = client

+ 9 - 0
src/index.js

@@ -1,2 +1,11 @@
+const client = require('./client')
+
 document.addEventListener('DOMContentLoaded', () => {
 document.addEventListener('DOMContentLoaded', () => {
+  client.connect()
+  client.addEventListener('open', () => {
+    client.send('Hello Server')
+  })
+  client.addEventListener('message', evt => {
+    console.log(evt.data)
+  })
 })
 })

+ 12 - 0
yarn.lock

@@ -358,6 +358,11 @@ async-each@^1.0.0:
   resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
   resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
   integrity sha1-GdOGodntxufByF04iu28xW0zYC0=
   integrity sha1-GdOGodntxufByF04iu28xW0zYC0=
 
 
+async-limiter@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
+  integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
+
 async@^1.5.2:
 async@^1.5.2:
   version "1.5.2"
   version "1.5.2"
   resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
   resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
@@ -4933,6 +4938,13 @@ wrappy@1:
   resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
   resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
   integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
   integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
 
 
+ws@^6.1.2:
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.2.tgz#3cc7462e98792f0ac679424148903ded3b9c3ad8"
+  integrity sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==
+  dependencies:
+    async-limiter "~1.0.0"
+
 xregexp@4.0.0:
 xregexp@4.0.0:
   version "4.0.0"
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
   resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"