160 lines
5.7 KiB
Bash
Executable File
160 lines
5.7 KiB
Bash
Executable File
#!/bin/bash
|
|
### BEGIN INIT INFO
|
|
# Provides: emalibre
|
|
# Required-Start: $remote_fs $network $syslog
|
|
# Required-Stop: $remote_fs $network $syslog
|
|
# Default-Start: 2 3 4 5
|
|
# Default-Stop: 0 1 6
|
|
# Short-Description: EMA Libre Carpincho web
|
|
### END INIT INFO
|
|
|
|
PATH=/usr/sbin:/usr/bin:/sbin:/bin
|
|
export PATH
|
|
. /lib/lsb/init-functions
|
|
|
|
appFilePath=/usr/share/emalibre
|
|
pidFile=/run/emalibre.pid
|
|
logDir=/var/log/emalibre
|
|
modeFile=/etc/emalibre_modo
|
|
foreverApp="$appFilePath/node_modules/forever/bin/forever"
|
|
# Mantener el registro de instalaciones anteriores iniciadas como root.
|
|
export HOME=/root
|
|
export FOREVER_ROOT=/root/.forever
|
|
nodeBin="$appFilePath/node_modules/node/bin/node"
|
|
export PATH="$appFilePath/node_modules/node/bin:$PATH"
|
|
|
|
fail() { echo "emalibre: $*" >&2; return 1; }
|
|
require_root() {
|
|
[ "$(id -u)" -eq 0 ] || { fail "Este comando requiere root."; return 4; }
|
|
}
|
|
check_runtime() {
|
|
[ -x "$nodeBin" ] || { fail "Falta el Node incluido en $nodeBin (Node.js >= 20)."; return 5; }
|
|
"$nodeBin" -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 20 ? 0 : 1)' || {
|
|
fail "Se requiere Node.js >= 20."; return 5;
|
|
}
|
|
[ -f "$foreverApp" ] && [ -f "$appFilePath/gui_web/express.js" ] || {
|
|
fail "La instalación web está incompleta."; return 5;
|
|
}
|
|
}
|
|
node_run() { "$nodeBin" "$@" 9>&-; }
|
|
forever_cmd() { node_run "$foreverApp" "$@"; }
|
|
# Consultar el supervisor, sin confiar en archivos PID residuales.
|
|
# 0: activo; 3: detenido; 4: no se pudo consultar.
|
|
process_status() {
|
|
"$nodeBin" - "$appFilePath" <<'JS'
|
|
const root = process.argv[2];
|
|
const timer = setTimeout(() => process.exit(4), 5000);
|
|
try {
|
|
require(root + '/node_modules/forever').list(false, (err, processes) => {
|
|
clearTimeout(timer);
|
|
if (err) { console.error(err.message); process.exit(4); }
|
|
const active = (processes || []).some(p => p.uid === 'EMA_Web');
|
|
process.exit(active ? 0 : 3);
|
|
});
|
|
} catch (err) { console.error(err.message); process.exit(4); }
|
|
JS
|
|
}
|
|
start() {
|
|
local state mode
|
|
process_status; state=$?
|
|
case "$state" in
|
|
0) echo "EMA Libre ya está ejecutándose."; return 0 ;;
|
|
3) ;;
|
|
*) fail "No se pudo consultar Forever."; return "$state" ;;
|
|
esac
|
|
if [ ! -f "$modeFile" ]; then
|
|
printf 'web\n' > "$modeFile" || return 1
|
|
fi
|
|
mode=$(tr -d '[:space:]' < "$modeFile") || return 1
|
|
[ "$mode" = web ] || { fail "Modo inválido: '$mode'; se esperaba web."; return 2; }
|
|
mkdir -p "$logDir" || return 1
|
|
rm -f "$pidFile" || return 1
|
|
# Forever concatena sourceDir y script: el script debe ser relativo.
|
|
forever_cmd start --uid EMA_Web --id EMA_Web --minUptime 5000 --spinSleepTime 5000 \
|
|
--sourceDir "$appFilePath" --workingDir "$appFilePath" --pidFile "$pidFile" \
|
|
-l "$logDir/forever.log" -o "$logDir/stdout.log" -e "$logDir/stderr.log" \
|
|
-a -c "$nodeBin" "gui_web/express.js" iniciar || return $?
|
|
# Forever arranca en segundo plano: esperar a que registre el supervisor.
|
|
local attempt
|
|
for attempt in {1..10}; do
|
|
process_status; state=$?
|
|
[ "$state" -eq 0 ] && { echo "EMA Libre iniciado."; return 0; }
|
|
[ "$state" -eq 3 ] || return "$state"
|
|
sleep 1
|
|
done
|
|
fail "El supervisor no arrancó; revise $logDir."
|
|
}
|
|
stop() {
|
|
local state
|
|
process_status; state=$?
|
|
case "$state" in
|
|
0) forever_cmd stop EMA_Web || return $? ;;
|
|
3) echo "EMA Libre ya está detenido." ;;
|
|
*) fail "No se pudo consultar Forever."; return "$state" ;;
|
|
esac
|
|
process_status; state=$?
|
|
[ "$state" -eq 3 ] || { fail "No se pudo confirmar la parada."; return 1; }
|
|
rm -f "$pidFile"
|
|
}
|
|
status() {
|
|
local state
|
|
process_status; state=$?
|
|
case "$state" in
|
|
0) echo "EMA Libre: supervisor activo." ;;
|
|
3) echo "EMA Libre: detenido." ;;
|
|
*) fail "Estado desconocido; no se pudo consultar Forever." ;;
|
|
esac
|
|
return "$state"
|
|
}
|
|
set_boot() {
|
|
# El arranque del servicio es independiente del inicio del recolector.
|
|
if [ -d /run/systemd/system ]; then
|
|
systemctl "$1" emalibre
|
|
else
|
|
update-rc.d emalibre defaults && update-rc.d emalibre "$1"
|
|
fi
|
|
}
|
|
view_conf() {
|
|
printf 'Modo: '; cat "$modeFile" || return 1
|
|
if [ -d /run/systemd/system ]; then
|
|
systemctl is-enabled emalibre
|
|
else
|
|
echo 'Inicio del servicio: consultar enlaces /etc/rc[2-5].d/*emalibre'
|
|
fi
|
|
"$nodeBin" - "$appFilePath/conf/ConfiguracionGeneral.js" <<'JS'
|
|
const cfg = require(process.argv[2]).ConfGeneral;
|
|
for (const key of ['Tiempo_de_Recoleccion', 'UTC', 'SistemaMetrico', 'debug',
|
|
'debugTamanio', 'NombreEstacion', 'Modo', 'inicio_automatico', 'Audio',
|
|
'notificar_cambios', 'audioVoces', 'IP', 'Puerto', 'Ruta']) {
|
|
console.log(key + ': ' + cfg[key]);
|
|
}
|
|
JS
|
|
}
|
|
|
|
case "${1:-}" in
|
|
start|stop|restart|force-reload|status|uptime|reporte|view-conf|set-inicio-enabled|set-inicio-disable) ;;
|
|
*) echo "Uso: $0 {start|stop|restart|force-reload|status|uptime|reporte|view-conf|set-inicio-enabled|set-inicio-disable}" >&2; exit 2 ;;
|
|
esac
|
|
require_root || exit $?
|
|
check_runtime || exit $?
|
|
case "$1" in
|
|
start|stop|restart|force-reload|set-inicio-enabled|set-inicio-disable)
|
|
# Evitar arranques/paradas simultáneos. Cerrar el descriptor en Node
|
|
# impide que el daemon herede y retenga el bloqueo.
|
|
exec 9>/run/lock/emalibre.lock || exit 1
|
|
flock -w 30 9 || exit 1
|
|
;;
|
|
esac
|
|
case "$1" in
|
|
start) start ;;
|
|
stop) stop ;;
|
|
restart|force-reload) stop && start ;;
|
|
status) status ;;
|
|
uptime) forever_cmd list ;;
|
|
reporte) (cd "$appFilePath" && node_run core/reporte.js) ;;
|
|
view-conf) view_conf ;;
|
|
set-inicio-enabled) set_boot enable ;;
|
|
set-inicio-disable) set_boot disable ;;
|
|
esac
|
|
exit $?
|