Last active
April 10, 2020 08:07
-
-
Save avielsh/d2b51bfbbe69c5d67bb6d6b3c5bc0d78 to your computer and use it in GitHub Desktop.
A simple internet connectivity test script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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