@@ -3,9 +3,11 @@ import {
33 type CoreProtocolResult ,
44 type IEncoder ,
55 type IMessage ,
6+ isSuccess as isV3Success ,
67 type Libp2p ,
78 ProtocolError ,
8- type ThisOrThat
9+ type ThisOrThat ,
10+ toProtocolError
911} from "@waku/interfaces" ;
1012import { PushResponse } from "@waku/proto" ;
1113import { isMessageSizeUnderCap } from "@waku/utils" ;
@@ -16,13 +18,16 @@ import { pipe } from "it-pipe";
1618import { Uint8ArrayList } from "uint8arraylist" ;
1719
1820import { StreamManager } from "../stream_manager/index.js" ;
21+ import { selectOpenConnection } from "../stream_manager/utils.js" ;
1922
2023import { PushRpc } from "./push_rpc.js" ;
2124import { isRLNResponseError } from "./utils.js" ;
2225
2326const log = new Logger ( "light-push" ) ;
2427
2528export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1" ;
29+ export const LightPushCodecV3 = "/vac/waku/lightpush/3.0.0" ;
30+ export const LightPushCodecs = [ LightPushCodecV3 , LightPushCodec ] ;
2631export { PushResponse } ;
2732
2833type PreparePushMessageResult = ThisOrThat < "query" , PushRpc > ;
@@ -34,11 +39,49 @@ export class LightPushCore {
3439 private readonly streamManager : StreamManager ;
3540
3641 public readonly multicodec = LightPushCodec ;
42+ public readonly multicodecs = LightPushCodecs ;
3743
38- public constructor ( libp2p : Libp2p ) {
44+ public constructor ( private libp2p : Libp2p ) {
3945 this . streamManager = new StreamManager ( LightPushCodec , libp2p . components ) ;
4046 }
4147
48+ private async getProtocolStream (
49+ peerId : PeerId
50+ ) : Promise < { stream : Stream ; protocol : string } > {
51+ const peer = await this . libp2p . peerStore . get ( peerId ) ;
52+ const protocols = peer . protocols ;
53+
54+ const supportsV3 = protocols . includes ( LightPushCodecV3 ) ;
55+ const supportsV2 = protocols . includes ( LightPushCodec ) ;
56+
57+ if ( ! supportsV2 && ! supportsV3 ) {
58+ throw new Error ( "Peer does not support any Light Push protocol" ) ;
59+ }
60+
61+ const protocol = supportsV3 ? LightPushCodecV3 : LightPushCodec ;
62+
63+ let stream : Stream ;
64+ try {
65+ const connections = this . libp2p . getConnections ( peerId ) ;
66+ const connection = selectOpenConnection ( connections ) ;
67+
68+ if ( ! connection ) {
69+ throw new Error ( "No open connection to peer" ) ;
70+ }
71+
72+ stream = await connection . newStream ( protocol ) ;
73+ } catch ( error ) {
74+ if ( supportsV3 && supportsV2 ) {
75+ log . warn ( "Failed to create v3 stream, falling back to v2" , error ) ;
76+ stream = await this . streamManager . getStream ( peerId ) ;
77+ return { stream, protocol : LightPushCodec } ;
78+ }
79+ throw error ;
80+ }
81+
82+ return { stream, protocol } ;
83+ }
84+
4285 private async preparePushMessage (
4386 encoder : IEncoder ,
4487 message : IMessage
@@ -96,17 +139,26 @@ export class LightPushCore {
96139 }
97140
98141 let stream : Stream ;
142+ let protocol : string ;
99143 try {
100- stream = await this . streamManager . getStream ( peerId ) ;
144+ const result = await this . getProtocolStream ( peerId ) ;
145+ stream = result . stream ;
146+ protocol = result . protocol ;
147+ log . info ( `Using protocol ${ protocol } for peer ${ peerId . toString ( ) } ` ) ;
101148 } catch ( error ) {
102149 log . error ( "Failed to get stream" , error ) ;
103- return {
104- success : null ,
105- failure : {
106- error : ProtocolError . NO_STREAM_AVAILABLE ,
107- peerId : peerId
108- }
109- } ;
150+ try {
151+ stream = await this . streamManager . getStream ( peerId ) ;
152+ protocol = LightPushCodec ;
153+ } catch ( fallbackError ) {
154+ return {
155+ success : null ,
156+ failure : {
157+ error : ProtocolError . NO_STREAM_AVAILABLE ,
158+ peerId : peerId
159+ }
160+ } ;
161+ }
110162 }
111163
112164 let res : Uint8ArrayList [ ] | undefined ;
@@ -160,6 +212,28 @@ export class LightPushCore {
160212 } ;
161213 }
162214
215+ if ( protocol === LightPushCodecV3 && response . statusCode !== undefined ) {
216+ if ( ! isV3Success ( response . statusCode ) ) {
217+ const error = toProtocolError ( response . statusCode ) ;
218+ log . error (
219+ `Remote peer rejected with v3 status code ${ response . statusCode } : ${ response . statusDesc || response . info } `
220+ ) ;
221+ return {
222+ success : null ,
223+ failure : {
224+ error,
225+ peerId : peerId
226+ }
227+ } ;
228+ }
229+
230+ if ( response . relayPeerCount !== undefined ) {
231+ log . info ( `Message relayed to ${ response . relayPeerCount } peers` ) ;
232+ }
233+
234+ return { success : peerId , failure : null } ;
235+ }
236+
163237 if ( isRLNResponseError ( response . info ) ) {
164238 log . error ( "Remote peer fault: RLN generation" ) ;
165239 return {
0 commit comments