-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
188 lines (165 loc) · 5.38 KB
/
index.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
var express = require('express');
var sockjs = require('sockjs');
var uid = require('uid2');
var MongoClient = require('mongodb').MongoClient;
var ObjectID = require('mongodb').ObjectID;
var app = express();
var server = require('http').Server(app);
function remove(arr, item) {
for (var i=0; i<arr.length; i++) {
if (arr[i] === item) {
arr.splice(i,1);
return;
}
}
}
var users = [];
function broadcast(sender, data) {
var payload = JSON.stringify(data);
console.log("Broadcast:", data.id);
for (var i=0; i<users.length; i++) {
var conn = users[i];
if (conn !== sender && conn.writable) {
conn.write(payload);
}
}
}
var url = 'mongodb://localhost:27017/pixlie';
MongoClient.connect(url, function(err, db) {
if (err) throw err;
console.log("Connected to mongodb.");
var layers = db.collection("layers");
var layerData = db.collection("layerdata");
app.use(express.static('static'));
var sockServ = sockjs.createServer({
sockjs_url: 'http://cdn.jsdelivr.net/sockjs/1.0.0/sockjs.min.js',
prefix: '/socket'
});
sockServ.on('connection', function(conn) {
console.log("SockJS connection");
users.push(conn);
function send(data) {
if (conn.writable) {
conn.write(JSON.stringify(data));
}
}
var sockOps = {};
// the client will send this if it needs an id for the device.
sockOps['getID'] = function (data) {
var id = uid(30);
var token = uid(60);
console.log("New ID:", id);
var doc = {_id:id, token:token, ver:0, ts:Date.now()};
layers.insert(doc, function (err, res) {
if (err) {
console.log("Cannot insert ID:", id, err);
return send({ op: "assignID", error: true });
}
if (res && res.writeError) {
console.log("Cannot insert ID:", id, res.writeError);
return send({ op: "assignID", error: true });
}
return send({ op: "assignID", id: id, token: token });
});
};
// the client will send this to load the layer index.
sockOps['getIndex'] = function (data) {
layers.find({ ver:{$gt:0} }).toArray(function(err, res) {
if (err) {
console.log("Cannot list layer index.", err);
return send({ op: "index", error: true });
}
res = res.map(function(doc){
return {
id: doc._id,
ver: doc.ver,
ts: doc.ts,
depth: doc.depth
};
});
return send({ op: "index", layers: res });
});
};
// fetch layer data for one layer.
sockOps['loadLayer'] = function (data) {
var id = data.id;
layerData.findOne({_id:id}, function(err, res) {
if (err) {
console.log("Cannot load layer:", id, err);
return send({ op: "didLoad", id: id, error: true });
}
return send({
op: "didLoad",
id: res._id,
ver: res.ver,
grid: res.grid,
gridTop: res.gridTop
});
});
};
// the client will send this when it has changes to upload.
sockOps['pushLayer'] = function (data) {
if (data && data.id && data.token && data.grid && data.gridTop != null) {
// validate layer id and token.
var id = data.id;
layers.findOne({ _id: id, token: data.token }, function (err, obj) {
if (err) return console.log(err);
if (obj) {
// correct id and token; save the new layer version.
var fields = {
ver: (obj.ver||0) + 1,
grid: data.grid,
gridTop: data.gridTop
};
layerData.update({_id:id}, {$set:fields}, {upsert:true}, function (err) {
if (err) {
console.log("Cannot upsert:", id, err);
return send({ op: "didPush", error: true });
}
layers.update({_id:id}, {$set:{ ver: fields.ver }}, function (err) {
if (err) {
console.log("Cannot update layer version:", id, err);
return send({ op: "didPush", error: true });
}
console.log("Saved layer:", id);
// notify all connected clients.
// include all metadata so clients can sort new layers.
broadcast(conn, {
op: "change",
id: id,
ver: fields.ver,
ts: obj.ts,
depth: obj.depth,
grid: data.grid,
gridTop: data.gridTop
});
return send({ op: "didPush", saved: true });
});
});
} else {
console.log("Did not find layer.");
return send({ op: "didPush", error: true });
}
});
} else {
console.log("Bad push data:", data && data.id);
return send({ op: "didPush", error: true });
}
};
conn.on('data', function(message) {
var msg = JSON.parse(message);
//conn.write(message);
console.log("SockJS data", Object.keys(msg));
var fun = sockOps[msg.op];
if (fun) { fun(msg); }
else console.log("Bad message:", msg);
});
conn.on('close', function() {
console.log("SockJS close");
remove(users, conn);
});
});
sockServ.installHandlers(server);
server.listen(+process.argv[2] || 8080);
//db.close();
});