-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
110 lines (103 loc) · 4.74 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
const bleno = require('bleno');
const msgpack = require('msgpack-lite');
const murmurhash = require('murmurhash');
const { PrimaryService, Characteristic } = bleno;
const emptyReadResponse = msgpack.encode({});
const packetSize = 21;
const emptyPacket = new Uint8Array(0);
let receivedPackets = [];
let responseQueue = [];
let firstRun = true;
exports.startServer = function ({ name, serviceUuid, characteristicUuid, handlers }) {
if (!firstRun) { return; }
firstRun = false;
let hashedHandlers = [];
Object.keys(handlers).forEach(handlerName => {
hashedHandlers[murmurhash.v3(handlerName)] = handlers[handlerName];
});
const commService = new PrimaryService({
uuid: serviceUuid,
characteristics: [
new Characteristic({
uuid: characteristicUuid,
properties: ['read', 'write'],
onReadRequest(offset, callback) {
if (responseQueue.length > 0) {
const packet = responseQueue.pop();
callback(Characteristic.RESULT_SUCCESS, packet);
if (responseQueue.length === 0) {
console.log('Responses sent.');
}
} else {
callback(Characteristic.RESULT_SUCCESS, emptyReadResponse);
}
},
async onWriteRequest(packet, offset, withoutResponse, callback) {
receivedPackets.push(packet);
if (packet.byteLength !== packetSize) {
const packets = receivedPackets;
receivedPackets = [];
const totalSize = packets
.reduce((total, p) => total + p.byteLength, 0);
let msg = new Uint8Array(totalSize);
for (let i = 0; i < packets.length; i++) {
msg.set(packets[i], i * packetSize);
}
let obj = msgpack.decode(msg);
console.log('Received request: ', obj);
callback(Characteristic.RESULT_SUCCESS);
(hashedHandlers[obj.h]
? hashedHandlers[obj.h](...(obj.a || []))
: Promise.reject(new Error('No such request type!')))
.then(response => {
let ro = { i: obj.i };
if (typeof response !== "undefined") {
ro.r = response;
}
return ro;
})
.catch(error => {
let ro = { i: obj.i };
if (typeof error !== "undefined") {
ro.e = error.toString();
}
return ro;
})
.then(responseObj => {
console.log('Response in queue', responseObj);
const responseMsg = msgpack.encode(responseObj);
for (let i = 0; i < responseMsg.byteLength; i += packetSize) {
let thisPacketSize = Math.min(responseMsg.byteLength - i, packetSize);
let packet = new Uint8Array(thisPacketSize);
for (let j = 0; j < thisPacketSize; j ++) {
packet[j] = responseMsg[i + j];
}
responseQueue.unshift(packet);
}
if (responseMsg.byteLength % packetSize === 0) {
responseQueue.unshift(emptyPacket);
}
});
} else {
callback(Characteristic.RESULT_SUCCESS);
}
},
}),
],
});
bleno.on('stateChange', state => {
if (state === 'poweredOn') {
bleno.startAdvertising(name, [commService.uuid]);
} else {
bleno.stopAdvertising();
}
});
bleno.on('advertisingStart', error => {
if (error) {
console.error(error);
} else {
console.log('Started advertising on Bluetooth!');
bleno.setServices([commService]);
}
});
};