← back to Animate Museum Posts

src/healthServer.js

116 lines

import http from 'http';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const PORT = process.env.PORT || 7890;

// Track bot state
let lastPostTime = null;
let nextPostTime = null;
let isRunning = false;

export function updateLastPost(time) {
  lastPostTime = time || new Date().toISOString();
  // Next post is 6 hours from now
  nextPostTime = new Date(Date.now() + 6 * 60 * 60 * 1000).toISOString();

  // Save to file for persistence
  const dataDir = path.join(__dirname, '..', 'data');
  if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
  fs.writeFileSync(path.join(dataDir, 'last-run.json'), JSON.stringify({
    lastPost: lastPostTime,
    nextPost: nextPostTime,
    updatedAt: new Date().toISOString()
  }, null, 2));
}

export function setRunning(running) {
  isRunning = running;
}

function getLast5Posts() {
  try {
    const logsDir = path.join(__dirname, '..', 'logs');
    const logFile = path.join(logsDir, 'posts.log');
    if (!fs.existsSync(logFile)) return [];

    const content = fs.readFileSync(logFile, 'utf-8');
    const lines = content.trim().split('\n').filter(Boolean);
    return lines.slice(-5).map(line => {
      try { return JSON.parse(line); } catch { return null; }
    }).filter(Boolean);
  } catch {
    return [];
  }
}

function loadLastRun() {
  try {
    const dataDir = path.join(__dirname, '..', 'data');
    const lastRunFile = path.join(dataDir, 'last-run.json');
    if (fs.existsSync(lastRunFile)) {
      const data = JSON.parse(fs.readFileSync(lastRunFile, 'utf-8'));
      lastPostTime = data.lastPost;
      nextPostTime = data.nextPost;
    }
  } catch {}
}

const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');

  if (req.url === '/health' || req.url === '/') {
    const response = {
      status: 'ok',
      service: 'museum-art-bot',
      isRunning,
      lastPost: lastPostTime,
      nextPost: nextPostTime,
      uptime: process.uptime(),
      timestamp: new Date().toISOString()
    };
    res.writeHead(200);
    res.end(JSON.stringify(response, null, 2));
  }
  else if (req.url === '/status') {
    const posts = getLast5Posts();
    const response = {
      status: 'ok',
      recentPosts: posts.map(p => ({
        timestamp: p.timestamp,
        tweetId: p.tweetId,
        artwork: p.artwork?.title,
        artist: p.artwork?.artist
      })),
      totalPosts: posts.length,
      lastPost: lastPostTime,
      nextPost: nextPostTime
    };
    res.writeHead(200);
    res.end(JSON.stringify(response, null, 2));
  }
  else {
    res.writeHead(404);
    res.end(JSON.stringify({ error: 'Not found' }));
  }
});

export function startHealthServer() {
  loadLastRun();
  server.listen(PORT, () => {
    console.log(`Health server running on port ${PORT}`);
    isRunning = true;
  });
  return server;
}

// If run directly
if (process.argv[1] === fileURLToPath(import.meta.url)) {
  startHealthServer();
}