Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place
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'; 19 20// Parse CLI arguments 21const args = process.argv.slice(2); 22const hasBackfillFlag = args.includes('--backfill'); 23const backfillOnStartup = hasBackfillFlag || process.env.BACKFILL_ON_STARTUP === 'true'; 24 25// Cache-only mode: service will only cache files locally, no DB writes 26const hasCacheOnlyFlag = args.includes('--cache-only'); 27export const CACHE_ONLY_MODE = hasCacheOnlyFlag || process.env.CACHE_ONLY_MODE === 'true'; 28 29// Configure cache-only mode in database module 30if (CACHE_ONLY_MODE) { 31 setCacheOnlyMode(true); 32} 33 34// Ensure cache directory exists 35if (!existsSync(CACHE_DIR)) { 36 mkdirSync(CACHE_DIR, { recursive: true }); 37 console.log('Created cache directory:', CACHE_DIR); 38} 39 40// Start domain cache cleanup 41startDomainCacheCleanup(); 42 43// Start firehose worker with observability logger 44const firehose = new FirehoseWorker((msg, data) => { 45 logger.info(msg, data); 46}); 47 48firehose.start(); 49 50// Run backfill if requested 51if (backfillOnStartup) { 52 console.log('🔄 Backfill requested, starting cache backfill...'); 53 backfillCache({ 54 skipExisting: true, 55 concurrency: 3, 56 }).then((stats) => { 57 console.log('✅ Cache backfill completed'); 58 }).catch((err) => { 59 console.error('❌ Cache backfill error:', err); 60 }); 61} 62 63// Add health check endpoint 64app.get('/health', (c) => { 65 const firehoseHealth = firehose.getHealth(); 66 return c.json({ 67 status: 'ok', 68 firehose: firehoseHealth, 69 }); 70}); 71 72// Start HTTP server with Node.js adapter 73const server = serve({ 74 fetch: app.fetch, 75 port: PORT, 76}); 77 78console.log(` 79Wisp Hosting Service 80 81Server: http://localhost:${PORT} 82Health: http://localhost:${PORT}/health 83Cache: ${CACHE_DIR} 84Firehose: Connected to Firehose 85Cache-Only: ${CACHE_ONLY_MODE ? 'ENABLED (no DB writes)' : 'DISABLED'} 86`); 87 88// Graceful shutdown 89process.on('SIGINT', async () => { 90 console.log('\n🛑 Shutting down...'); 91 firehose.stop(); 92 stopDomainCacheCleanup(); 93 server.close(); 94 process.exit(0); 95}); 96 97process.on('SIGTERM', async () => { 98 console.log('\n🛑 Shutting down...'); 99 firehose.stop(); 100 stopDomainCacheCleanup(); 101 server.close(); 102 process.exit(0); 103});