Add support for configuration files
This commit is contained in:
parent
7fdf9a8da8
commit
fe0fc27b26
1 changed files with 131 additions and 129 deletions
260
rowbot
260
rowbot
|
@ -1,7 +1,36 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
###
|
||||
# switch toggler
|
||||
###
|
||||
|
||||
shopt -s nullglob dotglob extglob
|
||||
|
||||
###
|
||||
# utilities
|
||||
###
|
||||
|
||||
parent() {
|
||||
(( BASHPID == $$ ))
|
||||
}
|
||||
|
||||
has() {
|
||||
hash "$1" 2>/dev/null
|
||||
}
|
||||
|
||||
die() {
|
||||
local status=1
|
||||
|
||||
if (( $# > 1 )) && [[ $1 = -s ]]; then
|
||||
status=$2
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
|
||||
error "$@"
|
||||
exit "$status"
|
||||
}
|
||||
|
||||
###
|
||||
# logger
|
||||
###
|
||||
|
@ -13,7 +42,7 @@ declare -A levels=(
|
|||
|
||||
log() {
|
||||
if [[ -v LEVEL ]] && (( levels[$level] <= levels[$LEVEL] )); then
|
||||
printf "%s: $1\n" "${LEVEL^^}" "${@:2}" >&"$log"
|
||||
printf "%s: $1\n" "${LEVEL^^}" "${@:2}" >&"$log_fd"
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -37,7 +66,7 @@ error() {
|
|||
# argument parser for parsing arguments
|
||||
##
|
||||
|
||||
original_args=("$0" "$@")
|
||||
original_args=( "$@" )
|
||||
declare -A opts
|
||||
|
||||
while (( $# )); do
|
||||
|
@ -69,79 +98,118 @@ done
|
|||
# default config
|
||||
##
|
||||
|
||||
server=${opts[server]:-irc.libera.chat}
|
||||
tls=${opts[tls]:-no}
|
||||
server=irc.libera.chat port=6667 tls=no client_cert=
|
||||
nick=rowbot-dev ident=rowbot realname=rowbot chan=
|
||||
trigger=\` fact_root=. reload=no level=info log_fd=1 log=
|
||||
# shellcheck disable=SC2034
|
||||
sys_root=sysfacts owner=${USER:-uplime} dev=no
|
||||
|
||||
###
|
||||
# apply custom config
|
||||
###
|
||||
|
||||
for file do
|
||||
if [[ -f $file ]]; then
|
||||
# These files are provided dynamically at run-time.
|
||||
# shellcheck disable=SC1090
|
||||
. "$file" # ha, dot file
|
||||
else
|
||||
die 'could not locate config file %s' "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
###
|
||||
# apply command line options
|
||||
###
|
||||
|
||||
if [[ -v opts[tls] ]]; then
|
||||
tls=${opts[tls]}
|
||||
fi
|
||||
|
||||
if [[ $tls = yes ]]; then
|
||||
if ! hash socat 2>/dev/null; then
|
||||
printf 'please install socat to use tls with rowbot.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# false positive
|
||||
# This is a false positive.
|
||||
# shellcheck disable=SC2102
|
||||
if [[ -v opts[client-cert] ]]; then
|
||||
if ! has socat; then
|
||||
die "please install socat to use tls with rowbot."
|
||||
elif [[ -v opts[client-cert] ]]; then
|
||||
client_cert=${opts[client-cert]}
|
||||
fi
|
||||
|
||||
port=${opts[port]:-6697}
|
||||
else
|
||||
port=${opts[port]:-6667}
|
||||
port=6697
|
||||
fi
|
||||
|
||||
nick=${opts[nick]:-rowbot-dev}
|
||||
ident=${opts[ident]:-rowbot}
|
||||
realname=${opts[realname]:-rowbot}
|
||||
chan=${opts[chan]:-}
|
||||
trigger=${opts[trigger]:-\`}
|
||||
fact_root=${opts[fact-root]:-.}
|
||||
reload=${opts[reload]:-no}
|
||||
dev=${opts[dev]:-no}
|
||||
sysfacts_file=${opts[sysfacts]:-./sysfacts.txt}
|
||||
config=(
|
||||
server port nick ident realname chan trigger
|
||||
fact_root reload dev level log owner sys_root
|
||||
reload
|
||||
)
|
||||
|
||||
if [[ -v USER ]]; then
|
||||
owner=${opts[owner]:-"$USER"}
|
||||
else
|
||||
owner=${opts[owner]:-uplime}
|
||||
fi
|
||||
for opt in "${config[@]}"; do
|
||||
declare -n config_var=$opt
|
||||
cmd_arg=${opt//_/-}
|
||||
|
||||
level=${opts[log-level]:-info}
|
||||
if [[ -v opts[$cmd_arg] ]]; then
|
||||
# This variable is only used for assignment.
|
||||
# shellcheck disable=SC2034
|
||||
config_var=${opts[$cmd_arg]}
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $reload = yes ]]; then
|
||||
log=$LOG_FD
|
||||
elif [[ ${opts[log]} ]]; then
|
||||
exec {log}>"${opts[log]}"
|
||||
else
|
||||
log=1
|
||||
if [[ $log && $reload = no ]]; then
|
||||
exec {log_fd}>"$log"
|
||||
fi
|
||||
|
||||
###
|
||||
# utilities
|
||||
# apply reloaded values
|
||||
###
|
||||
|
||||
if [[ $reload = yes ]]; then
|
||||
reload_vars=(
|
||||
nick ident host level log log_fd alarm_pid tls_pid in_sock
|
||||
out_sock sock_dir sys_root fact_root dev trigger registered
|
||||
keep_trying desired_nick
|
||||
)
|
||||
|
||||
for var in "${reload_vars[@]}"; do
|
||||
env_var=${var^^}
|
||||
declare -n reload_var=$var
|
||||
|
||||
if [[ -v $env_var ]]; then
|
||||
# This variable is only used for assignment.
|
||||
# shellcheck disable=SC2034
|
||||
reload_var=${!env_var}
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
###
|
||||
# process management
|
||||
###
|
||||
|
||||
cleanup() {
|
||||
debug "cleaning up rowbot"
|
||||
debug "reaping rowbot's children"
|
||||
|
||||
if [[ -v tls_pid ]]; then
|
||||
kill "$tls_pid"
|
||||
rm -rf "$sock_dir"
|
||||
if [[ -v alarm_pid ]]; then
|
||||
debug "killing alarm process (%d) from %d" "$alarm_pid" "$BASHPID"
|
||||
kill "$alarm_pid"
|
||||
fi
|
||||
|
||||
if [[ -v ping_pid ]]; then
|
||||
debug "cleaning up alarm in %d" "$BASHPID"
|
||||
kill "$ping_pid"
|
||||
if [[ -v tls_pid ]]; then
|
||||
debug "killing tls process (%d) from %d" "$tls_pid" "$BASHPID"
|
||||
kill "$tls_pid"
|
||||
rm -rf "$sock_dir"
|
||||
fi
|
||||
|
||||
if [[ -v tls_pid || $tls = no ]]; then
|
||||
exec {in_sock}>&- {out_sock}>&-
|
||||
|
||||
if (( log != 1 )); then
|
||||
exec {log}>&-
|
||||
if (( log_fd != 1 )); then
|
||||
exec {log_fd}>&-
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if (( BASHPID == $$ )); then
|
||||
if parent; then
|
||||
trap cleanup EXIT
|
||||
fi
|
||||
|
||||
|
@ -156,37 +224,6 @@ alarm-handler() {
|
|||
|
||||
trap alarm-handler ALRM
|
||||
|
||||
###
|
||||
# reload code
|
||||
###
|
||||
|
||||
if [[ $reload = yes ]]; then
|
||||
in_sock=$IN_SOCK out_sock=$OUT_SOCK
|
||||
trigger=$TRIGGER dev=$DEV level=$LOG_LEVEL
|
||||
registered=$REGISTERED
|
||||
|
||||
debug "doing a reload. pid is %d" "$BASHPID"
|
||||
|
||||
if [[ -v KEEP_TRYING ]]; then
|
||||
keep_trying=$KEEP_TRYING desired_nick=$DESIRED
|
||||
fi
|
||||
|
||||
if [[ $tls = yes ]]; then
|
||||
sock_dir=$SOCK_DIR
|
||||
tls_pid=$TLS_PID
|
||||
fi
|
||||
|
||||
if [[ -v PING_PID ]]; then
|
||||
ping_pid=$PING_PID
|
||||
fi
|
||||
|
||||
nick=$NICK ident=$IDENT
|
||||
|
||||
if [[ -v HOST ]]; then
|
||||
host=$HOST
|
||||
fi
|
||||
fi
|
||||
|
||||
###
|
||||
# net code
|
||||
###
|
||||
|
@ -195,10 +232,9 @@ if [[ $reload = no && $tls = yes ]]; then
|
|||
sock_dir=$(mktemp -d)
|
||||
mkfifo "$sock_dir"/rb{in,out}
|
||||
|
||||
if [[ -v client_cert ]]; then
|
||||
if [[ $client_cert ]]; then
|
||||
if [[ ! -f $client_cert ]]; then
|
||||
error "client certificate not found: %s" "$client_cert"
|
||||
exit 1
|
||||
die "client certificate not found: %s" "$client_cert"
|
||||
fi
|
||||
|
||||
conn_args=OPENSSL:$server:$port,cert=$client_cert
|
||||
|
@ -208,8 +244,8 @@ if [[ $reload = no && $tls = yes ]]; then
|
|||
|
||||
socat "$conn_args" - <"$sock_dir"/rbin >"$sock_dir"/rbout &
|
||||
tls_pid=$!
|
||||
debug "created tls connection (pid %d)" "$tls_pid"
|
||||
exec {out_sock}>"$sock_dir"/rbin {in_sock}<"$sock_dir"/rbout
|
||||
debug "created tls connection (pid %d)" "$tls_pid"
|
||||
elif [[ $reload = no ]]; then
|
||||
exec {sock}<>/dev/tcp/"$server"/"$port"
|
||||
in_sock=$sock out_sock=$sock
|
||||
|
@ -218,7 +254,7 @@ fi
|
|||
|
||||
send() {
|
||||
local fmt
|
||||
# As this is a printf wrapper, the format string is provided as an argument
|
||||
# As this is a printf wrapper, the format string is provided as an argument.
|
||||
# shellcheck disable=SC2059
|
||||
printf -v fmt "$1" "${@:2}"
|
||||
printf '%s\r\n' "$fmt" >&"$out_sock"
|
||||
|
@ -306,7 +342,7 @@ on_001() {
|
|||
done
|
||||
} &
|
||||
|
||||
ping_pid=$!
|
||||
alarm_pid=$!
|
||||
nick=${params[0]}
|
||||
registered=yes
|
||||
who "$nick" %%uht,42
|
||||
|
@ -330,11 +366,11 @@ on_005() {
|
|||
local param key value
|
||||
|
||||
for param in "${params[@]:1:${#params[@]}-2}"; do
|
||||
# This is a valid assignment, not a comparison
|
||||
# This is a valid assignment, not a comparison.
|
||||
# shellcheck disable=SC1097
|
||||
IFS== read -r key value <<< "$param"
|
||||
# While isupport is unused, it's still there in case later code wants to
|
||||
# use it
|
||||
# use it.
|
||||
# shellcheck disable=SC2034
|
||||
isupport[$key]=$value
|
||||
debug "isupport: %s = %s" "$key" "$value"
|
||||
|
@ -647,29 +683,18 @@ hook_post_PRIVMSG_control_panel() {
|
|||
privmsg "$to" "joined ${words[1]}"
|
||||
;;
|
||||
reload)
|
||||
export IN_SOCK=$in_sock OUT_SOCK=$out_sock LOG_FD=$log DEV=$dev
|
||||
export RELOAD_TO=$to TRIGGER=$trigger LOG_LEVEL=$level
|
||||
export NICK=$nick IDENT=$ident REGISTERED=$registered
|
||||
reload_vars=(
|
||||
nick ident host level log log_fd alarm_pid tls_pid in_sock
|
||||
out_sock sock_dir sys_root fact_root dev trigger registered
|
||||
keep_trying desired_nick to
|
||||
)
|
||||
|
||||
if [[ $keep_trying = yes ]]; then
|
||||
export KEEP_TRYING=yes DESIRED=$desired_nick
|
||||
fi
|
||||
|
||||
if [[ -v host ]]; then
|
||||
export HOST=$host
|
||||
fi
|
||||
|
||||
if [[ $tls = yes ]]; then
|
||||
export SOCK_DIR=$sock_dir
|
||||
export TLS_PID=$tls_pid
|
||||
fi
|
||||
|
||||
if [[ -v ping_pid ]]; then
|
||||
export PING_PID=$ping_pid
|
||||
fi
|
||||
for env_var in "${reload_vars[@]}"; do
|
||||
export "${env_var^^}"="${!env_var}"
|
||||
done
|
||||
|
||||
privmsg "$to" "reloading..."
|
||||
exec "${original_args[@]}" --reload
|
||||
exec "$0" --reload "${original_args[@]}"
|
||||
;;
|
||||
level)
|
||||
level=${words[1]}
|
||||
|
@ -713,29 +738,6 @@ hook_post_PRIVMSG_control_panel() {
|
|||
fi
|
||||
}
|
||||
|
||||
sysfacts=( )
|
||||
|
||||
if [[ -f $sysfacts_file ]]; then
|
||||
mapfile -t sysfacts < "$sysfacts_file"
|
||||
fi
|
||||
|
||||
hook_post_PRIVMSG_sysfacts() {
|
||||
local to=${params[0]} idx
|
||||
|
||||
if [[ ${params[0]:0:1} != \# ]]; then
|
||||
to=$from
|
||||
fi
|
||||
|
||||
if [[ ${words[0]} = "$trigger"sysfact ]]; then
|
||||
if (( ${#sysfacts[@]} == 0 )); then
|
||||
privmsg "$to" "sysfacts are not loaded :("
|
||||
else
|
||||
(( idx = RANDOM % ${#sysfacts[@]} ))
|
||||
privmsg "$to" "sysfact #$(( idx + 1 )): ${sysfacts[$idx]}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
hook_post_433_alternick() {
|
||||
if [[ -z $desired_nick && $registered = no ]]; then
|
||||
desired_nick=${params[1]}
|
||||
|
@ -755,7 +757,7 @@ hook_post_NICK_alternick() {
|
|||
###
|
||||
|
||||
if [[ $reload = yes ]]; then
|
||||
privmsg "$RELOAD_TO" done.
|
||||
privmsg "$TO" done.
|
||||
else
|
||||
registered=no
|
||||
info "rowbot's pid is %d" "$BASHPID"
|
||||
|
|
Loading…
Reference in a new issue