Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place
96
fork

Configure Feed

Select the types of activity you want to include in your feed.

1import app from './server'; 2import { serve } from '@hono/node-server'; 3import { FirehoseWorker } from './lib/firehose'; 4import { createLogger, initializeGrafanaExporters } from '@wisp/observability'; 5import { mkdirSync, existsSync } from 'fs'; 6import { backfillCache } from './lib/backfill'; 7import { startDomainCacheCleanup, stopDomainCacheCleanup, setCacheOnlyMode } from './lib/db'; 8 9// Initialize Grafana exporters if configured 10initializeGrafanaExporters({ 11 serviceName: 'hosting-service', 12 serviceVersion: '1.0.0' 13}); 14 15const logger = createLogger('hosting-service'); 16 17const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3001; 18const CACHE_DIR = process.env.CACHE_DIR || './cache/sites'; 19const BACKFILL_CONCURRENCY = process.env.BACKFILL_CONCURRENCY 20 ? parseInt(process.env.BACKFILL_CONCURRENCY) 21 : undefined; // Let backfill.ts default (10) apply 22 23// Parse CLI arguments 24const args = process.argv.slice(2); 25const hasBackfillFlag = args.includes('--backfill'); 26const backfillOnStartup = hasBackfillFlag || process.env.BACKFILL_ON_STARTUP === 'true'; 27 28// Cache-only mode: service will only cache files locally, no DB writes 29const hasCacheOnlyFlag = args.includes('--cache-only'); 30export const CACHE_ONLY_MODE = hasCacheOnlyFlag || process.env.CACHE_ONLY_MODE === 'true'; 31 32// Configure cache-only mode in database module 33if (CACHE_ONLY_MODE) { 34 setCacheOnlyMode(true); 35} 36 37// Ensure cache directory exists 38if (!existsSync(CACHE_DIR)) { 39 mkdirSync(CACHE_DIR, { recursive: true }); 40 console.log('Created cache directory:', CACHE_DIR); 41} 42 43// Start domain cache cleanup 44startDomainCacheCleanup(); 45 46// Start firehose worker with observability logger 47const firehose = new FirehoseWorker((msg, data) => { 48 logger.info(msg, data); 49}); 50 51firehose.start(); 52 53// Run backfill if requested 54if (backfillOnStartup) { 55 console.log('🔄 Backfill requested, starting cache backfill...'); 56 backfillCache({ 57 skipExisting: true, 58 concurrency: BACKFILL_CONCURRENCY, 59 }).then((stats) => { 60 console.log('✅ Cache backfill completed'); 61 }).catch((err) => { 62 console.error('❌ Cache backfill error:', err); 63 }); 64} 65 66// Add health check endpoint 67app.get('/health', (c) => { 68 const firehoseHealth = firehose.getHealth(); 69 return c.json({ 70 status: 'ok', 71 firehose: firehoseHealth, 72 }); 73}); 74 75// Start HTTP server with Node.js adapter 76const server = serve({ 77 fetch: app.fetch, 78 port: PORT, 79}); 80 81console.log(` 82Wisp Hosting Service 83 84Server: http://localhost:${PORT} 85Health: http://localhost:${PORT}/health 86Cache: ${CACHE_DIR} 87Firehose: Connected to Firehose 88Cache-Only: ${CACHE_ONLY_MODE ? 'ENABLED (no DB writes)' : 'DISABLED'} 89Backfill: ${backfillOnStartup ? `ENABLED (concurrency: ${BACKFILL_CONCURRENCY || 10})` : 'DISABLED'} 90`); 91 92// Graceful shutdown 93process.on('SIGINT', async () => { 94 console.log('\n🛑 Shutting down...'); 95 firehose.stop(); 96 stopDomainCacheCleanup(); 97 server.close(); 98 process.exit(0); 99}); 100 101process.on('SIGTERM', async () => { 102 console.log('\n🛑 Shutting down...'); 103 firehose.stop(); 104 stopDomainCacheCleanup(); 105 server.close(); 106 process.exit(0); 107});