|
1 | | -import {HttpClient, HttpError} from '@subsquid/http-client' |
| 1 | +import {HttpClient, HttpError, HttpResponse} from '@subsquid/http-client' |
2 | 2 | import { |
3 | 3 | addErrorContext, |
4 | 4 | createFuture, |
@@ -224,42 +224,7 @@ export class PortalClient { |
224 | 224 | request, |
225 | 225 | stopOnHead, |
226 | 226 | }, |
227 | | - async (q, o) => { |
228 | | - // NOTE: we emulate the same behavior as will be implemented for hot blocks stream, |
229 | | - // but unfortunately we don't have any information about finalized block hash at the moment |
230 | | - let finalizedHead = { |
231 | | - number: await this.getFinalizedHeight(o), |
232 | | - hash: '', |
233 | | - } |
234 | | - |
235 | | - let res = await this.client |
236 | | - .request<Readable>('POST', this.getDatasetUrl('finalized-stream'), { |
237 | | - ...o, |
238 | | - json: q, |
239 | | - stream: true, |
240 | | - }) |
241 | | - .catch( |
242 | | - withErrorContext({ |
243 | | - query: q, |
244 | | - }) |
245 | | - ) |
246 | | - |
247 | | - switch (res.status) { |
248 | | - case 200: |
249 | | - let stream = Readable.toWeb(res.body) as ReadableStream<Uint8Array> |
250 | | - |
251 | | - return { |
252 | | - finalizedHead, |
253 | | - stream: stream |
254 | | - .pipeThrough(new TextDecoderStream('utf8')) |
255 | | - .pipeThrough(new LineSplitStream('\n')), |
256 | | - } |
257 | | - case 204: |
258 | | - return undefined |
259 | | - default: |
260 | | - throw unexpectedCase(res.status) |
261 | | - } |
262 | | - } |
| 227 | + async (q, o) => this.getStreamRequest('finalized-stream', q, o) |
263 | 228 | ) |
264 | 229 | } |
265 | 230 |
|
@@ -288,67 +253,59 @@ export class PortalClient { |
288 | 253 | request, |
289 | 254 | stopOnHead, |
290 | 255 | }, |
291 | | - async (q, o) => { |
292 | | - try { |
293 | | - let res = await this.client |
294 | | - .request<Readable | undefined>('POST', this.getDatasetUrl('stream'), { |
295 | | - ...o, |
296 | | - json: q, |
297 | | - stream: true, |
298 | | - }) |
299 | | - .catch( |
300 | | - withErrorContext({ |
301 | | - query: q, |
302 | | - }) |
303 | | - ) |
304 | | - |
305 | | - switch (res.status) { |
306 | | - case 200: |
307 | | - let finalizedHeadHash = res.headers.get('X-Sqd-Finalized-Head-Hash') |
308 | | - let finalizedHeadNumber = res.headers.get('X-Sqd-Finalized-Head-Number') |
309 | | - |
310 | | - let finalizedHead: BlockRef | undefined = |
311 | | - finalizedHeadHash != null && finalizedHeadNumber != null |
312 | | - ? { |
313 | | - hash: finalizedHeadHash, |
314 | | - number: parseInt(finalizedHeadNumber), |
315 | | - } |
316 | | - : undefined |
317 | | - |
318 | | - let stream = res.body ? (Readable.toWeb(res.body) as ReadableStream<Uint8Array>) : undefined |
319 | | - |
320 | | - return { |
321 | | - finalizedHead, |
322 | | - stream: stream |
323 | | - ?.pipeThrough(new TextDecoderStream('utf8')) |
324 | | - ?.pipeThrough(new LineSplitStream('\n')), |
325 | | - } |
326 | | - case 204: |
327 | | - return undefined |
328 | | - default: |
329 | | - throw unexpectedCase(res.status) |
330 | | - } |
331 | | - } catch (e: unknown) { |
332 | | - if ( |
333 | | - e instanceof HttpError && |
334 | | - e.response.status === 409 && |
335 | | - q.fromBlock && |
336 | | - q.parentBlockHash && |
337 | | - e.response.body.lastBlocks |
338 | | - ) { |
339 | | - let blocks = e.response.body.lastBlocks as BlockRef[] |
340 | | - e = new ForkException(blocks, { |
341 | | - fromBlock: q.fromBlock, |
342 | | - parentBlockHash: q.parentBlockHash, |
343 | | - }) |
344 | | - } |
| 256 | + async (q, o) => this.getStreamRequest('stream', q, o) |
| 257 | + ) |
| 258 | + } |
345 | 259 |
|
346 | | - throw addErrorContext(e as any, { |
347 | | - query, |
| 260 | + private async getStreamRequest(path: string, query: PortalQuery, options?: PortalRequestOptions) { |
| 261 | + try { |
| 262 | + let res = await this.client |
| 263 | + .request<Readable | undefined>('POST', this.getDatasetUrl(path), { |
| 264 | + ...options, |
| 265 | + json: query, |
| 266 | + stream: true, |
| 267 | + }) |
| 268 | + .catch( |
| 269 | + withErrorContext({ |
| 270 | + query: query, |
348 | 271 | }) |
349 | | - } |
| 272 | + ) |
| 273 | + |
| 274 | + switch (res.status) { |
| 275 | + case 200: |
| 276 | + let finalizedHead = getFinalizedHeadHeader(res.headers) |
| 277 | + let stream = res.body ? (Readable.toWeb(res.body) as ReadableStream<Uint8Array>) : undefined |
| 278 | + |
| 279 | + return { |
| 280 | + finalizedHead, |
| 281 | + stream: stream |
| 282 | + ?.pipeThrough(new TextDecoderStream('utf8')) |
| 283 | + ?.pipeThrough(new LineSplitStream('\n')), |
| 284 | + } |
| 285 | + case 204: |
| 286 | + return undefined |
| 287 | + default: |
| 288 | + throw unexpectedCase(res.status) |
350 | 289 | } |
351 | | - ) |
| 290 | + } catch (e: unknown) { |
| 291 | + if ( |
| 292 | + e instanceof HttpError && |
| 293 | + e.response.status === 409 && |
| 294 | + query.fromBlock && |
| 295 | + query.parentBlockHash && |
| 296 | + e.response.body.lastBlocks |
| 297 | + ) { |
| 298 | + let blocks = e.response.body.lastBlocks as BlockRef[] |
| 299 | + e = new ForkException(blocks, { |
| 300 | + fromBlock: query.fromBlock, |
| 301 | + parentBlockHash: query.parentBlockHash, |
| 302 | + }) |
| 303 | + } |
| 304 | + |
| 305 | + throw addErrorContext(e as any, { |
| 306 | + query, |
| 307 | + }) |
| 308 | + } |
352 | 309 | } |
353 | 310 | } |
354 | 311 |
|
@@ -660,3 +617,15 @@ export function isForkException(err: unknown): err is ForkException { |
660 | 617 | if (err instanceof Error && err.name === 'ForkError') return true |
661 | 618 | return false |
662 | 619 | } |
| 620 | + |
| 621 | +function getFinalizedHeadHeader(headers: HttpResponse['headers']) { |
| 622 | + let finalizedHeadHash = headers.get('X-Sqd-Finalized-Head-Hash') |
| 623 | + let finalizedHeadNumber = headers.get('X-Sqd-Finalized-Head-Number') |
| 624 | + |
| 625 | + return finalizedHeadHash != null && finalizedHeadNumber != null |
| 626 | + ? { |
| 627 | + hash: finalizedHeadHash, |
| 628 | + number: parseInt(finalizedHeadNumber), |
| 629 | + } |
| 630 | + : undefined |
| 631 | +} |
0 commit comments