From 003e319699b8302746cae262b527e81d28ce0f53 Mon Sep 17 00:00:00 2001 From: piradio Date: Wed, 22 May 2019 20:44:29 +0200 Subject: [PATCH] Install phatbeatd as a daemon. --- stage2/04-pirate-radio/01-run.sh | 2 + stage2/04-pirate-radio/02-run-chroot.sh | 1 + stage2/04-pirate-radio/files/bin/phatbeatd | 231 +++++++++++++++++++++ stage2/04-pirate-radio/files/phatbeatd | 110 ++++++++++ 4 files changed, 344 insertions(+) create mode 100755 stage2/04-pirate-radio/files/bin/phatbeatd create mode 100755 stage2/04-pirate-radio/files/phatbeatd diff --git a/stage2/04-pirate-radio/01-run.sh b/stage2/04-pirate-radio/01-run.sh index f122071..afcfab3 100755 --- a/stage2/04-pirate-radio/01-run.sh +++ b/stage2/04-pirate-radio/01-run.sh @@ -10,3 +10,5 @@ install -v -m 755 files/vlcd "${ROOTFS_DIR}/etc/init.d/" install -v -m 755 files/bin/vlcd "${ROOTFS_DIR}/usr/bin/" mkdir "${ROOTFS_DIR}/etc/vlcd" install -v -m 644 files/default.m3u "${ROOTFS_DIR}/etc/vlcd/" +install -v -m 755 files/phatbeatd "${ROOTFS_DIR}/etc/init.d/" +install -v -m 755 files/bin/phatbeatd "${ROOTFS_DIR}/usr/bin/" diff --git a/stage2/04-pirate-radio/02-run-chroot.sh b/stage2/04-pirate-radio/02-run-chroot.sh index 74e7c19..b7cd329 100755 --- a/stage2/04-pirate-radio/02-run-chroot.sh +++ b/stage2/04-pirate-radio/02-run-chroot.sh @@ -9,3 +9,4 @@ autoconf && automake --add-missing make install systemctl daemon-reload systemctl enable vlcd +systemctl enable phatbeatd diff --git a/stage2/04-pirate-radio/files/bin/phatbeatd b/stage2/04-pirate-radio/files/bin/phatbeatd new file mode 100755 index 0000000..e220dc6 --- /dev/null +++ b/stage2/04-pirate-radio/files/bin/phatbeatd @@ -0,0 +1,231 @@ +#!/usr/bin/env python + +import atexit +import re +import socket +import subprocess +import time +import os +import signal +import sys +from datetime import datetime + +VLC_HOST = "127.0.0.1" +VLC_PORT = 9294 + +LOG_LEVEL = 0 + +PIDFILE = "/var/run/phatbeatd.pid" +LOGFILE = "/var/log/phatbeatd.log" +ERRFILE = "/var/log/phatbeatd.err" + +SHUTDOWN_HOLD_TIME = 3 + +LOG_INFO = 0 +LOG_WARN = 1 +LOG_FAIL = 2 +LOG_DEBUG = 3 + +def log(msg, level=LOG_INFO): + if level < LOG_LEVEL: return + + sys.stdout.write(str(datetime.now())) + sys.stdout.write(": ") + sys.stdout.write(msg) + sys.stdout.write("\n") + sys.stdout.flush() + +class VLC(): + + def __init__(self, host="127.0.0.1", port=9294): + self.host = host + self.port = port + self.current_stream = None + self.current_state = None + self.connecting = False + self.socket = None + + def send(self, command): + if self.connecting: + return False + + log("Sending command: {}".format(command), level=LOG_INFO) + command_string = command + "\n" + + if sys.version_info[0] >= 3: + command_string = command_string.encode("utf-8") + + try: + self.socket.send(command_string) + + except socket.error: + log("Failed to send command to VLC", level=LOG_WARN) + if self.connect(): + self.send(command) + + def recv(self, length): + value = self.socket.recv(8192) + + if sys.version_info[0] >= 3: + value = value.decode("utf-8") + + return value + + def communicate(self, command, response_length=8192): + self.send(command) + return self.recv(response_length) + + def get_current_stream(self): + self.send("status") + status = self.recv(8192) + + result = re.search("input:\ (.*)\ ", status) + state = re.search("state\ (.*)\ ", status) + + if state is not None: + self.current_state = state.group(1) + + if result is not None: + self.current_stream = result.group(1) + else: + self.current_stream = None + + return self.current_stream + + def connect(self): + if self.connecting: + return + + self.connecting = True + + if self.socket is not None: + self.socket.close() + + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + for attempt in range(10): + try: + log("Attempting to connect to VLC on {host}:{port}".format(host=self.host, port=self.port)) + self.socket.connect((self.host, self.port)) + log("Connection successful!", level=LOG_INFO) + self.connecting = False + return True + + except socket.error: + time.sleep(1) + + log("Connection failed!", level=LOG_FAIL) + self.connecting = False + return False + + +if __name__ == "__main__": + stdin = None + stdout = None + stderr = None + fpid = None + daemonize = True + pid = None + + def _signal_handler(signal, frame): + _cleanup() + sys.exit(0) + + def _cleanup(): + log("Exiting cleanly") + + try: + os.remove(PIDFILE) + except OSError: + pass + + if stdin is not None: stdin.close() + if stdout is not None: stdout.close() + if stderr is not None: stderr.close() + + if daemonize: + try: + pid = os.fork() + if pid > 0: + sys.exit(0) + + except OSError, e: + log("Fork #1 failed: {} ({})".format(e.errno, e.strerror)) + sys.exit(1) + + os.chdir("/") + os.setsid() + os.umask(0) + + try: + pid = os.fork() + if pid > 0: + sys.exit(0) + + except OSError, e: + log("Fork #2 failed: {} ({})".format(e.errno, e.strerror)) + sys.exit(1) + + pid = os.getpid() + fpid = open(PIDFILE, 'w') + fpid.write(str(pid)) + fpid.close() + + log("PHAT BEAT {} running with PID: {}".format("daemon" if daemonize else "process",pid)) + + stdin = file("/dev/null", 'r') + stdout = file(LOGFILE, 'a+') + stderr = file(ERRFILE, 'a+') + + os.dup2(stdin.fileno(), sys.stdin.fileno()) + os.dup2(stdout.fileno(), sys.stdout.fileno()) + os.dup2(stderr.fileno(), sys.stderr.fileno()) + + vlc = VLC(host=VLC_HOST, port=VLC_PORT) + + if vlc.connect(): + import phatbeat + phatbeat.set_all(0,128,0,0.1) + phatbeat.show() + time.sleep(1) + phatbeat.clear() + phatbeat.show() + + @phatbeat.on(phatbeat.BTN_VOLDN) + def pb_volume_down(pin): + log(vlc.communicate("voldown")) + + @phatbeat.on(phatbeat.BTN_VOLUP) + def pb_volume_up(pin): + log(vlc.communicate("volup")) + + @phatbeat.on(phatbeat.BTN_PLAYPAUSE) + def pb_play_pause(pin): + log(vlc.communicate("pause")) + time.sleep(0.1) + phatbeat.clear() + phatbeat.show() + + @phatbeat.on(phatbeat.BTN_FASTFWD) + def pb_fast_forward(pin): + log(vlc.communicate("next")) + + @phatbeat.on(phatbeat.BTN_REWIND) + def pb_rewind(pin): + log(vlc.communicate("prev")) + + @phatbeat.on(phatbeat.BTN_ONOFF) + def perform_shutdown(pin): + log(vlc.communicate("pause")) + os.system("sudo shutdown -h now") + + signal.signal(signal.SIGINT, _signal_handler) + signal.signal(signal.SIGTERM, _signal_handler) + signal.pause() + + _cleanup() + sys.exit(0) + + else: + _cleanup() + sys.exit(1) diff --git a/stage2/04-pirate-radio/files/phatbeatd b/stage2/04-pirate-radio/files/phatbeatd new file mode 100755 index 0000000..4d9f0d4 --- /dev/null +++ b/stage2/04-pirate-radio/files/phatbeatd @@ -0,0 +1,110 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: phatbeatd +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Starts PHAT BEAT VLC control daemon at boot time +# Description: Manages the PHAT BEAT VLC control daemon +### END INIT INFO + +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="Picade HAT Daemon" +NAME=phatbeatd +DAEMON=/usr/bin/$NAME +PIDFILE=/var/run/$NAME.pid +LOGFILE=/var/log/$NAME.log +ERRFILE=/var/log/$NAME.err +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE"); then + echo 'Service already running' >&2 + return 1 + fi + echo 'Starting...' >&2 + su -c "$DAEMON" root +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE"); then + echo 'Service not running' >&2 + return 1 + fi + echo 'Stopping...' >&2 + kill $(cat "$PIDFILE") + echo 'Service stopped!' >&2 + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + restart|force-reload) + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: