rowbot/rowbot

216 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
###
# feature switch toggling
###
shopt -s dotglob extglob lastpipe nullglob
###
# configure rowbot
###
# default config
declare -A config=(
# connection settings
[server]=irc.libera.chat [port]="" [tls]=no [client-cert]=""
# irc registration settings
[nick]=rowbot-dev [ident]=rowbot [realname]=rowbot [chan]=""
# bot control settings
[owner]="${USER:-uplime}" [trigger]=\` [dev]=yes
# log settings
[log]="" [overwrite]=no [log-level]=info
)
# parse command line arguments
declare -A opts
# This code is not used yet, but will be later.
# shellcheck disable=SC2034
cmd_line=( "${@:0}" )
while (( $# )); do
case $1 in
--*=*)
key=${1#--} key=${key%%=*}
opts[$key]=${1#--*=}
;;
--no-*)
key=${1#--no-}
opts[$key]=no
;;
--)
shift
break
;;
--*)
key=${1#--}
opts[$key]=yes
;;
*)
break
esac
shift
done
# apply custom configuration files
for file do
if [[ -f $file ]]; then
# These files (if any) are provided dynamically at run-time.
# shellcheck disable=SC1090
. "$file" # ha, dot file
else
die "could not locate config file %s" "$file"
fi
done
for setting in "${!config[@]}"; do
if [[ -v ${setting//-/_} ]]; then
declare -n setting_var=${setting//-/_}
config[$setting]=$setting_var
fi
done
# apply command line arguments
for setting in "${!config[@]}"; do
# This is a false positive.
# shellcheck disable=SC2102
if [[ -v opts[$setting] ]]; then
config[$setting]=${opts[$setting]}
fi
done
# apply default port if one isn't provided
if [[ -z ${config[port]} ]]; then
if [[ ${config[tls]} = yes ]]; then
config[port]=6697
else
config[port]=6667
fi
fi
# apply any reloaded values
for setting in "${!config[@]}"; do
env_name=${setting//-/_} env_name=${env_name^^}
declare -n env_var=$env_name
if [[ -v $env_name ]]; then
# This variable is only used for assignment.
# shellcheck disable=SC2034
config[$setting]=$env_var
fi
done
# cleanup
unset key file setting setting_var env_name env_var
###
# utility and helper functions
###
any_file() {
local files=( "${1:-.}"/* ) max idx
if (( ${#files[@]} > 1 )); then
(( max = ${#files[@]} - 1 ))
idx=$(random 0 "$max")
printf %s "${files[$idx]}"
fi
}
die() {
# error "$@"
exit "${STATUS:-42}"
}
get_option() {
if (( $# != 2 )); then
return 1
fi
local option_name=${1//-/_}
declare -n option_var=$option_name
if [[ -v opts[$1] ]]; then
option_var=${opts[log-level]}
elif [[ ! -v $option_name ]]; then
# This variable is only used for assignment.
# shellcheck disable=SC2034
option_var=$2
fi
}
has() {
if (( $# )); then
hash "$1" 2>/dev/null
else
return 1
fi
}
is_parent() {
(( BASHPID == $$ ))
}
is_reloaded() {
[[ $RELOADED = yes ]] || (( LORE_LIVES > 1 ))
}
random() {
local min=$1 max=$2
(( (RANDOM % max) + min ))
}
run_callbacks() {
if (( ! $# )); then
return 1
fi
local filter=$1
shift
while IFS= read -r; do
"$REPLY" "$@"
done < <(compgen -A function "$filter")
return 0
}
###
# live code reloader
###
reload() {
run_callbacks on_before_reload_
exec "${cmd_line[@]}"
}
hup_reload() {
reload
}
trap hup_reload HUP
on_init_debug() {
declare -p config
}
###
# initialization sequence
###
run_callbacks on_init_
if is_reloaded; then
run_callbacks on_after_reload_
else
run_callbacks on_first_
fi