diff --git a/src/pages/api/cron.ts b/src/pages/api/cron.ts index d9d2bf9..f1b5ea7 100644 --- a/src/pages/api/cron.ts +++ b/src/pages/api/cron.ts @@ -1,15 +1,26 @@ +import { getMatchingTime } from '@/timing'; // Next.js API route support: https://nextjs.org/docs/api-routes/introduction import type { NextApiRequest, NextApiResponse } from 'next'; import { getDistance } from '@/location'; import { env } from '@/env/server.mjs'; import monitorAsync from '@/monitor'; +import { sendNotification } from '@/notify'; +import { fetchConfiguration, checkIdentifier, markIdentifier } from '@/db'; type ResponseData = { diff: number; inRange: boolean; }; -type StatusData = { status: string }; +type StatusData = { status: ResponseStatus }; + +type ResponseStatus = + | 'unauthorized' + | 'out-of-range' + | 'no-matching-time' + | 'already-notified' + | 'notified' + | 'error'; const center = { latitude: env.CENTER_LATITUDE, @@ -22,28 +33,64 @@ export default async function handler( ) { if (req.query.key != env.API_KEY) { // auth failed - res.status(401).json({ status: 'Unauthorized' }); + res.status(401).json({ status: 'unauthorized' }); return; } - async function innerFunction() { - const diff = await getDistance(); - // auth passed - res.setHeader( - 'Cache-Control', - `max-age=0, s-maxage=${env.EDGE_CACHE_TIME_SECONDS}, stale-while-revalidate` - ); - res - .status(200) - .json({ diff, inRange: diff < env.MAX_DISTANCE, status: 'Success' }); + async function innerFunction(): Promise { + const now = new Date(); + + const config = await fetchConfiguration({ + times: [ + { + time: '03:13', + maxLate: '00:10', + days: [ + 'monday', + 'tuesday', + 'wednesday', + 'thursday', + 'friday', + 'saturday', + 'sunday' + ], + name: 'B' + }, + { + time: '23:26', + maxLate: '00:10', + days: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], + name: 'A' + } + ] + }); + const matching = await getMatchingTime(config, now); + + // No matching time - no notification to send. + if (matching == null) return 'no-matching-time'; + + // Check if I am in range of the center + const distanceToCenter = await getDistance(); + if (distanceToCenter > 280) return 'out-of-range'; + + // Check if I have already been notified + if (await checkIdentifier(matching.name, now)) return 'already-notified'; + + // Send notification, mark + await sendNotification(`The bus is leaving soon. (${matching.name}))`); + await markIdentifier(matching.name, true, 60 * 60 * 24 * 31, now); + + return 'notified'; } try { + let result; if (process.env.NODE_ENV === 'production') - await monitorAsync(innerFunction); - else await innerFunction(); + result = await monitorAsync(innerFunction); + else result = await innerFunction(); + res.status(200).json({ status: result }); } catch (e) { console.error(e); - res.status(500).json({ status: 'Error' }); + res.status(500).json({ status: 'error' }); } }