Attempt to cut down on spam from greet and bye triggers. Add ping/pong to help deal with flakey connections.?

This commit is contained in:
Storm Dragon
2025-11-13 14:57:45 -05:00
parent c3328e092d
commit 86a640ebe8
4 changed files with 141 additions and 4 deletions

View File

@@ -30,3 +30,9 @@ botCaller=",.!+?"
# People who are allowed to private message the bot separate multiple names with |
allowList=""
ignoreList="storm_bot"
# Interval in seconds to send PING to server for connection health check (default: 120)
# Set to 0 to disable proactive ping checks (not recommended)
pingInterval=120
# Timeout in seconds to wait for PONG response before considering connection dead (default: 30)
# If no PONG received within this time after sending PING, bot will reconnect
pongTimeout=30

95
bot.sh
View File

@@ -78,6 +78,10 @@ export nick
export quitMessage
export intentionalExit
# Set default values for ping/pong monitoring if not configured
pingInterval="${pingInterval:-120}"
pongTimeout="${pongTimeout:-30}"
# Check for critical dependencies needed by the bot core
coreDependencies=("socat" "tail" "shuf" "grep" "sed" "tr" "cut" "date")
missingCore=()
@@ -105,6 +109,74 @@ rm_input() {
fi
}
# Function to stop ping monitor process
stop_ping_monitor() {
if [[ -n "$pingMonitorPid" ]] && kill -0 "$pingMonitorPid" 2>/dev/null; then
kill "$pingMonitorPid" 2>/dev/null
wait "$pingMonitorPid" 2>/dev/null
fi
# Clean up ping/pong tracking files
rm -f "${input}.lastping" "${input}.lastpong" 2>/dev/null
}
# Start background ping monitor process
# Sends PING at regular intervals and monitors for PONG responses
start_ping_monitor() {
# Only start if ping interval is greater than 0
if [[ "$pingInterval" -le 0 ]]; then
return
fi
# Stop any existing monitor
stop_ping_monitor
# Capture variables for the background process
local monitorInput="$input"
local monitorLog="$log"
local monitorServer="$server"
local monitorPort="$port"
local monitorDateFormat="$dateFormat"
local monitorPingInterval="$pingInterval"
local monitorPongTimeout="$pongTimeout"
# Start ping monitor in background
(
while true; do
sleep "$monitorPingInterval"
# Send PING with timestamp
currentTime=$(date +%s)
echo "PING :healthcheck_${currentTime}" >> "$monitorInput"
echo "$currentTime" > "${monitorInput}.lastping"
# Wait for pong timeout period and check if we got a response
sleep "$monitorPongTimeout"
# Check if we received a PONG
if [[ -f "${monitorInput}.lastpong" ]]; then
lastPongTime=$(cat "${monitorInput}.lastpong")
# If last pong is newer than last ping, we're good
if [[ "$lastPongTime" -ge "$currentTime" ]]; then
continue
fi
fi
# No PONG received within timeout - connection is likely dead
echo "No PONG received within ${monitorPongTimeout}s. Connection appears dead. [$(date "+$monitorDateFormat")]" >> "$monitorLog"
# Kill the socat process to trigger reconnection
# Escape regex metacharacters in server and port to prevent injection
safeServer="${monitorServer//./\\.}"
safeServer="${safeServer//[/\\[}"
safeServer="${safeServer//]/\\]}"
safeServer="${safeServer//\*/\\*}"
safePort="${monitorPort//[^0-9]/}"
# Find and kill the socat process for this bot
pkill -f "socat.*${safeServer}:${safePort}" 2>/dev/null
exit 0
done
) &
pingMonitorPid=$!
}
# Function to trim log file to prevent unbounded growth
# Keeps log between 800-1000 lines by trimming oldest entries when limit reached
trim_log() {
@@ -127,8 +199,12 @@ trim_log() {
fi
}
# Trap exiting ffrom the program to remove the temporary input file.
trap rm_input EXIT
# Trap exiting from the program to remove the temporary input file and stop ping monitor
cleanup_on_exit() {
stop_ping_monitor
rm_input
}
trap cleanup_on_exit EXIT
# Flag to track intentional shutdown (set by exit module)
intentionalExit=false
@@ -159,6 +235,9 @@ while true; do
# Counter for log trimming (check every 50 messages)
logTrimCounter=0
# Start ping monitor for this connection
start_ping_monitor
tail -f "$input" | socat -,ignoreeof "$socatAddress" | while read -r result ; do
# Strip carriage return from IRC protocol (CRLF line endings)
result="${result%$'\r'}"
@@ -190,6 +269,15 @@ while true; do
PING*)
echo "${result/I/O}" >> "$input"
;;
# track pong responses for connection health monitoring
# Match PONG as IRC command, not user messages containing "pong"
*" PONG "*|PONG*)
# Only process if NOT a user PRIVMSG (prevents spoofing)
if [[ ! "$result" =~ PRIVMSG ]]; then
# Update last pong timestamp
date +%s > "${input}.lastpong"
fi
;;
# for pings on nick/user
*"You have not"*)
for channelName in "${channels[@]}"; do
@@ -338,6 +426,9 @@ while true; do
done
# If we reach here, the connection was dropped
# Stop the ping monitor for this connection
stop_ping_monitor
# Check if this was an intentional exit
if [[ "$intentionalExit" == "true" ]]; then
echo "Bot shutdown requested. Exiting. [$(date "+$dateFormat")]" | tee -a "$log"

View File

@@ -3,8 +3,28 @@
farewellsFile="triggers/bye/farewells.txt"
# Time tracking to prevent spam from flaky connections
# Track last bye time for each user (in seconds since epoch)
declare -A lastByeTime
# Only say bye if user hasn't been farewelled in the last hour (3600 seconds)
currentTime=$(date +%s)
userName="${1,,}"
cooldownPeriod=3600
if [[ -n "${lastByeTime[$userName]}" ]]; then
timeSinceLastBye=$((currentTime - lastByeTime[$userName]))
if [[ $timeSinceLastBye -lt $cooldownPeriod ]]; then
# User was farewelled recently, skip bye message
exit 0
fi
fi
# Update last bye time for this user
lastByeTime[$userName]=$currentTime
# All names to match are completely lowercase.
case "${1,,}" in
case "$userName" in
storm_dragon)
msg "${2%% :*}" "NOOOOOOOOOO!!! $1: come back!!!"
;;

View File

@@ -3,8 +3,28 @@
greetingsFile="triggers/greet/greetings.txt"
# Time tracking to prevent spam from flaky connections
# Track last greet time for each user (in seconds since epoch)
declare -A lastGreetTime
# Only greet if user hasn't been greeted in the last hour (3600 seconds)
currentTime=$(date +%s)
userName="${1,,}"
cooldownPeriod=3600
if [[ -n "${lastGreetTime[$userName]}" ]]; then
timeSinceLastGreet=$((currentTime - lastGreetTime[$userName]))
if [[ $timeSinceLastGreet -lt $cooldownPeriod ]]; then
# User was greeted recently, skip greeting
exit 0
fi
fi
# Update last greet time for this user
lastGreetTime[$userName]=$currentTime
# All names to match are completely lowercase.
case "${1,,}" in
case "$userName" in
storm_dragon)
msg "$2" "my lord, $1: how may I serve you?"
;;