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:
@@ -30,3 +30,9 @@ botCaller=",.!+?"
|
|||||||
# People who are allowed to private message the bot separate multiple names with |
|
# People who are allowed to private message the bot separate multiple names with |
|
||||||
allowList=""
|
allowList=""
|
||||||
ignoreList="storm_bot"
|
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
95
bot.sh
@@ -78,6 +78,10 @@ export nick
|
|||||||
export quitMessage
|
export quitMessage
|
||||||
export intentionalExit
|
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
|
# Check for critical dependencies needed by the bot core
|
||||||
coreDependencies=("socat" "tail" "shuf" "grep" "sed" "tr" "cut" "date")
|
coreDependencies=("socat" "tail" "shuf" "grep" "sed" "tr" "cut" "date")
|
||||||
missingCore=()
|
missingCore=()
|
||||||
@@ -105,6 +109,74 @@ rm_input() {
|
|||||||
fi
|
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
|
# Function to trim log file to prevent unbounded growth
|
||||||
# Keeps log between 800-1000 lines by trimming oldest entries when limit reached
|
# Keeps log between 800-1000 lines by trimming oldest entries when limit reached
|
||||||
trim_log() {
|
trim_log() {
|
||||||
@@ -127,8 +199,12 @@ trim_log() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Trap exiting ffrom the program to remove the temporary input file.
|
# Trap exiting from the program to remove the temporary input file and stop ping monitor
|
||||||
trap rm_input EXIT
|
cleanup_on_exit() {
|
||||||
|
stop_ping_monitor
|
||||||
|
rm_input
|
||||||
|
}
|
||||||
|
trap cleanup_on_exit EXIT
|
||||||
|
|
||||||
# Flag to track intentional shutdown (set by exit module)
|
# Flag to track intentional shutdown (set by exit module)
|
||||||
intentionalExit=false
|
intentionalExit=false
|
||||||
@@ -159,6 +235,9 @@ while true; do
|
|||||||
# Counter for log trimming (check every 50 messages)
|
# Counter for log trimming (check every 50 messages)
|
||||||
logTrimCounter=0
|
logTrimCounter=0
|
||||||
|
|
||||||
|
# Start ping monitor for this connection
|
||||||
|
start_ping_monitor
|
||||||
|
|
||||||
tail -f "$input" | socat -,ignoreeof "$socatAddress" | while read -r result ; do
|
tail -f "$input" | socat -,ignoreeof "$socatAddress" | while read -r result ; do
|
||||||
# Strip carriage return from IRC protocol (CRLF line endings)
|
# Strip carriage return from IRC protocol (CRLF line endings)
|
||||||
result="${result%$'\r'}"
|
result="${result%$'\r'}"
|
||||||
@@ -190,6 +269,15 @@ while true; do
|
|||||||
PING*)
|
PING*)
|
||||||
echo "${result/I/O}" >> "$input"
|
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
|
# for pings on nick/user
|
||||||
*"You have not"*)
|
*"You have not"*)
|
||||||
for channelName in "${channels[@]}"; do
|
for channelName in "${channels[@]}"; do
|
||||||
@@ -338,6 +426,9 @@ while true; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# If we reach here, the connection was dropped
|
# 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
|
# Check if this was an intentional exit
|
||||||
if [[ "$intentionalExit" == "true" ]]; then
|
if [[ "$intentionalExit" == "true" ]]; then
|
||||||
echo "Bot shutdown requested. Exiting. [$(date "+$dateFormat")]" | tee -a "$log"
|
echo "Bot shutdown requested. Exiting. [$(date "+$dateFormat")]" | tee -a "$log"
|
||||||
|
|||||||
@@ -3,8 +3,28 @@
|
|||||||
|
|
||||||
farewellsFile="triggers/bye/farewells.txt"
|
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.
|
# All names to match are completely lowercase.
|
||||||
case "${1,,}" in
|
case "$userName" in
|
||||||
storm_dragon)
|
storm_dragon)
|
||||||
msg "${2%% :*}" "NOOOOOOOOOO!!! $1: come back!!!"
|
msg "${2%% :*}" "NOOOOOOOOOO!!! $1: come back!!!"
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -3,8 +3,28 @@
|
|||||||
|
|
||||||
greetingsFile="triggers/greet/greetings.txt"
|
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.
|
# All names to match are completely lowercase.
|
||||||
case "${1,,}" in
|
case "$userName" in
|
||||||
storm_dragon)
|
storm_dragon)
|
||||||
msg "$2" "my lord, $1: how may I serve you?"
|
msg "$2" "my lord, $1: how may I serve you?"
|
||||||
;;
|
;;
|
||||||
|
|||||||
Reference in New Issue
Block a user