jserial
Version:
Fast JSON Serializer
150 lines (130 loc) • 5.06 kB
JavaScript
const Fs = require('fs')
const MsgPackr = require('msgpackr')
const WasmLZ4 = require('./lz4')
const Utility = require('./utility')
class JsonSerializer {
#namespace
#packerOptions
#defaultPacker
#dictionaryPacker
#minHeaderSize = 4
#_getStructures() {
const path = Utility.getCacheStoragePath(this.#namespace, 'SharedStructures.data')
if (Fs.existsSync(path)) {
const rawBuffer = Fs.readFileSync(path)
return this.deserializeTo(this.#defaultPacker, rawBuffer)
} else {
return []
}
}
#_saveStructures(structures) {
const path = Utility.getCacheStoragePath(this.#namespace, 'SharedStructures.data')
const result = this.serializeTo(this.#defaultPacker, structures)
Fs.writeFileSync(path, result)
}
constructor(opts = {}) {
if (typeof opts === "string") {
opts = {
namespace: opts
}
}
this.#namespace = opts.namespace
this.#packerOptions = {
mapsAsObjects: true,
variableMapSize: true,
moreTypes: true,
bundleStrings: true,
...opts.options
}
this.#defaultPacker = new MsgPackr.Packr(this.#packerOptions)
this.#dictionaryPacker = new MsgPackr.Packr({
getStructures: this.#_getStructures.bind(this),
saveStructures: this.#_saveStructures.bind(this),
...this.#packerOptions,
})
}
get defaultPacker() { return this.#defaultPacker }
get dictionaryPacker() { return this.#dictionaryPacker }
/**
* Byte structure
* n0 / Packed Size Header ByteSize
* n1 / Compressed Size Header ByteSize
* s0 / Packed Size
* s1 / Compressed Size
* cb / Compressed Buffer
*
* n0, n1, s0..., s1..., cb
*/
serialize(json) {
return this.serializeTo(this.defaultPacker, json)
}
/**
* @deprecated
*/
serializeHC(json) {
return this.serializeTo(this.defaultPacker, json)
}
serializeSimple(json, highComp = false) {
const packedBuffer = this.defaultPacker.pack(json)
return WasmLZ4.Compress(packedBuffer)
}
serializeWithDictionary(json) {
return this.serializeTo(this.dictionaryPacker, json)
}
serializeTo(packer = this.defaultPacker, json) {
const packedBuffer = packer.pack(json)
const compressedBuffer = WasmLZ4.CompressRaw(packedBuffer)
// Packed Size
const s0 = packedBuffer.length
// Compressed Size
const s1 = compressedBuffer.length
// Packed Size Header ByteSize
const n0 = Utility.getUIntBound(s0)
// Compressed Size Header ByteSize
const n1 = Utility.getUIntBound(s1)
const headerSize = 2 + n0 + n1
const headerBuffer = Buffer.allocUnsafe(headerSize)
let headerBufferIdx = 0
headerBufferIdx = headerBuffer.writeUIntBE(n0, headerBufferIdx, 1)
headerBufferIdx = headerBuffer.writeUIntBE(n1, headerBufferIdx, 1)
headerBufferIdx = headerBuffer.writeUIntBE(s0, headerBufferIdx, n0)
headerBuffer.writeUIntBE(s1, headerBufferIdx, n1)
return Buffer.concat([headerBuffer, compressedBuffer.subarray(0, s1)])
}
deserialize(buffer) {
return this.deserializeTo(this.defaultPacker, buffer)
}
deserializeSimple(buffer) {
const decompressedBuffer = WasmLZ4.Decompress(buffer)
return this.defaultPacker.unpack(decompressedBuffer)
}
deserializeWithDictionary(buffer) {
return this.deserializeTo(this.dictionaryPacker, buffer)
}
deserializeTo(packer = this.defaultPacker, buffer) {
if (!buffer || !Buffer.isBuffer(buffer) || buffer.length < this.#minHeaderSize) return new Error('Buffer is Wrong')
let idx = 0
// Packed Size Header ByteSize
const n0 = buffer.readUIntBE(idx, 1)
// Compressed Size Header ByteSize
const n1 = buffer.readUIntBE(idx += 1, 1)
// Packed Size
const s0 = buffer.readUIntBE(idx += 1, n0)
// Compressed Size
const s1 = buffer.readUIntBE(idx += n0, n1)
const headerSize = 2 + n0 + n1
if (buffer.length !== s1 + headerSize) return new Error('Buffer size is Wrong')
const dataBuffer = buffer.subarray(headerSize)
const decompressed = WasmLZ4.DecompressRaw(s0, dataBuffer)
const decompressedSize = decompressed.length
if (decompressedSize !== s0) return new Error('Buffer size is Wrong')
return packer.unpack(decompressed.subarray(0, decompressedSize))
}
addExtension(extension) {
MsgPackr.addExtension(extension)
}
static addExtension(extension) {
MsgPackr.addExtension(extension)
}
}
module.exports = JsonSerializer