kawanet / msgpack-lite

Fast Pure JavaScript MessagePack Encoder and Decoder / msgpack.org[JavaScript]
https://www.npmjs.com/package/msgpack-lite
MIT License
979 stars 126 forks source link

Implement MessagePack timestamp extension #87

Open dchenk opened 6 years ago

dchenk commented 6 years ago

The MessagePack has for a while now had a built-in timestamp extension: https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type

Are there any plans to implement the timestamp format? I'd be especially excited about the 0xc7 version.

kawanet commented 6 years ago

Yes, I've been working for it. I'll retry to merge it in this month.

ygoe commented 6 years ago

I've just stumbled across this as well, in my very first experiments with this. It doesn't seem easy to decode that 30/34 bit structure in JavaScript without putting almost every bit manually where it belongs. Do you have any code public to have a look at it while I'm writing a workaround?

Update: This seems to work for 8-byte-values: (I have only checked it down to the seconds)

if (time.type === 255 && time.buffer.length === 8) {
    var ns = (message.data.time.buffer[0] << 22) +
        (message.data.time.buffer[1] << 14) +
        (message.data.time.buffer[2] << 6) +
        (message.data.time.buffer[3] >> 2);
    var sec = ((message.data.time.buffer[3] & 0x3) << 32) +
        (message.data.time.buffer[4] << 24) +
        (message.data.time.buffer[5] << 16) +
        (message.data.time.buffer[6] << 8) +
        message.data.time.buffer[7];
    time = new Date(sec * 1000 + ns / 1000000);
}
ygoe commented 6 years ago

Revisited this. Here's my code that should be able to decode all three timestamp formats. It only handles a single value deserialised from MessagePack. It needs to be integrated into the deserialiser to work transparently on all data.

JavaScript can be a beast when it comes to numeric data. Hence all the funny extra bitwise operators and DWORD pairs in there. Learned a thing or two today.

I'm currently writing my own little MessagePack codec in JavaScript. The encoder is complete as of today (incl. timestamp support) and has only 250 loc. The whole thing should reach 1/10th of the size of this library. I can't say anything about its performance yet though.

var data = msgpack.decode(array);
if (data.type === 255) {
    switch (data.buffer.length) {
        case 4:
            let sec = ((data.buffer[0] << 24) >>> 0) +
                ((data.buffer[1] << 16) >>> 0) +
                ((data.buffer[2] << 8) >>> 0) +
                data.buffer[3];
            console.log("sec", sec);
            data = new Date(sec * 1000);
            break;
        case 8:
            let ns = ((data.buffer[0] << 22) >>> 0) +
                ((data.buffer[1] << 14) >>> 0) +
                ((data.buffer[2] << 6) >>> 0) +
                (data.buffer[3] >>> 2);
            let pow32 = 0x100000000;   // 2^32
            let sec = ((data.buffer[3] & 0x3) * pow32) +
                ((data.buffer[4] << 24) >>> 0) +
                ((data.buffer[5] << 16) >>> 0) +
                ((data.buffer[6] << 8) >>> 0) +
                data.buffer[7];
            console.log("sec", sec, "ns", ns);
            data = new Date(sec * 1000 + ns / 1000000);
            break;
        case 12:
            let ns = ((data.buffer[0] << 24) >>> 0) +
                ((data.buffer[1] << 16) >>> 0) +
                ((data.buffer[2] << 8) >>> 0) +
                data.buffer[3];
            let pow32 = 0x100000000;   // 2^32
            let hi = ((data.buffer[4] << 24) >>> 0) +
                ((data.buffer[5] << 16) >>> 0) +
                ((data.buffer[6] << 8) >>> 0) +
                data.buffer[7];
            let lo = ((data.buffer[8] << 24) >>> 0) +
                ((data.buffer[9] << 16) >>> 0) +
                ((data.buffer[10] << 8) >>> 0) +
                data.buffer[11];
            let sec = hi * pow32 + lo;
            console.log("sec", sec, "ns", ns);
            data = new Date(sec * 1000 + ns / 1000000);
            break;
        default:
            throw "Unsupported timestamp data length.";
    }
}

(Warning: I have rearranged this code for showing it here. This exact code is untested.)

ygoe commented 5 years ago

Just for information and maybe a reference implementation, I have now published my MessagePack codec for JavaScript: https://github.com/ygoe/msgpack.js