Skip to content

Commit 6491801

Browse files
committed
websocket mini
1 parent 7d376f2 commit 6491801

File tree

2 files changed

+163
-10
lines changed

2 files changed

+163
-10
lines changed

lib/bsb

+70-10
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,58 @@ var os = require('os');
1313
var bsconfig = 'bsconfig.json'
1414
var bsb_exe = __filename + ".exe"
1515

16+
var LAST_SUCCESS_BUILD_STAMP = 0
1617

18+
// All clients of type MiniWebSocket
19+
var wsClients = []
1720
var watch_mode = false
1821
var verbose = false
1922
var postBuild = undefined
23+
var useWebSocket = false
24+
var webSocketPort = 9999
25+
26+
function dlog(str){
27+
if(verbose){
28+
console.log(str)
29+
}
30+
}
31+
function notifyClients() {
32+
wsClients = wsClients.filter(x => !x.closed && !x.socket.destroyed )
33+
var wsClientsLen = wsClients.length
34+
dlog(`Alive sockets number: ${wsClientsLen}`)
35+
for (var i = 0; i < wsClientsLen; ++ i ) {
36+
var client = wsClients[i]
37+
if (!client.closed) {
38+
client.sendText(
39+
JSON.stringify(
40+
{
41+
LAST_SUCCESS_BUILD_STAMP: LAST_SUCCESS_BUILD_STAMP
42+
}
43+
)
44+
45+
)
46+
}
47+
}
48+
}
49+
50+
function setUpWebSocket() {
51+
var WebSocket = require('./minisocket.js').MiniWebSocket
52+
var id = setInterval(notifyClients, 3000)
53+
require('http').createServer()
54+
.on('upgrade', function (req, socket, upgradeHead) {
55+
dlog("connection opened");
56+
var ws = new WebSocket(req, socket, upgradeHead);
57+
wsClients.push(ws)
58+
})
59+
.on('error', function (err) {
60+
console.error(err)
61+
process.exit(2)
62+
})
63+
.listen(webSocketPort, "localhost");
64+
}
65+
66+
67+
2068
/**
2169
* @type {string[]}
2270
*/
@@ -28,17 +76,27 @@ for (var i = 2; i < process_argv.length; ++i) {
2876
// TODO boundary safety check
2977
// Not really needed
3078
postBuild = process_argv[++i]
79+
} else if (current === "-ws") {
80+
var portNumber = parseInt(process_argv[++i])
81+
dlog(`WebSocket port number: ${portNumber}`)
82+
if (!isNaN (portNumber )){
83+
webSocketPort = portNumber
84+
}
85+
useWebSocket = true
86+
3187
} else {
3288
delegate_args.push(current)
3389
if (current === '-w') {
3490
watch_mode = true
3591
} else if (current === "-verbose") {
3692
verbose = true
3793

38-
}
94+
}
3995
}
4096
}
4197

98+
99+
42100
try {
43101
child_process.execFileSync(bsb_exe, delegate_args, { stdio: 'inherit' })
44102
} catch (e) {
@@ -55,7 +113,9 @@ try {
55113
if (watch_mode) {
56114
var fs = require('fs')
57115
var path = require('path')
58-
116+
if (useWebSocket) {
117+
setUpWebSocket()
118+
}
59119
// for column one based error message
60120
process.env.BS_VSCODE = '1'
61121
var cwd = process.cwd()
@@ -192,20 +252,12 @@ if (watch_mode) {
192252
function logFinish(code) {
193253
if (std_is_tty) {
194254
if (code === 0) {
195-
if (postBuild) {
196-
console.log("running postbuild command", postBuild)
197-
child_process.exec(postBuild, { shell: true })
198-
}
199255
console.log("\x1b[36m>>>> Finish compiling\x1b[0m")
200256
} else {
201257
console.log("\x1b[1;31m>>>> Finish compiling(exit: " + code + ")\x1b[0m")
202258
}
203259
} else {
204260
if (code === 0) {
205-
if (postBuild) {
206-
console.log("running postbuild command", postBuild)
207-
child_process.exec(postBuild, { shell: true })
208-
}
209261
console.log(">>>> Finish compiling")
210262
} else {
211263
console.log(">>>> Finish compiling(exit: " + code + ")")
@@ -227,6 +279,14 @@ if (watch_mode) {
227279
* @param signal {string}
228280
*/
229281
function build_finished_callback(code, signal) {
282+
if(code === 0){
283+
LAST_SUCCESS_BUILD_STAMP = + new Date() ;
284+
notifyClients()
285+
if(postBuild){
286+
dlog(`running postbuild command: ${postBuild}`)
287+
child_process.exec(postBuild, { shell: true })
288+
}
289+
}
230290
logFinish(code)
231291
releaseBuild()
232292
if (needRebuild()) {

lib/minisocket.js

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
2+
var crypto = require("crypto");
3+
var KEY_SUFFIX = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4+
5+
function hashWebSocketKey(key) {
6+
var sha1 = crypto.createHash("sha1");
7+
sha1.update(key + KEY_SUFFIX, "ascii");
8+
return sha1.digest("base64");
9+
}
10+
11+
/**
12+
* Limitations: the current implementation does not
13+
* care about what the client send:
14+
* - we don't know `ws.close` only know `socket.closed` which is later so it has a latency
15+
* - ping pong protocol
16+
*/
17+
// http://tools.ietf.org/html/rfc6455#section-5.2
18+
var opcodes = {
19+
TEXT: 1,
20+
BINARY: 2,
21+
CLOSE: 8,
22+
PING: 9,
23+
PONG: 10
24+
};
25+
26+
/**
27+
*
28+
* @param {number} opcode
29+
* @param {Buffer} payload
30+
*/
31+
function encodeMessage(opcode, payload) {
32+
var buf; // Buffer type
33+
var b1 = 0x80 | opcode;
34+
// always send message as one frame (fin)
35+
36+
// second byte: maks and length part 1
37+
// followed by 0, 2, or 8 additional bytes of continued length
38+
var b2 = 0;
39+
// server does not mask frames
40+
var length = payload.length;
41+
if (length < 126) {
42+
buf = new Buffer(payload.length + 2 + 0);
43+
// zero extra bytes
44+
b2 |= length;
45+
buf.writeUInt8(b1, 0);
46+
buf.writeUInt8(b2, 1);
47+
payload.copy(buf, 2);
48+
} else if (length < (1 << 16)) {
49+
buf = new Buffer(payload.length + 2 + 2);
50+
// two bytes extra
51+
b2 |= 126;
52+
buf.writeUInt8(b1, 0);
53+
buf.writeUInt8(b2, 1);
54+
// add two byte length
55+
buf.writeUInt16BE(length, 2);
56+
payload.copy(buf, 4);
57+
} else {
58+
buf = new Buffer(payload.length + 2 + 8);
59+
// eight bytes extra
60+
b2 |= 127;
61+
buf.writeUInt8(b1, 0);
62+
buf.writeUInt8(b2, 1);
63+
// add eight byte length
64+
// note: this implementation cannot handle lengths greater than 2^32
65+
// the 32 bit length is prefixed with 0x0000
66+
buf.writeUInt32BE(0, 2);
67+
buf.writeUInt32BE(length, 6);
68+
payload.copy(buf, 10);
69+
}
70+
return buf;
71+
};
72+
73+
var upgradeHeader = 'HTTP/1.1 101 Web Socket Protocol Handshake\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\nsec-websocket-accept: '
74+
class MiniWebSocket {
75+
constructor(req, socket, upgradeHead) {
76+
this.socket = socket;
77+
this.closed = false;
78+
var self = this;
79+
var key = hashWebSocketKey(req.headers["sec-websocket-key"])
80+
81+
// http://tools.ietf.org/html/rfc6455#section-4.2.2
82+
socket.write( upgradeHeader + key + '\r\n\r\n');
83+
socket.on("close", function (hadError) {
84+
if (!self.closed) {
85+
self.closed = true;
86+
}
87+
});
88+
};
89+
sendText(obj) {
90+
this.socket.write(encodeMessage(opcodes.TEXT,new Buffer(obj, "utf8")))
91+
};
92+
}
93+
exports.MiniWebSocket = MiniWebSocket

0 commit comments

Comments
 (0)