// load configs and spaces const config = require("./config.json"); const spaces = require("./spaces.json"); // load modules const { setInterval } = require("node:timers/promises"); const fetch = require("node-fetch"); const express = require("express"); const { graphqlHTTP } = require('express-graphql'); const { buildSchema } = require('graphql'); const NodeCache = require("node-cache"); const jp = require('jsonpath'); const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); // set up things const cache = new NodeCache({ stdTTL: config.checkperiod * 3 }); let schema = buildSchema(` type Query { isOpen(id: String): Boolean } `); let root = { sisOpen({ id }) { let open = cache.get(id); return { open }; } }; let app = express(); app.use('/graphql', graphqlHTTP({ schema: schema, rootValue: root, graphiql: true, })); app.listen(4000); // CHECK LOOP (async function () { for await (const time of setInterval(config.checkperiod * 10)) { console.log("Checking for spaces..."); for (const space of spaces) { console.log(`Checking ${space.id}...`); let o = await checkSpace(space); console.log(`Space ${space.id} is ${o ? "open" : "closed"}`); if (o !== cache.get(space.id)) { cache.set(space.id, o); let update = await prisma.space.upsert({ where: { id: space.id }, update: { open: o }, create: { id: space.id, open: o } }); } } } })(); // HELPER FUNCTIONS async function checkSpace(space) { let response, data, open; try { response = await fetch(space.endpoint); data = await response.json(); } catch (e) { console.error(`The space ${space.id} might not be reachable. Please check the endpoint. Error: ${e}`); } if (!space.path) { try { open = data.state.open; } catch { console.error(`The space ${space.id} is not using the SpaceAPI standard. Please specify a path.`); } } else { try { open = (jp.query(data, space.path) == (space.expected ? space.expected : true)); } catch { console.error(`The space ${space.id} has an invalid JSONPath to the target value. Please use https://jsonpath.com/ to evaluate the path.`); } } return open; }