bash-com/pool

135 lines
3.5 KiB
Plaintext
Raw Normal View History

#!/bin/bash
# (1) Init.
#--------------------------------------------------------#
# (1) Get current absolute dir
ROOT=$(dirname `realpath $0`);
# (2) Check argc
test $# -lt 2 && echo -e "error: too fewarguments\n\n\e[1mUSAGE\e[0m\n\tpool <key> <port>\n\n\e[1mARGUMENTS\e[0m\n\t<key>\tThe key of the pool (client must match it)\n\t<port>\tTo port to listen to\n" && exit 1;
# (3) Check @PORT range #
MIN_PORT=1024;
MAX_PORT=49151;
test "$2" -gt "$MAX_PORT" -o "$2" -lt "$MIN_PORT" && echo "error: <port> must be between $MIN_PORT and $MAX_PORT" && exit 1;
# (4) Set argument explicit names #
POOL_KEY="$1";
POOL_PORT="$2";
# (5) init logger variables #
declare -A INPUT_PID; # will contain each bind-input pid
# (6) Define on-exit routine #
LOOP_PID="";
on_exit(){
echo "- killing 'pool' loop";
kill -INT $LOOP_PID 2>/dev/null;
echo "- killing ${#INPUT_PID[@]} background listeners";
for logger_name in "${!INPUT_PID[@]}"; do
# kill each logger input
echo " - killing input@$logger_name (${INPUT_PID[$logger_name]})";
test ! -z "${INPUT_PID[$logger_name]}" && kill -INT ${INPUT_PID[$logger_name]} 2>/dev/null;
done;
echo "- killing 'pool' input listener ($POOL_PID)";
kill -INT $POOL_PID 2>/dev/null;
exit 1;
}
# (2) Launch pool listener
#--------------------------------------------------------#
# (1) Bind-input #
echo "+ listen $POOL_PORT";
POOL_PID="`$ROOT/bind-input pool $POOL_PORT`";
# (4) Launch pool manager
#--------------------------------------------------------#
# infinite listener
PORT="$MIN_PORT";
(
trap "on_exit;" HUP INT KILL TERM;
while true; do
# Listen on port @POOL_PORT
MSG=`$ROOT/read pool`;
# Do nothing if empty msg or invalid format
test -z "$MSG" && sleep .5 && continue;
echo " + received '$MSG'";
echo -n "$MSG" | grep -vP '^([^:]+):([^:]+):([^:]+):([^:]+)$' >/dev/null && echo ' + invalid format' && sleep .5 && continue;
# Extract ID - PORT
KEY="`echo -ne \"$MSG\" | sed 's/^\(.\+\):\(.\+\):\(.\+\):\(.\+\)$/\1/'`";
LOGGER_NAME="`echo -ne \"$MSG\" | sed 's/^\(.\+\):\(.\+\):\(.\+\):\(.\+\)$/\2/'`";
LOGGER_HOST="`echo -ne \"$MSG\" | sed 's/^\(.\+\):\(.\+\):\(.\+\):\(.\+\)$/\3/'`";
LOGGER_PORT="`echo -ne \"$MSG\" | sed 's/^\(.\+\):\(.\+\):\(.\+\):\(.\+\)$/\4/'`";
# if ID does not match
test "$KEY" != "$POOL_KEY" && echo ' + wrong id' && sleep .5 && continue;
# create new listening socket
echo " + received logger: $LOGGER_NAME on $LOGGER_HOST:$LOGGER_PORT";
# Find an available port
PORT="`expr $PORT + 1`";
while true; do
# ignore pool port
test "$PORT" = "$POOL_PORT" && PORT="`expr $PORT + 1`" && continue;
# if port not in use -> use it
ss -tl4 "( sport = :$PORT )" | grep "$PORT" >/dev/null 2>&1 || break;
# else try next port (+1)
PORT="`expr $PORT + 1`";
done;
# if already an input for this logger -> kill it
if [ ! -z "${INPUT_PID[$LOGGER_NAME]}" ]; then
echo " + already an input -> killing it";
kill -INT ${INPUT_PID[$LOGGER_NAME]};
fi;
# Bind-input for the logger at the free port found
# Store bind-input PID
echo " + listen $PORT";
INPUT_PID["$LOGGER_NAME"]="`$ROOT/bind-input $LOGGER_NAME $PORT`";
# Notify that input is active to MASTER
echo " + sending back to port '$PORT' $LOGGER_HOST:$LOGGER_PORT";
bash -c "exec 4<>/dev/tcp/$LOGGER_HOST/$LOGGER_PORT; echo -n \"$PORT\" >&4;";
echo " + background process";
done;
)&
LOOP_PID=$!;
# (3) Set exit management
#--------------------------------------------------------#
trap "kill -INT $LOOP_PID;" HUP INT KILL TERM;
wait $LOOP_PID;