dotfiles/bin/rds
2020-11-17 16:26:46 +08:00

99 lines
2.7 KiB
Bash
Executable File

#!/bin/bash
# Following regex is based on https://tools.ietf.org/html/rfc3986#appendix-B with
# additional sub-expressions to split authority into userinfo, host and port
#
readonly URI_REGEX='^(([^:/?#]+):)?(//((([^:/?#]+)?(:([^:/?#]+))?@)?([^:/?#]+)(:([0-9]+))?))(/([^?#]*))?(\?([^#]*))?(#(.*))?'
# ↑↑ ↑ ↑↑↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
# |2 scheme | ||6 userinfo passwd 7 host | 9 port | 11 rpath | 13 query | 15 fragment
# 1 scheme: | |5 userinfo@ 8 :… 10 path 12 ?… 14 #…
# | 4 authority
# 3 //…
IDX_SCHEME=2
IDX_USER=6
IDX_PASSWD=8
IDX_HOST=9
IDX_PORT=11
IDX_PATH=12
IDX_RPATH=13
IDX_QUERY=15
IDX_FRAGMENT=17
# processing argument
POSITIONAL=()
while [[ $# -gt 0 ]]; do
case "$1" in
-s|--ssh)
SSH="$2"
shift
shift
;;
--)
shift
POSITIONAL+=("$@")
break
;;
*)
POSITIONAL+=("$1")
shift
;;
esac
done
set -- "${POSITIONAL[@]}"
# check arguments
if [[ $# == 0 ]]; then
echo "Usage: $0 [-s|--ssh SSH_DESTINATION] <REDIS_URI> [...REDIS_CLI_ARGS]"
echo " -s, --ssh for ssh tunnel"
echo " REDIS_URI redis://:passwd@host:port/db"
exit -1
fi
# pop the REDIS_URI and process it
if [[ ! ($1 =~ $URI_REGEX) ]]; then
echo "Invalid redis uri"
exit -1
fi
shift
SCHEME=${BASH_REMATCH[$IDX_SCHEME]}
USER=${BASH_REMATCH[$IDX_USER]}
PASSWD=${BASH_REMATCH[$IDX_PASSWD]}
HOST=${BASH_REMATCH[$IDX_HOST]}
PORT=${BASH_REMATCH[$IDX_PORT]}
UPATH=${BASH_REMATCH[$IDX_PATH]}
RPATH=${BASH_REMATCH[$IDX_RPATH]}
QUERY=${BASH_REMATCH[$IDX_QUERY]}
FRAGMENT=${BASH_REMATCH[$IDX_FRAGMENT]}
# create ssh tunnel if `--ssh` is assigned
is-port-used() {
lsof -i -P -n | awk '{print $9}' | grep -F ":$1" >/dev/null
}
if [[ -n $SSH ]]; then
# find available
read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range
while :; do
for (( port = lower_port ; port <= upper_port ; port++ )); do
! is-port-used $port && break 2
done
done
# forward local port to remote destination
ssh -N -L localhost:$port:$HOST:$PORT $SSH &
SSH_PID=$!
# wait until port is ready
while ! is-port-used $port; do
sleep 0.1
done
HOST=localhost
PORT=$port
fi
redis-cli -h "$HOST" -p "${PORT-6379}" -a "$PASSWD" -n "${RPATH-0}" "$@"
# clean up ssh connection
[[ -n $SSH_PID ]] && kill -9 $SSH_PID