Skip to content

Instantly share code, notes, and snippets.

@avielsh
Last active April 10, 2020 08:07
Show Gist options
  • Save avielsh/d2b51bfbbe69c5d67bb6d6b3c5bc0d78 to your computer and use it in GitHub Desktop.
Save avielsh/d2b51bfbbe69c5d67bb6d6b3c5bc0d78 to your computer and use it in GitHub Desktop.
A simple internet connectivity test script
#!/usr/bin/env zsh
#!/usr/bin/env bash
#Configure these as needed
host="google.com"
ping="ping -c1 -W1000 $host > /dev/null"
#Status update interval (In seconds)
statusinterval=300
dndstart="23:50"
dndend="09:30"
#reset wifi script - change this for a quick connection fix
resetwifi=~/reset_wifi.sh
maxwifiresets=3
retries=3
wifialreadyreset=0
#Init variables
scrname=$0
declare {SECONDS,RET,statustimer,pingfailures,internetlosses,keeprunning,_logtofile,usednd,verbose}=0
#log config
[[ -n "$TMP" ]] && log=$TMP/${scrname:t}.log || { [[ -d /tmp ]] && log=/tmp/${scrname:t}.log || log=~/${scrname:t}.log ; }
#Colors
blue='\033[0;34m'
green='\033[0;32m'
red='\033[0;31m'
white='\033[0m'
# positional arguments init
_arg_log="$log"
die()
{
local _ret=$2
test -n "$_ret" || _ret=1
test "$_PRINT_HELP" = yes && print_help >&2
echo "$1" >&2
exit ${_ret}
}
begins_with_short_option()
{
local first_option all_short_options='lvdch'
first_option="${1:0:1}"
test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0
}
print_help()
{
printf '%s\n' "Test internet connection"
printf 'Usage: %s [-l|--log=<logfile>] [-c|--(no-)continue] [-d|--dnd=[<dndstart>-<dndend>]] [-v|--verbose] [-h|--help]\n' "$scrname"
printf '\t%s\n' "-l=<logfile>, --log=<logfile>: log to file (default: $log)"
printf '\t%s\n' "-c, --continue, --no-continue: continue running on internet failure (off by default)"
printf '\t%s\n' "-d=[<dndstart>-<dndend>], --dnd=[<dndstart>-<dndend>]: Define a do not disturb time period for silent notifications (default: $dndstart-$dndend)"
printf '\t%s\n' "-v, --verbose: Prints verbose output"
printf '\t%s\n' "-h, --help: Prints help"
}
parse_commandline()
{
while test $# -gt 0
do
_key="$1"
case "$_key" in
-l|--log)
_logtofile=1
;;
--log=*)
_logtofile=1
_arg_log="${_key##--log=}"
;;
-l=*)
_logtofile=1
_arg_log="${_key##-l=}"
;;
-l*)
_logtofile=1
_next="${_key##-l}"
if test -n "$_next" -a "$_next" != "$_key"
then
{ begins_with_short_option "$_next" && shift && set -- "-l" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option."
fi
;;
-d|--dnd)
usednd=1
;;
--dnd=*)
usednd=1
_arg_dnd="${_key##--dnd=}"
dndstart="${_arg_dnd%%-*}"
dndend="${_arg_dnd##*-}"
;;
-d=*)
usednd=1
_arg_dnd="${_key##-d=}"
dndstart="${_arg_dnd%%-*}"
dndend="${_arg_dnd##*-}"
;;
-d*)
usednd=1
_next="${_key##-d}"
if test -n "$_next" -a "$_next" != "$_key"
then
{ begins_with_short_option "$_next" && shift && set -- "-d" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option."
fi
;;
-v|--verbose)
verbose=1
test "${1:0:5}" = "--no-" && verbose=0
;;
-v*)
verbose=1
_next="${_key##-v}"
if test -n "$_next" -a "$_next" != "$_key"
then
{ begins_with_short_option "$_next" && shift && set -- "-v" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option."
fi
;;
-c|--no-continue|--continue)
keeprunning=1
test "${1:0:5}" = "--no-" && keeprunning=0
;;
-c*)
keeprunning=1
_next="${_key##-c}"
if test -n "$_next" -a "$_next" != "$_key"
then
{ begins_with_short_option "$_next" && shift && set -- "-c" "-${_next}" "$@"; } || die "The short option '$_key' can't be decomposed to ${_key:0:2} and -${_key:2}, because ${_key:0:2} doesn't accept value and '-${_key:2:1}' doesn't correspond to a short option."
fi
;;
-h|--help)
print_help
exit 0
;;
-h*)
print_help
exit 0
;;
*)
_PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1
;;
esac
shift
done
}
#Functions
try_ping() {
trap - SIGALRM
[[ $verbose -eq 1 ]] && eval "$ping" || eval "$ping" >/dev/null 2>&1
}
logtofile() {
[[ $_logtofile -ne 1 ]] && return 0
D="$(get_date)"
echo "$D: $1" >> $log
}
in_dnd() {
currenttime=$(date +%H:%M)
if [[ "$dndstart" < "$dndend" ]]; then
[[ "$currenttime" > "$dndstart" ]] && [[ "$currenttime" < "$dndend" ]] && return 0 || return 1
else
[[ "$currenttime" > "$dndstart" ]] || [[ "$currenttime" < "$dndend" ]] && return 0 || return 1
fi
}
retry_connection() {
for I in $(seq 1 $retries)
do
pingfailures=$((pingfailures+1))
if [[ $I -gt 1 ]]
then
#make sure it's not a one time ping loss
ansi_msg notice "||Notice|| - Multiple ping failures detected after $(get_duration). (Total failures: $pingfailures). Retry: $I/$retries"
fi
sleep 2
try_ping
RET=$?
if [[ $RET -eq 0 ]]
then
#Notify only on more than one ping failure
[[ $I -gt 1 ]] && ansi_msg ok "||Notice|| - Internet is connected, temporary ping failure. resuming..."
return 0
fi
done
return 2
}
get_duration() {
duration=$SECONDS
minutes=$((duration /60))
seconds=$((duration % 60))
if [[ $minutes -gt 60 ]]
then
hours=$((minutes/60))
minutes=$((minutes % 60))
if [[ $hours -gt 24 ]]
then
days=$((hours/24))
hours=$((hours % 24))
hourstext="$days days and "
fi
hourstext="$hourstext $hours hours and"
fi
echo "$hourstext $minutes minutes and $seconds seconds"
}
status_update() {
if [[ $((SECONDS-statustimer)) -ge $statusinterval ]]
then
statustimer=$SECONDS
ansi_msg notice "||Status update|| - Internet is connected. $(get_duration) elapsed."
fi
}
notify() {
msg="$1"
if [[ $usednd -eq 1 ]] && in_dnd
then
osascript -e 'display notification "'$msg'" with title "'$scrname:t' says"'
else
msg="${msg//./[[slnc 300]]}"
say "$msg"
fi
}
internet_down_message() {
local flags="LN"
[[ $1 =~ ^- ]] && flags="${1/-/}" && shift
internetdownmessage="Internet connection is down. $(get_duration) elapsed."
ansi_msg -${flags} err "||Error|| - $internetdownmessage"
return 0
}
reset_wifi() {
[[ -f $resetwifi ]] &&
{ ansi_msg -L notice "||Notice|| - Rsetting wifi" ;
sudo $resetwifi ; }
sleep 3
}
ansi_msg() {
[[ $1 =~ ^- ]] && local flags="$1" && shift
msgtype="$1"
msg="$2"
case "$msgtype" in
ok)
prefix=${green}
;;
err)
prefix=${red}
;;
notice)
prefix=${blue}
;;
esac
msg="$(echo $msg | sed 's/||/${prefix}/;s/||/${white}/;s/(/\\(/;s/)/\\)/')"
eval echo -e "$(get_date) - ${msg}"
if [[ -n "$flags" ]]
then
msg=$(echo "$2" | sed -E 's/\|\|.*\|\|//;s/\-//;s/^ +//')
[[ $flags =~ L ]] && logtofile "$msg"
[[ $flags =~ N ]] && notify "$msg"
fi
}
ctrl_c() {
ansi_msg -L notice "||Summary|| - Total internet losses: $internetlosses. Total ping failures: $pingfailures"
ansi_msg -L notice "||Warning|| - Terminating..."
exit 0
}
get_date() {
date +'%b %d %H:%M:%S'
}
main() {
[[ $_logtofile -eq 1 ]] && log="$_arg_log" && echo "Notice: Logging to file: $log" && logtofile "Start logging"
[[ $keeprunning -eq 1 ]] && echo "Notice: Continuous mode"
[[ $verbose -eq 1 ]] && echo "Notice: Verbose output"
[[ $usednd -eq 1 ]] && echo "Notice: Do not disturb period: $dndstart - $dndend"
[[ $((statusinterval % 60)) -eq 0 ]] &&
echo "Notice: Status update every $((statusinterval/60)) minutes" ||
echo "Notice: Status update every $((statusinterval/60)) minutes and $((statusinterval % 60)) seconds"
echo "$(get_date) - Check Internet connection - $scrname:t"
trap ctrl_c INT
#Main loop
while [[ $RET -eq 0 ]]
do
status_update
sleep 0.5
try_ping
RET=$?
if [[ $RET -ne 0 ]]
then
retry_connection
RET=$?
fi
if [[ $RET -eq 0 && ${internetwasdown:-0} -eq 1 ]]
then
internetwasdown=0
ansi_msg -LN ok "||Update|| - Internet is connected again"
wifialreadyreset=0
fi
if [[ $RET -ne 0 ]]
then
[[ $wifialreadyreset -ge 1 ]] &&
internet_down_message -L ||
internet_down_message
internetwasdown=1
SECONDS=0
statustimer=0
[[ $wifialreadyreset -lt $maxwifiresets ]] && reset_wifi && wifialreadyreset=$((wifialreadyreset+1))
if [[ $keeprunning -eq 1 ]]
then
RET=0
internetlosses=$((internetlosses+1))
ansi_msg err "||Notice|| - Internet losses until now: $internetlosses"
else
break
fi
fi
done
}
parse_commandline "$@"
# ansi_msg ok "asd ||this is at test|| asdasd"
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment