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
|
const util = require("util");
module.exports = {};
module.exports.debug = true;
{
let id = 0;
function uniqid() {
return id++;
}
}
module.exports.uniqid = uniqid;
function lineReader(conn, lineCb) {
let buffer = "";
conn.on("data", (data) => {
buffer += data.toString();
let idx = buffer.indexOf("\n");
while (idx != -1) {
lineCb(buffer.slice(0, idx));
buffer = buffer.slice(idx + 1);
idx = buffer.indexOf("\n");
}
});
}
module.exports.lineReader = lineReader;
class Message {
constructor(/*...*/) {
if (typeof arguments[0] == "number") this.makeReply(...arguments);
else this.makeCommand(...arguments);
}
makeCommand(method, ...args) {
this.isCommand = true;
this.method = method;
this.args = args;
this.id = uniqid();
}
makeReply(id, res, err) {
this.isCommand = false;
this.id = id;
this.res = res;
this.err = err;
}
toJSON() {
if (this.isCommand) {
return JSON.stringify({
method: this.method,
args: this.args,
id: this.id,
});
} else {
return JSON.stringify({
res: this.res,
err: this.err,
id: this.id,
});
}
}
}
module.exports.Message = Message;
class Connection {
constructor(conn, msgCb) {
this.conn = conn;
lineReader(conn, (line) => {
console.log("Received line '" + line + "'");
let obj;
try {
obj = JSON.parse(line);
} catch (e) {
if (module.exports.debug) console.log("Invalid JSON received: " + line);
return;
}
if (obj.method) {
msgCb(new Message(obj.method, ...obj.args));
} else {
const msg = new Message(obj.id, obj.res, obj.err);
if (this.replyHandlers[msg.id]) {
this.replyHandlers[msg.id](msg);
this.replyHandlers[msg.id] = null;
} else {
if (module.exports.debug) console.log("Reply for unexpected message id " + msg.id);
}
}
});
this.replyHandlers = {};
// Send a ping once in a while
this.pingInterval = setInterval(async () => {
const msg = await this.send(new Message("ping"));
if (module.exports.debug) console.log("Ping reply: " + util.inspect(msg));
}, 600000);
}
send(msg) {
const data = msg.toJSON();
if (module.exports.debug) console.log("Writing to conn: " + data);
this.conn.write(data + "\n");
return new Promise((resolve, reject) => {
this.replyHandlers[msg.id] = resolve;
});
}
end() {
clearInterval(this.pingInterval);
this.conn.end();
}
}
module.exports.Connection = Connection;
|