-
Notifications
You must be signed in to change notification settings - Fork 319
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(weather): Fix timeout, reduce calls, apply shellcheck (#327)
* refactor(weather): Fix timeout, reduce calls, apply shellcheck Fix Darwin timeout function duration argument. Remove unnecessary API calls to “ipinfo.io”. Confirm to Google Shell style guide and appease shellcheck. * fixup! refactor(weather): Fix timeout, reduce calls, apply shellcheck remove forgotten test string * fixup! refactor(weather): Fix timeout, reduce calls, apply shellcheck add return when unknown location * fixup! refactor(weather): Fix timeout, reduce calls, apply shellcheck update weather_wrapped local vars * fixup! refactor(weather): Fix timeout, reduce calls, apply shellcheck add curl --fail flag * fixup! refactor(weather): Fix timeout, reduce calls, apply shellcheck update fetch_weather_information argument comments, missing API_URLwq * fixup! refactor(weather): Fix timeout, reduce calls, apply shellcheck comment example raw response body * fixup! refactor(weather): Fix timeout, reduce calls, apply shellcheck change locale * fixup! refactor(weather): Fix timeout, reduce calls, apply shellcheck use tr for lowercase due to OSX bash3.2
- Loading branch information
Showing
2 changed files
with
126 additions
and
89 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,129 @@ | ||
#!/usr/bin/env bash | ||
# setting the locale, some users have issues with different locales, this forces the correct one | ||
export LC_ALL=C.utf8 | ||
export LC_ALL=en_US.UTF-8 | ||
|
||
fahrenheit=$1 | ||
location=$2 | ||
fixedlocation=$3 | ||
API_URL="https://wttr.in" | ||
DELIM=":" | ||
|
||
# emulate timeout command from bash - timeout is not available by default on OSX | ||
if [ "$(uname)" == "Darwin" ]; then | ||
timeout() { | ||
perl -e 'alarm shift; exec @ARGV' "$duration" "$@" | ||
function timeout() { | ||
local _duration | ||
_duration="${1:-1}" | ||
command -p perl -e 'alarm shift; exec @ARGV' "$_duration" "$@" | ||
} | ||
fi | ||
|
||
display_location() | ||
{ | ||
if $location && [[ ! -z "$fixedlocation" ]]; then | ||
echo " $fixedlocation" | ||
elif $location; then | ||
city=$(curl -s https://ipinfo.io/city 2> /dev/null) | ||
region=$(curl -s https://ipinfo.io/region 2> /dev/null) | ||
echo " $city, $region" | ||
else | ||
echo '' | ||
fi | ||
} | ||
# Fetch weather information from remote API | ||
# Globals: | ||
# API_URL | ||
# DELIM | ||
# Arguments: | ||
# show fahrenheit, either "true" or "false" | ||
# optional fixed location to query weather data about | ||
function fetch_weather_information() { | ||
local _show_fahrenheit _location _unit | ||
_show_fahrenheit="$1" | ||
_location="$2" | ||
|
||
fetch_weather_information() | ||
{ | ||
display_weather=$1 | ||
# it gets the weather condition textual name (%C), and the temperature (%t) | ||
api_response=$(curl -sL wttr.in/${fixedlocation// /%20}\?format="%C+%t$display_weather") | ||
|
||
if [[ $api_response = "Unknown location;"* ]]; then | ||
echo "Unknown location error" | ||
if "$_show_fahrenheit"; then | ||
_unit="u" | ||
else | ||
echo $api_response | ||
_unit="m" | ||
fi | ||
|
||
# If the user provies a "fixed location", `@dracula-fixed-location`, that the | ||
# API does not recognize, the API may suggest a users actual geoip GPS | ||
# location in the response body. This can lead to user PI leak. | ||
# Drop response body when status code >= 400 and return nonzero by passing the | ||
# `--fail` flag. Execute curl last to allow the consumer to leverage the | ||
# return code. Pass `--show-error` and redirect stderr for the consumer. | ||
command -p curl -L --silent --fail --show-error \ | ||
"${API_URL}/${_location// /%20}?format=%C${DELIM}%t${DELIM}%l&${_unit}" 2>&1 | ||
} | ||
|
||
#get weather display | ||
display_weather() | ||
{ | ||
if $fahrenheit; then | ||
display_weather='&u' # for USA system | ||
else | ||
display_weather='&m' # for metric system | ||
fi | ||
weather_information=$(fetch_weather_information $display_weather) | ||
# Format raw weather information from API | ||
# Globals: | ||
# DELIM | ||
# Arguments: | ||
# The raw weather data as returned by "fetch_weather_information()" | ||
# show location, either "true" or "false" | ||
function format_weather_info() { | ||
local _raw _show_location | ||
_raw="$1" # e.g. "Rain:+63°F:Houston, Texas, United States" | ||
_show_location="$2" | ||
|
||
weather_condition=$(echo "$weather_information" | awk -F' -?[0-9]' '{print $1}' | xargs) # Extract condition before temperature, e.g. Sunny, Snow, etc | ||
temperature=$(echo "$weather_information" | grep -oE '[-+]?[0-9]+°[CF]') # Extract temperature, e.g. +31°C, -3°F, etc | ||
unicode=$(forecast_unicode $weather_condition) | ||
local _weather _temp _location | ||
_weather="${_raw%%"${DELIM}"*}" # slice temp and location to get weather | ||
_weather=$(printf '%s' "$_weather" | tr '[:upper:]' '[:lower:]') # lowercase weather, OSX’s bash3.2 does not support ${v,,} | ||
_temp="${_raw#*"${DELIM}"}" # slice weather to get temp and location | ||
_temp="${_temp%%"${DELIM}"*}" # slice location to get temp | ||
_temp="${_temp/+/}" # slice "+" from "+74°F" | ||
_location="${_raw##*"${DELIM}"}" # slice weather and temp to get location | ||
[ "${_location//[^,]/}" == ",," ] && _location="${_location%,*}" # slice country if it exists | ||
|
||
# Mac Only variant should be transparent on Linux | ||
if [[ "${temperature/+/}" == *"===="* ]]; then | ||
temperature="error" | ||
fi | ||
case "$_weather" in | ||
'snow') | ||
_weather='❄' | ||
;; | ||
'rain' | 'shower') | ||
_weather='☂' | ||
;; | ||
'overcast' | 'cloud') | ||
_weather='☁' | ||
;; | ||
'na') | ||
_weather='' | ||
;; | ||
*) | ||
_weather='☀' | ||
;; | ||
esac | ||
|
||
if [[ "${temperature/+/}" == "error" ]]; then | ||
# Propagate Error | ||
echo "error" | ||
if "$_show_location"; then | ||
printf '%s %s %s' "$_weather" "$_temp" "$_location" | ||
else | ||
echo "$unicode ${temperature/+/}" # remove the plus sign to the temperature | ||
printf '%s %s' "$_weather" "$_temp" | ||
fi | ||
} | ||
|
||
forecast_unicode() | ||
{ | ||
weather_condition=$(echo $weather_condition | awk '{print tolower($0)}') | ||
|
||
if [[ $weather_condition =~ 'snow' ]]; then | ||
echo '❄ ' | ||
elif [[ (($weather_condition =~ 'rain') || ($weather_condition =~ 'shower')) ]]; then | ||
echo '☂ ' | ||
elif [[ (($weather_condition =~ 'overcast') || ($weather_condition =~ 'cloud')) ]]; then | ||
echo '☁ ' | ||
elif [[ $weather_condition = 'NA' ]]; then | ||
echo '' | ||
else | ||
echo '☀ ' | ||
fi | ||
} | ||
# Display weather, temperature, and location | ||
# Globals | ||
# none | ||
# Arguments | ||
# show fahrenheit, either "true" (default) or "false" | ||
# show location, either "true" (default) or "false" | ||
# optional fixed location to query data about, e.g. "Houston, Texas" | ||
function main() { | ||
local _show_fahrenheit _show_location _location | ||
_show_fahrenheit="${1:-true}" | ||
_show_location="${2:-true}" | ||
_location="$3" | ||
|
||
main() | ||
{ | ||
# process should be cancelled when session is killed | ||
if timeout 1 bash -c "</dev/tcp/ipinfo.io/443" && timeout 1 bash -c "</dev/tcp/wttr.in/443" && [[ "$(display_weather)" != "error" ]]; then | ||
echo "$(display_weather)$(display_location)" | ||
else | ||
echo "Weather Unavailable" | ||
if ! timeout 1 bash -c "</dev/tcp/wttr.in/443"; then | ||
printf 'Weather Unavailable\n' | ||
return | ||
fi | ||
|
||
# BashFAQ/002: assignment of substitution does not effect status code. | ||
local _resp | ||
if ! _resp=$(fetch_weather_information "$_show_fahrenheit" "$_location"); then | ||
|
||
# e.g. "curl: (22) The requested URL returned error: 404" | ||
case "${_resp##* }" in | ||
404) | ||
printf 'Unknown Location\n' | ||
;; | ||
*) | ||
printf 'Weather Unavailable\n' | ||
;; | ||
esac | ||
|
||
return | ||
fi | ||
|
||
format_weather_info "$_resp" "$_show_location" | ||
} | ||
|
||
#run main driver program | ||
main | ||
main "$@" |
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