├── README.md ├── app.js ├── bin └── www ├── files └── VID_20181215_075710.mp4 ├── package-lock.json ├── package.json ├── public ├── javascripts │ ├── WSAvcPlayer.js │ ├── WSAvcPlayer.min.js │ ├── http-live-player.js │ └── wfs.js └── stylesheets │ └── style.css ├── routes ├── index.js ├── users.js └── websocket.js ├── service ├── lib │ └── wSAvcServerLib.js ├── mpeg-converter.js ├── socketClient.js ├── socketServer.js ├── wsAvcPlayer.js └── wsclient.js └── views ├── error.pug ├── index.pug ├── layout.pug ├── video.pug └── video_wfs.pug /README.md: -------------------------------------------------------------------------------- 1 | # scrcpyConnectNode 2 | scrcpy将Android图像通过视频流的方式给web展现,用于云控云测操作 3 | 目前实现了利用socket通信,将node服务与scrcpy对接,然后再通过websocket通信传送到web页面,实时渲染手机屏幕 4 | 5 | 6 | 一、在设备上开启socket 7 | 8 | 以下是相关命令来开启设备的相关通信端口 9 | >adb push /Users/heyongchao/StudioProjects/scrcpy/x/server/scrcpy-server.jar /data/local/tmp/ 10 | 11 | >adb shell CLASSPATH=/data/local/tmp/scrcpy-server.jar app_process / com.genymobile.scrcpy.Server 0 8000000 true 1080:1920:0:0 true true 12 | 13 | >//adb forward tcp:3002 localabstract:scrcpy 14 | 15 | >adb reverse tcp:3001 localabstract:scrcpy 16 | 17 | 二、本地启动node服务来接收数据 18 | node ./bin/www 19 | 20 | 三、访问以下网址看效果,测试 21 | http://localhost:3000 22 | http://localhost:3000/video1 23 | http://localhost:3000/video 24 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var createError = require('http-errors'); 2 | var express = require('express'); 3 | var expressWs = require('express-ws'); 4 | 5 | var path = require('path'); 6 | var cookieParser = require('cookie-parser'); 7 | var logger = require('morgan'); 8 | 9 | 10 | 11 | var indexRouter = require('./routes/index'); 12 | var usersRouter = require('./routes/users'); 13 | var websocket = require('./routes/websocket'); 14 | var wsClient = require('./service/wsclient'); 15 | var wSAvcPlayer = require('./service/wsAvcPlayer'); 16 | var socketClient = require('./service/socketClient'); 17 | var socketServer = require('./service/socketServer'); 18 | 19 | var app = express(); 20 | expressWs(app); 21 | 22 | 23 | // view engine setup 24 | app.set('views', path.join(__dirname, 'views')); 25 | app.set('view engine', 'pug'); 26 | 27 | app.use(logger('dev')); 28 | app.use(express.json()); 29 | app.use(express.urlencoded({ extended: false })); 30 | app.use(cookieParser()); 31 | app.use(express.static(path.join(__dirname, 'public')));//express.static是express提供的内置的中间件用来设置静态文件路径 32 | 33 | //app.use(express.static('static'));//express.static是express提供的内置的中间件用来设置静态文件路径 34 | 35 | 36 | app.use('/', indexRouter); 37 | app.use('/users', usersRouter); 38 | app.use('/', websocket); 39 | 40 | 41 | // catch 404 and forward to error handler 42 | app.use(function(req, res, next) { 43 | next(createError(404)); 44 | }); 45 | 46 | // error handler 47 | app.use(function(err, req, res, next) { 48 | // set locals, only providing error in development 49 | res.locals.message = err.message; 50 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 51 | 52 | // render the error page 53 | res.status(err.status || 500); 54 | res.render('error'); 55 | }); 56 | //wsClient.init(); //这个是服务器作为client连别人 57 | wSAvcPlayer.init(); 58 | //socketClient.init(); 59 | //socketServer.init(); 60 | app.listen(3002); //websocket端口监听用这个 61 | module.exports = app; 62 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('nodestream:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /files/VID_20181215_075710.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CoderToPM/scrcpyConnectNode/159a579d01cfc021c5db1879a4aebbaa0b3ec9ef/files/VID_20181215_075710.mp4 -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodestream", 3 | "version": "0.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/babel-types": { 8 | "version": "7.0.7", 9 | "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.7.tgz", 10 | "integrity": "sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==" 11 | }, 12 | "@types/babylon": { 13 | "version": "6.16.5", 14 | "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.5.tgz", 15 | "integrity": "sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==", 16 | "requires": { 17 | "@types/babel-types": "*" 18 | } 19 | }, 20 | "accepts": { 21 | "version": "1.3.7", 22 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 23 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 24 | "requires": { 25 | "mime-types": "~2.1.24", 26 | "negotiator": "0.6.2" 27 | } 28 | }, 29 | "acorn": { 30 | "version": "3.3.0", 31 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", 32 | "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" 33 | }, 34 | "acorn-globals": { 35 | "version": "3.1.0", 36 | "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", 37 | "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", 38 | "requires": { 39 | "acorn": "^4.0.4" 40 | }, 41 | "dependencies": { 42 | "acorn": { 43 | "version": "4.0.13", 44 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", 45 | "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" 46 | } 47 | } 48 | }, 49 | "after": { 50 | "version": "0.8.2", 51 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", 52 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" 53 | }, 54 | "align-text": { 55 | "version": "0.1.4", 56 | "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", 57 | "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", 58 | "requires": { 59 | "kind-of": "^3.0.2", 60 | "longest": "^1.0.1", 61 | "repeat-string": "^1.5.2" 62 | } 63 | }, 64 | "array-flatten": { 65 | "version": "1.1.1", 66 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 67 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 68 | }, 69 | "arraybuffer.slice": { 70 | "version": "0.0.7", 71 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", 72 | "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" 73 | }, 74 | "asap": { 75 | "version": "2.0.6", 76 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", 77 | "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" 78 | }, 79 | "async-limiter": { 80 | "version": "1.0.0", 81 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", 82 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" 83 | }, 84 | "babel-runtime": { 85 | "version": "6.26.0", 86 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 87 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 88 | "requires": { 89 | "core-js": "^2.4.0", 90 | "regenerator-runtime": "^0.11.0" 91 | } 92 | }, 93 | "babel-types": { 94 | "version": "6.26.0", 95 | "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", 96 | "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", 97 | "requires": { 98 | "babel-runtime": "^6.26.0", 99 | "esutils": "^2.0.2", 100 | "lodash": "^4.17.4", 101 | "to-fast-properties": "^1.0.3" 102 | } 103 | }, 104 | "babylon": { 105 | "version": "6.18.0", 106 | "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", 107 | "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" 108 | }, 109 | "backo2": { 110 | "version": "1.0.2", 111 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 112 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 113 | }, 114 | "base64-arraybuffer": { 115 | "version": "0.1.5", 116 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", 117 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" 118 | }, 119 | "base64id": { 120 | "version": "1.0.0", 121 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", 122 | "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" 123 | }, 124 | "basic-auth": { 125 | "version": "2.0.1", 126 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", 127 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", 128 | "requires": { 129 | "safe-buffer": "5.1.2" 130 | } 131 | }, 132 | "better-assert": { 133 | "version": "1.0.2", 134 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", 135 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", 136 | "requires": { 137 | "callsite": "1.0.0" 138 | } 139 | }, 140 | "blob": { 141 | "version": "0.0.5", 142 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", 143 | "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" 144 | }, 145 | "body-parser": { 146 | "version": "1.18.3", 147 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 148 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 149 | "requires": { 150 | "bytes": "3.0.0", 151 | "content-type": "~1.0.4", 152 | "debug": "2.6.9", 153 | "depd": "~1.1.2", 154 | "http-errors": "~1.6.3", 155 | "iconv-lite": "0.4.23", 156 | "on-finished": "~2.3.0", 157 | "qs": "6.5.2", 158 | "raw-body": "2.3.3", 159 | "type-is": "~1.6.16" 160 | } 161 | }, 162 | "bytes": { 163 | "version": "3.0.0", 164 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 165 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 166 | }, 167 | "callsite": { 168 | "version": "1.0.0", 169 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", 170 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" 171 | }, 172 | "camelcase": { 173 | "version": "1.2.1", 174 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", 175 | "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" 176 | }, 177 | "center-align": { 178 | "version": "0.1.3", 179 | "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", 180 | "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", 181 | "requires": { 182 | "align-text": "^0.1.3", 183 | "lazy-cache": "^1.0.3" 184 | } 185 | }, 186 | "character-parser": { 187 | "version": "2.2.0", 188 | "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", 189 | "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", 190 | "requires": { 191 | "is-regex": "^1.0.3" 192 | } 193 | }, 194 | "clean-css": { 195 | "version": "4.2.1", 196 | "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", 197 | "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", 198 | "requires": { 199 | "source-map": "~0.6.0" 200 | } 201 | }, 202 | "cliui": { 203 | "version": "2.1.0", 204 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", 205 | "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", 206 | "requires": { 207 | "center-align": "^0.1.1", 208 | "right-align": "^0.1.1", 209 | "wordwrap": "0.0.2" 210 | } 211 | }, 212 | "component-bind": { 213 | "version": "1.0.0", 214 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", 215 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" 216 | }, 217 | "component-emitter": { 218 | "version": "1.2.1", 219 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 220 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 221 | }, 222 | "component-inherit": { 223 | "version": "0.0.3", 224 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", 225 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" 226 | }, 227 | "constantinople": { 228 | "version": "3.1.2", 229 | "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", 230 | "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==", 231 | "requires": { 232 | "@types/babel-types": "^7.0.0", 233 | "@types/babylon": "^6.16.2", 234 | "babel-types": "^6.26.0", 235 | "babylon": "^6.18.0" 236 | } 237 | }, 238 | "content-disposition": { 239 | "version": "0.5.2", 240 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 241 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 242 | }, 243 | "content-type": { 244 | "version": "1.0.4", 245 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 246 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 247 | }, 248 | "cookie": { 249 | "version": "0.3.1", 250 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 251 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 252 | }, 253 | "cookie-parser": { 254 | "version": "1.4.4", 255 | "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz", 256 | "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==", 257 | "requires": { 258 | "cookie": "0.3.1", 259 | "cookie-signature": "1.0.6" 260 | } 261 | }, 262 | "cookie-signature": { 263 | "version": "1.0.6", 264 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 265 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 266 | }, 267 | "core-js": { 268 | "version": "2.6.9", 269 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", 270 | "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" 271 | }, 272 | "debug": { 273 | "version": "2.6.9", 274 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 275 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 276 | "requires": { 277 | "ms": "2.0.0" 278 | } 279 | }, 280 | "decamelize": { 281 | "version": "1.2.0", 282 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 283 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" 284 | }, 285 | "depd": { 286 | "version": "1.1.2", 287 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 288 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 289 | }, 290 | "destroy": { 291 | "version": "1.0.4", 292 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 293 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 294 | }, 295 | "doctypes": { 296 | "version": "1.1.0", 297 | "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", 298 | "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" 299 | }, 300 | "ee-first": { 301 | "version": "1.1.1", 302 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 303 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 304 | }, 305 | "encodeurl": { 306 | "version": "1.0.2", 307 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 308 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 309 | }, 310 | "engine.io": { 311 | "version": "3.3.2", 312 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.3.2.tgz", 313 | "integrity": "sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w==", 314 | "requires": { 315 | "accepts": "~1.3.4", 316 | "base64id": "1.0.0", 317 | "cookie": "0.3.1", 318 | "debug": "~3.1.0", 319 | "engine.io-parser": "~2.1.0", 320 | "ws": "~6.1.0" 321 | }, 322 | "dependencies": { 323 | "debug": { 324 | "version": "3.1.0", 325 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 326 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 327 | "requires": { 328 | "ms": "2.0.0" 329 | } 330 | } 331 | } 332 | }, 333 | "engine.io-client": { 334 | "version": "3.3.2", 335 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz", 336 | "integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==", 337 | "requires": { 338 | "component-emitter": "1.2.1", 339 | "component-inherit": "0.0.3", 340 | "debug": "~3.1.0", 341 | "engine.io-parser": "~2.1.1", 342 | "has-cors": "1.1.0", 343 | "indexof": "0.0.1", 344 | "parseqs": "0.0.5", 345 | "parseuri": "0.0.5", 346 | "ws": "~6.1.0", 347 | "xmlhttprequest-ssl": "~1.5.4", 348 | "yeast": "0.1.2" 349 | }, 350 | "dependencies": { 351 | "debug": { 352 | "version": "3.1.0", 353 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 354 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 355 | "requires": { 356 | "ms": "2.0.0" 357 | } 358 | } 359 | } 360 | }, 361 | "engine.io-parser": { 362 | "version": "2.1.3", 363 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", 364 | "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", 365 | "requires": { 366 | "after": "0.8.2", 367 | "arraybuffer.slice": "~0.0.7", 368 | "base64-arraybuffer": "0.1.5", 369 | "blob": "0.0.5", 370 | "has-binary2": "~1.0.2" 371 | } 372 | }, 373 | "escape-html": { 374 | "version": "1.0.3", 375 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 376 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 377 | }, 378 | "esutils": { 379 | "version": "2.0.2", 380 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 381 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" 382 | }, 383 | "etag": { 384 | "version": "1.8.1", 385 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 386 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 387 | }, 388 | "express": { 389 | "version": "4.16.4", 390 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", 391 | "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", 392 | "requires": { 393 | "accepts": "~1.3.5", 394 | "array-flatten": "1.1.1", 395 | "body-parser": "1.18.3", 396 | "content-disposition": "0.5.2", 397 | "content-type": "~1.0.4", 398 | "cookie": "0.3.1", 399 | "cookie-signature": "1.0.6", 400 | "debug": "2.6.9", 401 | "depd": "~1.1.2", 402 | "encodeurl": "~1.0.2", 403 | "escape-html": "~1.0.3", 404 | "etag": "~1.8.1", 405 | "finalhandler": "1.1.1", 406 | "fresh": "0.5.2", 407 | "merge-descriptors": "1.0.1", 408 | "methods": "~1.1.2", 409 | "on-finished": "~2.3.0", 410 | "parseurl": "~1.3.2", 411 | "path-to-regexp": "0.1.7", 412 | "proxy-addr": "~2.0.4", 413 | "qs": "6.5.2", 414 | "range-parser": "~1.2.0", 415 | "safe-buffer": "5.1.2", 416 | "send": "0.16.2", 417 | "serve-static": "1.13.2", 418 | "setprototypeof": "1.1.0", 419 | "statuses": "~1.4.0", 420 | "type-is": "~1.6.16", 421 | "utils-merge": "1.0.1", 422 | "vary": "~1.1.2" 423 | } 424 | }, 425 | "express-ws": { 426 | "version": "4.0.0", 427 | "resolved": "https://registry.npmjs.org/express-ws/-/express-ws-4.0.0.tgz", 428 | "integrity": "sha512-KEyUw8AwRET2iFjFsI1EJQrJ/fHeGiJtgpYgEWG3yDv4l/To/m3a2GaYfeGyB3lsWdvbesjF5XCMx+SVBgAAYw==", 429 | "requires": { 430 | "ws": "^5.2.0" 431 | }, 432 | "dependencies": { 433 | "ws": { 434 | "version": "5.2.2", 435 | "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", 436 | "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", 437 | "requires": { 438 | "async-limiter": "~1.0.0" 439 | } 440 | } 441 | } 442 | }, 443 | "finalhandler": { 444 | "version": "1.1.1", 445 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 446 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 447 | "requires": { 448 | "debug": "2.6.9", 449 | "encodeurl": "~1.0.2", 450 | "escape-html": "~1.0.3", 451 | "on-finished": "~2.3.0", 452 | "parseurl": "~1.3.2", 453 | "statuses": "~1.4.0", 454 | "unpipe": "~1.0.0" 455 | } 456 | }, 457 | "forwarded": { 458 | "version": "0.1.2", 459 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 460 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 461 | }, 462 | "fresh": { 463 | "version": "0.5.2", 464 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 465 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 466 | }, 467 | "function-bind": { 468 | "version": "1.1.1", 469 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 470 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 471 | }, 472 | "has": { 473 | "version": "1.0.3", 474 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 475 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 476 | "requires": { 477 | "function-bind": "^1.1.1" 478 | } 479 | }, 480 | "has-binary2": { 481 | "version": "1.0.3", 482 | "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", 483 | "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", 484 | "requires": { 485 | "isarray": "2.0.1" 486 | } 487 | }, 488 | "has-cors": { 489 | "version": "1.1.0", 490 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", 491 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" 492 | }, 493 | "http-errors": { 494 | "version": "1.6.3", 495 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 496 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 497 | "requires": { 498 | "depd": "~1.1.2", 499 | "inherits": "2.0.3", 500 | "setprototypeof": "1.1.0", 501 | "statuses": ">= 1.4.0 < 2" 502 | } 503 | }, 504 | "iconv-lite": { 505 | "version": "0.4.23", 506 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 507 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 508 | "requires": { 509 | "safer-buffer": ">= 2.1.2 < 3" 510 | } 511 | }, 512 | "indexof": { 513 | "version": "0.0.1", 514 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 515 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" 516 | }, 517 | "inherits": { 518 | "version": "2.0.3", 519 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 520 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 521 | }, 522 | "ipaddr.js": { 523 | "version": "1.9.0", 524 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", 525 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" 526 | }, 527 | "is-buffer": { 528 | "version": "1.1.6", 529 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 530 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 531 | }, 532 | "is-expression": { 533 | "version": "3.0.0", 534 | "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", 535 | "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=", 536 | "requires": { 537 | "acorn": "~4.0.2", 538 | "object-assign": "^4.0.1" 539 | }, 540 | "dependencies": { 541 | "acorn": { 542 | "version": "4.0.13", 543 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", 544 | "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" 545 | } 546 | } 547 | }, 548 | "is-promise": { 549 | "version": "2.1.0", 550 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 551 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" 552 | }, 553 | "is-regex": { 554 | "version": "1.0.4", 555 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", 556 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", 557 | "requires": { 558 | "has": "^1.0.1" 559 | } 560 | }, 561 | "isarray": { 562 | "version": "2.0.1", 563 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", 564 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" 565 | }, 566 | "js-stringify": { 567 | "version": "1.0.2", 568 | "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", 569 | "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" 570 | }, 571 | "jstransformer": { 572 | "version": "1.0.0", 573 | "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", 574 | "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", 575 | "requires": { 576 | "is-promise": "^2.0.0", 577 | "promise": "^7.0.1" 578 | } 579 | }, 580 | "kind-of": { 581 | "version": "3.2.2", 582 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 583 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 584 | "requires": { 585 | "is-buffer": "^1.1.5" 586 | } 587 | }, 588 | "lazy-cache": { 589 | "version": "1.0.4", 590 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", 591 | "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" 592 | }, 593 | "lodash": { 594 | "version": "4.17.14", 595 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", 596 | "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" 597 | }, 598 | "longest": { 599 | "version": "1.0.1", 600 | "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", 601 | "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" 602 | }, 603 | "media-typer": { 604 | "version": "0.3.0", 605 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 606 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 607 | }, 608 | "merge-descriptors": { 609 | "version": "1.0.1", 610 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 611 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 612 | }, 613 | "methods": { 614 | "version": "1.1.2", 615 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 616 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 617 | }, 618 | "mime": { 619 | "version": "1.4.1", 620 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 621 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 622 | }, 623 | "mime-db": { 624 | "version": "1.40.0", 625 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 626 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 627 | }, 628 | "mime-types": { 629 | "version": "2.1.24", 630 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 631 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 632 | "requires": { 633 | "mime-db": "1.40.0" 634 | } 635 | }, 636 | "morgan": { 637 | "version": "1.9.1", 638 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", 639 | "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", 640 | "requires": { 641 | "basic-auth": "~2.0.0", 642 | "debug": "2.6.9", 643 | "depd": "~1.1.2", 644 | "on-finished": "~2.3.0", 645 | "on-headers": "~1.0.1" 646 | } 647 | }, 648 | "ms": { 649 | "version": "2.0.0", 650 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 651 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 652 | }, 653 | "negotiator": { 654 | "version": "0.6.2", 655 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 656 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 657 | }, 658 | "object-assign": { 659 | "version": "4.1.1", 660 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 661 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 662 | }, 663 | "object-component": { 664 | "version": "0.0.3", 665 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", 666 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" 667 | }, 668 | "on-finished": { 669 | "version": "2.3.0", 670 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 671 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 672 | "requires": { 673 | "ee-first": "1.1.1" 674 | } 675 | }, 676 | "on-headers": { 677 | "version": "1.0.2", 678 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", 679 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" 680 | }, 681 | "parseqs": { 682 | "version": "0.0.5", 683 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", 684 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", 685 | "requires": { 686 | "better-assert": "~1.0.0" 687 | } 688 | }, 689 | "parseuri": { 690 | "version": "0.0.5", 691 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", 692 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", 693 | "requires": { 694 | "better-assert": "~1.0.0" 695 | } 696 | }, 697 | "parseurl": { 698 | "version": "1.3.3", 699 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 700 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 701 | }, 702 | "path-parse": { 703 | "version": "1.0.6", 704 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 705 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" 706 | }, 707 | "path-to-regexp": { 708 | "version": "0.1.7", 709 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 710 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 711 | }, 712 | "promise": { 713 | "version": "7.3.1", 714 | "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", 715 | "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", 716 | "requires": { 717 | "asap": "~2.0.3" 718 | } 719 | }, 720 | "proxy-addr": { 721 | "version": "2.0.5", 722 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", 723 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", 724 | "requires": { 725 | "forwarded": "~0.1.2", 726 | "ipaddr.js": "1.9.0" 727 | } 728 | }, 729 | "pug": { 730 | "version": "2.0.4", 731 | "resolved": "https://registry.npmjs.org/pug/-/pug-2.0.4.tgz", 732 | "integrity": "sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==", 733 | "requires": { 734 | "pug-code-gen": "^2.0.2", 735 | "pug-filters": "^3.1.1", 736 | "pug-lexer": "^4.1.0", 737 | "pug-linker": "^3.0.6", 738 | "pug-load": "^2.0.12", 739 | "pug-parser": "^5.0.1", 740 | "pug-runtime": "^2.0.5", 741 | "pug-strip-comments": "^1.0.4" 742 | } 743 | }, 744 | "pug-attrs": { 745 | "version": "2.0.4", 746 | "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-2.0.4.tgz", 747 | "integrity": "sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==", 748 | "requires": { 749 | "constantinople": "^3.0.1", 750 | "js-stringify": "^1.0.1", 751 | "pug-runtime": "^2.0.5" 752 | } 753 | }, 754 | "pug-code-gen": { 755 | "version": "2.0.2", 756 | "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-2.0.2.tgz", 757 | "integrity": "sha512-kROFWv/AHx/9CRgoGJeRSm+4mLWchbgpRzTEn8XCiwwOy6Vh0gAClS8Vh5TEJ9DBjaP8wCjS3J6HKsEsYdvaCw==", 758 | "requires": { 759 | "constantinople": "^3.1.2", 760 | "doctypes": "^1.1.0", 761 | "js-stringify": "^1.0.1", 762 | "pug-attrs": "^2.0.4", 763 | "pug-error": "^1.3.3", 764 | "pug-runtime": "^2.0.5", 765 | "void-elements": "^2.0.1", 766 | "with": "^5.0.0" 767 | } 768 | }, 769 | "pug-error": { 770 | "version": "1.3.3", 771 | "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-1.3.3.tgz", 772 | "integrity": "sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==" 773 | }, 774 | "pug-filters": { 775 | "version": "3.1.1", 776 | "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.1.1.tgz", 777 | "integrity": "sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==", 778 | "requires": { 779 | "clean-css": "^4.1.11", 780 | "constantinople": "^3.0.1", 781 | "jstransformer": "1.0.0", 782 | "pug-error": "^1.3.3", 783 | "pug-walk": "^1.1.8", 784 | "resolve": "^1.1.6", 785 | "uglify-js": "^2.6.1" 786 | } 787 | }, 788 | "pug-lexer": { 789 | "version": "4.1.0", 790 | "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.1.0.tgz", 791 | "integrity": "sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==", 792 | "requires": { 793 | "character-parser": "^2.1.1", 794 | "is-expression": "^3.0.0", 795 | "pug-error": "^1.3.3" 796 | } 797 | }, 798 | "pug-linker": { 799 | "version": "3.0.6", 800 | "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-3.0.6.tgz", 801 | "integrity": "sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==", 802 | "requires": { 803 | "pug-error": "^1.3.3", 804 | "pug-walk": "^1.1.8" 805 | } 806 | }, 807 | "pug-load": { 808 | "version": "2.0.12", 809 | "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-2.0.12.tgz", 810 | "integrity": "sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==", 811 | "requires": { 812 | "object-assign": "^4.1.0", 813 | "pug-walk": "^1.1.8" 814 | } 815 | }, 816 | "pug-parser": { 817 | "version": "5.0.1", 818 | "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.1.tgz", 819 | "integrity": "sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==", 820 | "requires": { 821 | "pug-error": "^1.3.3", 822 | "token-stream": "0.0.1" 823 | } 824 | }, 825 | "pug-runtime": { 826 | "version": "2.0.5", 827 | "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-2.0.5.tgz", 828 | "integrity": "sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==" 829 | }, 830 | "pug-strip-comments": { 831 | "version": "1.0.4", 832 | "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz", 833 | "integrity": "sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==", 834 | "requires": { 835 | "pug-error": "^1.3.3" 836 | } 837 | }, 838 | "pug-walk": { 839 | "version": "1.1.8", 840 | "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz", 841 | "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==" 842 | }, 843 | "qs": { 844 | "version": "6.5.2", 845 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 846 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 847 | }, 848 | "range-parser": { 849 | "version": "1.2.0", 850 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 851 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 852 | }, 853 | "raw-body": { 854 | "version": "2.3.3", 855 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 856 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 857 | "requires": { 858 | "bytes": "3.0.0", 859 | "http-errors": "1.6.3", 860 | "iconv-lite": "0.4.23", 861 | "unpipe": "1.0.0" 862 | } 863 | }, 864 | "regenerator-runtime": { 865 | "version": "0.11.1", 866 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 867 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" 868 | }, 869 | "repeat-string": { 870 | "version": "1.6.1", 871 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 872 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" 873 | }, 874 | "resolve": { 875 | "version": "1.11.1", 876 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", 877 | "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", 878 | "requires": { 879 | "path-parse": "^1.0.6" 880 | } 881 | }, 882 | "right-align": { 883 | "version": "0.1.3", 884 | "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", 885 | "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", 886 | "requires": { 887 | "align-text": "^0.1.1" 888 | } 889 | }, 890 | "safe-buffer": { 891 | "version": "5.1.2", 892 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 893 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 894 | }, 895 | "safer-buffer": { 896 | "version": "2.1.2", 897 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 898 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 899 | }, 900 | "send": { 901 | "version": "0.16.2", 902 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 903 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 904 | "requires": { 905 | "debug": "2.6.9", 906 | "depd": "~1.1.2", 907 | "destroy": "~1.0.4", 908 | "encodeurl": "~1.0.2", 909 | "escape-html": "~1.0.3", 910 | "etag": "~1.8.1", 911 | "fresh": "0.5.2", 912 | "http-errors": "~1.6.2", 913 | "mime": "1.4.1", 914 | "ms": "2.0.0", 915 | "on-finished": "~2.3.0", 916 | "range-parser": "~1.2.0", 917 | "statuses": "~1.4.0" 918 | } 919 | }, 920 | "serve-static": { 921 | "version": "1.13.2", 922 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 923 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 924 | "requires": { 925 | "encodeurl": "~1.0.2", 926 | "escape-html": "~1.0.3", 927 | "parseurl": "~1.3.2", 928 | "send": "0.16.2" 929 | } 930 | }, 931 | "setprototypeof": { 932 | "version": "1.1.0", 933 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 934 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 935 | }, 936 | "socket.io": { 937 | "version": "2.2.0", 938 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.2.0.tgz", 939 | "integrity": "sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==", 940 | "requires": { 941 | "debug": "~4.1.0", 942 | "engine.io": "~3.3.1", 943 | "has-binary2": "~1.0.2", 944 | "socket.io-adapter": "~1.1.0", 945 | "socket.io-client": "2.2.0", 946 | "socket.io-parser": "~3.3.0" 947 | }, 948 | "dependencies": { 949 | "debug": { 950 | "version": "4.1.1", 951 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 952 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 953 | "requires": { 954 | "ms": "^2.1.1" 955 | } 956 | }, 957 | "ms": { 958 | "version": "2.1.2", 959 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 960 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 961 | } 962 | } 963 | }, 964 | "socket.io-adapter": { 965 | "version": "1.1.1", 966 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", 967 | "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" 968 | }, 969 | "socket.io-client": { 970 | "version": "2.2.0", 971 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz", 972 | "integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==", 973 | "requires": { 974 | "backo2": "1.0.2", 975 | "base64-arraybuffer": "0.1.5", 976 | "component-bind": "1.0.0", 977 | "component-emitter": "1.2.1", 978 | "debug": "~3.1.0", 979 | "engine.io-client": "~3.3.1", 980 | "has-binary2": "~1.0.2", 981 | "has-cors": "1.1.0", 982 | "indexof": "0.0.1", 983 | "object-component": "0.0.3", 984 | "parseqs": "0.0.5", 985 | "parseuri": "0.0.5", 986 | "socket.io-parser": "~3.3.0", 987 | "to-array": "0.1.4" 988 | }, 989 | "dependencies": { 990 | "debug": { 991 | "version": "3.1.0", 992 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 993 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 994 | "requires": { 995 | "ms": "2.0.0" 996 | } 997 | } 998 | } 999 | }, 1000 | "socket.io-parser": { 1001 | "version": "3.3.0", 1002 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", 1003 | "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", 1004 | "requires": { 1005 | "component-emitter": "1.2.1", 1006 | "debug": "~3.1.0", 1007 | "isarray": "2.0.1" 1008 | }, 1009 | "dependencies": { 1010 | "debug": { 1011 | "version": "3.1.0", 1012 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 1013 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 1014 | "requires": { 1015 | "ms": "2.0.0" 1016 | } 1017 | } 1018 | } 1019 | }, 1020 | "source-map": { 1021 | "version": "0.6.1", 1022 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1023 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 1024 | }, 1025 | "statuses": { 1026 | "version": "1.4.0", 1027 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 1028 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 1029 | }, 1030 | "stream-split": { 1031 | "version": "1.1.0", 1032 | "resolved": "https://registry.npmjs.org/stream-split/-/stream-split-1.1.0.tgz", 1033 | "integrity": "sha1-2bXF4PoJkaTalflukfXxUYBNPTw=" 1034 | }, 1035 | "to-array": { 1036 | "version": "0.1.4", 1037 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", 1038 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" 1039 | }, 1040 | "to-fast-properties": { 1041 | "version": "1.0.3", 1042 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", 1043 | "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" 1044 | }, 1045 | "token-stream": { 1046 | "version": "0.0.1", 1047 | "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz", 1048 | "integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=" 1049 | }, 1050 | "type-is": { 1051 | "version": "1.6.18", 1052 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1053 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1054 | "requires": { 1055 | "media-typer": "0.3.0", 1056 | "mime-types": "~2.1.24" 1057 | } 1058 | }, 1059 | "uglify-js": { 1060 | "version": "2.8.29", 1061 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", 1062 | "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", 1063 | "requires": { 1064 | "source-map": "~0.5.1", 1065 | "uglify-to-browserify": "~1.0.0", 1066 | "yargs": "~3.10.0" 1067 | }, 1068 | "dependencies": { 1069 | "source-map": { 1070 | "version": "0.5.7", 1071 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 1072 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" 1073 | } 1074 | } 1075 | }, 1076 | "uglify-to-browserify": { 1077 | "version": "1.0.2", 1078 | "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", 1079 | "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", 1080 | "optional": true 1081 | }, 1082 | "unpipe": { 1083 | "version": "1.0.0", 1084 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1085 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1086 | }, 1087 | "utils-merge": { 1088 | "version": "1.0.1", 1089 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1090 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 1091 | }, 1092 | "uws": { 1093 | "version": "9.14.0", 1094 | "resolved": "https://registry.npmjs.org/uws/-/uws-9.14.0.tgz", 1095 | "integrity": "sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg==" 1096 | }, 1097 | "vary": { 1098 | "version": "1.1.2", 1099 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1100 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1101 | }, 1102 | "void-elements": { 1103 | "version": "2.0.1", 1104 | "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", 1105 | "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" 1106 | }, 1107 | "window-size": { 1108 | "version": "0.1.0", 1109 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", 1110 | "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" 1111 | }, 1112 | "with": { 1113 | "version": "5.1.1", 1114 | "resolved": "https://registry.npmjs.org/with/-/with-5.1.1.tgz", 1115 | "integrity": "sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=", 1116 | "requires": { 1117 | "acorn": "^3.1.0", 1118 | "acorn-globals": "^3.0.0" 1119 | } 1120 | }, 1121 | "wordwrap": { 1122 | "version": "0.0.2", 1123 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", 1124 | "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" 1125 | }, 1126 | "ws": { 1127 | "version": "6.1.4", 1128 | "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", 1129 | "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", 1130 | "requires": { 1131 | "async-limiter": "~1.0.0" 1132 | } 1133 | }, 1134 | "xmlhttprequest-ssl": { 1135 | "version": "1.5.5", 1136 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", 1137 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" 1138 | }, 1139 | "yargs": { 1140 | "version": "3.10.0", 1141 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", 1142 | "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", 1143 | "requires": { 1144 | "camelcase": "^1.0.2", 1145 | "cliui": "^2.1.0", 1146 | "decamelize": "^1.0.0", 1147 | "window-size": "0.1.0" 1148 | } 1149 | }, 1150 | "yeast": { 1151 | "version": "0.1.2", 1152 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", 1153 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" 1154 | } 1155 | } 1156 | } 1157 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodestream", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "cookie-parser": "~1.4.4", 10 | "debug": "~2.6.9", 11 | "express": "~4.16.1", 12 | "express-ws": "^4.0.0", 13 | "http-errors": "~1.6.3", 14 | "morgan": "~1.9.1", 15 | "pug": "^2.0.4", 16 | "socket.io": "^2.2.0", 17 | "socket.io-client": "^2.2.0", 18 | "stream-split": "^1.1.0", 19 | "uws": "^9.14.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | const fs = require('fs'); 4 | 5 | 6 | /* GET home page. */ 7 | router.get('/', function(req, res, next) { 8 | res.render('video', { title: 'Video' }); 9 | //res.render('video_wfs', { title: 'Video' }); 10 | }); 11 | 12 | 13 | router.get('/video1', function(req, res, next) { 14 | 15 | let head = { 'Content-Type': 'video/mp4' }; 16 | //需要设置HTTP HEAD 17 | res.writeHead(200, head); 18 | //使用pipe 19 | fs.createReadStream('./files/VID_20181215_075710.mp4') 20 | .pipe(res); 21 | 22 | }); 23 | router.get('/video', function(req, res, next) { 24 | let path = './files/VID_20181215_075710.mp4'; 25 | let stat = fs.statSync(path); 26 | let fileSize = stat.size; 27 | let range = req.headers.range; 28 | 29 | // fileSize 3332038 30 | 31 | if (range) { 32 | //有range头才使用206状态码 33 | 34 | let parts = range.replace(/bytes=/, "").split("-"); 35 | let start = parseInt(parts[0], 10); 36 | let end = parts[1] ? parseInt(parts[1], 10) : start + 999999; 37 | 38 | // end 在最后取值为 fileSize - 1 39 | end = end > fileSize - 1 ? fileSize - 1 : end; 40 | 41 | let chunksize = (end - start) + 1; 42 | let file = fs.createReadStream(path, { start, end }); 43 | let head = { 44 | 'Content-Range': `bytes ${start}-${end}/${fileSize}`, 45 | 'Accept-Ranges': 'bytes', 46 | 'Content-Length': chunksize, 47 | 'Content-Type': 'video/mp4', 48 | }; 49 | res.writeHead(206, head); 50 | file.pipe(res); 51 | } else { 52 | let head = { 53 | 'Content-Length': fileSize, 54 | 'Content-Type': 'video/mp4', 55 | }; 56 | res.writeHead(200, head); 57 | fs.createReadStream(path).pipe(res); 58 | } 59 | 60 | }); 61 | 62 | /*io.on('connection', function(ws){ // socket相关监听都要放在这个回调里 63 | console.log('a user connected'); 64 | ws.on('error', (err)=>{ 65 | debug(`${err} happened for connection`); 66 | }); 67 | 68 | ws.on("disconnect", function() { 69 | console.log("a user go out"); 70 | }); 71 | 72 | ws.on("msg", function(obj) { 73 | //延迟3s返回信息给客户端 74 | setTimeout(function(){ 75 | console.log('the websokcet message is'+obj); 76 | io.emit("msg", obj); 77 | },3000); 78 | }); 79 | }); 80 | //开启端口监听socket 81 | server.listen(3001);*/ 82 | 83 | module.exports = router; 84 | -------------------------------------------------------------------------------- /routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET users listing. */ 5 | router.get('/', function(req, res, next) { 6 | res.send('respond with a resource'); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /routes/websocket.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by heyongchao on 2019/7/18 12:57 PM 3 | */ 4 | 5 | var express = require('express'); 6 | var expressWs = require('express-ws'); 7 | 8 | var router = express.Router(); 9 | expressWs(router); 10 | const WebSocket = require("ws"); 11 | 12 | const MpegMuxer = require("../service/mpeg-converter"); 13 | const querystring = require('querystring') 14 | const debug = require("debug")("rtsp-server"); 15 | const url = require("url"); 16 | var socketServer = require('../service/socketServer'); 17 | 18 | 19 | 20 | CLIENTS = {}; 21 | PROC = {}; 22 | PROC_LRU = {}; 23 | THRESHOLD = 16; 24 | 25 | router 26 | .ws('/', function (ws, req){ 27 | ws.send('你连接成功了'); 28 | var name = url.parse(req.url).pathname; 29 | var arg = url.parse(req.url).query; 30 | var params = querystring.parse(arg); 31 | var rtspAddr = params.addr; 32 | var display = params.method; 33 | if(!name || !arg || !rtspAddr){ 34 | debug(`requested url ${req.url} is error`); 35 | return; 36 | } 37 | else 38 | debug(`requested url is ${req.url}`); 39 | 40 | 41 | if (! (rtspAddr in CLIENTS)){ 42 | debug("client for new channel"); 43 | CLIENTS[rtspAddr] = [ws]; 44 | //create a child_process to convert video type 45 | var muxer = new MpegMuxer({id: name , url: rtspAddr, display: display}); 46 | PROC[rtspAddr] = muxer; 47 | muxer.on(name + "-data", (data) =>{ 48 | CLIENTS[rtspAddr] = CLIENTS[rtspAddr].filter((ele) => ele.readyState === WebSocket.OPEN); 49 | CLIENTS[rtspAddr].forEach((client) =>{ 50 | client.send(data); 51 | }); 52 | }); 53 | muxer.on(name + "-error", (err) => { 54 | debug(`the error happend for ${name} : ${err}`) 55 | }); 56 | muxer.on(name + "-output", (output) => { 57 | debug(`the output for ${name} : ${output}`); 58 | }) 59 | 60 | } 61 | else { 62 | debug("client for existing channel"); 63 | CLIENTS[rtspAddr].push(ws); 64 | } 65 | 66 | ws.on('message', function (msg) { 67 | // 业务代码 68 | console.log("msg:",msg); 69 | }); 70 | ws.on('close',()=> { 71 | CLIENTS[rtspAddr] = CLIENTS[rtspAddr].filter((ele) => ele.readyState === WebSocket.OPEN) 72 | //close no connected process 73 | Object.keys(CLIENTS).forEach((rtsp) =>{ 74 | if(Object.keys(CLIENTS).length > THRESHOLD && CLIENTS[rtsp].length === 0 ){ 75 | debug("there are no socket listening " + rtsp); 76 | PROC[rtsp].stream.stdout.end(); 77 | PROC[rtsp].stream.kill(); 78 | PROC[rtsp].destroy(); 79 | delete PROC[rtsp]; 80 | delete CLIENTS[rtsp]; 81 | } 82 | 83 | }); 84 | }) 85 | }) 86 | .ws('/getVideo', function(ws, req) { 87 | socketServer.init(ws); 88 | }) 89 | .post('/post', function(req, res) { 90 | }); 91 | 92 | module.exports = router; 93 | -------------------------------------------------------------------------------- /service/lib/wSAvcServerLib.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by heyongchao on 2019/7/18 4:18 PM 3 | */ 4 | // stream splitter, broadcasting, and player signaling 5 | const Splitter = require('stream-split') 6 | const EventEmitter = require('events').EventEmitter 7 | const NALseparator = new Buffer([ 0, 0, 0, 1 ])// NAL break 8 | 9 | 10 | function sendFrame (socket, frame) { 11 | 12 | /* handle streams that don't retransmit sps/pps like fmpeg omx -.- */ 13 | /* const frameType = data[0] & 0x1f 14 | if (frameType == 7) { 15 | this.lastSPS = data 16 | } 17 | else if (frameType == 8) { 18 | this.lastPPS = data 19 | } */ 20 | 21 | if (socket.buzy) 22 | return 23 | 24 | socket.buzy = true 25 | socket.buzy = false 26 | 27 | socket.send(Buffer.concat([ NALseparator, frame ]), { binary: true }, function ack () { 28 | socket.buzy = false 29 | }) 30 | } 31 | 32 | module.exports = class WSAvcServer extends EventEmitter { 33 | // TODO: changable width and height 34 | constructor (wss, width, height, options = {}) { 35 | super() 36 | // init ws 37 | /* if (!wss) { 38 | throw new Error('WS is required') 39 | } */ 40 | // etc 41 | this.options = options; 42 | this.options.width = width || 960; 43 | this.options.height = height || 540; 44 | 45 | this.clients = new Set() 46 | 47 | this.broadcast = this.broadcast.bind(this) 48 | this.new_client = this.new_client.bind(this) 49 | this.client_events = new EventEmitter() 50 | if (wss) { 51 | wss.on('connection', this.new_client) 52 | } 53 | 54 | 55 | } 56 | 57 | setVideoStream (readStream) { 58 | this.readStream = readStream 59 | readStream = readStream.pipe(new Splitter(NALseparator)) 60 | readStream.on('data', this.broadcast(sendFrame)) 61 | 62 | this.broadcast('stream_active', true ) 63 | 64 | readStream.on('end', () => this.broadcast('stream_active', false )) 65 | 66 | 67 | } 68 | 69 | broadcast (action, payload) { 70 | // callback mode 71 | if (typeof action === 'function') { 72 | return data => this.clients.forEach(socket => action(socket, data)) 73 | } else { 74 | return this.clients.forEach(socket => socket.send(JSON.stringify({ action, payload }))) 75 | } 76 | } 77 | 78 | new_client (socket) { 79 | 80 | this.clients.add(socket) 81 | this.emit('client_connected', socket) 82 | // console.log(`currently there are ${ this.clients.size } connected clients`) 83 | socket.on('close', () => { 84 | this.clients.delete(socket) 85 | this.emit('client_disconnected', socket) 86 | // console.log(`currently there are ${ this.clients.size } connected clients`) 87 | }) 88 | socket.send(JSON.stringify({ 89 | action: 'initalize', 90 | payload: { 91 | width: this.options.width, 92 | height: this.options.height, 93 | stream_active: !!(this.readStream && this.readStream.readable), 94 | }, 95 | })) 96 | 97 | socket.send(JSON.stringify({ action: 'stream_active', payload: !!(this.readStream && this.readStream.readable) })) 98 | 99 | socket.on('message', m => { 100 | const { action, payload } = JSON.parse(m) 101 | this.client_events.emit(action, payload) 102 | }) 103 | 104 | 105 | /* handle streams that don't retransmit sps/pps like fmpeg omx -.- */ 106 | /* 107 | if (this.lastSPS) { 108 | socket.send(Buffer.concat([ NALseparator, this.lastSPS ]), { binary: true }) 109 | } 110 | if (this.lastPPS) { 111 | socket.send(Buffer.concat([ NALseparator, this.lastPPS ]), { binary: true }) 112 | } 113 | */ 114 | } 115 | 116 | } -------------------------------------------------------------------------------- /service/mpeg-converter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by heyongchao on 2019/7/18 2:15 PM 3 | */ 4 | const debug = require("debug")("mpeg-redux"); 5 | var child_process = require("child_process") 6 | var EventEmitter = require("events").EventEmitter 7 | 8 | class MpegMuxer extends EventEmitter { 9 | constructor(options) { 10 | super() 11 | this.setMaxListeners(0); 12 | this.id = options.id; 13 | this.lastTime = 0; 14 | this.currentTime = 0; 15 | this.url = options.url; 16 | if (options.display === "multiple") { 17 | this._startRtspMuxer(); 18 | this._monitorRtsp(); 19 | } 20 | else if (options.display === "single") { 21 | this._startRtpMuxer(); 22 | this._monitorRtp(); 23 | } 24 | this._listenEvent(); 25 | 26 | } 27 | 28 | _listenEvent(){ 29 | this.stream.stdout.on("data", (data) => { 30 | this.currentTime += 1; 31 | this.emit(this.id + "-data", data); 32 | }) 33 | this.stream.stdout.on("error", (err) => { 34 | this.emit(this.id + "-error", err); 35 | }) 36 | this.stream.stderr.on("data", (data) => { 37 | this.emit(this.id + "-output", data); 38 | }); 39 | } 40 | 41 | _startRtspMuxer() { 42 | this.stream = child_process.spawn("ffmpeg", ["-rtsp_transport", "tcp", '-r', '25', "-i", this.url, '-threads', '8', '-f', 'mpegts', '-c:v', 'mpeg1video', '-s', '960x540', '-b:v', '1500k', '-preset', 'ultrafast', '-preset', 'zerolatency', '-bf', '0', '-'], { 43 | detached: false 44 | }); 45 | } 46 | 47 | _startRtpMuxer() { 48 | this.currentTime = 0; 49 | this.lastTime = 0; 50 | this.stream = child_process.spawn("ffmpeg", ['-r', '25', "-i", this.url, '-threads', '8', '-vcodec', 'h264', '-b:v', '1500k', '-preset', 'ultrafast'], { 51 | //this.stream = child_process.spawn("ffmpeg", ['-r', '25', "-i", this.url, '-threads', '8', '-f', 'mpegts', '-c:v', 'mpeg1video', '-s', '960x540', '-b:v', '1500k', '-preset', 'ultrafast', '-preset', 'zerolatency', '-bf', '0', '-'], { 52 | detached: false 53 | }); 54 | } 55 | 56 | _monitorRtsp(){ 57 | this.timerRtsp = setInterval(() => { 58 | if (this.currentTime > this.lastTime) { 59 | this.lastTime = this.currentTime = 0; 60 | } 61 | else { 62 | console.log("restart rtsp hangout ffmpeg"); 63 | debug("restart rtsp hangout ffmpeg"); 64 | this.stream.stdout.end(); 65 | this.stream.kill(); 66 | this._startRtspMuxer(); 67 | this._listenEvent("multiple"); 68 | } 69 | }, 5000); 70 | } 71 | 72 | _monitorRtp() { 73 | this.timerRtp = setInterval(() => { 74 | if (this.currentTime > this.lastTime) { 75 | this.lastTime = this.currentTime = 0; 76 | } 77 | else { 78 | debug("restart rtp hangout ffmpeg"); 79 | console.log("restart rtp hangout ffmpeg"); 80 | this.stream.stdout.end(); 81 | this.stream.kill(); 82 | this._startRtpMuxer(); 83 | this._listenEvent("single"); 84 | } 85 | }, 5000); 86 | } 87 | 88 | destory(){ 89 | this.timerRtp && clearInterval(this.timerRtp); 90 | this.timerRtsp && clearInterval(this.timerRtsp); 91 | } 92 | } 93 | module.exports = MpegMuxer; -------------------------------------------------------------------------------- /service/socketClient.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by heyongchao on 2019/7/18 8:36 PM 3 | */ 4 | // 1 引入模块 5 | const net = require('net'); 6 | const readline = require('readline'); 7 | 8 | class SocketClient{ 9 | init(){ 10 | 11 | // 2 创建套接字和输入输出命令行 12 | let rl = readline.createInterface({ 13 | // 调用std接口 14 | input:process.stdin, 15 | output:process.stdout 16 | }) 17 | let client = new net.Socket(); 18 | // 3 链接 19 | client.connect(5000,'localhost'); 20 | 21 | client.setEncoding('utf8'); 22 | client.on('data',(chunk)=>{ 23 | console.log(chunk); 24 | }) 25 | client.on('error',(e)=>{ 26 | console.log(e.message); 27 | }) 28 | // 绑定输io流事件,获取输入输出字符 29 | rl.on('line',(mes)=>{ 30 | client.write(mes); 31 | }) 32 | } 33 | } 34 | module.exports = new SocketClient(); -------------------------------------------------------------------------------- /service/socketServer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by heyongchao on 2019/7/18 8:40 PM 3 | */ 4 | // 1 引入模块 5 | const net = require('net'); 6 | 7 | class SocketServer{ 8 | init(ws){ 9 | // 2 创建服务器 10 | let clientArr = []; 11 | const server = net.createServer(); 12 | // 3 绑定链接事件 13 | server.on('connection',(person)=>{ 14 | console.log(clientArr.length); 15 | // 记录链接的进程 16 | person.id = clientArr.length; 17 | clientArr.push(person); 18 | person.setEncoding('utf8'); 19 | // 客户socket进程绑定事件 20 | person.on('data',(chunk)=>{ 21 | console.log(chunk); 22 | 23 | clientArr.forEach((val)=>{ 24 | // 数据写入全部客户进程中 25 | val.write(chunk); 26 | ws.send(val); 27 | 28 | }) 29 | }) 30 | person.on('close',(p1)=>{ 31 | clientArr[p1.id] = null; 32 | } ) 33 | person.on('error',(p1)=>{ 34 | clientArr[p1.id] = null; 35 | }) 36 | }) 37 | server.listen(5000); 38 | } 39 | } 40 | module.exports = new SocketServer(); -------------------------------------------------------------------------------- /service/wsAvcPlayer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by heyongchao on 2019/7/18 4:04 PM 3 | */ 4 | /* eslint-disable no-console */ 5 | const AvcServer = require('./lib/wSAvcServerLib') 6 | const path = require('path') 7 | const http = require('http') 8 | const WebSocketServer = require('uws').Server 9 | const net = require('net') 10 | const spawn = require('child_process').spawn; 11 | 12 | const useRaspivid = process.argv.includes('raspivid') 13 | const width = 1280; 14 | const height = 720; 15 | 16 | const express = require('express') 17 | const app = express(); 18 | 19 | const server = http.createServer(app); 20 | class WSAvcPlayer { 21 | init(){ 22 | // init web socket 23 | const wss = new WebSocketServer({ /* port: 3333 */ server }) 24 | // init the avc server. 25 | const avcServer = new AvcServer(wss, width, height); 26 | 27 | // handling custom events from client 28 | avcServer.client_events.on('custom_event_from_client', e => { 29 | console.log('a client sent', e) 30 | // broadcasting custom events to all clients (if you wish to send a event to specific client, handle sockets and new connections yourself) 31 | avcServer.broadcast('custom_event_from_server', { hello: 'from server' }) 32 | }) 33 | 34 | // RPI example 35 | if (useRaspivid) { 36 | let streamer = null; 37 | 38 | const startStreamer = () => { 39 | console.log('starting raspivid'); 40 | //streamer = spawn('raspivid', [ '-pf', 'baseline', '-ih', '-t', '0', '-w', width, '-h', height, '-hf', '-fps', '15', '-g', '30', '-o', '-' ]) 41 | //streamer = spawn('ffmpeg', [ '-framerate', 30, '-video_size', '640x480', '-f', 'avfoundation', '-i', '0', "-vcodec", 'libx264', '-vprofile', 'baseline', '-b:v', '500k', '-bufsize', '600k', '-tune', 'zerolatency', '-pix_fmt', 'yuv420p', '-r', 15, '-g', 30, '-f', 'format', 'ws://localhost:3001']); 42 | streamer = spawn("ffmpeg", ["-rtsp_transport", "tcp", '-r', '25', "-i", '127.0.0.1:3001', '-threads', '8', '-f', 'mpegts', '-c:v', 'mpeg1video', '-s', '960x540', '-b:v', '1500k', '-preset', 'ultrafast', '-preset', 'zerolatency', '-bf', '0', '-'], { 43 | detached: false 44 | }); 45 | streamer.on('close', () => { 46 | console.log("streamer closed") 47 | streamer = null 48 | }); 49 | avcServer.setVideoStream(streamer.stdout); 50 | } 51 | 52 | // OPTIONAL: start on connect 53 | avcServer.on('client_connected', () => { 54 | if (!streamer) { 55 | startStreamer() 56 | } 57 | }) 58 | 59 | 60 | // OPTIONAL: stop on disconnect 61 | avcServer.on('client_disconnected', () => { 62 | console.log('client disconnected') 63 | if (avcServer.clients.size < 1) { 64 | if (!streamer) { 65 | console.log('raspivid not running') 66 | return 67 | } 68 | console.log('stopping raspivid') 69 | streamer.kill('SIGTERM') 70 | } 71 | }) 72 | 73 | } else { 74 | // create the tcp sever that accepts a h264 stream and broadcasts it back to the clients 75 | this.tcpServer = net.createServer((socket) => { 76 | // set video stream 77 | avcServer.setVideoStream(socket) 78 | 79 | }) 80 | this.tcpServer.listen(5000, '0.0.0.0') 81 | } 82 | server.listen(3333); 83 | } 84 | } 85 | 86 | 87 | module.exports = new WSAvcPlayer(); 88 | 89 | // if not using raspivid option than use one of this to stream 90 | // ffmpeg OSX 91 | // then run ffmpeg: ffmpeg -framerate 30 -video_size 640x480 -f avfoundation -i 0 -vcodec libx264 -vprofile baseline -b:v 500k -bufsize 600k -tune zerolatency -pix_fmt yuv420p -r 15 -g 30 -f rawvideo tcp://localhost:3001 92 | 93 | // fmpeg Windows: 94 | 95 | // ffmpeg -framerate 25 -video_size 640x480 -f dshow -i "video=" -vcodec libx264 -vprofile baseline -b:v 500k -bufsize 600k -tune zerolatency -pix_fmt yuv420p -f rawvideo tcp://localhost:5000 96 | // to get video devices run: 97 | // ffmpeg -list_devices true -f dshow -i dummy 98 | 99 | 100 | // ffmpeg -framerate 25 -video_size 1280x720 -f dshow -i "video=Logitech HD Webcam C270" -vcodec libx264 -vprofile baseline -b:v 500k -bufsize 600k -tune zerolatency -pix_fmt yuv420p -f rawvideo tcp://localhost:5000 101 | 102 | // RPI 103 | // /opt/vc/bin/raspivid -pf baseline -ih -t 0 -w 640 -h 480 -hf -fps 15 -g 30 -o - | nc localhost 5000 -------------------------------------------------------------------------------- /service/wsclient.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by heyongchao on 2019/7/18 1:25 PM 3 | */ 4 | var ws = require("ws"); 5 | 6 | class WsClient { 7 | init(){ 8 | 9 | // url ws://127.0.0.1:3001 10 | // 创建了一个客户端的socket,然后让这个客户端去连接服务器的socket 11 | var sock = new ws("ws://127.0.0.1:3001"); 12 | sock.on("open", function () { 13 | console.log("connect success !!!!"); 14 | 15 | sock.send("HelloWorld1"); 16 | sock.send("HelloWorld2"); 17 | sock.send("HelloWorld3"); 18 | sock.send("HelloWorld4"); 19 | sock.send(Buffer.alloc(10)); 20 | }); 21 | 22 | sock.on("error", function(err) { 23 | console.log("error: ", err); 24 | }); 25 | 26 | sock.on("close", function() { 27 | console.log("close"); 28 | }); 29 | 30 | sock.on("message", function(data) { 31 | console.log(data); 32 | }); 33 | } 34 | }; 35 | module.exports = new WsClient(); -------------------------------------------------------------------------------- /views/error.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /views/index.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | video(scr="/video") 7 | -------------------------------------------------------------------------------- /views/layout.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | -------------------------------------------------------------------------------- /views/video.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | meta(charset="utf-8") 5 | | 6 | title video stream 7 | | 8 | style(type="text/css"). 9 | html, body{ 10 | width: 100%; 11 | height: 100%; 12 | margin: 0; 13 | padding: 0; 14 | } 15 | script(type="text/javascript",src="javascripts/WSAvcPlayer.js") 16 | //script(type="text/javascript",src="javascripts/http-live-player.js") 17 | 18 | body 19 | button(type="button",onclick="wsavc.send('custom_event_from_client',{ hello:'world' })") 20 | |Send event to server 21 | br 22 | p(id='frame_buffer') 23 | br 24 | div(style="width:100px; height:600px;") 25 | canvas(id='cam') 26 | 27 | //video(src="/video", controls="controls", style="margin: auto;display: block;padding: 30px;width:500px") 28 | // | 您的浏览器不支持 video 标签。 29 | script. 30 | var canvas = document.getElementById('cam') 31 | var fb = document.getElementById('frame_buffer') 32 | 33 | // Create h264 player 34 | var wsavc = new WSAvcPlayer(canvas, "webgl", 1, 35); 35 | //expose instance for button callbacks 36 | window.wsavc = wsavc; 37 | 38 | //maybe get rid of the ws inside the player? 39 | //var uri = "ws://meganeko:3000/videoStream"// + document.location.host; 40 | //var uri = "ws://" + document.location.host; 41 | //var uri = "ws://localhost:3333/" 42 | //wsavc.connect(uri); 43 | 44 | //wsavc.on('message', m=>console.log(m)) 45 | wsavc.on('disconnected', function () { 46 | console.log('WS Disconnected') 47 | }); 48 | wsavc.on('connected', function () { 49 | console.log('WS connected'); 50 | }); 51 | wsavc.on('frame_shift', function (fbl) { 52 | fb.innerText = 'fl: ' + fbl 53 | }); 54 | 55 | wsavc.on('initalized', function (payload) { 56 | console.log('Initialized', payload) 57 | }); 58 | 59 | wsavc.on('stream_active', function (active) { 60 | console.log('Stream is ', active ? 'active' : 'offline') 61 | }); 62 | 63 | 64 | wsavc.on('custom_event_from_server', function (event) { 65 | console.log('got event from server', event) 66 | }) 67 | wsavc.connect("ws://127.0.0.1:3333"); 68 | 69 | //wsavc.connect("ws://127.0.0.1:3333?addr=tcp://127.0.0.1:3001&method=single"); 70 | //wsavc.connect("ws://127.0.0.1:3002/getVideo"); -------------------------------------------------------------------------------- /views/video_wfs.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | meta(charset="utf-8") 5 | | 6 | title video stream 7 | | 8 | style(type="text/css"). 9 | video.rotate180 { 10 | width: 100%; 11 | height: 100%; 12 | transform: rotateX(180deg); 13 | -moz-transform: rotateX(180deg); 14 | -webkit-transform: rotateX(180deg); 15 | -o-transform: rotateX(180deg); 16 | -ms-transform: rotateX(180deg); 17 | } 18 | script(type="text/javascript",src="javascripts/wfs.js") 19 | body 20 | div(class="wfsjs") 21 | video(id="video1",autoplay,class="rotate180") 22 | div(class="ratio") 23 | script. 24 | window.onload = function () { 25 | if (Wfs.isSupported()) { 26 | 27 | var video1 = document.getElementById("video1"), 28 | wfs = new Wfs(); 29 | 30 | wfs.attachMedia(video1, 'chX','H264Raw','play2'); 31 | } 32 | }; --------------------------------------------------------------------------------