-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.js
219 lines (200 loc) · 7 KB
/
server.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
var cluster = require('cluster');
var express = require('express');
var http = require('http');
var net = require('net');
var ws = require('ws');
var files = require('files');
var persist = require('persist');
var fs = require('fs');
var auth = require('auth');
var special_subdomains = {
files : files.server
};
function parseCookies (request) {
var list = {};
var rc = request.headers.cookie;
rc && rc.split(';').forEach(function( cookie ) {
var parts = cookie.split('=');
list[parts.shift().trim()] = unescape(parts.join('='));
});
return list;
}
if (cluster.isMaster) {
var workers = [];
var hosts = {
'auth' : {
root : 'auth',
host : '127.0.0.1',
port : 8001
}
};
control_root_object('ol-c', '[email protected]', function (err) {
if (err) console.log(err);
else {}
});
function control_root_object(root, owner, callback) {
// Check if root already exists, if not
// create it here and unload it so worker
// can take control
persist.exists(root, function (err, exists) {
if (err) callback('error checking if root object exists');
else if (exists) spawn_worker_for_root(root, owner, callback);
else {
persist.set_root(root);
var root_object = persist.create('hashmap', root);
if (persist.get_owner(root_object) == undefined) {
persist.set_owner(root_object, owner);
}
persist.unload(root_object, function (err) {
if (err) callback('error unloading before spawning worker');
else spawn_worker_for_root(root, owner, callback);
});
}
});
}
function spawn_worker_for_root(root, owner, callback) {
var environment = {
root : root,
host : '127.0.0.1',
port : 8001 + workers.length
};
worker = cluster.fork(environment);
worker.host = environment;
hosts[environment.root] = environment;
workers.push(worker);
worker.onServerReady = function (err) {
// TODO: broadcast control to all other servers
if (err) callback(err);
else callback(null, environment);
}
worker.on('message', respond(worker));
}
function get_host(objectID, callback) {
// TODO: check other servers
callback(null, hosts[objectID]);
}
function respond(worker) {
var reactions = {
'host request' : function (message) {
get_host(message.id, function (err, host) {
function respond(host) {
worker.send({
token : message.token,
response : host
});
}
if (err) callback('error getting external host');
else if (host) respond(host);
else if (message.requester === 'anonymous') {
// if no host and anonymous, return no host
respond(null);
}
else {
// claim control of this root since there is no other host
control_root_object(message.id, message.requester, function (err) {
if (err) console.log('error occurred controlling root object');
else respond(hosts[message.id]);
});
}
});
},
'object controlled' : function (message) {
hosts[message.id] = worker.host;
},
'control root' : function (message) {
control_root_object(message.name, message.owner, function (err) {
if (err) console.log(err);
else {}
});
},
'initialized' : function (message) {
if (worker.onServerReady) worker.onServerReady();
delete worker.onServerReady;
}
};
return function (message) {
var reaction = reactions[message.event];
reaction(message);
}
}
}
else {
// set agent so we know what agent to attach to executing functions
persist.set_agent(process.env.root);
persist.set_root(process.env.root);
var app = express();
app.use(auth.middleware);
app.use(function (req, res, next) {
var subdomain = req.headers.host.split('.').shift();
if (special_subdomains[subdomain]) {
special_subdomains[subdomain](req, res, next);
}
else {
next();
}
});
app.use(express.static(__dirname + '/static'));
app.use(function (request, response) {
response.end(fs.readFileSync(__dirname + '/static/index.html'));
});
var HTTPserver = http.createServer(app);
var WSserver = new ws.Server({server : HTTPserver});
WSserver.on('connection', function (websocket) {
var cookies = parseCookies(websocket.upgradeReq);
websocket.session = {
id : cookies.id
};
websocket.type = 'websocket';
persist.handleWS(websocket);
});
HTTPserver.listen(80, initialize);
// notify master process when this worker has taken
// control of an object
persist.on('control', function (id) {
process.send({
'event' : 'object controlled',
'id' : id
});
});
// load root object
persist.load(process.env.root, function (err, res) {
if (err) throw new Error('Could not load root object');
else initialize();
});
// create resolver so persist can connect
// to other persist instances
var waiting_responses = {};
persist.resolve_hosts(function (id, requester, callback) {
var token = Math.random();
process.send({
'token' : token,
'event' : 'host request',
'requester' : requester,
'id' : id
});
waiting_responses[token] = callback;
});
// react to messages from master
process.on('message', function (message) {
var waiting = waiting_responses[message.token];
if (waiting) {
waiting(null, message.response);
delete waiting_responses[message.token];
}
});
// catch exceptions in this process
process.on('uncaughtException', function (err) {
// log all the stuff leading up to this
console.log(err.stack);
});
// persist instances communicat over TCP
TCPserver = net.createServer(persist.handleTCP);
TCPserver.listen(process.env.port, initialize);
var initializing = 3;
function initialize() {
initializing -= 1;
if (initializing == 0) {
process.send({ event : 'initialized'});
}
}
}