import is from 'is_js' ; import { string as VarString } from "protocol-buffers-encodings" ; import typeToTyp3 from "./encoderHelper" ; import { UVarInt } from './varint' ; export const sortObject = ( obj ) : any => { if ( obj === null ) return null ; if ( typeof obj !== "object" ) return obj ; if ( Array . isArray ( obj ) ) return obj . map ( sortObject ) ; const sortedKeys = Object . keys ( obj ) . sort ( ) ; const result = { } ; sortedKeys . forEach ( ( key ) => { result [ key ] = sortObject ( obj [ key ] ) ; } ) ; return result ; } ; category param num export const encodeNumber = ( num ) => UVarInt . encode ( num ) ; category param b export const encodeBool = ( b ) => b ? UVarInt . encode ( 1 ) : UVarInt . encode ( 0 ) ; category param str export const encodeString = ( str ) => { const buf = Buffer . alloc ( VarString . encodingLength ( str ) ) ; return VarString . encode ( str , buf , 0 ) ; } ; category param value export const encodeTime = ( value ) => { const millis = new Date ( value ) . getTime ( ) ; const seconds = Math . floor ( millis / 1000 ) ; const nanos = Number ( seconds . toString ( ) . padEnd ( 9 , "0" ) ) ; const buffer = Buffer . alloc ( 14 ) ; buffer . writeInt32LE ( ( 1 << 3 ) | 1 , 0 ) ; buffer . writeUInt32LE ( seconds , 1 ) ; buffer . writeInt32LE ( ( 2 << 3 ) | 5 , 9 ) ; buffer . writeUInt32LE ( nanos , 10 ) ; return buffer ; } ; category param obj return export const convertObjectToSignBytes = ( obj ) => Buffer . from ( JSON . stringify ( sortObject ( obj ) ) ) ; category param { Object } obj export const marshalBinary = ( obj ) => { if ( ! is . object ( obj ) ) throw new TypeError ( "data must be an object" ) ; return encodeBinary ( obj , - 1 , true ) . toString ( "hex" ) ; } ; category param { Object } obj export const marshalBinaryBare = ( obj ) => { if ( ! is . object ( obj ) ) throw new TypeError ( "data must be an object" ) ; return encodeBinary ( obj ) . toString ( "hex" ) ; } ; category param { * } js param { Number } field param { Boolean } isByteLenPrefix return { Buffer } export const encodeBinary = ( val , fieldNum ? , isByteLenPrefix ? ) : Buffer => { if ( val === null || val === undefined ) throw new TypeError ( "unsupported type" ) ; if ( Buffer . isBuffer ( val ) ) { if ( isByteLenPrefix ) { return Buffer . concat ( [ UVarInt . encode ( val . length ) , val ] ) ; } return val ; } if ( is . array ( val ) ) { return encodeArrayBinary ( fieldNum , val , isByteLenPrefix ) ; } if ( is . number ( val ) ) { return encodeNumber ( val ) ; } if ( is . boolean ( val ) ) { return encodeBool ( val ) ; } if ( is . string ( val ) ) { return encodeString ( val ) ; } if ( is . object ( val ) ) { return encodeObjectBinary ( val , isByteLenPrefix ) ; } throw new TypeError ( "unsupported type" ) ; } ; category param { Buffer } bytes return { Buffer } export const encodeBinaryByteArray = ( bytes ) : Buffer => { const lenPrefix = bytes . length ; return Buffer . concat ( [ UVarInt . encode ( lenPrefix ) , bytes ] ) ; } ; category param { Object } obj return { Buffer } export const encodeObjectBinary = ( obj , isByteLenPrefix ? ) : Buffer => { const bufferArr = [ ] ; Object . keys ( obj ) . forEach ( ( key , index ) => { if ( key === "msgType" || key === "version" ) return ; if ( isDefaultValue ( obj [ key ] ) ) return ; if ( is . array ( obj [ key ] ) && obj [ key ] . length > 0 ) { bufferArr . push ( encodeArrayBinary ( index , obj [ key ] ) ) ; } else { bufferArr . push ( encodeTypeAndField ( index , obj [ key ] ) ) ; bufferArr . push ( encodeBinary ( obj [ key ] , index , true ) ) ; } } ) ; let bytes = Buffer . concat ( bufferArr ) ; if ( obj . msgType ) { const prefix = Buffer . from ( obj . msgType , "hex" ) ; bytes = Buffer . concat ( [ prefix , bytes ] ) ; } if ( isByteLenPrefix ) { const lenBytes = UVarInt . encode ( bytes . length ) ; bytes = Buffer . concat ( [ lenBytes , bytes ] ) ; } return bytes ; } ; category param { Number } fieldNum param { Array } arr param { Boolean } isByteLenPrefix return { Buffer } export const encodeArrayBinary = ( fieldNum , arr , isByteLenPrefix ? ) : Buffer => { const result = [ ] ; arr . forEach ( ( item ) => { result . push ( encodeTypeAndField ( fieldNum , item ) ) ; if ( isDefaultValue ( item ) ) { result . push ( Buffer . from ( "00" , "hex" ) ) ; return ; } result . push ( encodeBinary ( item , fieldNum , true ) ) ; } ) ; if ( isByteLenPrefix ) { const length = result . reduce ( ( prev , item ) => prev + item . length , 0 ) ; result . unshift ( UVarInt . encode ( length ) ) ; } return Buffer . concat ( result ) ; } ; const encodeTypeAndField = ( index , field ) => { index = Number ( index ) ; const value = ( ( index + 1 ) << 3 ) | typeToTyp3 ( field ) ; return UVarInt . encode ( value ) ; } ; const isDefaultValue = ( obj ) => { if ( obj === null ) return false ; return ( ( is . number ( obj ) && obj === 0 ) || ( is . string ( obj ) && obj === "" ) || ( is . array ( obj ) && obj . length === 0 ) || ( is . boolean ( obj ) && ! obj ) ) ; } ;