Intial Version
This commit is contained in:
91
backend/src/index.ts
Normal file
91
backend/src/index.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import 'dotenv/config';
|
||||
import server from './api/server';
|
||||
import { ScraperScheduler } from './scrapers/scheduler';
|
||||
import { PriceRepository } from './database/repository';
|
||||
import { broadcastPriceUpdate } from './api/routes/websocket';
|
||||
|
||||
const PORT = parseInt(process.env.PORT || '3000', 10);
|
||||
const HOST = process.env.HOST || '0.0.0.0';
|
||||
const SCRAPE_INTERVAL = parseInt(process.env.SCRAPE_INTERVAL_MINUTES || '5', 10);
|
||||
|
||||
const repository = new PriceRepository();
|
||||
const scheduler = new ScraperScheduler(SCRAPE_INTERVAL);
|
||||
|
||||
// Handle scrape results
|
||||
scheduler.onScrapeComplete(async (results) => {
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
// Save all listings
|
||||
const allListings = results.flatMap(r => r.listings);
|
||||
if (allListings.length > 0) {
|
||||
await repository.saveListings(allListings);
|
||||
|
||||
// Find and save lowest price
|
||||
const lowestListing = allListings.reduce((min, listing) =>
|
||||
listing.pricePerMillion < min.pricePerMillion ? listing : min
|
||||
);
|
||||
|
||||
await repository.savePriceIndex(
|
||||
lowestListing.pricePerMillion,
|
||||
lowestListing.vendor,
|
||||
lowestListing.seller
|
||||
);
|
||||
|
||||
// Broadcast update to WebSocket clients
|
||||
const latestPrices = await repository.getLatestPrices();
|
||||
broadcastPriceUpdate({
|
||||
timestamp: new Date(),
|
||||
lowestPrice: lowestListing.pricePerMillion,
|
||||
platform: lowestListing.vendor,
|
||||
sellerName: lowestListing.seller,
|
||||
allPrices: latestPrices.map((p: any) => ({
|
||||
id: p.id,
|
||||
platform: p.vendor,
|
||||
sellerName: p.sellerName,
|
||||
pricePerMillion: Number(p.usdPerMillion),
|
||||
timestamp: p.timestamp,
|
||||
url: p.url
|
||||
}))
|
||||
});
|
||||
|
||||
console.log(`✓ Broadcasted price update to ${latestPrices.length} listings`);
|
||||
}
|
||||
|
||||
// Log successful scrape
|
||||
const runtimeMs = Date.now() - startTime;
|
||||
await repository.logScrape('success', `Saved ${allListings.length} listings`, runtimeMs);
|
||||
|
||||
console.log(`✓ Saved ${allListings.length} listings to database`);
|
||||
} catch (error) {
|
||||
const runtimeMs = Date.now() - startTime;
|
||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||
await repository.logScrape('failure', message, runtimeMs);
|
||||
console.error('✗ Failed to save listings:', message);
|
||||
}
|
||||
});
|
||||
|
||||
// Start server
|
||||
const start = async () => {
|
||||
try {
|
||||
await server.listen({ port: PORT, host: HOST });
|
||||
console.log(`Server listening on ${HOST}:${PORT}`);
|
||||
|
||||
// Start scraper
|
||||
scheduler.start();
|
||||
console.log(`Scraper started (interval: ${SCRAPE_INTERVAL} minutes)`);
|
||||
} catch (err) {
|
||||
server.log.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Graceful shutdown
|
||||
process.on('SIGINT', async () => {
|
||||
console.log('\nShutting down gracefully...');
|
||||
await scheduler.close();
|
||||
await server.close();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
start();
|
||||
Reference in New Issue
Block a user