diff --git a/frontend/src/resources/previews/dashboard.png b/frontend/src/resources/previews/dashboard.png
new file mode 100644
index 000000000..f2f20b9d8
Binary files /dev/null and b/frontend/src/resources/previews/dashboard.png differ
diff --git a/frontend/src/resources/previews/lightning.png b/frontend/src/resources/previews/lightning.png
new file mode 100644
index 000000000..f214dc1f9
Binary files /dev/null and b/frontend/src/resources/previews/lightning.png differ
diff --git a/frontend/src/resources/previews/mining.png b/frontend/src/resources/previews/mining.png
new file mode 100644
index 000000000..37c3873c1
Binary files /dev/null and b/frontend/src/resources/previews/mining.png differ
diff --git a/unfurler/package-lock.json b/unfurler/package-lock.json
index 3da33c69f..40520d413 100644
--- a/unfurler/package-lock.json
+++ b/unfurler/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mempool-unfurl",
- "version": "0.0.1",
+ "version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "mempool-unfurl",
- "version": "0.0.1",
+ "version": "0.1.0",
"dependencies": {
"@types/node": "^16.11.41",
"express": "^4.18.0",
diff --git a/unfurler/package.json b/unfurler/package.json
index ca60201b3..59d48aa50 100644
--- a/unfurler/package.json
+++ b/unfurler/package.json
@@ -1,6 +1,6 @@
{
"name": "mempool-unfurl",
- "version": "0.0.2",
+ "version": "0.1.0",
"description": "Renderer for mempool open graph link preview images",
"repository": {
"type": "git",
diff --git a/unfurler/src/index.ts b/unfurler/src/index.ts
index 08dff3964..e4c1f7fc5 100644
--- a/unfurler/src/index.ts
+++ b/unfurler/src/index.ts
@@ -1,10 +1,12 @@
import express from "express";
import { Application, Request, Response, NextFunction } from 'express';
import * as http from 'http';
+import * as https from 'https';
import config from './config';
import { Cluster } from 'puppeteer-cluster';
import ReusablePage from './concurrency/ReusablePage';
import { parseLanguageUrl } from './language/lang';
+import { matchRoute } from './routes';
const puppeteerConfig = require('../puppeteer.config.json');
if (config.PUPPETEER.EXEC_PATH) {
@@ -17,13 +19,13 @@ class Server {
cluster?: Cluster;
mempoolHost: string;
network: string;
- defaultImageUrl: string;
+ secureHost = true;
constructor() {
this.app = express();
this.mempoolHost = config.MEMPOOL.HTTP_HOST + (config.MEMPOOL.HTTP_PORT ? ':' + config.MEMPOOL.HTTP_PORT : '');
+ this.secureHost = this.mempoolHost.startsWith('https');
this.network = config.MEMPOOL.NETWORK || 'bitcoin';
- this.defaultImageUrl = this.getDefaultImageUrl();
this.startServer();
}
@@ -113,11 +115,25 @@ class Server {
async renderPreview(req, res) {
try {
- const path = req.params[0]
- const img = await this.cluster?.execute({ url: this.mempoolHost + path, path: path, action: 'screenshot' });
+ const rawPath = req.params[0];
+
+ let img = null;
+
+ const { lang, path } = parseLanguageUrl(rawPath);
+ const matchedRoute = matchRoute(this.network, path);
+
+ // don't bother unless the route is definitely renderable
+ if (rawPath.includes('/preview/') && matchedRoute.render) {
+ img = await this.cluster?.execute({ url: this.mempoolHost + rawPath, path: rawPath, action: 'screenshot' });
+ }
if (!img) {
- res.status(500).send('failed to render page preview');
+ // proxy fallback image from the frontend
+ if (this.secureHost) {
+ https.get(this.mempoolHost + matchedRoute.fallbackImg, (got) => got.pipe(res));
+ } else {
+ http.get(this.mempoolHost + matchedRoute.fallbackImg, (got) => got.pipe(res));
+ }
} else {
res.contentType('image/png');
res.send(img);
@@ -137,50 +153,14 @@ class Server {
return;
}
- let previewSupported = true;
- let mode = 'mainnet'
- let ogImageUrl = this.defaultImageUrl;
- let ogTitle;
const { lang, path } = parseLanguageUrl(rawPath);
- const parts = path.slice(1).split('/');
+ const matchedRoute = matchRoute(this.network, path);
+ let ogImageUrl = this.mempoolHost + (matchedRoute.staticImg || matchedRoute.fallbackImg);
+ let ogTitle = 'The Mempool Open Source Projectâ„¢';
- // handle network mode modifiers
- if (['testnet', 'signet'].includes(parts[0])) {
- mode = parts.shift();
- }
-
- // handle supported preview routes
- switch (parts[0]) {
- case 'block':
- ogTitle = `Block: ${parts[1]}`;
- break;
- case 'address':
- ogTitle = `Address: ${parts[1]}`;
- break;
- case 'tx':
- ogTitle = `Transaction: ${parts[1]}`;
- break;
- case 'lightning':
- switch (parts[1]) {
- case 'node':
- ogTitle = `Lightning Node: ${parts[2]}`;
- break;
- case 'channel':
- ogTitle = `Lightning Channel: ${parts[2]}`;
- break;
- default:
- previewSupported = false;
- }
- break;
- default:
- previewSupported = false;
- }
-
- if (previewSupported) {
+ if (matchedRoute.render) {
ogImageUrl = `${config.SERVER.HOST}/render/${lang || 'en'}/preview${path}`;
- ogTitle = `${this.network ? capitalize(this.network) + ' ' : ''}${mode !== 'mainnet' ? capitalize(mode) + ' ' : ''}${ogTitle}`;
- } else {
- ogTitle = 'The Mempool Open Source Projectâ„¢';
+ ogTitle = `${this.network ? capitalize(this.network) + ' ' : ''}${matchedRoute.networkMode !== 'mainnet' ? capitalize(matchedRoute.networkMode) + ' ' : ''}${matchedRoute.title}`;
}
res.send(`
@@ -192,8 +172,8 @@ class Server {
-
-
+
+
@@ -206,17 +186,6 @@ class Server {