*/
validRoutes: /[a-zA-Z][a-zA-Z0-9\-_]*/,
+ /** A map of routes
+ * @prop {Object.Map} routes - all the routes!
+ */
+ routes: {},
+
/** Parameters set on bootup (startHttpServer)
* @prop {string[2]} skelPage - html document split in twain for JS injection
* @prop {string} clientJS - jerverscripps to inject in skelPage for clients
httpdRoot: undefined,
bindJail: undefined,
-
-
/** @func
* @summary Start main HTTP server
* @desc starts up an HTTP or HTTPS server used for routing
})
this.httpd =
require('https').createServer(this.httpsOpts, this.httpdListener)
+ .listen(conf.port)
})
- this.httpd.listen(conf.port)
- this.httpdRoot =
- conf.httpdRoot ? require('path').normalize(conf.httpdRoot) : undefined
- while (this.httpdRoot[this.httpdRoot.length - 1] == require('path').sep)
- this.httpdRoot = this.httpdRoot.slice(0,-1)
- this.syncReads(conf.skelFile, conf.clientJS, conf.hostJS)
+ if (conf.httpdRoot) {
+ this.httpdRoot = require('path').normalize(conf.httpdRoot)
+ while (this.httpdRoot[this.httpdRoot.length - 1] == require('path').sep)
+ this.httpdRoot = this.httpdRoot.slice(0,-1)
+ }
+ this.syncReads([conf.skelFile, conf.clientJS, conf.hostJS])
.then((results) => {
this.skelPage = results[conf.skelFile].split('<!--STRAPP_SRC-->')
this.clientJS = results[conf.clientJS]
&& this.bindJail != path)
throw new Error(`${routeName}:${path} jailed to ${this.bindJail}`)
if (require('fs').existsSync(path)) {
- this.route[routeName] = {
+ this.routes[routeName] = {
bind: {
path: path,
dir: require('fs').lstatSync(path).isDirectory()
htArgv[0] = htArgv[0].slice(1)
this.serveBind(response, route.bind, htArgv)
}
+ //TODO: auth better than this (ip spoofing is easy)
else if (route.host == (request.headers['x-forwarded-for'] ||
request.connection.remoteAddress))
this.serveHost(response, route, htArgv)
* and responds to either the host or the client, or both. Commands
* are whitespace separated strings.
* Commands:
+ * Forward Payload to Client)
* < clientKey payload [header]
* Route 'payload' to the client identified by 'clientKey'.
* The optional 'header' argument is a stringified JSON object,
* which will be written to the HTTP response header
* In case of multiple requests from a single client, the
* oldest request will be serviced on arrival of message
+ * Translate SDP and Forward to Client)
+ * ^ clientKey sdp [header]
+ * Route the JSON object 'sdp' to the client, after translating
+ * for interop between browsers using planB or Unified. Other
+ * than the interop step, this is identical to the '<' command
+ * Error)
* ! errorMessage errorCode [offendingMessage]
* Notify host that an error has occured, providing a message
* and error code. 'offendingMessage', if present, is the
argv = argv.slice(1)
dlog(`Received host message from ${route.name}: ${command}`)
switch (command) {
+ case '^':
+ if (argv.length < 2) {
+ dlog(`Malformed '${command}' command from ${route.host}`)
+ route.socket.send(`! "Insufficient arguments" 0 ${message}`)
+ break
+ }
+ argv[1] = JSON.parse(argv[1])
+ //TODO: interop step
+ argv[1] = JSON.stringify(argv[1])
+ //TODO: argv[1] = encryptForClient(argv[0], argv[1])
+ /* Fallthrough to '<' behavior after translating argv[1] */
case '<':
const response = route.pendingResponses.get(argv[0]).shift()
if (!response)
argv[0] += `\nIn message: ${argv[2]}`
console.log(`Error[${route.host}|${argv[1]}]:${argv[0]}`)
break
+ default:
+ route.socket.send(`! "Unknown command '${command}'" 0 ${message}`)
+ dlog(`Host ${route.host} send unknown command: ${message}`)
+ break
}
},
* @arg {Object} [readOpts] - options to pass to fs.readFile()
*/
syncReads: (files, readOpts) => new Promise((resolve,reject) => {
- dlog(`syncReads: ${files}`)
+ dlog(`syncing reads from ${files}`)
let count = 0
let results = {}
const read_cb = (fileName) => (err, data) => {
files.forEach((file) =>
require('fs').readFile(file, readOpts, read_cb(file)))
})
-
}
+
+module.exports = exports