11import WebSocket from "isomorphic-ws" ;
22
3+ import { IsomorphicBuffer } from "./buffer/index.js" ;
34import type { ParsedPayload , Request , Response } from "./protocol.js" ;
45import { BINARY_UPDATE_FORMAT_MAGIC_LE , FORMAT_MAGICS_LE } from "./protocol.js" ;
56import type { WebSocketPoolConfig } from "./socket/websocket-pool.js" ;
67import { WebSocketPool } from "./socket/websocket-pool.js" ;
8+ import { convertWebsocketDataToArrayBuffer } from "./util.js" ;
79
810export type BinaryResponse = {
911 subscriptionId : number ;
@@ -15,17 +17,17 @@ export type BinaryResponse = {
1517} ;
1618export type JsonOrBinaryResponse =
1719 | {
18- type : "json" ;
19- value : Response ;
20- }
20+ type : "json" ;
21+ value : Response ;
22+ }
2123 | { type : "binary" ; value : BinaryResponse } ;
2224
2325const UINT16_NUM_BYTES = 2 ;
2426const UINT32_NUM_BYTES = 4 ;
2527const UINT64_NUM_BYTES = 8 ;
2628
2729export class PythLazerClient {
28- private constructor ( private readonly wsp : WebSocketPool ) { }
30+ private constructor ( private readonly wsp : WebSocketPool ) { }
2931
3032 /**
3133 * Creates a new PythLazerClient instance.
@@ -46,53 +48,55 @@ export class PythLazerClient {
4648 * or a binary response containing EVM, Solana, or parsed payload data.
4749 */
4850 addMessageListener ( handler : ( event : JsonOrBinaryResponse ) => void ) {
49- this . wsp . addMessageListener ( ( data : WebSocket . Data ) => {
50- if ( typeof data == "string" ) {
51+ this . wsp . addMessageListener ( async ( data : WebSocket . Data ) => {
52+ if ( typeof data === "string" ) {
5153 handler ( {
5254 type : "json" ,
5355 value : JSON . parse ( data ) as Response ,
5456 } ) ;
55- } else if ( Buffer . isBuffer ( data ) ) {
56- let pos = 0 ;
57- const magic = data . subarray ( pos , pos + UINT32_NUM_BYTES ) . readUint32LE ( ) ;
58- pos += UINT32_NUM_BYTES ;
59- if ( magic != BINARY_UPDATE_FORMAT_MAGIC_LE ) {
60- throw new Error ( "binary update format magic mismatch" ) ;
61- }
62- // TODO: some uint64 values may not be representable as Number.
63- const subscriptionId = Number (
64- data . subarray ( pos , pos + UINT64_NUM_BYTES ) . readBigInt64BE ( ) ,
65- ) ;
66- pos += UINT64_NUM_BYTES ;
57+ return ;
58+ }
59+
60+ const buff = IsomorphicBuffer . from ( await convertWebsocketDataToArrayBuffer ( data ) ) ;
61+
62+ let pos = 0 ;
63+ const magic = buff . subarray ( pos , pos + UINT32_NUM_BYTES ) . readUint32LE ( ) ;
64+ pos += UINT32_NUM_BYTES ;
65+ if ( magic != BINARY_UPDATE_FORMAT_MAGIC_LE ) {
66+ throw new Error ( "binary update format magic mismatch" ) ;
67+ }
68+ // TODO: some uint64 values may not be representable as Number.
69+ const subscriptionId = Number (
70+ buff . subarray ( pos , pos + UINT64_NUM_BYTES ) . readBigInt64BE ( ) ,
71+ ) ;
72+ pos += UINT64_NUM_BYTES ;
6773
68- const value : BinaryResponse = { subscriptionId } ;
69- while ( pos < data . length ) {
70- const len = data . subarray ( pos , pos + UINT16_NUM_BYTES ) . readUint16BE ( ) ;
71- pos += UINT16_NUM_BYTES ;
72- const magic = data
73- . subarray ( pos , pos + UINT32_NUM_BYTES )
74- . readUint32LE ( ) ;
75- if ( magic == FORMAT_MAGICS_LE . EVM ) {
76- value . evm = data . subarray ( pos , pos + len ) ;
77- } else if ( magic == FORMAT_MAGICS_LE . SOLANA ) {
78- value . solana = data . subarray ( pos , pos + len ) ;
79- } else if ( magic == FORMAT_MAGICS_LE . LE_ECDSA ) {
80- value . leEcdsa = data . subarray ( pos , pos + len ) ;
81- } else if ( magic == FORMAT_MAGICS_LE . LE_UNSIGNED ) {
82- value . leUnsigned = data . subarray ( pos , pos + len ) ;
83- } else if ( magic == FORMAT_MAGICS_LE . JSON ) {
84- value . parsed = JSON . parse (
85- data . subarray ( pos + UINT32_NUM_BYTES , pos + len ) . toString ( ) ,
86- ) as ParsedPayload ;
87- } else {
88- throw new Error ( "unknown magic: " + magic . toString ( ) ) ;
89- }
90- pos += len ;
74+ const value : BinaryResponse = { subscriptionId } ;
75+ while ( pos < buff . length ) {
76+ const len = buff . subarray ( pos , pos + UINT16_NUM_BYTES ) . readUint16BE ( ) ;
77+ pos += UINT16_NUM_BYTES ;
78+ const magic = buff
79+ . subarray ( pos , pos + UINT32_NUM_BYTES )
80+ . readUint32LE ( ) ;
81+ if ( magic == FORMAT_MAGICS_LE . EVM ) {
82+ value . evm = buff . subarray ( pos , pos + len ) ;
83+ } else if ( magic == FORMAT_MAGICS_LE . SOLANA ) {
84+ value . solana = buff . subarray ( pos , pos + len ) ;
85+ } else if ( magic == FORMAT_MAGICS_LE . LE_ECDSA ) {
86+ value . leEcdsa = buff . subarray ( pos , pos + len ) ;
87+ } else if ( magic == FORMAT_MAGICS_LE . LE_UNSIGNED ) {
88+ value . leUnsigned = buff . subarray ( pos , pos + len ) ;
89+ } else if ( magic == FORMAT_MAGICS_LE . JSON ) {
90+ value . parsed = JSON . parse (
91+ buff . subarray ( pos + UINT32_NUM_BYTES , pos + len ) . toString ( ) ,
92+ ) as ParsedPayload ;
93+ } else {
94+ throw new Error ( "unknown magic: " + magic . toString ( ) ) ;
9195 }
92- handler ( { type : "binary" , value } ) ;
93- } else {
94- throw new TypeError ( "unexpected event data type" ) ;
96+ pos += len ;
9597 }
98+ handler ( { type : "binary" , value } ) ;
99+ return ;
96100 } ) ;
97101 }
98102
0 commit comments