foam-framework
Version:
MVC metaprogramming framework
194 lines (179 loc) • 5.36 kB
JavaScript
/**
* @license
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
CLASS({
package: 'foam.node.handlers',
name: 'DAOHandler',
requires: [
'foam.node.ws.WebSocket'
],
properties: [
'path',
{
name: 'crypto',
factory: function() { return require('crypto'); }
},
{
name: 'daoMap',
factory: function() { return {}; }
}
],
imports: [
'log',
'error'
],
methods: [
function upgrade(req, socket, data) {
if ( req.url != this.path ) return false;
var key = req.headers['sec-websocket-key'];
key += '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
var hash = this.crypto.createHash('SHA1');
hash.update(key);
hash = hash.digest('base64');
socket.write(
'HTTP/1.1 101 Switching Protocols\r\n' +
'Upgrade: websocket\r\n' +
'Connection: upgrade\r\n' +
'Sec-WebSocket-Accept: ' + hash + '\r\n\r\n');
var ws = this.WebSocket.create({
socket: socket
});
ws.subscribe(ws.ON_MESSAGE, function(_, _, message) {
// Warning insecure parser.
var msg = JSONUtil.parse(this.Y, message);
var msgid = msg.msgid;
if ( msg.method == 'listen' ) {
var dao = this.daoMap[msg.subject];
if ( ! dao ) {
ws.send(JSON.stringify({ msgid: msgid, msg: { error: 'No dao found.' } }));
return;
}
dao.listen({
put: function(o) {
ws.send(JSONUtil.stringify({
msg: {
notify: ["put", o]
}
}));
},
remove: function(o) {
ws.send(JSONUtil.stringify({
msg: {
notify: ["remove",o]
}
}));p
},
reset: function() {
ws.send(JSON.stringify({
msg: {
notify: ["reset"]
}
}));
}
});
ws.send(JSON.stringify({
msgid: msgid,
msg: true
}));
} else {
this.handleDAORequest(msg, {
put: function(m) {
ws.send(JSONUtil.stringify({
msgid: msgid,
msg: m
}));
},
error: function(msg) {
ws.send(JSONUtil.stringify({
msgid: msgid,
msg: { error: msg }
}));
}
});
}
}.bind(this));
return true;
},
function handleDAORequest(msg, resp, X) {
var dao = this.daoMap[msg.subject];
if ( ! dao ) {
resp.error && resp.error('no such dao');
return;
}
switch ( msg.method ) {
case 'select':
case 'removeAll':
dao[msg.method].apply(dao, msg.params.concat(X))(function(sink) {
resp.put && resp.put(sink);
});
break;
case 'put':
case 'remove':
case 'find':
var sink = {
send: function(method, x) {
var payload = {};
payload[method] = x;
resp.put && resp.put(payload);
},
put: function(x) { this.send('put', x) },
remove: function(x) { this.send('remove', x) },
error: function(x) { this.send('error', x); }
};
dao[msg.method](msg.params[0], sink, X);
break;
default:
resp.error && resp.error("Unsupported dao method.");
}
},
function handle(req, resp) {
if ( req.url != this.path ) return false;
var body = '';
req.on('data', function(data) { body += data; });
req.on('end', function() {
/*
Secure parser, requires JSONParser improvements
var map = JSONParser.parseString(body, JSONParser.obj);
if ( ! map ) {
this.error('Failed to parse request.', body)
}
var msg = JSONUtil.mapToObj(this.Y, map);
*/
var subX = this.Y;
if (req.headers && req.headers['x-foam-auth']) {
subX = subX.sub({ authHeader: req.headers['x-foam-auth'] });
}
// Warning insecure parser.
var msg = JSONUtil.parse(this.Y, body);
this.handleDAORequest(msg, {
put: function(msg) {
resp.statusCode = 200;
resp.setHeader("Content-Type", "application/json");
resp.write(JSONUtil.stringify(msg));
resp.end();
},
error: function(err) {
resp.statusCode = 400;
resp.setHeader("Content-Type", "application/json");
resp.write(JSON.stringify({ error: err }));
resp.end();
}
}, subX);
}.bind(this));
return true;
}
]
});