'use strict'; const http = require('node:http'); const fs = require('node:fs'); const path = require('node:path'); const { buildOverview } = require('./days.js'); const PORT = process.env.PORT || 3000; const TAGS_PATH = path.join(__dirname, 'tags.json'); const INDEX_PATH = path.join(__dirname, 'public', 'index.html'); function readTags() { return JSON.parse(fs.readFileSync(TAGS_PATH, 'utf8')); } function sendJSON(res, status, body) { res.writeHead(status, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(body)); } async function handleOverview(res, query) { const icsUrl = query.get('url'); if (!icsUrl) return sendJSON(res, 400, { error: 'missing url parameter' }); let parsedUrl; try { parsedUrl = new URL(icsUrl); } catch { return sendJSON(res, 400, { error: 'invalid url' }); } if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') { return sendJSON(res, 400, { error: 'url must be http or https' }); } let icsText; try { const fetchRes = await fetch(icsUrl); if (!fetchRes.ok) throw new Error(`HTTP ${fetchRes.status}`); icsText = await fetchRes.text(); } catch (err) { return sendJSON(res, 502, { error: `could not fetch calendar: ${err.message}` }); } const now = new Date(); const rangeStart = `${now.getFullYear()}-01-01`; const rangeEnd = `${now.getFullYear() + 1}-12-31`; let overview; try { overview = buildOverview(icsText, readTags(), rangeStart, rangeEnd); } catch (err) { return sendJSON(res, 500, { error: `could not parse calendar: ${err.message}` }); } sendJSON(res, 200, { rangeStart, rangeEnd, days: overview }); } const server = http.createServer(async (req, res) => { const url = new URL(req.url, `http://localhost:${PORT}`); if (req.method === 'GET' && url.pathname === '/') { res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(fs.readFileSync(INDEX_PATH)); return; } if (req.method === 'GET' && url.pathname === '/tags.json') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(fs.readFileSync(TAGS_PATH)); return; } if (req.method === 'GET' && url.pathname === '/api/default-url') { return sendJSON(res, 200, { url: process.env.CALURL || null }); } if (req.method === 'GET' && url.pathname === '/api/overview') { await handleOverview(res, url.searchParams); return; } res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('not found'); }); server.listen(PORT, () => { console.log(`http://localhost:${PORT}`); });