1- import { getInt64 , setInt64 } from "./utils/int" ;
2- import { ExtData } from "./ExtData" ;
3-
4- export const EXT_TIMESTAMP = - 1 ;
5-
6- function isDate ( object : unknown ) : object is Date {
7- return object instanceof Date ;
8- }
9-
10- export type TimeSpec = {
11- sec : number ;
12- nsec : number ;
13- } ;
14-
15- const TIMESTAMP32_MAX_SEC = 0x100000000 ; // 32-bit unsigned int
16- const TIMESTAMP64_MAX_SEC = 0x400000000 ; // 34-bit unsigned int
17-
18- export function encodeTimestampFromTimeSpec ( { sec, nsec } : TimeSpec ) : Uint8Array {
19- if ( sec >= 0 && nsec >= 0 && sec < TIMESTAMP64_MAX_SEC ) {
20- // Here sec >= 0 && nsec >= 0
21- if ( nsec === 0 && sec < TIMESTAMP32_MAX_SEC ) {
22- // timestamp 32 = { sec32 (unsigned) }
23- const rv = new Uint8Array ( 4 ) ;
24- const view = new DataView ( rv . buffer ) ;
25- view . setUint32 ( 0 , sec ) ;
26- return rv ;
27- } else {
28- // timestamp 64 = { nsec30 (unsigned), sec34 (unsigned) }
29- const secHigh = sec / 0x100000000 ;
30- const secLow = sec & 0xffffffff ;
31- const rv = new Uint8Array ( 8 ) ;
32- const view = new DataView ( rv . buffer ) ;
33- // nsec30 | secHigh2
34- view . setUint32 ( 0 , ( nsec << 2 ) | ( secHigh & 0x3 ) ) ;
35- // secLow32
36- view . setUint32 ( 4 , secLow ) ;
37- return rv ;
38- }
39- } else {
40- // timestamp 96 = { nsec32 (unsigned), sec64 (signed) }
41- const rv = new Uint8Array ( 12 ) ;
42- const view = new DataView ( rv . buffer ) ;
43- view . setUint32 ( 0 , nsec ) ;
44- setInt64 ( view , 4 , sec ) ;
45- return rv ;
46- }
47- }
48-
49- export function encodeDateToTimeSpec ( date : Date ) : TimeSpec {
50- const msec = date . getTime ( ) ;
51- const sec = Math . floor ( msec / 1000 ) ;
52- const nsec = ( msec - sec * 1000 ) * 1e6 ;
53-
54- // Normalizes { sec, nsec } to ensure nsec is unsigned.
55- const nsecInSec = Math . floor ( nsec / 1e9 ) ;
56- return {
57- sec : sec + nsecInSec ,
58- nsec : nsec - nsecInSec * 1e9 ,
59- } ;
60- }
61-
62- export const encodeTimestampExtension : ExtensionEncoderType = ( object : unknown ) => {
63- if ( isDate ( object ) ) {
64- const timeSpec = encodeDateToTimeSpec ( object ) ;
65- return encodeTimestampFromTimeSpec ( timeSpec ) ;
66- } else {
67- return null ;
68- }
69- } ;
70-
71- // https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type
72- export const decodeTimestampExtension : ExtensionDecoderType = ( data : Uint8Array ) => {
73- // data may be 32, 64, or 96 bits
74- switch ( data . byteLength ) {
75- case 4 : {
76- // timestamp 32 = { sec32 }
77- const view = new DataView ( data . buffer , data . byteOffset , data . byteLength ) ;
78- const sec = view . getUint32 ( 0 ) ;
79- return new Date ( sec * 1000 ) ;
80- }
81- case 8 : {
82- // timestamp 64 = { nsec30, sec34 }
83- const view = new DataView ( data . buffer , data . byteOffset , data . byteLength ) ;
1+ // ExtensionCodec to handle MessagePack extensions
842
85- const nsec30AndSecHigh2 = view . getUint32 ( 0 ) ;
86- const secLow32 = view . getUint32 ( 4 ) ;
87- const nsec = nsec30AndSecHigh2 >>> 2 ;
88- const sec = ( nsec30AndSecHigh2 & 0x3 ) * 0x100000000 + secLow32 ;
89- return new Date ( sec * 1000 + nsec / 1e6 ) ;
90- }
91- case 12 : {
92- // timestamp 96 = { nsec32 (unsigned), sec64 (signed) }
93- const view = new DataView ( data . buffer , data . byteOffset , data . byteLength ) ;
94-
95- const nsec = view . getUint32 ( 0 ) ;
96- const sec = getInt64 ( view , 4 ) ;
97-
98- return new Date ( sec * 1000 + nsec / 1e6 ) ;
99- }
100- default :
101- throw new Error ( `Unrecognized data size for timestamp: ${ data . length } ` ) ;
102- }
103- } ;
3+ import { ExtData } from "./ExtData" ;
4+ import { timestampExtension } from "./timestamp" ;
1045
105- // extensionType is signed 8-bit integer
106- export type ExtensionDecoderType = ( data : Uint8Array , extensionType : number ) => any ;
6+ export type ExtensionDecoderType = ( data : Uint8Array , extensionType : number ) => unknown ;
1077
1088export type ExtensionEncoderType = ( input : unknown ) => Uint8Array | null ;
1099
@@ -125,11 +25,7 @@ export class ExtensionCodec implements ExtensionCodecType {
12525 private readonly decoders : Array < ExtensionDecoderType > = [ ] ;
12626
12727 public constructor ( ) {
128- this . register ( {
129- type : EXT_TIMESTAMP ,
130- encode : encodeTimestampExtension ,
131- decode : decodeTimestampExtension ,
132- } ) ;
28+ this . register ( timestampExtension ) ;
13329 }
13430
13531 public register ( {
0 commit comments