|
1 |
| -import type { PeerId, Stream } from "@libp2p/interface"; |
2 |
| -import { |
3 |
| - type CoreProtocolResult, |
4 |
| - type IBaseProtocolCore, |
5 |
| - type IEncoder, |
6 |
| - type IMessage, |
7 |
| - type Libp2p, |
8 |
| - ProtocolError, |
9 |
| - PubsubTopic, |
10 |
| - type ThisOrThat |
11 |
| -} from "@waku/interfaces"; |
12 |
| -import { PushResponse } from "@waku/proto"; |
13 |
| -import { isMessageSizeUnderCap } from "@waku/utils"; |
14 |
| -import { Logger } from "@waku/utils"; |
15 |
| -import all from "it-all"; |
16 |
| -import * as lp from "it-length-prefixed"; |
17 |
| -import { pipe } from "it-pipe"; |
18 |
| -import { Uint8ArrayList } from "uint8arraylist"; |
19 |
| - |
20 |
| -import { BaseProtocol } from "../base_protocol.js"; |
21 |
| - |
22 |
| -import { PushRpc } from "./push_rpc.js"; |
23 |
| -import { isRLNResponseError } from "./utils.js"; |
24 |
| - |
25 |
| -const log = new Logger("light-push"); |
26 |
| - |
27 |
| -export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1"; |
28 |
| -export { PushResponse }; |
29 |
| - |
30 |
| -type PreparePushMessageResult = ThisOrThat<"query", PushRpc>; |
31 |
| - |
32 |
| -/** |
33 |
| - * Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/). |
34 |
| - */ |
35 |
| -export class LightPushCore extends BaseProtocol implements IBaseProtocolCore { |
36 |
| - public constructor( |
37 |
| - public readonly pubsubTopics: PubsubTopic[], |
38 |
| - libp2p: Libp2p |
39 |
| - ) { |
40 |
| - super(LightPushCodec, libp2p.components, pubsubTopics); |
41 |
| - } |
42 |
| - |
43 |
| - private async preparePushMessage( |
44 |
| - encoder: IEncoder, |
45 |
| - message: IMessage |
46 |
| - ): Promise<PreparePushMessageResult> { |
47 |
| - try { |
48 |
| - if (!message.payload || message.payload.length === 0) { |
49 |
| - log.error("Failed to send waku light push: payload is empty"); |
50 |
| - return { query: null, error: ProtocolError.EMPTY_PAYLOAD }; |
51 |
| - } |
52 |
| - |
53 |
| - if (!(await isMessageSizeUnderCap(encoder, message))) { |
54 |
| - log.error("Failed to send waku light push: message is bigger than 1MB"); |
55 |
| - return { query: null, error: ProtocolError.SIZE_TOO_BIG }; |
56 |
| - } |
57 |
| - |
58 |
| - const protoMessage = await encoder.toProtoObj(message); |
59 |
| - if (!protoMessage) { |
60 |
| - log.error("Failed to encode to protoMessage, aborting push"); |
61 |
| - return { |
62 |
| - query: null, |
63 |
| - error: ProtocolError.ENCODE_FAILED |
64 |
| - }; |
65 |
| - } |
66 |
| - |
67 |
| - const query = PushRpc.createRequest(protoMessage, encoder.pubsubTopic); |
68 |
| - return { query, error: null }; |
69 |
| - } catch (error) { |
70 |
| - log.error("Failed to prepare push message", error); |
71 |
| - |
72 |
| - return { |
73 |
| - query: null, |
74 |
| - error: ProtocolError.GENERIC_FAIL |
75 |
| - }; |
76 |
| - } |
77 |
| - } |
78 |
| - |
79 |
| - public async send( |
80 |
| - encoder: IEncoder, |
81 |
| - message: IMessage, |
82 |
| - peerId: PeerId |
83 |
| - ): Promise<CoreProtocolResult> { |
84 |
| - const { query, error: preparationError } = await this.preparePushMessage( |
85 |
| - encoder, |
86 |
| - message |
87 |
| - ); |
88 |
| - |
89 |
| - if (preparationError || !query) { |
90 |
| - return { |
91 |
| - success: null, |
92 |
| - failure: { |
93 |
| - error: preparationError, |
94 |
| - peerId |
95 |
| - } |
96 |
| - }; |
97 |
| - } |
98 |
| - |
99 |
| - let stream: Stream; |
100 |
| - try { |
101 |
| - stream = await this.getStream(peerId); |
102 |
| - } catch (error) { |
103 |
| - log.error("Failed to get stream", error); |
104 |
| - return { |
105 |
| - success: null, |
106 |
| - failure: { |
107 |
| - error: ProtocolError.NO_STREAM_AVAILABLE, |
108 |
| - peerId: peerId |
109 |
| - } |
110 |
| - }; |
111 |
| - } |
112 |
| - |
113 |
| - let res: Uint8ArrayList[] | undefined; |
114 |
| - try { |
115 |
| - res = await pipe( |
116 |
| - [query.encode()], |
117 |
| - lp.encode, |
118 |
| - stream, |
119 |
| - lp.decode, |
120 |
| - async (source) => await all(source) |
121 |
| - ); |
122 |
| - } catch (err) { |
123 |
| - // can fail only because of `stream` abortion |
124 |
| - log.error("Failed to send waku light push request", err); |
125 |
| - return { |
126 |
| - success: null, |
127 |
| - failure: { |
128 |
| - error: ProtocolError.STREAM_ABORTED, |
129 |
| - peerId: peerId |
130 |
| - } |
131 |
| - }; |
132 |
| - } |
133 |
| - |
134 |
| - const bytes = new Uint8ArrayList(); |
135 |
| - res.forEach((chunk) => { |
136 |
| - bytes.append(chunk); |
137 |
| - }); |
138 |
| - |
139 |
| - let response: PushResponse | undefined; |
140 |
| - try { |
141 |
| - response = PushRpc.decode(bytes).response; |
142 |
| - } catch (err) { |
143 |
| - log.error("Failed to decode push reply", err); |
144 |
| - return { |
145 |
| - success: null, |
146 |
| - failure: { |
147 |
| - error: ProtocolError.DECODE_FAILED, |
148 |
| - peerId: peerId |
149 |
| - } |
150 |
| - }; |
151 |
| - } |
152 |
| - |
153 |
| - if (!response) { |
154 |
| - log.error("Remote peer fault: No response in PushRPC"); |
155 |
| - return { |
156 |
| - success: null, |
157 |
| - failure: { |
158 |
| - error: ProtocolError.NO_RESPONSE, |
159 |
| - peerId: peerId |
160 |
| - } |
161 |
| - }; |
162 |
| - } |
163 |
| - |
164 |
| - if (isRLNResponseError(response.info)) { |
165 |
| - log.error("Remote peer fault: RLN generation"); |
166 |
| - return { |
167 |
| - success: null, |
168 |
| - failure: { |
169 |
| - error: ProtocolError.RLN_PROOF_GENERATION, |
170 |
| - peerId: peerId |
171 |
| - } |
172 |
| - }; |
173 |
| - } |
174 |
| - |
175 |
| - if (!response.isSuccess) { |
176 |
| - log.error("Remote peer rejected the message: ", response.info); |
177 |
| - return { |
178 |
| - success: null, |
179 |
| - failure: { |
180 |
| - error: ProtocolError.REMOTE_PEER_REJECTED, |
181 |
| - peerId: peerId |
182 |
| - } |
183 |
| - }; |
184 |
| - } |
185 |
| - |
186 |
| - return { success: peerId, failure: null }; |
187 |
| - } |
188 |
| -} |
| 1 | +// Re-export v3 as the default implementation for backward compatibility |
| 2 | +export { |
| 3 | + LightPushCoreV3 as LightPushCore, |
| 4 | + LightPushCodecV3 as LightPushCodec |
| 5 | +} from "./light_push_v3.js"; |
| 6 | +export { PushResponse } from "@waku/proto"; |
0 commit comments