Implement a state manager POC

This commit is contained in:
Nick Chambers 2021-11-17 16:29:47 -06:00
parent 6a855e1d60
commit e42a2b248f
1 changed files with 149 additions and 48 deletions

197
rowbot
View File

@ -97,23 +97,6 @@ b64_encode() {
# code reloading helpers # code reloading helpers
get_option() {
local var_name=${1//-/_}
local env_var=${var_name^^}
if [[ ! -v config[$1] || -v OPT_OW ]]; then
if [[ -v $env_var ]]; then
config[$1]=${!env_var}
elif [[ -v opts[$1] ]]; then
config[$1]=${opts[$1]}
elif [[ -v $var_name ]]; then
config[$1]=${!var_name}
elif (( $# > 1 )); then
config[$1]=$2
fi
fi
}
is_reloaded() { is_reloaded() {
[[ $RELOADED = yes ]] || (( RELOAD_COUNT )) [[ $RELOADED = yes ]] || (( RELOAD_COUNT ))
} }
@ -157,11 +140,7 @@ shuffle() {
done done
} }
# misc # process management and friends
is_running () {
kill -0 "$1" 2>/dev/null
}
die() { die() {
local fmt=$1 local fmt=$1
@ -181,6 +160,12 @@ has() {
fi fi
} }
is_running () {
kill -0 "$1" 2>/dev/null
}
# misc
run_callbacks() { run_callbacks() {
if (( ! $# )); then if (( ! $# )); then
return 1 return 1
@ -245,12 +230,12 @@ url() {
} }
### ###
# configure rowbot's environment # Prepare rowbot's configuration
### ###
# parse command line arguments # parse command line arguments
declare -A opts declare -A config opts
cmd_line=( "${@:0}" ) cmd_line=( "${@:0}" )
while (( $# )); do while (( $# )); do
@ -280,6 +265,8 @@ done
# load custom configuration files # load custom configuration files
mapfile -t old_set < <(compgen -v)
for file do for file do
if [[ -f $file ]]; then if [[ -f $file ]]; then
# These files (if any) are provided dynamically at run-time. # These files (if any) are provided dynamically at run-time.
@ -290,27 +277,131 @@ for file do
fi fi
done done
mapfile -t new_set < <(compgen -v)
for new in "${new_set[@]}"; do
found=0
for old in "${old_set[@]}"; do
if [[ $new = "$old" ]]; then
found=1
break
fi
done
if (( !found )); then
config[$new]=${!new}
fi
done
for setting in "${!opts[@]}"; do
config[$setting]=${opts[$setting]}
done
while IFS= read -r setting; do
config[${setting,,}]=${!setting}
done < <(compgen -e)
# cleanup # cleanup
unset key file unset key opts old_set file new_set new found old setting
### ###
# load default config # state management
### ###
declare -A config state_resolve() {
local ns=${NS-global} managed found=0
declare -gA __rowbot_state_store_"$ns"
declare -n ns_config=__rowbot_state_store_"$ns"
get_option owner "${USER:-uplime}" if [[ $ns != global ]]; then
get_option trigger \` for managed in "${states_managed[@]}"; do
get_option dev yes if [[ $managed = "$ns" ]]; then
found=1
break
fi
done
if (( !found )); then
states_managed+=( "$ns" )
fi
fi
if [[ -v config[$1] ]]; then
ns_config[$1]=${config[$1]}
elif [[ -v DEFAULT ]]; then
ns_config[$1]=$DEFAULT
else
return 1
fi
}
state_get() {
local ns=${NS-global}
# The `ns_config` variable is a reference to an array
# shellcheck disable=SC2178
declare -n ns_config=__rowbot_state_store_"$ns"
if [[ -v ns_config[$1] ]]; then
printf %s "${ns_config[$1]}"
elif [[ -v DEFAULT ]]; then
printf %s "$DEFAULT"
else
return 1
fi
}
state_has() {
local ns=${NS-global} found=1 managed
declare -n ns_config=__rowbot_state_store_"$ns"
for managed in "${ns_config[@]}"; do
if [[ $managed = "$1" ]]; then
found=0
break
fi
done
return "$found"
}
on_sys_init_001_state() {
states_managed=( global )
}
on_sys_before_999_state() {
local managed
for managed in "${states_managed[@]}"; do
put_assoc_array __rowbot_state_store_"$managed"
done
put_array states_managed
}
on_sys_after_001_state() {
local managed
get_array states_managed
for managed in "${states_managed[@]}"; do
get_assoc_array __rowbot_state_store_"$managed"
done
}
### ###
# logger # logger
### ###
log() { log() {
if [[ -v LOG_LEVEL ]] && (( log_levels[$log_level] <= log_levels[$LOG_LEVEL] )); then if NS=log state_has fd; then
printf "%s: $1\n" "${LOG_LEVEL^^}" "${@:2}" >&"$log_fd" # The only possible fail conditions are already checked for.
# shellcheck disable=SC2155
local level=$(NS=log state_get level) fd=$(NS=log state_get fd)
if (( log_levels[$level] <= log_levels[$LOG_LEVEL] )); then
printf "%s: $1\n" "${LOG_LEVEL^^}" "${@:2}" >&"$fd"
fi
fi fi
} }
@ -346,40 +437,50 @@ log_has_level() {
return 1 return 1
} }
on_sys_init_001_log() { on_sys_init_005_log() {
declare -gA log_levels=( [trace]=1 [debug]=2 [info]=3 [warn]=4 [error]=5 ) declare -gA log_levels=( [trace]=1 [debug]=2 [info]=3 [warn]=4 [error]=5 )
get_option log-level info NS=log DEFAULT=info state_resolve level
if ! log_has_level "${config[log-level]}"; then if ! log_has_level "$(NS=log state_get level)"; then
die "%s is not a valid logging level" "${config[log-level]}" die "%s is not a valid logging level" "$(NS=log state_get level)"
fi fi
get_option log "" local log_fd=1
get_option overwrite no
log_level=${config[log-level]}
if [[ ${config[log]} ]]; then if [[ -v ${config[log]} ]]; then
if [[ ${config[overwrite]} = yes ]]; then if [[ ${config[overwrite]} = yes ]]; then
exec {log_fd}>"${config[log]}" exec {log_fd}>"${config[log]}"
else else
exec {log_fd}>>"${config[log]}" exec {log_fd}>>"${config[log]}"
fi fi
else
log_fd=1
fi fi
NS=log DEFAULT=$log_fd state_resolve fd
} }
on_sys_before_999_log() { on_sys_before_999_log() {
if [[ -v log_fd ]] && (( log_fd != 1 )); then if NS=log state_has fd; then
log_debug "shutting logger down for reload" # The only possible fail condition is already checked for.
exec {log_fd}>&- # shellcheck disable=2155
local fd=$(NS=log state_get fd)
if (( fd != 1 )); then
log_debug "shutting logger down for reload"
exec {fd}>&-
fi
fi fi
} }
on_sys_exit_999_log() { on_sys_exit_999_log() {
if [[ -v log_fd ]] && (( log_fd != 1 )); then if NS=log state_has fd; then
log_debug "shutting logger down for good" # The only possible fail condition is already checked for.
exec {log_fd}>&- # shellcheck disable=2155
local fd=$(NS=log state_get fd)
if (( fd != 1 )); then
log_debug "shutting logger down for good"
exec {fd}>&-
fi
fi fi
} }