#!/bin/sh
# EasyLife CRM keepalive — keeps the WhatsApp sessions connected on shared hosting.
#
# THE PROBLEM THIS SOLVES
#
# Phusion Passenger (what cPanel's "Setup Node.js App" runs behind) stops an application process
# once it has been idle for a while, and starts it again on the next HTTP request. That is fine for
# a website. It is not fine for this app: stopping the process kills the live WhatsApp engine
# sockets, so every quiet stretch — a lunch break, a night — silently disconnects every session.
# The next person to open the dashboard wakes the app back up and finds the sessions dead.
#
# Two things fix it together, and both are needed:
#   1. AUTO_START_SESSIONS (default ON in this build) — when the app starts, it reconnects the
#      sessions it had. Without this, a restart is permanent until a human clicks Start.
#   2. This script — a cron job that requests a cheap endpoint often enough that Passenger never
#      considers the app idle in the first place, so the restart mostly does not happen at all.
#
# WHAT IT DOES NOT DO
#
# It is not a process supervisor and cannot restart a crashed app: nothing on shared hosting gives
# us that. It reduces how often the app is stopped, and AUTO_START_SESSIONS handles the times it
# still is. If sessions keep dropping even with both in place, the next thing to look at is the
# account's process limit in cPanel — an app that cannot fork a new process will not come back no
# matter how often it is pinged.
#
# INSTALL (cPanel -> Cron Jobs), every 5 minutes:
#
#   */5 * * * * /bin/sh /home2/easylife/crm.easylife.com.pk/scripts/easylife-keepalive.sh
#
# Set "Common Settings" to "Every 5 Minutes" and paste the command. Leave the email field blank or
# cron will mail you 288 messages a day.
#
# It writes one line per run to keepalive.log, kept under KEEPALIVE_LOG_MAX_BYTES so it cannot grow
# into the account's disk quota.

set -eu

URL="${KEEPALIVE_URL:-https://crm.easylife.com.pk/api/health}"
LOG="${KEEPALIVE_LOG:-/home2/easylife/crm.easylife.com.pk/keepalive.log}"
MAX_BYTES="${KEEPALIVE_LOG_MAX_BYTES:-262144}"
TIMEOUT="${KEEPALIVE_TIMEOUT:-30}"

timestamp() {
  date -u '+%Y-%m-%dT%H:%M:%SZ'
}

# Truncate rather than rotate: this log is a heartbeat trail, not an audit record, and a second
# rotated file on a quota-limited account is a cost with no matching benefit.
if [ -f "$LOG" ]; then
  size=$(wc -c < "$LOG" 2>/dev/null || echo 0)
  if [ "$size" -gt "$MAX_BYTES" ]; then
    : > "$LOG"
    echo "$(timestamp) log truncated at ${size} bytes" >> "$LOG"
  fi
fi

# --max-time bounds the whole request: a hung app must not leave a curl running until the next tick
# stacks another one on top of it. -s -o /dev/null keeps cron quiet; -w gives us the status code.
#
# curl already prints 000 on a connection failure, so `|| echo 000` would CONCATENATE a second 000
# onto it and produce "000000", which matches no case below. Take curl's own output and only
# substitute when it printed nothing at all.
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time "$TIMEOUT" "$URL" 2>/dev/null) || true
[ -n "$code" ] || code=000

case "$code" in
  200)
    echo "$(timestamp) ok" >> "$LOG"
    ;;
  000)
    # No response at all — DNS, TLS, timeout, or the app failed to boot. Worth seeing in the log,
    # but there is nothing useful to do about it from here.
    echo "$(timestamp) unreachable" >> "$LOG"
    ;;
  *)
    echo "$(timestamp) http ${code}" >> "$LOG"
    ;;
esac

exit 0
