1 | (function() {
|
2 | var Client, Linda, Tuple, TupleSpace, debug, events, fs, http, path, request, socketio, url,
|
3 | __hasProp = {}.hasOwnProperty,
|
4 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
5 |
|
6 | http = require('http');
|
7 |
|
8 | path = require('path');
|
9 |
|
10 | url = require('url');
|
11 |
|
12 | fs = require('fs');
|
13 |
|
14 | request = require('request');
|
15 |
|
16 | events = require('eventemitter2');
|
17 |
|
18 | socketio = require('socket.io');
|
19 |
|
20 | debug = require('debug')('linda');
|
21 |
|
22 | TupleSpace = require(path.join(__dirname, 'tuplespace'));
|
23 |
|
24 | Tuple = require(path.join(__dirname, 'tuple'));
|
25 |
|
26 | Client = require(path.join(__dirname, 'linda-client'));
|
27 |
|
28 | module.exports.TupleSpace = TupleSpace;
|
29 |
|
30 | module.exports.Tuple = Tuple;
|
31 |
|
32 | module.exports.Client = Client;
|
33 |
|
34 | Linda = (function(_super) {
|
35 | __extends(Linda, _super);
|
36 |
|
37 | function Linda() {
|
38 | this.spaces = {};
|
39 | fs.readFile(path.join(__dirname, 'linda-client.js'), (function(_this) {
|
40 | return function(err, data) {
|
41 | if (err) {
|
42 | throw new Error("client js load error");
|
43 | }
|
44 | return _this.client_js_code = data;
|
45 | };
|
46 | })(this));
|
47 | setInterval((function(_this) {
|
48 | return function() {
|
49 | var name, space, _ref;
|
50 | debug("TupleSpace\tcheck expire");
|
51 | _ref = _this.spaces;
|
52 | for (name in _ref) {
|
53 | space = _ref[name];
|
54 | if (space != null) {
|
55 | space.check_expire();
|
56 | }
|
57 | }
|
58 | return debug("TupleSpace\tcheck expire done");
|
59 | };
|
60 | })(this), 60 * 3 * 1000);
|
61 | this.tuplespace('__linda').watch({
|
62 | type: 'keepalive'
|
63 | }, function(err, tuple) {
|
64 | if (err || (tuple.data.to == null)) {
|
65 | return;
|
66 | }
|
67 | if (/^https?:\/\/.+/.test(tuple.data.to)) {
|
68 | return request("" + tuple.data.to + "?keepalive=" + (Date.now()));
|
69 | }
|
70 | });
|
71 | }
|
72 |
|
73 | Linda.prototype.tuplespace = function(name) {
|
74 | return this.spaces[name] || (this.spaces[name] = new TupleSpace(name));
|
75 | };
|
76 |
|
77 | Linda.prototype.listen = function(opts) {
|
78 | if (opts == null) {
|
79 | opts = {
|
80 | io: null,
|
81 | server: null
|
82 | };
|
83 | }
|
84 | if (opts.io == null) {
|
85 | throw new Error('"io" must be instance of Socket.IO');
|
86 | }
|
87 | if (!(opts.server instanceof http.Server)) {
|
88 | throw new Error('"server" must be instance of http.Server');
|
89 | }
|
90 | this.io = opts.io;
|
91 | this.server = opts.server;
|
92 | this.oldListeners = this.server.listeners('request').splice(0);
|
93 | this.server.removeAllListeners('request');
|
94 | this.server.on('request', (function(_this) {
|
95 | return function(req, res) {
|
96 | var listener, _i, _len, _ref, _results, _url;
|
97 | _url = url.parse(decodeURI(req.url), true);
|
98 | if (_url.pathname === "/linda/linda.js") {
|
99 | debug("GET\t" + _url.pathname);
|
100 | res.setHeader('Content-Type', 'application/javascript');
|
101 | res.writeHead(200);
|
102 | res.end(_this.client_js_code);
|
103 | return;
|
104 | }
|
105 | _ref = _this.oldListeners;
|
106 | _results = [];
|
107 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
108 | listener = _ref[_i];
|
109 | _results.push(listener.call(_this.server, req, res));
|
110 | }
|
111 | return _results;
|
112 | };
|
113 | })(this));
|
114 | this.io.sockets.on('connection', (function(_this) {
|
115 | return function(socket) {
|
116 | var cids, info, watch_cids, _ref;
|
117 | cids = {};
|
118 | info = {
|
119 | from: socket.handshake.headers['x-forwarded-for'] || ((_ref = socket.handshake.address) != null ? _ref.address : void 0)
|
120 | };
|
121 | socket.on('__linda_write', function(data) {
|
122 | var _ref1;
|
123 | if ((_ref1 = data.options) != null) {
|
124 | _ref1.from = info.from;
|
125 | }
|
126 | _this.tuplespace(data.tuplespace).write(data.tuple, data.options);
|
127 | debug("write\t" + (JSON.stringify(data)) + " from " + info.from);
|
128 | return _this.emit('write', data);
|
129 | });
|
130 | socket.on('__linda_take', function(data) {
|
131 | var cid;
|
132 | cid = _this.tuplespace(data.tuplespace).take(data.tuple, function(err, tuple) {
|
133 | cid = null;
|
134 | return socket.emit("__linda_take_" + data.id, err, tuple);
|
135 | });
|
136 | cids[data.id] = cid;
|
137 | debug("take\t" + (JSON.stringify(data)) + " from " + info.from);
|
138 | _this.emit('take', data);
|
139 | return socket.once('disconnect', function() {
|
140 | if (cid) {
|
141 | return _this.tuplespace(data.tuplespace).cancel(cid);
|
142 | }
|
143 | });
|
144 | });
|
145 | socket.on('__linda_read', function(data) {
|
146 | var cid;
|
147 | cid = _this.tuplespace(data.tuplespace).read(data.tuple, function(err, tuple) {
|
148 | cid = null;
|
149 | return socket.emit("__linda_read_" + data.id, err, tuple);
|
150 | });
|
151 | cids[data.id] = cid;
|
152 | debug("read\t" + (JSON.stringify(data)) + " from " + info.from);
|
153 | _this.emit('read', data);
|
154 | return socket.once('disconnect', function() {
|
155 | if (cid) {
|
156 | return _this.tuplespace(data.tuplespace).cancel(cid);
|
157 | }
|
158 | });
|
159 | });
|
160 | watch_cids = {};
|
161 | socket.on('__linda_watch', function(data) {
|
162 | var cid;
|
163 | debug("watch\t" + (JSON.stringify(data)) + " from " + info.from);
|
164 | _this.emit('watch', data);
|
165 | if (watch_cids[data.id]) {
|
166 | return;
|
167 | }
|
168 | watch_cids[data.id] = true;
|
169 | cid = _this.tuplespace(data.tuplespace).watch(data.tuple, function(err, tuple) {
|
170 | return socket.emit("__linda_watch_" + data.id, err, tuple);
|
171 | });
|
172 | cids[data.id] = cid;
|
173 | return socket.once('disconnect', function() {
|
174 | if (cid) {
|
175 | return _this.tuplespace(data.tuplespace).cancel(cid);
|
176 | }
|
177 | });
|
178 | });
|
179 | return socket.on('__linda_cancel', function(data) {
|
180 | debug("cancel\t" + (JSON.stringify(data)) + " from " + info.from);
|
181 | _this.emit('cancel', data);
|
182 | _this.tuplespace(data.tuplespace).cancel(cids[data.id]);
|
183 | return watch_cids[data.id] = false;
|
184 | });
|
185 | };
|
186 | })(this));
|
187 | return this;
|
188 | };
|
189 |
|
190 | return Linda;
|
191 |
|
192 | })(events.EventEmitter2);
|
193 |
|
194 | module.exports.Server = new Linda;
|
195 |
|
196 | }).call(this);
|