iosignal 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +247 -240
- package/auth_file.json +13 -13
- package/auth_file.mjs +23 -23
- package/dist/iosignal.cjs +1 -1
- package/dist/iosignal.esm.js.map +1 -1
- package/dist/iosignal.min.js.map +1 -1
- package/index.js +19 -19
- package/indexWebBrowser.js +13 -13
- package/package.json +59 -60
- package/rollup.config.js +69 -69
- package/src/api/RedisAPI.js +68 -68
- package/src/api/api_constant.js +7 -7
- package/src/api/api_reply.js +34 -34
- package/src/api/api_sudo.js +96 -96
- package/src/auth/Auth_Env.js +78 -78
- package/src/auth/Auth_File.js +75 -75
- package/src/auth/Auth_Redis.js +50 -50
- package/src/auth/BohoAuth.js +168 -168
- package/src/client/CongPacket.js +150 -150
- package/src/client/IOCongSocket.js +88 -88
- package/src/client/IOCore.js +851 -851
- package/src/client/IOWS.js +81 -81
- package/src/client/IOWebSocket.js +95 -95
- package/src/common/constants.js +159 -159
- package/src/common/payload.js +82 -82
- package/src/common/quotaTable.js +68 -68
- package/src/common/util.js +61 -61
- package/src/server/FileLogger.js +30 -30
- package/src/server/Manager.js +449 -449
- package/src/server/Metric.js +154 -154
- package/src/server/Server.js +166 -148
- package/src/server/ServerRemote.js +227 -227
- package/src/server/ServerRemoteCore.js +467 -467
- package/src/server/serverOption.js +56 -55
- package/test-browser/favicon.ico +0 -0
- package/test-browser/index.html +92 -92
- package/test-browser/server.js +11 -11
- package/test-client-nodejs/client.cjs +17 -17
- package/test-client-nodejs/client.mjs +17 -17
- package/test-client-nodejs/client_api_reply.mjs +15 -15
- package/test-client-nodejs/stateChange.mjs +19 -19
- package/test-server/server-Auth_Env.js +19 -19
- package/test-server/server-Auth_File.js +12 -12
- package/test-server/server-api_reply.js +6 -6
- package/test-server/server-api_sudo.js +7 -7
- package/test-server/server-commonjs.cjs +8 -8
- package/test-server/server-esm.mjs +19 -19
- package/test-server/simple-server.mjs +11 -11
- package/test-signal-payloadType/signalPack.js +34 -34
- package/test-signal-payloadType/signaling.js +60 -60
package/src/auth/BohoAuth.js
CHANGED
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BohoAuth
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { MBP } from 'meta-buffer-pack'
|
|
6
|
-
import { BohoMsg , Meta } from 'boho'
|
|
7
|
-
import { quotaTable } from '../common/quotaTable.js'
|
|
8
|
-
import { serverOption } from '../server/serverOption.js'
|
|
9
|
-
import { IOMsg ,CLIENT_STATE } from '../common/constants.js'
|
|
10
|
-
import { FileLogger } from '../server/FileLogger.js'
|
|
11
|
-
|
|
12
|
-
const decoder = new TextDecoder()
|
|
13
|
-
export class BohoAuth{
|
|
14
|
-
constructor(){
|
|
15
|
-
this.authLogger;
|
|
16
|
-
if( serverOption.fileLogger.auth.use ){
|
|
17
|
-
this.authLogger = new FileLogger( serverOption.fileLogger.auth.path)
|
|
18
|
-
console.log('Auth: begin file logger.[auth]')
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
send_auth_fail( peer , reason){
|
|
23
|
-
if( this.authLogger ){
|
|
24
|
-
let peerInfo = `FAIL #${peer.ssid} reason:${reason} `
|
|
25
|
-
this.authLogger.log( peerInfo )
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
console.log('## AUTH_FAIL reason:', reason )
|
|
29
|
-
// peer.send( Buffer.from( [BohoMsg.AUTH_FAIL] ))
|
|
30
|
-
peer.setState( CLIENT_STATE.AUTH_FAIL )
|
|
31
|
-
setTimeout(e=>{
|
|
32
|
-
peer.send( Buffer.from( [BohoMsg.AUTH_FAIL] ))
|
|
33
|
-
}, serverOption.auth.delay_auth_fail )
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async verify_auth_hmac( auth_hmac , peer ){
|
|
37
|
-
try {
|
|
38
|
-
//1. unpack
|
|
39
|
-
let infoPack = MBP.unpack( auth_hmac , Meta.AUTH_HMAC )
|
|
40
|
-
if(!infoPack){
|
|
41
|
-
this.send_auth_fail( peer ,'unpack auth_pack fail');
|
|
42
|
-
return
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let id = ""
|
|
46
|
-
if( infoPack.id8.includes(0)){
|
|
47
|
-
id = decoder.decode( infoPack.id8.subarray( 0, infoPack.id8.indexOf(0) ) );
|
|
48
|
-
}else{
|
|
49
|
-
id = decoder.decode( infoPack.id8 );
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
//2. get key of id from DB
|
|
53
|
-
let authInfo = await this.getAuth( id )
|
|
54
|
-
|
|
55
|
-
// console.log('##### authInfo',authInfo )
|
|
56
|
-
if(serverOption.debug.showAuthInfo ){
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if( !authInfo ){
|
|
60
|
-
this.send_auth_fail( peer , 'NO ID:'+ id);
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// console.log('db authInfo.key: ', authInfo.key)
|
|
65
|
-
peer.boho.copy_id8( infoPack.id8 )
|
|
66
|
-
// type of key
|
|
67
|
-
let authKey ;
|
|
68
|
-
const SHA256_HASH_BASE64_LEN = 44
|
|
69
|
-
if( authInfo.key.length == SHA256_HASH_BASE64_LEN){
|
|
70
|
-
// hashed key
|
|
71
|
-
authKey = Buffer.from( authInfo.key, 'base64')
|
|
72
|
-
peer.boho.copy_key( authKey )
|
|
73
|
-
}else{
|
|
74
|
-
// plain key
|
|
75
|
-
peer.boho.set_key( authInfo.key )
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
//3. check hmac
|
|
79
|
-
// console.log('-- found: authKey of id: ', id, authKey.toString('hex'))
|
|
80
|
-
let auth_ack = peer.boho.check_auth_hmac( infoPack )
|
|
81
|
-
|
|
82
|
-
// console.log('auth_ack', auth_ack )
|
|
83
|
-
if( !auth_ack ){
|
|
84
|
-
this.send_auth_fail( peer, 'hmac dismatched' );
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
//4. get info
|
|
89
|
-
// console.log('#### auth success' )
|
|
90
|
-
|
|
91
|
-
//5. check duplicate login.
|
|
92
|
-
// current policy. Deny duplicate login
|
|
93
|
-
|
|
94
|
-
// duplicate login policy.
|
|
95
|
-
// 1. send clear_auth signal to the old connection.
|
|
96
|
-
// 2. close old connection.
|
|
97
|
-
// 3. close new connection. retry from begining.
|
|
98
|
-
if( peer.manager.cid2remote.has( authInfo.cid ) ){
|
|
99
|
-
let old = peer.manager.cid2remote.get(authInfo.cid )
|
|
100
|
-
if( old == peer ){
|
|
101
|
-
console.log('## trying RELOGIN with SAME ID. ignored.')
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
console.log('### clear_auth and close old connection:', old.cid )
|
|
105
|
-
old.send( Buffer.from( [ IOMsg.SERVER_CLEAR_AUTH ]))
|
|
106
|
-
old.close()
|
|
107
|
-
peer.close() // auto relogin
|
|
108
|
-
return
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
//6. delete current (temp rand)cid if exist.
|
|
113
|
-
if( peer.cid ){
|
|
114
|
-
peer.manager.cid2remote.delete( peer.cid )
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
//7. setting info.
|
|
118
|
-
peer.did = id
|
|
119
|
-
peer.cid = authInfo.cid
|
|
120
|
-
peer.nick = authInfo.cid // temporary: nick as cid
|
|
121
|
-
|
|
122
|
-
//8. setting quota level.
|
|
123
|
-
let quotaLevel = serverOption.defaultQuotaIndex;
|
|
124
|
-
if(authInfo.level) quotaLevel = authInfo.level;
|
|
125
|
-
quotaLevel = parseInt( quotaLevel )
|
|
126
|
-
let newQuota = quotaTable[ quotaLevel ];
|
|
127
|
-
if(!newQuota){
|
|
128
|
-
let err = 'no index quotaTable for auth.level: ' + quotaLevel
|
|
129
|
-
console.log('##AUTH:DATA ERROR##', err)
|
|
130
|
-
this.send_auth_fail( peer, err );
|
|
131
|
-
return
|
|
132
|
-
}else{
|
|
133
|
-
peer.level = quotaLevel;
|
|
134
|
-
peer.quota = newQuota;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if( peer.level === serverOption.adminLevel){
|
|
138
|
-
console.log('## LOGIN ADMIN CID:', peer.cid )
|
|
139
|
-
peer.isAdmin = true;
|
|
140
|
-
}
|
|
141
|
-
// console.log('auth: peer.quota', peer.quota )
|
|
142
|
-
// send quota.level
|
|
143
|
-
peer.send( Buffer.from( [IOMsg.QUOTA_LEVEL, quotaLevel] ))
|
|
144
|
-
|
|
145
|
-
//9. set cid2remote
|
|
146
|
-
peer.manager.cid2remote.set( peer.cid , peer )
|
|
147
|
-
// console.log( 'done: cid2remote:', peer.manager.cid2remote.keys() )
|
|
148
|
-
// console.log("LOGIN: ", `id: ${ peer.did}(${peer.cid})` )
|
|
149
|
-
//10. send ack.
|
|
150
|
-
peer.send( auth_ack )
|
|
151
|
-
peer.setState( CLIENT_STATE.AUTH_READY )
|
|
152
|
-
if( this.authLogger ){
|
|
153
|
-
let peerInfo = `OK #${peer.ssid} cid: ${peer.cid} did:${ peer.did }`
|
|
154
|
-
if( peer.isAdmin ) peerInfo = "#ADMIN# "+ peerInfo
|
|
155
|
-
this.authLogger.log( peerInfo )
|
|
156
|
-
}
|
|
157
|
-
return authInfo
|
|
158
|
-
} catch (error) {
|
|
159
|
-
this.send_auth_fail( peer , 'caught: unknown error' + error );
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
1
|
+
/**
|
|
2
|
+
* BohoAuth
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { MBP } from 'meta-buffer-pack'
|
|
6
|
+
import { BohoMsg , Meta } from 'boho'
|
|
7
|
+
import { quotaTable } from '../common/quotaTable.js'
|
|
8
|
+
import { serverOption } from '../server/serverOption.js'
|
|
9
|
+
import { IOMsg ,CLIENT_STATE } from '../common/constants.js'
|
|
10
|
+
import { FileLogger } from '../server/FileLogger.js'
|
|
11
|
+
|
|
12
|
+
const decoder = new TextDecoder()
|
|
13
|
+
export class BohoAuth{
|
|
14
|
+
constructor(){
|
|
15
|
+
this.authLogger;
|
|
16
|
+
if( serverOption.fileLogger.auth.use ){
|
|
17
|
+
this.authLogger = new FileLogger( serverOption.fileLogger.auth.path)
|
|
18
|
+
console.log('Auth: begin file logger.[auth]')
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
send_auth_fail( peer , reason){
|
|
23
|
+
if( this.authLogger ){
|
|
24
|
+
let peerInfo = `FAIL #${peer.ssid} reason:${reason} `
|
|
25
|
+
this.authLogger.log( peerInfo )
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log('## AUTH_FAIL reason:', reason )
|
|
29
|
+
// peer.send( Buffer.from( [BohoMsg.AUTH_FAIL] ))
|
|
30
|
+
peer.setState( CLIENT_STATE.AUTH_FAIL )
|
|
31
|
+
setTimeout(e=>{
|
|
32
|
+
peer.send( Buffer.from( [BohoMsg.AUTH_FAIL] ))
|
|
33
|
+
}, serverOption.auth.delay_auth_fail )
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async verify_auth_hmac( auth_hmac , peer ){
|
|
37
|
+
try {
|
|
38
|
+
//1. unpack
|
|
39
|
+
let infoPack = MBP.unpack( auth_hmac , Meta.AUTH_HMAC )
|
|
40
|
+
if(!infoPack){
|
|
41
|
+
this.send_auth_fail( peer ,'unpack auth_pack fail');
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let id = ""
|
|
46
|
+
if( infoPack.id8.includes(0)){
|
|
47
|
+
id = decoder.decode( infoPack.id8.subarray( 0, infoPack.id8.indexOf(0) ) );
|
|
48
|
+
}else{
|
|
49
|
+
id = decoder.decode( infoPack.id8 );
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//2. get key of id from DB
|
|
53
|
+
let authInfo = await this.getAuth( id )
|
|
54
|
+
|
|
55
|
+
// console.log('##### authInfo',authInfo )
|
|
56
|
+
if(serverOption.debug.showAuthInfo ){
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if( !authInfo ){
|
|
60
|
+
this.send_auth_fail( peer , 'NO ID:'+ id);
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// console.log('db authInfo.key: ', authInfo.key)
|
|
65
|
+
peer.boho.copy_id8( infoPack.id8 )
|
|
66
|
+
// type of key
|
|
67
|
+
let authKey ;
|
|
68
|
+
const SHA256_HASH_BASE64_LEN = 44
|
|
69
|
+
if( authInfo.key.length == SHA256_HASH_BASE64_LEN){
|
|
70
|
+
// hashed key
|
|
71
|
+
authKey = Buffer.from( authInfo.key, 'base64')
|
|
72
|
+
peer.boho.copy_key( authKey )
|
|
73
|
+
}else{
|
|
74
|
+
// plain key
|
|
75
|
+
peer.boho.set_key( authInfo.key )
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//3. check hmac
|
|
79
|
+
// console.log('-- found: authKey of id: ', id, authKey.toString('hex'))
|
|
80
|
+
let auth_ack = peer.boho.check_auth_hmac( infoPack )
|
|
81
|
+
|
|
82
|
+
// console.log('auth_ack', auth_ack )
|
|
83
|
+
if( !auth_ack ){
|
|
84
|
+
this.send_auth_fail( peer, 'hmac dismatched' );
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//4. get info
|
|
89
|
+
// console.log('#### auth success' )
|
|
90
|
+
|
|
91
|
+
//5. check duplicate login.
|
|
92
|
+
// current policy. Deny duplicate login
|
|
93
|
+
|
|
94
|
+
// duplicate login policy.
|
|
95
|
+
// 1. send clear_auth signal to the old connection.
|
|
96
|
+
// 2. close old connection.
|
|
97
|
+
// 3. close new connection. retry from begining.
|
|
98
|
+
if( peer.manager.cid2remote.has( authInfo.cid ) ){
|
|
99
|
+
let old = peer.manager.cid2remote.get(authInfo.cid )
|
|
100
|
+
if( old == peer ){
|
|
101
|
+
console.log('## trying RELOGIN with SAME ID. ignored.')
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
console.log('### clear_auth and close old connection:', old.cid )
|
|
105
|
+
old.send( Buffer.from( [ IOMsg.SERVER_CLEAR_AUTH ]))
|
|
106
|
+
old.close()
|
|
107
|
+
peer.close() // auto relogin
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
//6. delete current (temp rand)cid if exist.
|
|
113
|
+
if( peer.cid ){
|
|
114
|
+
peer.manager.cid2remote.delete( peer.cid )
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//7. setting info.
|
|
118
|
+
peer.did = id
|
|
119
|
+
peer.cid = authInfo.cid
|
|
120
|
+
peer.nick = authInfo.cid // temporary: nick as cid
|
|
121
|
+
|
|
122
|
+
//8. setting quota level.
|
|
123
|
+
let quotaLevel = serverOption.defaultQuotaIndex;
|
|
124
|
+
if(authInfo.level) quotaLevel = authInfo.level;
|
|
125
|
+
quotaLevel = parseInt( quotaLevel )
|
|
126
|
+
let newQuota = quotaTable[ quotaLevel ];
|
|
127
|
+
if(!newQuota){
|
|
128
|
+
let err = 'no index quotaTable for auth.level: ' + quotaLevel
|
|
129
|
+
console.log('##AUTH:DATA ERROR##', err)
|
|
130
|
+
this.send_auth_fail( peer, err );
|
|
131
|
+
return
|
|
132
|
+
}else{
|
|
133
|
+
peer.level = quotaLevel;
|
|
134
|
+
peer.quota = newQuota;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if( peer.level === serverOption.adminLevel){
|
|
138
|
+
console.log('## LOGIN ADMIN CID:', peer.cid )
|
|
139
|
+
peer.isAdmin = true;
|
|
140
|
+
}
|
|
141
|
+
// console.log('auth: peer.quota', peer.quota )
|
|
142
|
+
// send quota.level
|
|
143
|
+
peer.send( Buffer.from( [IOMsg.QUOTA_LEVEL, quotaLevel] ))
|
|
144
|
+
|
|
145
|
+
//9. set cid2remote
|
|
146
|
+
peer.manager.cid2remote.set( peer.cid , peer )
|
|
147
|
+
// console.log( 'done: cid2remote:', peer.manager.cid2remote.keys() )
|
|
148
|
+
// console.log("LOGIN: ", `id: ${ peer.did}(${peer.cid})` )
|
|
149
|
+
//10. send ack.
|
|
150
|
+
peer.send( auth_ack )
|
|
151
|
+
peer.setState( CLIENT_STATE.AUTH_READY )
|
|
152
|
+
if( this.authLogger ){
|
|
153
|
+
let peerInfo = `OK #${peer.ssid} cid: ${peer.cid} did:${ peer.did }`
|
|
154
|
+
if( peer.isAdmin ) peerInfo = "#ADMIN# "+ peerInfo
|
|
155
|
+
this.authLogger.log( peerInfo )
|
|
156
|
+
}
|
|
157
|
+
return authInfo
|
|
158
|
+
} catch (error) {
|
|
159
|
+
this.send_auth_fail( peer , 'caught: unknown error' + error );
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
}
|
|
168
|
+
|
package/src/client/CongPacket.js
CHANGED
|
@@ -1,150 +1,150 @@
|
|
|
1
|
-
import { Transform } from 'stream'
|
|
2
|
-
import { MBP } from 'meta-buffer-pack'
|
|
3
|
-
|
|
4
|
-
export const CongType = {
|
|
5
|
-
TYPE_LEN1: 1,
|
|
6
|
-
TYPE_LEN2: 2,
|
|
7
|
-
TYPE_LEN3: 3,
|
|
8
|
-
TYPE_LEN4: 4
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// support LittleEndian system.
|
|
12
|
-
export function pack(payload) {
|
|
13
|
-
|
|
14
|
-
if (payload.byteLength < 256) { //one byte len
|
|
15
|
-
return MBP.pack(
|
|
16
|
-
MBP.MB('#type', '8', CongType.TYPE_LEN1),
|
|
17
|
-
MBP.MB('#payloadLen1', '8', payload.byteLength),
|
|
18
|
-
MBP.MB('#payload', payload)
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
} else if (payload.byteLength < 65536) { // 2bytes len
|
|
22
|
-
return MBP.pack(
|
|
23
|
-
MBP.MB('#type', '8', CongType.TYPE_LEN2),
|
|
24
|
-
MBP.MB('#payloadLen2', '16L', payload.byteLength),
|
|
25
|
-
MBP.MB('#payload', payload)
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
} else if (payload.byteLength < 2 ** 24) { // 3bytes len
|
|
29
|
-
let len4Buffer = Buffer.alloc(4)
|
|
30
|
-
len4Buffer.writeUint32LE( payload.byteLength )
|
|
31
|
-
let cropLen3 = len4Buffer.subarray(0,3)
|
|
32
|
-
return MBP.pack(
|
|
33
|
-
MBP.MB('#type', '8', CongType.TYPE_LEN3),
|
|
34
|
-
MBP.MB('#payloadLen3', cropLen3),
|
|
35
|
-
MBP.MB('#payload', payload)
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
} else { //use 4 bytes.
|
|
39
|
-
return MBP.pack(
|
|
40
|
-
MBP.MB('#type', '8', CongType.TYPE_LEN4),
|
|
41
|
-
MBP.MB('#payloadLen4', '32L', payload.byteLength),
|
|
42
|
-
MBP.MB('#payload', payload)
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// let totalCong = 0;
|
|
49
|
-
|
|
50
|
-
export class CongRx extends Transform {
|
|
51
|
-
constructor(options) {
|
|
52
|
-
super(options)
|
|
53
|
-
// console.log('new congRx. totalCong:', ++totalCong )
|
|
54
|
-
this.buffer = Buffer.alloc(0)
|
|
55
|
-
this.frames = []
|
|
56
|
-
this.rxi = 0;
|
|
57
|
-
this.rxi_zero = 0;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
_transform(chunk, encoding, callback) {
|
|
63
|
-
this.addData(chunk)
|
|
64
|
-
if (this.frames.length > 0) {
|
|
65
|
-
this.frames.forEach(frame => {
|
|
66
|
-
// console.log('emit frame:', frame)
|
|
67
|
-
this.push(frame)
|
|
68
|
-
})
|
|
69
|
-
this.frames = []
|
|
70
|
-
}
|
|
71
|
-
callback()
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
addData(chunk) {
|
|
76
|
-
// console.log('congpack chunk:', chunk )
|
|
77
|
-
let c = chunk.byteLength;
|
|
78
|
-
let i = 0;
|
|
79
|
-
while( c-- ){
|
|
80
|
-
this.rxi++
|
|
81
|
-
if( chunk[ i++ ] == 0 ){
|
|
82
|
-
this.rxi_zero++
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (this.buffer.byteLength > 0) {
|
|
87
|
-
this.buffer = Buffer.concat([this.buffer, chunk])
|
|
88
|
-
} else {
|
|
89
|
-
this.buffer = chunk
|
|
90
|
-
}
|
|
91
|
-
// console.log('buffer before parse', this.buffer )
|
|
92
|
-
this.parse()
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
parse() {
|
|
97
|
-
let head = this.buffer[0]
|
|
98
|
-
let headerLen;
|
|
99
|
-
let payloadSize;
|
|
100
|
-
// find header
|
|
101
|
-
// console.log('>> parser head, buffer:', head , this.buffer )
|
|
102
|
-
|
|
103
|
-
if (head == CongType.TYPE_LEN1) {
|
|
104
|
-
headerLen = 2;
|
|
105
|
-
if (this.buffer.byteLength < headerLen) return;
|
|
106
|
-
payloadSize = this.buffer.readUint8(1)
|
|
107
|
-
|
|
108
|
-
} else if (head == CongType.TYPE_LEN2) {
|
|
109
|
-
headerLen = 3;
|
|
110
|
-
if (this.buffer.byteLength < headerLen) return;
|
|
111
|
-
payloadSize = this.buffer.readUint16LE(1)
|
|
112
|
-
|
|
113
|
-
} else if (head == CongType.TYPE_LEN3) {
|
|
114
|
-
headerLen = 4;
|
|
115
|
-
if (this.buffer.byteLength < headerLen) return;
|
|
116
|
-
payloadSize = this.buffer.readUint16LE(1) + this.buffer.readUint8(3) * 65536
|
|
117
|
-
|
|
118
|
-
} else if (head == CongType.TYPE_LEN4) {
|
|
119
|
-
headerLen = 5;
|
|
120
|
-
if (this.buffer.byteLength < headerLen) return;
|
|
121
|
-
payloadSize = this.buffer.readUint32LE(1)
|
|
122
|
-
|
|
123
|
-
} else {
|
|
124
|
-
// console.log('CongPacket: UNKNOWN_HEAD drop', this.buffer)
|
|
125
|
-
this.emit('wrong',this.buffer)
|
|
126
|
-
this.buffer = Buffer.alloc(0)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (payloadSize == this.buffer.byteLength - headerLen) {
|
|
131
|
-
this.frames.push(this.buffer.subarray(headerLen))
|
|
132
|
-
this.buffer = Buffer.alloc(0)
|
|
133
|
-
return
|
|
134
|
-
} else if (payloadSize < this.buffer.byteLength - headerLen) {
|
|
135
|
-
this.frames.push(this.buffer.subarray(headerLen, headerLen + payloadSize))
|
|
136
|
-
this.buffer = this.buffer.subarray(headerLen + payloadSize)
|
|
137
|
-
this.parse()
|
|
138
|
-
} else {
|
|
139
|
-
//not ready
|
|
140
|
-
// console.log('+')
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
1
|
+
import { Transform } from 'stream'
|
|
2
|
+
import { MBP } from 'meta-buffer-pack'
|
|
3
|
+
|
|
4
|
+
export const CongType = {
|
|
5
|
+
TYPE_LEN1: 1,
|
|
6
|
+
TYPE_LEN2: 2,
|
|
7
|
+
TYPE_LEN3: 3,
|
|
8
|
+
TYPE_LEN4: 4
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// support LittleEndian system.
|
|
12
|
+
export function pack(payload) {
|
|
13
|
+
|
|
14
|
+
if (payload.byteLength < 256) { //one byte len
|
|
15
|
+
return MBP.pack(
|
|
16
|
+
MBP.MB('#type', '8', CongType.TYPE_LEN1),
|
|
17
|
+
MBP.MB('#payloadLen1', '8', payload.byteLength),
|
|
18
|
+
MBP.MB('#payload', payload)
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
} else if (payload.byteLength < 65536) { // 2bytes len
|
|
22
|
+
return MBP.pack(
|
|
23
|
+
MBP.MB('#type', '8', CongType.TYPE_LEN2),
|
|
24
|
+
MBP.MB('#payloadLen2', '16L', payload.byteLength),
|
|
25
|
+
MBP.MB('#payload', payload)
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
} else if (payload.byteLength < 2 ** 24) { // 3bytes len
|
|
29
|
+
let len4Buffer = Buffer.alloc(4)
|
|
30
|
+
len4Buffer.writeUint32LE( payload.byteLength )
|
|
31
|
+
let cropLen3 = len4Buffer.subarray(0,3)
|
|
32
|
+
return MBP.pack(
|
|
33
|
+
MBP.MB('#type', '8', CongType.TYPE_LEN3),
|
|
34
|
+
MBP.MB('#payloadLen3', cropLen3),
|
|
35
|
+
MBP.MB('#payload', payload)
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
} else { //use 4 bytes.
|
|
39
|
+
return MBP.pack(
|
|
40
|
+
MBP.MB('#type', '8', CongType.TYPE_LEN4),
|
|
41
|
+
MBP.MB('#payloadLen4', '32L', payload.byteLength),
|
|
42
|
+
MBP.MB('#payload', payload)
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// let totalCong = 0;
|
|
49
|
+
|
|
50
|
+
export class CongRx extends Transform {
|
|
51
|
+
constructor(options) {
|
|
52
|
+
super(options)
|
|
53
|
+
// console.log('new congRx. totalCong:', ++totalCong )
|
|
54
|
+
this.buffer = Buffer.alloc(0)
|
|
55
|
+
this.frames = []
|
|
56
|
+
this.rxi = 0;
|
|
57
|
+
this.rxi_zero = 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
_transform(chunk, encoding, callback) {
|
|
63
|
+
this.addData(chunk)
|
|
64
|
+
if (this.frames.length > 0) {
|
|
65
|
+
this.frames.forEach(frame => {
|
|
66
|
+
// console.log('emit frame:', frame)
|
|
67
|
+
this.push(frame)
|
|
68
|
+
})
|
|
69
|
+
this.frames = []
|
|
70
|
+
}
|
|
71
|
+
callback()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
addData(chunk) {
|
|
76
|
+
// console.log('congpack chunk:', chunk )
|
|
77
|
+
let c = chunk.byteLength;
|
|
78
|
+
let i = 0;
|
|
79
|
+
while( c-- ){
|
|
80
|
+
this.rxi++
|
|
81
|
+
if( chunk[ i++ ] == 0 ){
|
|
82
|
+
this.rxi_zero++
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (this.buffer.byteLength > 0) {
|
|
87
|
+
this.buffer = Buffer.concat([this.buffer, chunk])
|
|
88
|
+
} else {
|
|
89
|
+
this.buffer = chunk
|
|
90
|
+
}
|
|
91
|
+
// console.log('buffer before parse', this.buffer )
|
|
92
|
+
this.parse()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
parse() {
|
|
97
|
+
let head = this.buffer[0]
|
|
98
|
+
let headerLen;
|
|
99
|
+
let payloadSize;
|
|
100
|
+
// find header
|
|
101
|
+
// console.log('>> parser head, buffer:', head , this.buffer )
|
|
102
|
+
|
|
103
|
+
if (head == CongType.TYPE_LEN1) {
|
|
104
|
+
headerLen = 2;
|
|
105
|
+
if (this.buffer.byteLength < headerLen) return;
|
|
106
|
+
payloadSize = this.buffer.readUint8(1)
|
|
107
|
+
|
|
108
|
+
} else if (head == CongType.TYPE_LEN2) {
|
|
109
|
+
headerLen = 3;
|
|
110
|
+
if (this.buffer.byteLength < headerLen) return;
|
|
111
|
+
payloadSize = this.buffer.readUint16LE(1)
|
|
112
|
+
|
|
113
|
+
} else if (head == CongType.TYPE_LEN3) {
|
|
114
|
+
headerLen = 4;
|
|
115
|
+
if (this.buffer.byteLength < headerLen) return;
|
|
116
|
+
payloadSize = this.buffer.readUint16LE(1) + this.buffer.readUint8(3) * 65536
|
|
117
|
+
|
|
118
|
+
} else if (head == CongType.TYPE_LEN4) {
|
|
119
|
+
headerLen = 5;
|
|
120
|
+
if (this.buffer.byteLength < headerLen) return;
|
|
121
|
+
payloadSize = this.buffer.readUint32LE(1)
|
|
122
|
+
|
|
123
|
+
} else {
|
|
124
|
+
// console.log('CongPacket: UNKNOWN_HEAD drop', this.buffer)
|
|
125
|
+
this.emit('wrong',this.buffer)
|
|
126
|
+
this.buffer = Buffer.alloc(0)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if (payloadSize == this.buffer.byteLength - headerLen) {
|
|
131
|
+
this.frames.push(this.buffer.subarray(headerLen))
|
|
132
|
+
this.buffer = Buffer.alloc(0)
|
|
133
|
+
return
|
|
134
|
+
} else if (payloadSize < this.buffer.byteLength - headerLen) {
|
|
135
|
+
this.frames.push(this.buffer.subarray(headerLen, headerLen + payloadSize))
|
|
136
|
+
this.buffer = this.buffer.subarray(headerLen + payloadSize)
|
|
137
|
+
this.parse()
|
|
138
|
+
} else {
|
|
139
|
+
//not ready
|
|
140
|
+
// console.log('+')
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|