Add what every bash script needs: live reloading for code

This commit is contained in:
Nick Chambers 2021-06-15 16:21:29 -05:00
parent c7a0f8896f
commit e29a3a79ec
1 changed files with 116 additions and 17 deletions

133
rowbot
View File

@ -35,6 +35,7 @@ error() {
# argument parser for parsing arguments
##
original_args=("$0" "$@")
declare -A opts
while (( $# )); do
@ -80,28 +81,71 @@ else
port=${opts[port]:-6667}
fi
level=${opts[log-level]:-info}
if [[ ${opts[log]} ]]; then
exec {log}>"${opts[log]}"
else
log=1
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}
if [[ -v USER ]]; then
owner=${opts[owner]:-"$USER"}
else
owner=${opts[owner]:-uplime}
fi
level=${opts[log-level]:-info}
if [[ $reload = yes ]]; then
log=$LOG_FD
elif [[ ${opts[log]} ]]; then
exec {log}>"${opts[log]}"
else
log=1
fi
###
# utilities
###
cleanup() {
exec {in_sock}>&- {out_sock}>&- {log}>&-
if [[ $tls = yes ]]; then
kill "$tls_pid"
rm -rf "$sock_dir"
fi
if [[ -v ping_pid ]]; then
kill "$ping_pid"
fi
}
trap cleanup EXIT
###
# net code
###
if [[ $tls = yes ]]; then
coproc sock { socat OPENSSL:"$server":"$port" -; }
exec {in_sock}<&"${sock[0]}" {out_sock}>&"${sock[1]}"
if [[ $reload = yes ]]; then
in_sock=$IN_SOCK out_sock=$OUT_SOCK
if [[ $tls = yes ]]; then
sock_dir=$SOCK_DIR
tls_pid=$tls_pid
fi
if [[ -v PING_PID ]]; then
ping_pid=$PING_PID
fi
elif [[ $tls = yes ]]; then
sock_dir=$(mktemp -d)
mkfifo "$sock_dir"/rb{in,out}
socat OPENSSL:"$server":"$port" - <"$sock_dir"/rbin >"$sock_dir"/rbout &
tls_pid=$!
exec {out_sock}>"$sock_dir"/rbin {in_sock}<"$sock_dir"/rbout
else
exec {sock}<>/dev/tcp/"$server"/"$port"
in_sock=$sock out_sock=$sock
@ -175,7 +219,7 @@ on_001() {
sleep 10
done &
trap "kill $!" EXIT
ping_pid=$!
}
on_002() {
@ -291,6 +335,7 @@ pong() {
privmsg() {
send "PRIVMSG %s :\u200b%s" "$1" "$2"
info "<%s/%s> %s" "$nick" "$1" "$2"
}
user() {
@ -301,7 +346,7 @@ user() {
# app hooks
##
hook_PRIVMSG_factoids() {
hook_post_PRIVMSG_factoids() {
if [[ ${params[0]:0:1} != \# ]]; then
return 0
elif [[ ${words[0]} = "$trigger"* ]]; then
@ -348,12 +393,55 @@ hook_PRIVMSG_factoids() {
fi
}
hook_post_PRIVMSG_control_panel() {
if [[ ${words[0]} = "$trigger"* ]]; then
if [[ $from != $owner && $dev != yes ]]; then
return 0
fi
local to=${params[0]}
if [[ ${params[0]:0:1} != \# ]]; then
to=$from
fi
case ${words[0]:${#trigger}} in
raw)
local cmd
cmd=${params[1]#*"$trigger"raw} cmd=${cmd# }
info "%s is executing command: %s" "$from" "$cmd"
send "$cmd"
;;
join)
join "${words[1]}"
;;
reload)
export IN_SOCK=$in_sock OUT_SOCK=$out_sock LOG_FD=$log
if [[ -v tls_pid ]]; then
export SOCK_DIR=$sock_dir
export TLS_PID=$tls_pid
fi
if [[ -v ping_pid ]]; then
export PING_pid=$ping_pid
fi
privmsg "$to" "reloading..."
exec "${original_args[@]}" --reload
;;
esac
fi
}
###
# driver
###
nick "$nick"
user "$ident" "$realname"
if [[ $reload != yes ]]; then
nick "$nick"
user "$ident" "$realname"
fi
while recv line; do
params=( )
@ -389,13 +477,24 @@ while recv line; do
words=( )
fi
skip_handler=0
while IFS= read -r hook; do
"$hook"
done < <(compgen -A function "hook_${cmd^^}_")
(( skip_handler |= $? ))
done < <(compgen -A function "hook_pre_${cmd^^}_")
if hash "on_${cmd^^}" 2>/dev/null; then
"on_${cmd^^}"
if (( ! skip_handler )); then
"on_${cmd^^}"
else
debug "handler for %s was skipped" "${cmd^^}"
fi
else
warn "unhandled line: %s" "$orig_line"
fi
while IFS= read -r hook; do
"$hook"
done < <(compgen -A function "hook_post_${cmd^^}_")
done