diff --git a/src/api.ts b/src/api.ts index 8c1b36b..02f3f12 100644 --- a/src/api.ts +++ b/src/api.ts @@ -9,6 +9,7 @@ import { queue, getProgress } from './lib/queue'; import { snapshotFee } from './lib/nftClaimer/utils'; import AiSummary from './lib/ai/summary'; import AiTextToSpeech from './lib/ai/textToSpeech'; +import { getDomain } from './lib/domain'; const router = express.Router(); @@ -101,6 +102,17 @@ router.get('/moderation', async (req, res) => { } }); +router.get('/domains/:domain', async (req, res) => { + const { domain } = req.params; + + try { + res.json({ domain, space_id: getDomain(domain) }); + } catch (e) { + capture(e); + return rpcError(res, 'INTERNAL_ERROR', ''); + } +}); + router.get('/nft-claimer', async (req, res) => { try { return res.json({ snapshotFee: await snapshotFee() }); diff --git a/src/index.ts b/src/index.ts index c784869..0a9ec0c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ import { name, version } from '../package.json'; import { rpcError } from './helpers/utils'; import initMetrics from './lib/metrics'; import initCacheRefresher from './lib/cacheRefresher'; +import { initDomainsRefresher } from './lib/domain'; const app = express(); const PORT = process.env.PORT || 3005; @@ -18,6 +19,7 @@ const PORT = process.env.PORT || 3005; initLogger(app); initMetrics(app); initCacheRefresher(); +initDomainsRefresher(); app.disable('x-powered-by'); app.use(express.json({ limit: '4mb' })); diff --git a/src/lib/domain.ts b/src/lib/domain.ts new file mode 100644 index 0000000..ac42755 --- /dev/null +++ b/src/lib/domain.ts @@ -0,0 +1,39 @@ +import { capture } from '@snapshot-labs/snapshot-sentry'; +import { sleep } from '../helpers/utils'; + +const LIST_URL = + 'https://raw.githubusercontent.com/snapshot-labs/snapshot-spaces/master/spaces/domains.json'; + +const REFRESH_INTERVAL = 1000 * 60 * 5; // 5 minutes + +// Map of domain (vote.snapshot.org) to space ID (s:snapshot.eth/eth:0x0) +let data = new Map(); + +export function getDomain(domain: string): string | null { + return data.get(domain.toLowerCase()) ?? null; +} + +export async function initDomainsRefresher() { + try { + console.log(`[domains-refresh] Refreshing domains list`); + await refreshList(); + console.log(`[domains-refresh] ${data.size} domains found`); + } catch (e) { + capture(e); + } finally { + await sleep(REFRESH_INTERVAL); + await initDomainsRefresher(); + } +} + +async function refreshList() { + const response = await fetch(LIST_URL, { + headers: { + 'content-type': 'application/json' + } + }); + + const body: Record = await response.json(); + + data = new Map(Object.entries(body).map(([domain, spaceId]) => [domain, `s:${spaceId}`])); +}