diff --git a/frontend/src/app/components/address/address-preview.component.ts b/frontend/src/app/components/address/address-preview.component.ts index 37ee44e2e..c0f6fff81 100644 --- a/frontend/src/app/components/address/address-preview.component.ts +++ b/frontend/src/app/components/address/address-preview.component.ts @@ -73,7 +73,7 @@ export class AddressPreviewComponent implements OnInit, OnDestroy { this.isLoadingAddress = false; this.error = err; console.log(err); - this.openGraphService.waitOver('address-data'); + this.openGraphService.fail('address-data'); return of(null); }) ); @@ -99,7 +99,7 @@ export class AddressPreviewComponent implements OnInit, OnDestroy { console.log(error); this.error = error; this.isLoadingAddress = false; - this.openGraphService.waitOver('address-data'); + this.openGraphService.fail('address-data'); } ); } diff --git a/frontend/src/app/components/block/block-preview.component.ts b/frontend/src/app/components/block/block-preview.component.ts index dd8ca170f..f1c7216e1 100644 --- a/frontend/src/app/components/block/block-preview.component.ts +++ b/frontend/src/app/components/block/block-preview.component.ts @@ -80,8 +80,8 @@ export class BlockPreviewComponent implements OnInit, OnDestroy { }), catchError((err) => { this.error = err; - this.openGraphService.waitOver('block-data'); - this.openGraphService.waitOver('block-viz'); + this.openGraphService.fail('block-data'); + this.openGraphService.fail('block-viz'); return of(null); }), ); @@ -116,7 +116,7 @@ export class BlockPreviewComponent implements OnInit, OnDestroy { .pipe( catchError((err) => { this.overviewError = err; - this.openGraphService.waitOver('block-viz'); + this.openGraphService.fail('block-viz'); return of([]); }), switchMap((transactions) => { @@ -136,8 +136,8 @@ export class BlockPreviewComponent implements OnInit, OnDestroy { (error) => { this.error = error; this.isLoadingOverview = false; - this.openGraphService.waitOver('block-viz'); - this.openGraphService.waitOver('block-data'); + this.openGraphService.fail('block-viz'); + this.openGraphService.fail('block-data'); if (this.blockGraph) { this.blockGraph.destroy(); } diff --git a/frontend/src/app/services/opengraph.service.ts b/frontend/src/app/services/opengraph.service.ts index 9ed57b9e8..dc62db0f3 100644 --- a/frontend/src/app/services/opengraph.service.ts +++ b/frontend/src/app/services/opengraph.service.ts @@ -93,11 +93,18 @@ export class OpenGraphService { } } + fail(event) { + if (this.previewLoadingEvents[event]) { + this.metaService.updateTag({ property: 'og:preview:fail', content: 'fail'}); + } + } + resetLoading() { this.previewLoadingEvents = {}; this.previewLoadingCount = 0; this.metaService.removeTag("property='og:preview:loading'"); this.metaService.removeTag("property='og:preview:ready'"); + this.metaService.removeTag("property='og:preview:fail'"); this.metaService.removeTag("property='og:meta:ready'"); } diff --git a/unfurler/src/index.ts b/unfurler/src/index.ts index d97bd652d..81edd9325 100644 --- a/unfurler/src/index.ts +++ b/unfurler/src/index.ts @@ -102,10 +102,20 @@ class Server { } const waitForReady = await page.$('meta[property="og:preview:loading"]'); + let success = true; if (waitForReady != null) { - await page.waitForSelector('meta[property="og:preview:ready"]', { timeout: config.PUPPETEER.RENDER_TIMEOUT || 3000 }); + success = await Promise.race([ + page.waitForSelector('meta[property="og:preview:ready"]', { timeout: config.PUPPETEER.RENDER_TIMEOUT || 3000 }).then(() => true), + page.waitForSelector('meta[property="og:preview:fail"]', { timeout: config.PUPPETEER.RENDER_TIMEOUT || 3000 }).then(() => false) + ]) + } + if (success) { + const screenshot = await page.screenshot(); + return screenshot; + } else { + console.log(`failed to render page preview for ${action} due to client-side error. probably requested an invalid ID`); + page.repairRequested = true; } - return page.screenshot(); } catch (e) { console.log(`failed to render page for ${action}`, e instanceof Error ? e.message : e); page.repairRequested = true; @@ -118,11 +128,11 @@ class Server { const img = await this.cluster?.execute({ url: this.mempoolHost + path, path: path, action: 'screenshot' }); if (!img) { - throw new Error('failed to render preview image'); + res.status(500).send('failed to render page preview'); + } else { + res.contentType('image/png'); + res.send(img); } - - res.contentType('image/png'); - res.send(img); } catch (e) { console.log(e); res.status(500).send(e instanceof Error ? e.message : e);