diff --git a/crons/backup-log.sh b/crons/backup-log.sh
index c7c3408..1e8c8ae 100755
--- a/crons/backup-log.sh
+++ b/crons/backup-log.sh
@@ -1,16 +1,33 @@
#!/bin/bash
-LOCATION=`dirname "$0"`
+backupDir="$1"
+backupType="$2"
-source "${LOCATION}/../config.sh"
+# load in defaults from config
+scriptRoot="$(dirname "$0")/.."
+configFile="$scriptRoot/config.sh"
+if [[ -f "$configFile" ]]; then
+ source "$configFile"
-cd "${BACKUP_DIRECTORY}"
+ if [[ -z "$backupDir" ]]; then
+ backupDir="$BACKUP_DIRECTORY"
+ fi
+ if [[ -z "$backupType" ]]; then
+ backupType="$PRUNE_TYPE"
+ fi
+fi
-backups=`find * -type f | sort | xargs du -h`
-echo "${backups}"
-${LOCATION}/../discord.sh block "${backups}"
+if [[ "$backupType" = "
" ]]; then
+ backups=$(find "$backupDir" -maxdepth 1 -type d | grep -v "^$backupDir$" | sort | xargs du -h --summarize)
+ hashes=""
+else
+ backups=$(find "$backupDir" -type f -name "$backupType" | sort | xargs du -h)
+ hashes=$(find "$backupDir" -type f -name "$backupType" | sort | xargs md5sum --tag)
+fi
-hashes=`find * -type f | sort | xargs md5sum --tag`
-echo "${hashes}"
-${LOCATION}/../discord.sh block "${hashes}"
+echo "$backups"
+if [[ -n "$hashes" ]]; then
+ echo "$hashes"
+fi
+"$scriptRoot/discord.sh" -c "mint" -t "Backup Status" "$backups" "$hashes"
diff --git a/crons/storage-alert.sh b/crons/storage-alert.sh
index c7204aa..8e5106e 100755
--- a/crons/storage-alert.sh
+++ b/crons/storage-alert.sh
@@ -1,23 +1,35 @@
#!/bin/bash
-LOCATION=`dirname "$0"`
+locations="$@"
-source "${LOCATION}/../config.sh"
+# load in defaults from config
+scriptRoot="$(dirname "$0")/.."
+configFile="$scriptRoot/config.sh"
+if [[ -f "$configFile" ]]; then
+ source "$configFile"
-COUNT=1
-for index in "${!STORAGE_ALERT[@]}"; do
- storage=`${LOCATION}/../storage.sh $index ${STORAGE_ALERT[$index]}`
- alert=$?
-
- if [[ "0" != "${alert}" ]]; then
- echo "${storage} is below threshold ${STORAGE_ALERT[$index]}G"
- ${LOCATION}/../discord-if-distinct.sh block "storage-${COUNT}" "${storage} is below threshold ${STORAGE_ALERT[$index]}G"
- else
- echo "${storage} is above threshold ${STORAGE_ALERT[$index]}G"
-
- ${LOCATION}/../discord-if-distinct.sh block "storage-${COUNT}" "${storage} is above threshold ${STORAGE_ALERT[$index]}G"
+ if [[ -z "$locations" ]]; then
+ locations=${STORAGE_MONITOR[@]}
fi
+fi
- let "COUNT++"
+warn=false
+messages=()
+for index in "${!STORAGE_ALERT[@]}"; do
+ storage=$("$scriptRoot/storage.sh" "$index" "${STORAGE_ALERT[$index]}")
+ alert="$?"
+
+ if [[ "0" != "$alert" ]]; then
+ warn=true
+ messages+=("$storage is below threshold ${STORAGE_ALERT[$index]}G")
+ else
+ messages+=("$storage is above threshold ${STORAGE_ALERT[$index]}G")
+ fi
done
+if [[ "$warn" = true ]]; then
+ purple="purple"
+fi
+
+printf "%s\n" "${messages[@]}"
+printf "%s\n" "${messages[@]}" | "$scriptRoot/discord.sh" -c "${purple-blue}" -d "Storage Alert"
diff --git a/crons/storage-log.sh b/crons/storage-log.sh
index d08de18..c603c96 100755
--- a/crons/storage-log.sh
+++ b/crons/storage-log.sh
@@ -1,11 +1,17 @@
#!/bin/bash
-LOCATION=`dirname "$0"`
+locations="$@"
-source "${LOCATION}/../config.sh"
+# load in defaults from config
+scriptRoot="$(dirname "$0")/.."
+configFile="$scriptRoot/config.sh"
+if [[ -f "$configFile" ]]; then
+ source "$configFile"
-storage=`${LOCATION}/../df-custom.sh ${STORAGE_MONITOR[@]}`
+ if [[ -z "$locations" ]]; then
+ locations=${STORAGE_MONITOR[@]}
+ fi
+fi
-echo "${storage}"
-${LOCATION}/../discord.sh block "${storage}"
+"$scriptRoot/df-custom.sh" $locations | "$scriptRoot/discord.sh" -c "blue" -t "Storage Status"
diff --git a/crons/thermal-alert.sh b/crons/thermal-alert.sh
index 8953c5a..39a97c6 100755
--- a/crons/thermal-alert.sh
+++ b/crons/thermal-alert.sh
@@ -21,12 +21,12 @@ alert="$?"
if [[ "0" -ne "$alert" ]]; then
# if currently in an alert status
alertLevelF=`echo "scale=1 ; $alertLevel * 9 / 5 + 32" | bc -l`
- "$scriptRoot/discord.sh" "$thermal, above threshold $alertLevel C ($alertLevelF F)"
+ "$scriptRoot/discord.sh" -c "red" -t "Thermal Alert" "$thermal" $'\n' "above threshold $alertLevel C ($alertLevelF F)"
touch "$HOME/.thermal.alert"
elif [[ -f "$HOME/.thermal.alert" ]]; then
# if previously in an alert status
alertLevelF=`echo "scale=1 ; $alertLevel * 9 / 5 + 32" | bc -l`
- "$scriptRoot/discord.sh" "$thermal, previously above threshold $alertLevel C ($alertLevelF F)"
+ "$scriptRoot/discord.sh" -c "orange" -t "Thermal Alert" "$thermal" $'\n' "previously above threshold $alertLevel C ($alertLevelF F)"
rm "$HOME/.thermal.alert"
fi
diff --git a/crons/thermal-log.sh b/crons/thermal-log.sh
index 7c6c4dc..fd2e509 100755
--- a/crons/thermal-log.sh
+++ b/crons/thermal-log.sh
@@ -2,7 +2,5 @@
scriptRoot="$(dirname "$0")/.."
-thermal=$("$scriptRoot/thermal.sh")
-
-"$scriptRoot/discord.sh" "$thermal"
+"$scriptRoot/thermal.sh" | "$scriptRoot/discord.sh" -c "yellow" -t "Thermal Status"
diff --git a/discord-if-distinct.sh b/discord-if-distinct.sh
index f28ca9f..d66197e 100755
--- a/discord-if-distinct.sh
+++ b/discord-if-distinct.sh
@@ -86,7 +86,7 @@ if [ "${FULL_MESSAGE}" != "${OLD_MSG}" ]; then
curl -s -H "Content-Type: application/json" -X POST -d "{\"username\": \"${DISCORD_SERVER_NAME}\", \"content\": ${MESSAGE}}" $HOOK_URL | jq -r '.id,.message'
if [ -n "${EXTRA}" ]; then
- "${LOCATION}/discord.sh" "${HOOK}" "${EXTRA}"
+ "${LOCATION}/discord-old.sh" "${HOOK}" "${EXTRA}"
fi
fi
diff --git a/discord-old.sh b/discord-old.sh
new file mode 100755
index 0000000..1f43e10
--- /dev/null
+++ b/discord-old.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+LOCATION=`dirname "$0"`
+
+source "${LOCATION}/config.sh"
+
+if [[ $# -gt 1 ]]; then
+ HOOK_ARG="$1"
+ # sed removes spaces before each line
+ MESSAGE=`echo "${@:2}" | sed 's/^ *//' | sed 's/ *$//'`
+else
+ # sed removes spaces before each line
+ MESSAGE=`echo "${@}" | sed 's/^ *//' | sed 's/ *$//'`
+
+ if [[ "$MESSAGE" == "general" ]] || [[ "$MESSAGE" == "block" ]] || [[ "$MESSAGE" == "restake" ]] || [[ "$MESSAGE" == "storage" ]]; then
+ HOOK_ARG="$MESSAGE"
+ MESSAGE=''
+ fi
+fi
+
+if [[ -z "$MESSAGE" ]]; then
+ echo 'no message provided'
+ exit 0
+fi
+
+# if message is too long, split it, and after curl, recursively call with remainder
+# 2k max, but we must account for escaping text in json, so limit to 90% capacity
+EXTRA="${MESSAGE:1800}"
+
+if [ -n "${EXTRA}" ]; then
+ MESSAGE="${MESSAGE:0:1800}"
+
+ # as an added elegance, when spliting into pieces, find the last \n newline,
+ # and break there instead, but only if the new smaller chunk is of sufficient size
+ chunk1=`echo "$MESSAGE" | head -n -1`
+ chunks=`echo "$MESSAGE" | tail -n 1`
+ if (( "${#chunk1}" >= 1000 )); then
+ MESSAGE="$chunk1"
+ EXTRA="${chunks}${EXTRA}"
+ fi
+fi
+
+
+# sed: rewrite json string, because "\u001b[m" needs to "\u001b[0m" instead
+# linux is fine with the missing zero, but discord needs it
+MESSAGE=`echo "${MESSAGE}" | jq -aRs . | sed 's/\\\\u001b\[m/\\\\u001b[0m/g'`
+HOOK="general"
+HOOK_URL=$DISCORD_GENERAL_HOOK
+
+case $HOOK_ARG in
+ block)
+ # force block format without color
+ if [[ "$MESSAGE" != *"\\u001b"* ]]; then
+ MESSAGE="\"\`\`\`${MESSAGE:1:-1}\n\`\`\`\""
+ # just here to resolve formatting issue in vim "`"
+ fi
+ ;;
+ restake)
+ HOOK="restake"
+ HOOK_URL=$DISCORD_RESTAKE_HOOK
+ ;;
+ storage)
+ HOOK="storage"
+ HOOK_URL=$DISCORD_STORAGE_HOOK
+ ;;
+esac
+
+# if color detected, update message from "" to "```ansi ```", so it gets displayed correctly
+if [[ "$MESSAGE" == *"\\u001b"* ]]; then
+ MESSAGE="\"\`\`\`ansi\n${MESSAGE:1:-1}\n\`\`\`\""
+ # just here to resolve formatting issue in vim "`"
+fi
+
+curl -s -H "Content-Type: application/json" -X POST -d "{\"username\": \"${DISCORD_SERVER_NAME}\", \"content\": ${MESSAGE}}" $HOOK_URL | jq -r '.id,.message'
+
+if [ -n "${EXTRA}" ]; then
+ "${LOCATION}/discord-old.sh" "${HOOK}" "${EXTRA}"
+fi
+
diff --git a/discord.sh b/discord.sh
index d61c9b4..40b77f6 100755
--- a/discord.sh
+++ b/discord.sh
@@ -1,79 +1,170 @@
#!/bin/bash
-LOCATION=`dirname "$0"`
+# discord colors are standard 6-digit hex, but converted to a base-10 integer
+# colors taken from https://xkcd.com/color/rgb/
+# and built into a palette based on https://sashamaps.net/docs/resources/20-colors/
+#
+# DARK: maroon(#650021), brown(#653700), olive(#6e750e), teal(#029386), navy(#01153e), black(#000000),
+# BRIGHT: red(#e50000), orange(#f97306), yellow(#ffff14), lime(#aaff32), green(#15b01a),
+# cyan(#00ffff), blue(#0343df), purple(#7e1e9c), magenta(#c20078), grey(#929591),
+# LIGHT: pink(#ff81c0), apricot(#ffb16d), beige(#e6daa6), mint(#9ffeb0), lavender(#c79fef), white(#ffffff).
-source "${LOCATION}/config.sh"
+declare -A colors
+colors=(
+ ["maroon"]=6619169 ["brown"]=6633216 ["olive"]=7238926 ["teal"]=168838 ["navy"]=70974 ["black"]=0
+ ["red"]=15007744 ["orange"]=16347910 ["yellow"]=16776980 ["lime"]=11206450 ["green"]=1421338
+ ["cyan"]=65535 ["blue"]=213983 ["purple"]=8265372 ["magenta"]=12714104 ["grey"]=9606545
+ ["pink"]=16744896 ["apricot"]=16757101 ["beige"]=15129254 ["mint"]=10485424 ["lavender"]=13082607 ["white"]=16777215
+)
-if [[ $# -gt 1 ]]; then
- HOOK_ARG="$1"
- # sed removes spaces before each line
- MESSAGE=`echo "${@:2}" | sed 's/^ *//' | sed 's/ *$//'`
-else
- # sed removes spaces before each line
- MESSAGE=`echo "${@}" | sed 's/^ *//' | sed 's/ *$//'`
+print_usage() {
+ echo "Usage: $0 [-h hook-url], [-c color], [-d [distinct-name] | -t title] message..."
+}
- if [[ "$MESSAGE" == "general" ]] || [[ "$MESSAGE" == "block" ]] || [[ "$MESSAGE" == "restake" ]] || [[ "$MESSAGE" == "storage" ]]; then
- HOOK_ARG="$MESSAGE"
- MESSAGE=''
+# handle all arguments provided
+while getopts 'h:c:d:t:' flag; do
+ case "$flag" in
+ h)
+ if [[ "$OPTARG" == "http"*"?wait=true" ]]; then
+ hookUrl="$OPTARG"
+ else
+ echo "Invalid hook-url provided, should be something like:"
+ echo "https://discord.com/api/webhooks/***?wait=true"
+ print_usage
+ exit 1
+ fi
+ ;;
+ c)
+ if [[ -v "colors[$OPTARG]" ]]; then
+ color="$OPTARG"
+ else
+ echo "Invalid color provided, colors available:"
+ echo "maroon, brown, olive, teal, navy, black,"
+ echo "red, orange, yellow, lime, green,"
+ echo " cyan, blue, purple, magenta, grey,"
+ echo "pink, apricot, beige, mint, lavender, white."
+ print_usage
+ exit 1
+ fi
+ ;;
+ d)
+ # '-d' without value is allowed, but generates a warning
+ # in which case we'll use name of parent command with arguments
+ # whatever the distinct key, we clean it up, since it will be used as a filename
+ if [[ -z "$OPTARG" ]]; then
+ distinct=$(ps -o args= $PPID | sed 's/[\/\|]/_/g')
+ echo "Warning: doing distinct by parent, with key '$distinct'" >&2
+ else
+ distinct=$(echo "$OPTARG" | sed 's/[\/\|]/_/g')
+ fi
+ ;;
+ t)
+ # title, for supplying a title, without activing the "distinct" feature
+ title="$OPTARG"
+ ;;
+ *)
+ echo "unknown option provided '$flag'"
+ print_usage
+ exit 1
+ ;;
+ esac
+done
+shift "$((OPTIND-1))"
+
+# load in defaults from config
+scriptRoot=$(dirname "$0")
+configFile="$scriptRoot/config.sh"
+if [[ -f "$configFile" ]]; then
+ source "$configFile"
+
+ botName="$DISCORD_SERVER_NAME"
+ if [[ -z "$hookUrl" ]]; then
+ hookUrl="$DISCORD_GENERAL_HOOK"
fi
fi
-if [[ -z "$MESSAGE" ]]; then
- echo 'no message provided'
- exit 0
+# stop if we have no hook to send message to
+if [[ -z "$hookUrl" ]]; then
+ echo "Discord Hook URL must either be in config file, or supplied via '-h' argument."
+ exit 1
fi
-# if message is too long, split it, and after curl, recursively call with remainder
-# 2k max, but we must account for escaping text in json, so limit to 90% capacity
-EXTRA="${MESSAGE:1800}"
+# get full message, read from arguments
+message=$(echo "$@" | sed 's/^ *//' | sed 's/ *$//')
-if [ -n "${EXTRA}" ]; then
- MESSAGE="${MESSAGE:0:1800}"
+# if we have no message, read from stdin instead
+if [[ -z "$message" ]]; then
+ message=$(cat - | sed 's/^ *//' | sed 's/ *$//')
+fi
+
+# sed removes blank lines from the end of the message
+fullMsg=$(echo "$message" | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}')
+
+# if message is too long, split it, and after curl, recursively call with remainder
+# 4k max, but we must account for escaping text in json, so limit to 90% capacity
+extra="${message:3600}"
+
+if [ -n "$extra" ]; then
+ message="${message:0:3600}"
# as an added elegance, when spliting into pieces, find the last \n newline,
# and break there instead, but only if the new smaller chunk is of sufficient size
- chunk1=`echo "$MESSAGE" | head -n -1`
- chunks=`echo "$MESSAGE" | tail -n 1`
+ chunk1=$(echo "$message" | head -n -1)
+ chunks=$(echo "$message" | tail -n 1)
if (( "${#chunk1}" >= 1000 )); then
- MESSAGE="$chunk1"
- EXTRA="${chunks}${EXTRA}"
+ message="$chunk1"
+ extra="$chunks$extra"
fi
fi
-
# sed: rewrite json string, because "\u001b[m" needs to "\u001b[0m" instead
# linux is fine with the missing zero, but discord needs it
-MESSAGE=`echo "${MESSAGE}" | jq -aRs . | sed 's/\\\\u001b\[m/\\\\u001b[0m/g'`
-HOOK="general"
-HOOK_URL=$DISCORD_GENERAL_HOOK
+message=$(echo "$message" | jq -aRs . | sed 's/\\u001b\[m/\\u001b[0m/g')
-case $HOOK_ARG in
- block)
- # force block format without color
- if [[ "$MESSAGE" != *"\\u001b"* ]]; then
- MESSAGE="\"\`\`\`${MESSAGE:1:-1}\n\`\`\`\""
- # just here to resolve formatting issue in vim "`"
- fi
- ;;
- restake)
- HOOK="restake"
- HOOK_URL=$DISCORD_RESTAKE_HOOK
- ;;
- storage)
- HOOK="storage"
- HOOK_URL=$DISCORD_STORAGE_HOOK
- ;;
-esac
+message="\"\`\`\`ansi\n${message:1:-1}\n\`\`\`\""
-# if color detected, update message from "" to "```ansi ```", so it gets displayed correctly
-if [[ "$MESSAGE" == *"\\u001b"* ]]; then
- MESSAGE="\"\`\`\`ansi\n${MESSAGE:1:-1}\n\`\`\`\""
- # just here to resolve formatting issue in vim "`"
+# handle distinct stuff
+oldMsg=""
+if [[ -n "$distinct" ]]; then
+ if [[ -f "$scriptRoot/distinct/$distinct.msg" ]]; then
+ oldMsg=$(cat "$scriptRoot/distinct/$distinct.msg")
+ fi
+
+ if [[ "$fullMsg" = "$oldMsg" ]]; then
+ echo "duplicate message"
+ exit 0
+ fi
+
+ echo "$fullMsg" > "$scriptRoot/distinct/$distinct.msg"
fi
-curl -s -H "Content-Type: application/json" -X POST -d "{\"username\": \"${DISCORD_SERVER_NAME}\", \"content\": ${MESSAGE}}" $HOOK_URL | jq -r '.id,.message'
-
-if [ -n "${EXTRA}" ]; then
- "${LOCATION}/discord.sh" "${HOOK}" "${EXTRA}"
+# build content json
+content="{"
+if [[ -n "$botName" ]]; then
+ content="$content\"username\": $(echo "$botName" | jq -aRs .), "
fi
+content="$content\"embeds\":[{\"description\": $message"
+if [[ -n "$color" ]]; then
+ content="$content, \"color\": ${colors[$color]}"
+fi
+if [[ -n "$distinct" ]] || [[ -n "$title" ]]; then
+ content="$content, \"title\": $(echo "${distinct-$title}" | jq -aRs .)"
+fi
+content="$content}]}"
+# actually send the message to discord
+curl -s -H "Content-Type: application/json" -X POST -d "$content" "$hookUrl" | jq -r '.id,.message'
+
+# if the message was too long, send along the rest as a separate message
+if [ -n "$extra" ]; then
+ script=$(basename "$0")
+ args=("-h" "$hookUrl")
+ # when we call again, we convert distinct into a title
+ if [[ -n "$distinct" ]] || [[ -n "$title" ]]; then
+ args+=("-t" "${distinct-$title}")
+ fi
+ if [[ -n "$color" ]]; then
+ args+=("-c" "$color")
+ fi
+ "$scriptRoot/$script" ${args[@]} "$extra"
+fi