@leofcoin/codec-format-interface 1.0.1
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/.gitattributes +2 -0
- package/LICENSE +21 -0
- package/README.md +2 -0
- package/dist/index.js +523 -0
- package/package.json +33 -0
- package/rollup.config.js +7 -0
- package/src/basic-interface.js +123 -0
- package/src/codec-format-interface.js +93 -0
- package/src/codec-hash.js +127 -0
- package/src/codec.js +94 -0
- package/src/codecs.js +79 -0
- package/src/index.js +7 -0
- package/test/test.js +9 -0
package/.gitattributes
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 vandeurenglenn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var bs32 = require('@vandeurenglenn/base32');
|
|
4
|
+
var bs58 = require('@vandeurenglenn/base58');
|
|
5
|
+
var isHex = require('@vandeurenglenn/is-hex');
|
|
6
|
+
var varint = require('varint');
|
|
7
|
+
var createKeccakHash = require('keccak');
|
|
8
|
+
|
|
9
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
10
|
+
|
|
11
|
+
var bs32__default = /*#__PURE__*/_interopDefaultLegacy(bs32);
|
|
12
|
+
var bs58__default = /*#__PURE__*/_interopDefaultLegacy(bs58);
|
|
13
|
+
var isHex__default = /*#__PURE__*/_interopDefaultLegacy(isHex);
|
|
14
|
+
var varint__default = /*#__PURE__*/_interopDefaultLegacy(varint);
|
|
15
|
+
var createKeccakHash__default = /*#__PURE__*/_interopDefaultLegacy(createKeccakHash);
|
|
16
|
+
|
|
17
|
+
class BasicInterface {
|
|
18
|
+
#handleDecode() {
|
|
19
|
+
if (!this.decode) throw new Error('bad implementation: needs decode func')
|
|
20
|
+
this.decode();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#handleEncode() {
|
|
24
|
+
if (!this.encode) throw new Error('bad implementation: needs encode func')
|
|
25
|
+
this.encode();
|
|
26
|
+
}
|
|
27
|
+
isHex(string) {
|
|
28
|
+
return isHex__default["default"](string)
|
|
29
|
+
}
|
|
30
|
+
isBase32(string) {
|
|
31
|
+
return base32.isBase32(string)
|
|
32
|
+
}
|
|
33
|
+
isBase58(string) {
|
|
34
|
+
return base58.isBase32(string)
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @param {String} encoded
|
|
38
|
+
*/
|
|
39
|
+
fromBs32(encoded) {
|
|
40
|
+
this.encoded = bs32__default["default"].decode(encoded);
|
|
41
|
+
return this.#handleDecode()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {String} encoded
|
|
46
|
+
*/
|
|
47
|
+
fromBs58(encoded) {
|
|
48
|
+
this.encoded = bs58__default["default"].decode(encoded);
|
|
49
|
+
return this.#handleDecode()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async toArray() {
|
|
53
|
+
const array = [];
|
|
54
|
+
for await (const value of this.encoded.values()) {
|
|
55
|
+
array.push(value);
|
|
56
|
+
}
|
|
57
|
+
return array
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fromString(string) {
|
|
61
|
+
this.encoded = new Uint8Array(string.split(','));
|
|
62
|
+
return this.#handleDecode()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fromArray(array) {
|
|
66
|
+
this.encoded = new Uint8Array([...array]);
|
|
67
|
+
return this.#handleDecode()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {Buffer} encoded
|
|
72
|
+
*/
|
|
73
|
+
fromEncoded(encoded) {
|
|
74
|
+
this.encoded = encoded;
|
|
75
|
+
return this.#handleDecode()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @param {String} encoded
|
|
80
|
+
*/
|
|
81
|
+
fromHex(encoded) {
|
|
82
|
+
this.encoded = Buffer.from(encoded, 'hex');
|
|
83
|
+
return this.#handleDecode()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
toString(encoding = 'utf8') {
|
|
87
|
+
if (!this.encoded) this.#handleEncode();
|
|
88
|
+
return this.encoded.toString(encoding)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @return {String} encoded
|
|
93
|
+
*/
|
|
94
|
+
toHex() {
|
|
95
|
+
return this.toString('hex')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @return {String} encoded
|
|
100
|
+
*/
|
|
101
|
+
toBs32() {
|
|
102
|
+
if (!this.encoded) this.#handleEncode();
|
|
103
|
+
return bs32__default["default"].encode(this.encoded)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @return {String} encoded
|
|
108
|
+
*/
|
|
109
|
+
toBs58() {
|
|
110
|
+
if (!this.encoded) this.#handleEncode();
|
|
111
|
+
return bs58__default["default"].encode(this.encoded)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @param {Object} data
|
|
116
|
+
*/
|
|
117
|
+
create(data) {
|
|
118
|
+
const decoded = {};
|
|
119
|
+
if (this.keys?.length > 0) {
|
|
120
|
+
for (const key of this.keys) {
|
|
121
|
+
Object.defineProperties(decoded, {
|
|
122
|
+
[key]: {
|
|
123
|
+
enumerable: true,
|
|
124
|
+
configurable: true,
|
|
125
|
+
set: (val) => value = data[key],
|
|
126
|
+
get: () => data[key]
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
this.decoded = decoded;
|
|
132
|
+
this.encode();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
var codecs = {
|
|
138
|
+
// just a hash
|
|
139
|
+
'disco-hash': {
|
|
140
|
+
codec: parseInt('30', 16),
|
|
141
|
+
hashAlg: 'dbl-keccak-256', // ,
|
|
142
|
+
// testnet: 'olivia'
|
|
143
|
+
},
|
|
144
|
+
'peernet-peer-response': {
|
|
145
|
+
codec: parseInt('707072', 16),
|
|
146
|
+
hashAlg: 'keccak-256',
|
|
147
|
+
},
|
|
148
|
+
'peernet-peer': {
|
|
149
|
+
codec: parseInt('7070', 16),
|
|
150
|
+
hashAlg: 'keccak-256',
|
|
151
|
+
},
|
|
152
|
+
'peernet-dht': {
|
|
153
|
+
codec: parseInt('706468', 16),
|
|
154
|
+
hashAlg: 'keccak-256',
|
|
155
|
+
},
|
|
156
|
+
'peernet-dht-response': {
|
|
157
|
+
codec: parseInt('706472', 16),
|
|
158
|
+
hashAlg: 'keccak-256',
|
|
159
|
+
},
|
|
160
|
+
// data
|
|
161
|
+
'peernet-data': {
|
|
162
|
+
codec: parseInt('706461', 16),
|
|
163
|
+
hashAlg: 'keccak-256',
|
|
164
|
+
},
|
|
165
|
+
'peernet-data-response': {
|
|
166
|
+
codec: parseInt('70646172', 16),
|
|
167
|
+
hashAlg: 'keccak-256',
|
|
168
|
+
},
|
|
169
|
+
// message
|
|
170
|
+
'peernet-message': {
|
|
171
|
+
codec: parseInt('706d65', 16),
|
|
172
|
+
hashAlg: 'keccak-256',
|
|
173
|
+
},
|
|
174
|
+
// pubsub
|
|
175
|
+
'peernet-ps': {
|
|
176
|
+
codec: parseInt('707073', 16),
|
|
177
|
+
hashAlg: 'keccak-256',
|
|
178
|
+
},
|
|
179
|
+
'peernet-response': {
|
|
180
|
+
codec: parseInt('7072', 16),
|
|
181
|
+
hashAlg: 'keccak-256',
|
|
182
|
+
},
|
|
183
|
+
'peernet-request': {
|
|
184
|
+
codec: parseInt('707271', 16),
|
|
185
|
+
hashAlg: 'keccak-256',
|
|
186
|
+
},
|
|
187
|
+
// normal block
|
|
188
|
+
'leofcoin-block': {
|
|
189
|
+
codec: parseInt('6c62', 16),
|
|
190
|
+
hashAlg: 'dbl-keccak-512', // ,
|
|
191
|
+
// testnet: 'olivia'
|
|
192
|
+
},
|
|
193
|
+
'leofcoin-tx': {
|
|
194
|
+
codec: parseInt('6c74', 16),
|
|
195
|
+
hashAlg: 'dbl-keccak-512', // ,
|
|
196
|
+
// testnet: 'olivia'
|
|
197
|
+
},
|
|
198
|
+
// itx
|
|
199
|
+
'leofcoin-itx': {
|
|
200
|
+
codec: parseInt('6c69', 16),
|
|
201
|
+
hashAlg: 'keccak-512', // ,
|
|
202
|
+
// testnet: 'olivia'
|
|
203
|
+
},
|
|
204
|
+
// peer reputation
|
|
205
|
+
'leofcoin-pr': {
|
|
206
|
+
codec: parseInt('6c70', 16),
|
|
207
|
+
hashAlg: 'keccak-256', // ,
|
|
208
|
+
// testnet: 'olivia'
|
|
209
|
+
},
|
|
210
|
+
// chat message
|
|
211
|
+
'chat-message': {
|
|
212
|
+
codec: parseInt('636d', 16),
|
|
213
|
+
hashAlg: 'dbl-keccak-256',
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
class PeernetCodec extends BasicInterface {
|
|
218
|
+
get codecs() {
|
|
219
|
+
return {...globalThis.peernet.codecs, ...codecs}
|
|
220
|
+
}
|
|
221
|
+
constructor(buffer) {
|
|
222
|
+
super();
|
|
223
|
+
if (buffer) {
|
|
224
|
+
if (buffer instanceof Uint8Array) {
|
|
225
|
+
const codec = varint__default["default"].decode(buffer);
|
|
226
|
+
const name = this.getCodecName(codec);
|
|
227
|
+
if (name) {
|
|
228
|
+
this.name = name;
|
|
229
|
+
this.encoded = buffer;
|
|
230
|
+
this.decode(buffer);
|
|
231
|
+
} else {
|
|
232
|
+
this.encode(buffer);
|
|
233
|
+
}
|
|
234
|
+
} else if (buffer instanceof ArrayBuffer) {
|
|
235
|
+
const encoded = new Uint8Array(buffer.byteLength);
|
|
236
|
+
|
|
237
|
+
for (let i = 0; i < buffer.byteLength; i++) {
|
|
238
|
+
encoded[i] = buffer[i];
|
|
239
|
+
}
|
|
240
|
+
this.encoded = encoded;
|
|
241
|
+
// this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
|
|
242
|
+
this.decode(buffer);
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
if (typeof buffer === 'string') {
|
|
246
|
+
if (this.codecs[buffer]) this.fromName(buffer);
|
|
247
|
+
else if (this.isHex(buffer)) this.fromHex(buffer);
|
|
248
|
+
else if (this.isBase32(buffer)) this.fromBs32(buffer);
|
|
249
|
+
else if (this.isBase58(buffer)) this.fromBs58(buffer);
|
|
250
|
+
else throw new Error(`unsupported string ${buffer}`)
|
|
251
|
+
}
|
|
252
|
+
if (!isNaN(buffer)) if (this.codecs[this.getCodecName(buffer)]) this.fromCodec(buffer);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
fromEncoded(encoded) {
|
|
257
|
+
const codec = varint__default["default"].decode(encoded);
|
|
258
|
+
const name = this.getCodecName(codec);
|
|
259
|
+
this.name = name;
|
|
260
|
+
this.encoded = encoded;
|
|
261
|
+
this.decode(encoded);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
getCodec(name) {
|
|
265
|
+
return this.codecs[name].codec
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
getCodecName(codec) {
|
|
269
|
+
return Object.keys(this.codecs).reduce((p, c) => {
|
|
270
|
+
const item = this.codecs[c];
|
|
271
|
+
if (item.codec === codec) return c;
|
|
272
|
+
else return p;
|
|
273
|
+
}, undefined)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
getHashAlg(name) {
|
|
277
|
+
return this.codecs[name].hashAlg
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
fromCodec(codec) {
|
|
281
|
+
this.name = this.getCodecName(codec);
|
|
282
|
+
this.hashAlg = this.getHashAlg(this.name);
|
|
283
|
+
|
|
284
|
+
this.codec = this.getCodec(this.name);
|
|
285
|
+
this.codecBuffer = varint__default["default"].encode(codec);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
fromName(name) {
|
|
289
|
+
const codec = this.getCodec(name);
|
|
290
|
+
this.name = name;
|
|
291
|
+
this.codec = codec;
|
|
292
|
+
this.hashAlg = this.getHashAlg(name);
|
|
293
|
+
this.codecBuffer = varint__default["default"].encode(codec);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
decode() {
|
|
297
|
+
const codec = varint__default["default"].decode(this.encoded);
|
|
298
|
+
this.fromCodec(codec);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
encode() {
|
|
302
|
+
const codec = varint__default["default"].encode(this.decoded);
|
|
303
|
+
this.encoded = codec;
|
|
304
|
+
return this.encoded
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
class CodecHash extends BasicInterface {
|
|
309
|
+
constructor(buffer, options = {}) {
|
|
310
|
+
super();
|
|
311
|
+
if (options.name) this.name = options.name;
|
|
312
|
+
else this.name = 'disco-hash';
|
|
313
|
+
if (options.codecs) this.codecs = options.codecs;
|
|
314
|
+
if (buffer) {
|
|
315
|
+
if (buffer instanceof Uint8Array) {
|
|
316
|
+
this.discoCodec = new PeernetCodec(buffer, this.codecs);
|
|
317
|
+
const name = this.discoCodec.name;
|
|
318
|
+
|
|
319
|
+
if (name) {
|
|
320
|
+
this.name = name;
|
|
321
|
+
this.decode(buffer);
|
|
322
|
+
} else {
|
|
323
|
+
this.encode(buffer);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (typeof buffer === 'string') {
|
|
328
|
+
if (this.isHex(buffer)) this.fromHex(buffer);
|
|
329
|
+
if (this.isBase32(buffer)) this.fromBs32(buffer);
|
|
330
|
+
else if (this.isBase58(buffer)) this.fromBs58(buffer);
|
|
331
|
+
else throw new Error(`unsupported string ${buffer}`)
|
|
332
|
+
} else if (typeof buffer === 'object') this.fromJSON(buffer);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
get prefix() {
|
|
337
|
+
const length = this.length;
|
|
338
|
+
const uint8Array = new Uint8Array(length.length + this.discoCodec.codecBuffer.length);
|
|
339
|
+
uint8Array.set(length);
|
|
340
|
+
uint8Array.set(this.discoCodec.codecBuffer, length.length);
|
|
341
|
+
|
|
342
|
+
return uint8Array
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
get length() {
|
|
346
|
+
return varint__default["default"].encode(this.size)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
get buffer() {
|
|
350
|
+
return this.encoded
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
get hash() {
|
|
354
|
+
return this.encoded
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
fromJSON(json) {
|
|
358
|
+
return this.encode(Buffer.from(JSON.stringify(json)))
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
encode(buffer, name) {
|
|
362
|
+
if (!this.name && name) this.name = name;
|
|
363
|
+
if (!buffer) buffer = this.buffer;
|
|
364
|
+
this.discoCodec = new PeernetCodec(this.name, this.codecs);
|
|
365
|
+
this.discoCodec.fromName(this.name);
|
|
366
|
+
let hashAlg = this.discoCodec.hashAlg;
|
|
367
|
+
if (hashAlg.includes('dbl')) {
|
|
368
|
+
hashAlg = hashAlg.replace('dbl-', '');
|
|
369
|
+
buffer = createKeccakHash__default["default"](hashAlg.replace('-', '')).update(buffer).digest();
|
|
370
|
+
}
|
|
371
|
+
this.digest = createKeccakHash__default["default"](hashAlg.replace('-', '')).update(buffer).digest();
|
|
372
|
+
this.size = this.digest.length;
|
|
373
|
+
|
|
374
|
+
this.codec = this.discoCodec.encode();
|
|
375
|
+
this.codec = this.discoCodec.codecBuffer;
|
|
376
|
+
const uint8Array = new Uint8Array(this.digest.length + this.prefix.length);
|
|
377
|
+
uint8Array.set(this.prefix);
|
|
378
|
+
uint8Array.set(this.digest, this.prefix.length);
|
|
379
|
+
|
|
380
|
+
this.encoded = uint8Array;
|
|
381
|
+
|
|
382
|
+
return this.encoded
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
validate(buffer) {
|
|
386
|
+
if (Buffer.isBuffer(buffer)) {
|
|
387
|
+
const codec = varint__default["default"].decode(buffer);
|
|
388
|
+
if (this.codecs[codec]) {
|
|
389
|
+
this.decode(buffer);
|
|
390
|
+
} else {
|
|
391
|
+
this.encode(buffer);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (typeof buffer === 'string') {
|
|
395
|
+
if (this.isHex(buffer)) this.fromHex(buffer);
|
|
396
|
+
if (this.isBase32(buffer)) this.fromBs32(buffer);
|
|
397
|
+
}
|
|
398
|
+
if (typeof buffer === 'object') this.fromJSON(buffer);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
decode(buffer) {
|
|
402
|
+
this.encoded = buffer;
|
|
403
|
+
const codec = varint__default["default"].decode(buffer);
|
|
404
|
+
|
|
405
|
+
this.discoCodec = new PeernetCodec(codec, this.codecs);
|
|
406
|
+
// TODO: validate codec
|
|
407
|
+
buffer = buffer.slice(varint__default["default"].decode.bytes);
|
|
408
|
+
this.size = varint__default["default"].decode(buffer);
|
|
409
|
+
this.digest = buffer.slice(varint__default["default"].decode.bytes);
|
|
410
|
+
if (this.digest.length !== this.size) {
|
|
411
|
+
throw new Error(`hash length inconsistent: 0x${this.encoded.toString('hex')}`)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// const discoCodec = new Codec(codec, this.codecs)
|
|
415
|
+
|
|
416
|
+
this.name = this.discoCodec.name;
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
this.size = this.digest.length;
|
|
420
|
+
|
|
421
|
+
return {
|
|
422
|
+
codec: this.codec,
|
|
423
|
+
name: this.name,
|
|
424
|
+
size: this.size,
|
|
425
|
+
length: this.length,
|
|
426
|
+
digest: this.digest,
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
class FormatInterface extends BasicInterface {
|
|
432
|
+
/**
|
|
433
|
+
* @param {Buffer|String|Object} buffer - data - The data needed to create the desired message
|
|
434
|
+
* @param {Object} proto - {encode, decode}
|
|
435
|
+
* @param {Object} options - {hashFormat, name}
|
|
436
|
+
*/
|
|
437
|
+
constructor(buffer, proto, options = {}) {
|
|
438
|
+
super();
|
|
439
|
+
this.protoEncode = proto.encode;
|
|
440
|
+
this.protoDecode = proto.decode;
|
|
441
|
+
this.hashFormat = options.hashFormat || 'bs32';
|
|
442
|
+
if (options.name) this.name = options.name;
|
|
443
|
+
if (buffer instanceof Uint8Array) this.fromUint8Array(buffer);
|
|
444
|
+
else if (buffer instanceof ArrayBuffer) this.fromArrayBuffer(buffer);
|
|
445
|
+
else if (buffer.name === options.name) return buffer
|
|
446
|
+
else if (buffer instanceof String) {
|
|
447
|
+
if (this.isHex(buffer)) this.fromHex(buffer);
|
|
448
|
+
else if (this.isBase32(buffer)) this.fromBs32(buffer);
|
|
449
|
+
else if (this.isBase58(buffer)) this.fromBs58(buffer);
|
|
450
|
+
else throw new Error(`unsupported string ${buffer}`)
|
|
451
|
+
} else {
|
|
452
|
+
this.create(buffer);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* @return {PeernetHash}
|
|
458
|
+
*/
|
|
459
|
+
get peernetHash() {
|
|
460
|
+
return new CodecHash(this.decoded, {name: this.name})
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* @return {peernetHash}
|
|
465
|
+
*/
|
|
466
|
+
get hash() {
|
|
467
|
+
const upper = this.hashFormat.charAt(0).toUpperCase();
|
|
468
|
+
const format = `${upper}${this.hashFormat.substring(1, this.hashFormat.length)}`;
|
|
469
|
+
return this.peernetHash[`to${format}`]()
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* @return {Object}
|
|
474
|
+
*/
|
|
475
|
+
decode() {
|
|
476
|
+
let encoded = this.encoded;
|
|
477
|
+
const discoCodec = new PeernetCodec(this.encoded);
|
|
478
|
+
encoded = encoded.slice(discoCodec.codecBuffer.length);
|
|
479
|
+
this.name = discoCodec.name;
|
|
480
|
+
this.decoded = this.protoDecode(encoded);
|
|
481
|
+
return this.decoded
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* @return {Buffer}
|
|
486
|
+
*/
|
|
487
|
+
encode(decoded) {
|
|
488
|
+
if (!decoded) decoded = this.decoded;
|
|
489
|
+
const codec = new PeernetCodec(this.name);
|
|
490
|
+
const encoded = this.protoEncode(decoded);
|
|
491
|
+
const uint8Array = new Uint8Array(encoded.length + codec.codecBuffer.length);
|
|
492
|
+
uint8Array.set(codec.codecBuffer);
|
|
493
|
+
uint8Array.set(encoded, codec.codecBuffer.length);
|
|
494
|
+
this.encoded = uint8Array;
|
|
495
|
+
return this.encoded
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
hasCodec() {
|
|
499
|
+
if (!this.encoded) return false
|
|
500
|
+
const codec = new PeernetCodec(this.encoded);
|
|
501
|
+
if (codec.name) return true
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
fromUint8Array(buffer) {
|
|
505
|
+
this.encoded = buffer;
|
|
506
|
+
if (!this.hasCodec()) this.create(
|
|
507
|
+
JSON.parse(new TextDecoder().decode(this.encoded))
|
|
508
|
+
);
|
|
509
|
+
else this.decode();
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
fromArrayBuffer(buffer) {
|
|
513
|
+
this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength);
|
|
514
|
+
if (!this.hasCodec()) this.create(
|
|
515
|
+
JSON.parse(new TextDecoder().decode(this.encoded))
|
|
516
|
+
);
|
|
517
|
+
else this.decode();
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
var index = { codecs, Codec: PeernetCodec, CodecHash, FormatInterface, BasicInterface };
|
|
522
|
+
|
|
523
|
+
module.exports = index;
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@leofcoin/codec-format-interface",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "src/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
+
"c": "rollup -c"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/leofcoin/codec-format-interface.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [],
|
|
16
|
+
"author": "",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/leofcoin/codec-format-interface/issues"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/leofcoin/codec-format-interface#readme",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@vandeurenglenn/base32": "^1.1.0",
|
|
24
|
+
"@vandeurenglenn/base58": "^1.1.0",
|
|
25
|
+
"@vandeurenglenn/is-hex": "^1.0.0",
|
|
26
|
+
"keccak": "^3.0.2",
|
|
27
|
+
"varint": "^6.0.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"rollup": "^2.74.1",
|
|
31
|
+
"tape": "^5.5.3"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import bs32 from '@vandeurenglenn/base32';
|
|
2
|
+
import bs58 from '@vandeurenglenn/base58';
|
|
3
|
+
import isHex from '@vandeurenglenn/is-hex';
|
|
4
|
+
|
|
5
|
+
export default class BasicInterface {
|
|
6
|
+
#handleDecode() {
|
|
7
|
+
if (!this.decode) throw new Error('bad implementation: needs decode func')
|
|
8
|
+
this.decode()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
#handleEncode() {
|
|
12
|
+
if (!this.encode) throw new Error('bad implementation: needs encode func')
|
|
13
|
+
this.encode()
|
|
14
|
+
}
|
|
15
|
+
isHex(string) {
|
|
16
|
+
return isHex(string)
|
|
17
|
+
}
|
|
18
|
+
isBase32(string) {
|
|
19
|
+
return base32.isBase32(string)
|
|
20
|
+
}
|
|
21
|
+
isBase58(string) {
|
|
22
|
+
return base58.isBase32(string)
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* @param {String} encoded
|
|
26
|
+
*/
|
|
27
|
+
fromBs32(encoded) {
|
|
28
|
+
this.encoded = bs32.decode(encoded)
|
|
29
|
+
return this.#handleDecode()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {String} encoded
|
|
34
|
+
*/
|
|
35
|
+
fromBs58(encoded) {
|
|
36
|
+
this.encoded = bs58.decode(encoded)
|
|
37
|
+
return this.#handleDecode()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async toArray() {
|
|
41
|
+
const array = []
|
|
42
|
+
for await (const value of this.encoded.values()) {
|
|
43
|
+
array.push(value)
|
|
44
|
+
}
|
|
45
|
+
return array
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fromString(string) {
|
|
49
|
+
this.encoded = new Uint8Array(string.split(','))
|
|
50
|
+
return this.#handleDecode()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fromArray(array) {
|
|
54
|
+
this.encoded = new Uint8Array([...array])
|
|
55
|
+
return this.#handleDecode()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {Buffer} encoded
|
|
60
|
+
*/
|
|
61
|
+
fromEncoded(encoded) {
|
|
62
|
+
this.encoded = encoded
|
|
63
|
+
return this.#handleDecode()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {String} encoded
|
|
68
|
+
*/
|
|
69
|
+
fromHex(encoded) {
|
|
70
|
+
this.encoded = Buffer.from(encoded, 'hex')
|
|
71
|
+
return this.#handleDecode()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
toString(encoding = 'utf8') {
|
|
75
|
+
if (!this.encoded) this.#handleEncode()
|
|
76
|
+
return this.encoded.toString(encoding)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @return {String} encoded
|
|
81
|
+
*/
|
|
82
|
+
toHex() {
|
|
83
|
+
return this.toString('hex')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @return {String} encoded
|
|
88
|
+
*/
|
|
89
|
+
toBs32() {
|
|
90
|
+
if (!this.encoded) this.#handleEncode()
|
|
91
|
+
return bs32.encode(this.encoded)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @return {String} encoded
|
|
96
|
+
*/
|
|
97
|
+
toBs58() {
|
|
98
|
+
if (!this.encoded) this.#handleEncode()
|
|
99
|
+
return bs58.encode(this.encoded)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {Object} data
|
|
104
|
+
*/
|
|
105
|
+
create(data) {
|
|
106
|
+
const decoded = {}
|
|
107
|
+
if (this.keys?.length > 0) {
|
|
108
|
+
for (const key of this.keys) {
|
|
109
|
+
Object.defineProperties(decoded, {
|
|
110
|
+
[key]: {
|
|
111
|
+
enumerable: true,
|
|
112
|
+
configurable: true,
|
|
113
|
+
set: (val) => value = data[key],
|
|
114
|
+
get: () => data[key]
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
this.decoded = decoded
|
|
120
|
+
this.encode()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import BasicInterface from './basic-interface.js'
|
|
2
|
+
import Codec from './codec.js';
|
|
3
|
+
import Hash from './codec-hash.js'
|
|
4
|
+
|
|
5
|
+
export default class FormatInterface extends BasicInterface {
|
|
6
|
+
/**
|
|
7
|
+
* @param {Buffer|String|Object} buffer - data - The data needed to create the desired message
|
|
8
|
+
* @param {Object} proto - {encode, decode}
|
|
9
|
+
* @param {Object} options - {hashFormat, name}
|
|
10
|
+
*/
|
|
11
|
+
constructor(buffer, proto, options = {}) {
|
|
12
|
+
super()
|
|
13
|
+
this.protoEncode = proto.encode
|
|
14
|
+
this.protoDecode = proto.decode
|
|
15
|
+
this.hashFormat = options.hashFormat || 'bs32'
|
|
16
|
+
if (options.name) this.name = options.name
|
|
17
|
+
if (buffer instanceof Uint8Array) this.fromUint8Array(buffer)
|
|
18
|
+
else if (buffer instanceof ArrayBuffer) this.fromArrayBuffer(buffer)
|
|
19
|
+
else if (buffer.name === options.name) return buffer
|
|
20
|
+
else if (buffer instanceof String) {
|
|
21
|
+
if (this.isHex(buffer)) this.fromHex(buffer)
|
|
22
|
+
else if (this.isBase32(buffer)) this.fromBs32(buffer)
|
|
23
|
+
else if (this.isBase58(buffer)) this.fromBs58(buffer)
|
|
24
|
+
else throw new Error(`unsupported string ${buffer}`)
|
|
25
|
+
} else {
|
|
26
|
+
this.create(buffer)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @return {PeernetHash}
|
|
32
|
+
*/
|
|
33
|
+
get peernetHash() {
|
|
34
|
+
return new Hash(this.decoded, {name: this.name})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @return {peernetHash}
|
|
39
|
+
*/
|
|
40
|
+
get hash() {
|
|
41
|
+
const upper = this.hashFormat.charAt(0).toUpperCase()
|
|
42
|
+
const format = `${upper}${this.hashFormat.substring(1, this.hashFormat.length)}`
|
|
43
|
+
return this.peernetHash[`to${format}`]()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @return {Object}
|
|
48
|
+
*/
|
|
49
|
+
decode() {
|
|
50
|
+
let encoded = this.encoded;
|
|
51
|
+
const discoCodec = new Codec(this.encoded)
|
|
52
|
+
encoded = encoded.slice(discoCodec.codecBuffer.length)
|
|
53
|
+
this.name = discoCodec.name
|
|
54
|
+
this.decoded = this.protoDecode(encoded)
|
|
55
|
+
return this.decoded
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @return {Buffer}
|
|
60
|
+
*/
|
|
61
|
+
encode(decoded) {
|
|
62
|
+
if (!decoded) decoded = this.decoded;
|
|
63
|
+
const codec = new Codec(this.name)
|
|
64
|
+
const encoded = this.protoEncode(decoded)
|
|
65
|
+
const uint8Array = new Uint8Array(encoded.length + codec.codecBuffer.length)
|
|
66
|
+
uint8Array.set(codec.codecBuffer)
|
|
67
|
+
uint8Array.set(encoded, codec.codecBuffer.length)
|
|
68
|
+
this.encoded = uint8Array
|
|
69
|
+
return this.encoded
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
hasCodec() {
|
|
73
|
+
if (!this.encoded) return false
|
|
74
|
+
const codec = new Codec(this.encoded)
|
|
75
|
+
if (codec.name) return true
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fromUint8Array(buffer) {
|
|
79
|
+
this.encoded = buffer
|
|
80
|
+
if (!this.hasCodec()) this.create(
|
|
81
|
+
JSON.parse(new TextDecoder().decode(this.encoded))
|
|
82
|
+
)
|
|
83
|
+
else this.decode()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fromArrayBuffer(buffer) {
|
|
87
|
+
this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
|
|
88
|
+
if (!this.hasCodec()) this.create(
|
|
89
|
+
JSON.parse(new TextDecoder().decode(this.encoded))
|
|
90
|
+
)
|
|
91
|
+
else this.decode()
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import createKeccakHash from 'keccak';
|
|
2
|
+
import varint from 'varint';
|
|
3
|
+
import BasicInterface from './basic-interface.js'
|
|
4
|
+
import Codec from './codec';
|
|
5
|
+
|
|
6
|
+
export default class CodecHash extends BasicInterface {
|
|
7
|
+
constructor(buffer, options = {}) {
|
|
8
|
+
super()
|
|
9
|
+
if (options.name) this.name = options.name
|
|
10
|
+
else this.name = 'disco-hash'
|
|
11
|
+
if (options.codecs) this.codecs = options.codecs
|
|
12
|
+
if (buffer) {
|
|
13
|
+
if (buffer instanceof Uint8Array) {
|
|
14
|
+
this.discoCodec = new Codec(buffer, this.codecs)
|
|
15
|
+
const name = this.discoCodec.name
|
|
16
|
+
|
|
17
|
+
if (name) {
|
|
18
|
+
this.name = name
|
|
19
|
+
this.decode(buffer)
|
|
20
|
+
} else {
|
|
21
|
+
this.encode(buffer)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (typeof buffer === 'string') {
|
|
26
|
+
if (this.isHex(buffer)) this.fromHex(buffer)
|
|
27
|
+
if (this.isBase32(buffer)) this.fromBs32(buffer)
|
|
28
|
+
else if (this.isBase58(buffer)) this.fromBs58(buffer)
|
|
29
|
+
else throw new Error(`unsupported string ${buffer}`)
|
|
30
|
+
} else if (typeof buffer === 'object') this.fromJSON(buffer)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get prefix() {
|
|
35
|
+
const length = this.length
|
|
36
|
+
const uint8Array = new Uint8Array(length.length + this.discoCodec.codecBuffer.length)
|
|
37
|
+
uint8Array.set(length)
|
|
38
|
+
uint8Array.set(this.discoCodec.codecBuffer, length.length)
|
|
39
|
+
|
|
40
|
+
return uint8Array
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get length() {
|
|
44
|
+
return varint.encode(this.size)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get buffer() {
|
|
48
|
+
return this.encoded
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get hash() {
|
|
52
|
+
return this.encoded
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fromJSON(json) {
|
|
56
|
+
return this.encode(Buffer.from(JSON.stringify(json)))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
encode(buffer, name) {
|
|
60
|
+
if (!this.name && name) this.name = name;
|
|
61
|
+
if (!buffer) buffer = this.buffer;
|
|
62
|
+
this.discoCodec = new Codec(this.name, this.codecs)
|
|
63
|
+
this.discoCodec.fromName(this.name)
|
|
64
|
+
let hashAlg = this.discoCodec.hashAlg
|
|
65
|
+
if (hashAlg.includes('dbl')) {
|
|
66
|
+
hashAlg = hashAlg.replace('dbl-', '')
|
|
67
|
+
buffer = createKeccakHash(hashAlg.replace('-', '')).update(buffer).digest()
|
|
68
|
+
}
|
|
69
|
+
this.digest = createKeccakHash(hashAlg.replace('-', '')).update(buffer).digest()
|
|
70
|
+
this.size = this.digest.length
|
|
71
|
+
|
|
72
|
+
this.codec = this.discoCodec.encode();
|
|
73
|
+
this.codec = this.discoCodec.codecBuffer
|
|
74
|
+
const uint8Array = new Uint8Array(this.digest.length + this.prefix.length)
|
|
75
|
+
uint8Array.set(this.prefix)
|
|
76
|
+
uint8Array.set(this.digest, this.prefix.length)
|
|
77
|
+
|
|
78
|
+
this.encoded = uint8Array
|
|
79
|
+
|
|
80
|
+
return this.encoded
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
validate(buffer) {
|
|
84
|
+
if (Buffer.isBuffer(buffer)) {
|
|
85
|
+
const codec = varint.decode(buffer);
|
|
86
|
+
if (this.codecs[codec]) {
|
|
87
|
+
this.decode(buffer)
|
|
88
|
+
} else {
|
|
89
|
+
this.encode(buffer)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (typeof buffer === 'string') {
|
|
93
|
+
if (this.isHex(buffer)) this.fromHex(buffer)
|
|
94
|
+
if (this.isBase32(buffer)) this.fromBs32(buffer)
|
|
95
|
+
}
|
|
96
|
+
if (typeof buffer === 'object') this.fromJSON(buffer)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
decode(buffer) {
|
|
100
|
+
this.encoded = buffer
|
|
101
|
+
const codec = varint.decode(buffer);
|
|
102
|
+
|
|
103
|
+
this.discoCodec = new Codec(codec, this.codecs)
|
|
104
|
+
// TODO: validate codec
|
|
105
|
+
buffer = buffer.slice(varint.decode.bytes);
|
|
106
|
+
this.size = varint.decode(buffer);
|
|
107
|
+
this.digest = buffer.slice(varint.decode.bytes);
|
|
108
|
+
if (this.digest.length !== this.size) {
|
|
109
|
+
throw new Error(`hash length inconsistent: 0x${this.encoded.toString('hex')}`)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// const discoCodec = new Codec(codec, this.codecs)
|
|
113
|
+
|
|
114
|
+
this.name = this.discoCodec.name
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
this.size = this.digest.length
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
codec: this.codec,
|
|
121
|
+
name: this.name,
|
|
122
|
+
size: this.size,
|
|
123
|
+
length: this.length,
|
|
124
|
+
digest: this.digest,
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/codec.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import varint from 'varint';
|
|
2
|
+
import codecs from './codecs.js'
|
|
3
|
+
import BasicInterface from './basic-interface.js'
|
|
4
|
+
|
|
5
|
+
export default class PeernetCodec extends BasicInterface {
|
|
6
|
+
get codecs() {
|
|
7
|
+
return {...globalThis.peernet.codecs, ...codecs}
|
|
8
|
+
}
|
|
9
|
+
constructor(buffer) {
|
|
10
|
+
super()
|
|
11
|
+
if (buffer) {
|
|
12
|
+
if (buffer instanceof Uint8Array) {
|
|
13
|
+
const codec = varint.decode(buffer);
|
|
14
|
+
const name = this.getCodecName(codec)
|
|
15
|
+
if (name) {
|
|
16
|
+
this.name = name
|
|
17
|
+
this.encoded = buffer
|
|
18
|
+
this.decode(buffer)
|
|
19
|
+
} else {
|
|
20
|
+
this.encode(buffer)
|
|
21
|
+
}
|
|
22
|
+
} else if (buffer instanceof ArrayBuffer) {
|
|
23
|
+
const encoded = new Uint8Array(buffer.byteLength)
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < buffer.byteLength; i++) {
|
|
26
|
+
encoded[i] = buffer[i]
|
|
27
|
+
}
|
|
28
|
+
this.encoded = encoded
|
|
29
|
+
// this.encoded = new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength)
|
|
30
|
+
this.decode(buffer)
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
if (typeof buffer === 'string') {
|
|
34
|
+
if (this.codecs[buffer]) this.fromName(buffer)
|
|
35
|
+
else if (this.isHex(buffer)) this.fromHex(buffer)
|
|
36
|
+
else if (this.isBase32(buffer)) this.fromBs32(buffer)
|
|
37
|
+
else if (this.isBase58(buffer)) this.fromBs58(buffer)
|
|
38
|
+
else throw new Error(`unsupported string ${buffer}`)
|
|
39
|
+
}
|
|
40
|
+
if (!isNaN(buffer)) if (this.codecs[this.getCodecName(buffer)]) this.fromCodec(buffer)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fromEncoded(encoded) {
|
|
45
|
+
const codec = varint.decode(encoded);
|
|
46
|
+
const name = this.getCodecName(codec)
|
|
47
|
+
this.name = name
|
|
48
|
+
this.encoded = encoded
|
|
49
|
+
this.decode(encoded)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getCodec(name) {
|
|
53
|
+
return this.codecs[name].codec
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getCodecName(codec) {
|
|
57
|
+
return Object.keys(this.codecs).reduce((p, c) => {
|
|
58
|
+
const item = this.codecs[c]
|
|
59
|
+
if (item.codec === codec) return c;
|
|
60
|
+
else return p;
|
|
61
|
+
}, undefined)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getHashAlg(name) {
|
|
65
|
+
return this.codecs[name].hashAlg
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fromCodec(codec) {
|
|
69
|
+
this.name = this.getCodecName(codec)
|
|
70
|
+
this.hashAlg = this.getHashAlg(this.name)
|
|
71
|
+
|
|
72
|
+
this.codec = this.getCodec(this.name)
|
|
73
|
+
this.codecBuffer = varint.encode(codec)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fromName(name) {
|
|
77
|
+
const codec = this.getCodec(name)
|
|
78
|
+
this.name = name
|
|
79
|
+
this.codec = codec
|
|
80
|
+
this.hashAlg = this.getHashAlg(name)
|
|
81
|
+
this.codecBuffer = varint.encode(codec)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
decode() {
|
|
85
|
+
const codec = varint.decode(this.encoded);
|
|
86
|
+
this.fromCodec(codec)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
encode() {
|
|
90
|
+
const codec = varint.encode(this.decoded)
|
|
91
|
+
this.encoded = codec
|
|
92
|
+
return this.encoded
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/codecs.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
// just a hash
|
|
3
|
+
'disco-hash': {
|
|
4
|
+
codec: parseInt('30', 16),
|
|
5
|
+
hashAlg: 'dbl-keccak-256', // ,
|
|
6
|
+
// testnet: 'olivia'
|
|
7
|
+
},
|
|
8
|
+
'peernet-peer-response': {
|
|
9
|
+
codec: parseInt('707072', 16),
|
|
10
|
+
hashAlg: 'keccak-256',
|
|
11
|
+
},
|
|
12
|
+
'peernet-peer': {
|
|
13
|
+
codec: parseInt('7070', 16),
|
|
14
|
+
hashAlg: 'keccak-256',
|
|
15
|
+
},
|
|
16
|
+
'peernet-dht': {
|
|
17
|
+
codec: parseInt('706468', 16),
|
|
18
|
+
hashAlg: 'keccak-256',
|
|
19
|
+
},
|
|
20
|
+
'peernet-dht-response': {
|
|
21
|
+
codec: parseInt('706472', 16),
|
|
22
|
+
hashAlg: 'keccak-256',
|
|
23
|
+
},
|
|
24
|
+
// data
|
|
25
|
+
'peernet-data': {
|
|
26
|
+
codec: parseInt('706461', 16),
|
|
27
|
+
hashAlg: 'keccak-256',
|
|
28
|
+
},
|
|
29
|
+
'peernet-data-response': {
|
|
30
|
+
codec: parseInt('70646172', 16),
|
|
31
|
+
hashAlg: 'keccak-256',
|
|
32
|
+
},
|
|
33
|
+
// message
|
|
34
|
+
'peernet-message': {
|
|
35
|
+
codec: parseInt('706d65', 16),
|
|
36
|
+
hashAlg: 'keccak-256',
|
|
37
|
+
},
|
|
38
|
+
// pubsub
|
|
39
|
+
'peernet-ps': {
|
|
40
|
+
codec: parseInt('707073', 16),
|
|
41
|
+
hashAlg: 'keccak-256',
|
|
42
|
+
},
|
|
43
|
+
'peernet-response': {
|
|
44
|
+
codec: parseInt('7072', 16),
|
|
45
|
+
hashAlg: 'keccak-256',
|
|
46
|
+
},
|
|
47
|
+
'peernet-request': {
|
|
48
|
+
codec: parseInt('707271', 16),
|
|
49
|
+
hashAlg: 'keccak-256',
|
|
50
|
+
},
|
|
51
|
+
// normal block
|
|
52
|
+
'leofcoin-block': {
|
|
53
|
+
codec: parseInt('6c62', 16),
|
|
54
|
+
hashAlg: 'dbl-keccak-512', // ,
|
|
55
|
+
// testnet: 'olivia'
|
|
56
|
+
},
|
|
57
|
+
'leofcoin-tx': {
|
|
58
|
+
codec: parseInt('6c74', 16),
|
|
59
|
+
hashAlg: 'dbl-keccak-512', // ,
|
|
60
|
+
// testnet: 'olivia'
|
|
61
|
+
},
|
|
62
|
+
// itx
|
|
63
|
+
'leofcoin-itx': {
|
|
64
|
+
codec: parseInt('6c69', 16),
|
|
65
|
+
hashAlg: 'keccak-512', // ,
|
|
66
|
+
// testnet: 'olivia'
|
|
67
|
+
},
|
|
68
|
+
// peer reputation
|
|
69
|
+
'leofcoin-pr': {
|
|
70
|
+
codec: parseInt('6c70', 16),
|
|
71
|
+
hashAlg: 'keccak-256', // ,
|
|
72
|
+
// testnet: 'olivia'
|
|
73
|
+
},
|
|
74
|
+
// chat message
|
|
75
|
+
'chat-message': {
|
|
76
|
+
codec: parseInt('636d', 16),
|
|
77
|
+
hashAlg: 'dbl-keccak-256',
|
|
78
|
+
},
|
|
79
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import BasicInterface from './basic-interface.js'
|
|
2
|
+
import FormatInterface from './codec-format-interface.js'
|
|
3
|
+
import CodecHash from './codec-hash.js'
|
|
4
|
+
import Codec from './codec.js'
|
|
5
|
+
import codecs from './codecs.js'
|
|
6
|
+
|
|
7
|
+
export default { codecs, Codec, CodecHash, FormatInterface, BasicInterface }
|