import { encode , types , decode } from "binary-data" ; import { HandshakeType } from "../../handshake/const" ; export class FragmentedHandshake { static readonly spec = { msg_type : types . uint8 , length : types . uint24be , message_seq : types . uint16be , fragment_offset : types . uint24be , fragment_length : types . uint24be , fragment : types . buffer ( ( context ) => context . current . fragment_length ) , } ; constructor ( public msg_type , public length , public message_seq , public fragment_offset , public fragment_length , public fragment ) { } static createEmpty ( ) { return new FragmentedHandshake ( undefined as any , undefined as any , undefined as any , undefined as any , undefined as any , undefined as any ) ; } static deSerialize ( buf ) { return new FragmentedHandshake ( ... Object . values ( decode ( buf , FragmentedHandshake . spec ) ) ) ; } serialize ( ) { const res = encode ( this , FragmentedHandshake . spec ) . slice ( ) ; return Buffer . from ( res ) ; } chunk ( maxFragmentLength ? ) { let start = 0 ; const totalLength = this . fragment . length ; if ( totalLength === 0 ) return [ new FragmentedHandshake ( this . msg_type , totalLength , this . message_seq , start , 0 , this . fragment ) , ] ; const fragments = [ ] ; if ( ! maxFragmentLength ) { maxFragmentLength = 1280 - ( 20 + 8 ) - ( 1 + 3 + 2 + 3 + 3 ) ; } while ( start < totalLength ) { const fragmentLength = Math . min ( maxFragmentLength , totalLength - start ) ; const data = Buffer . from ( this . fragment . slice ( start , start + fragmentLength ) ) ; if ( data . length <= 0 ) { throw new Error ( `Zero or less bytes processed while fragmenting handshake message.` ) ; } fragments . push ( new FragmentedHandshake ( this . msg_type , totalLength , this . message_seq , start , data . length , data ) ) ; start += data . length ; } return fragments ; } static assemble ( messages ) { if ( ! ( messages && messages . length ) ) { throw new Error ( "cannot reassemble handshake from empty array" ) ; } messages = messages . sort ( ( a , b ) => a . fragment_offset - b . fragment_offset ) ; const combined = Buffer . alloc ( messages [ 0 ] . length ) ; for ( const msg of messages ) { msg . fragment . copy ( combined , msg . fragment_offset ) ; } return new FragmentedHandshake ( messages [ 0 ] . msg_type , messages [ 0 ] . length , messages [ 0 ] . message_seq , 0 , combined . length , combined ) ; } static findAllFragments ( fragments , type ) { const reference = fragments . find ( ( v ) => v . msg_type === type ) ; if ( ! reference ) return [ ] ; if ( ! ( fragments && fragments . length ) ) return [ ] ; return fragments . filter ( ( f ) => { return ( f . msg_type === reference . msg_type && f . message_seq === reference . message_seq && f . length === reference . length ) ; } ) ; } }