-
Notifications
You must be signed in to change notification settings - Fork 9
/
omega.js
157 lines (140 loc) · 4.15 KB
/
omega.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
'use strict';
var Route = require('routable');
/**
* Broadcast messages using HTTP.
*
* Options:
*
* - method: HTTP method we should respond to, defaults to PUT.
* - password: Password for basic auth, defaults to supreme.
* - username: Username for basic auth, defaults to omega.
* - url: Access path, defaults to /primus/omega/supreme.
*
* @param {Object} options Middleware configuration.
* @returns {Function} The configured middleware function.
* @api public
*/
module.exports = function omega(options) {
//
// Compile an identical header as we expect to be send from the client so we
// can easily validate the request.
//
var authorization = 'Basic '+
Buffer.from(options.username +':'+ options.password).toString('base64');
//
// Create an URL that we can test against.
//
var route = new Route(options.url);
/**
* The actual middleware layer.
*
* @param {Request} req Incoming HTTP request.
* @param {Response} res Outgoing HTTP response.
* @param {Function} next Middleware continuation.
* @api private
*/
function intercept(req, res, next) {
if (
!route.test(req.url) // Incorrect URL.
|| !req.headers.authorization // Missing authorization.
|| options.method !== req.method // Invalid method.
) return next();
//
// Handle unauthorized requests.
//
if (authorization !== req.headers.authorization) {
res.statusCode = 401;
res.setHeader('Content-Type', 'application/json');
return res.end(JSON.stringify({
ok: false,
reason: [
'I am programmed to protect, and sacrifice if necessary.',
'Feel the power of my lazers! Pew pew!'
].join(' ')
}));
}
var primus = this
, buff = '';
if (typeof options.middleware === 'function') {
options.middleware(primus, parse, req, res, next);
} else {
//
// Receive the data from the socket. The `setEncoding` ensures that Unicode
// chars are correctly buffered and parsed before the `data` event is
// emitted.
//
req.setEncoding('utf8');
req.on('data', function data(chunk) {
buff += chunk;
}).once('end', function end() {
parse(primus, buff, res);
});
}
}
//
// Don't run on HTTP upgrades as we only process POST requests.
//
intercept.upgrade = false;
return intercept;
};
/**
* Parse the incoming so we can hand it off to the correct spark for further
* processing.
*
* @param {String} raw Raw text data.
* @param {Response} res HTTP response.
* @api private
*/
function parse(primus, raw, res) {
var called = 0
, data
, err;
try {
data = JSON.parse(raw);
} catch (e) {
err = e;
}
if (
err // No error..
|| 'object' !== typeof data // Should be an object.
|| Array.isArray(data) // A real object, not array.
|| !data.msg // The data we send should be defined.
) {
res.statusCode = 500;
res.setHeader('Content-Type', 'application/json');
return res.end('{ "ok": false, "reason": "invalid data structure" }');
}
//
// Process the incoming messages in three different modes:
//
// Sparks: The data.sparks is an array with spark id's which we should write
// the data to.
// Spark: The data.sparks is the id of one single individual spark which
// should receive the data.
// All: Broadcast the message to every single connected spark if no
// `data.sparks` has been provided.
//
if (Array.isArray(data.sparks)) {
data.sparks.forEach(function each(id) {
var spark = primus.spark(id);
if (spark) {
spark.write(data.msg);
called++;
}
});
} else if ('string' === typeof data.sparks && data.sparks) {
var spark = primus.spark(data.sparks);
if (spark) {
spark.write(data.msg);
called++;
}
} else {
primus.forEach(function each(spark) {
spark.write(data.msg);
called++;
});
}
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.end('{ "ok": true, "send":'+ called +' }');
}