Attempted fixes for weather.

This commit is contained in:
Storm Dragon
2025-10-27 14:39:46 -04:00
parent d6825c4a92
commit 9b7a786a96

View File

@@ -17,6 +17,8 @@ shift 2
# Database file for user locations and cached geocoding
weatherDb="data/weather.db"
weatherDbLock="${weatherDb}.lock"
nominatimRateLimitFile="data/nominatim_last_request"
mkdir -p "$(dirname "$weatherDb")"
touch "$weatherDb"
@@ -73,6 +75,10 @@ save_user_location() {
local lon="$4"
local formatted="$5"
# Use flock to prevent race conditions
(
flock -x 200
# Remove old entry if exists
if [[ -f "$weatherDb" ]]; then
grep -v "^USER|${user}|" "$weatherDb" > "${weatherDb}.tmp"
@@ -81,16 +87,54 @@ save_user_location() {
# Add new entry
echo "USER|${user}|${location}|${lat}|${lon}|${formatted}" >> "$weatherDb"
) 200>"$weatherDbLock"
}
# Function to delete user location
delete_user_location() {
local user="$1"
# Use flock to prevent race conditions
(
flock -x 200
if [[ -f "$weatherDb" ]]; then
grep -v "^USER|${user}|" "$weatherDb" > "${weatherDb}.tmp"
mv "${weatherDb}.tmp" "$weatherDb"
fi
) 200>"$weatherDbLock"
}
# Function to maintain cache size
maintain_cache() {
# Use flock to prevent race conditions
(
flock -x 200
if [[ ! -f "$weatherDb" ]]; then
return 0
fi
local lineCount
lineCount=$(wc -l < "$weatherDb")
# If file has 2000 or more lines, keep only the most recent 1500
if [[ $lineCount -ge 2000 ]]; then
# Separate USER and CACHE entries
grep "^USER|" "$weatherDb" > "${weatherDb}.tmp.user" 2>/dev/null || true
grep "^CACHE|" "$weatherDb" | tail -n 1000 > "${weatherDb}.tmp.cache" 2>/dev/null || true
# Combine them back (keep all user entries, trim cache entries)
cat "${weatherDb}.tmp.user" "${weatherDb}.tmp.cache" > "${weatherDb}.tmp" 2>/dev/null
mv "${weatherDb}.tmp" "$weatherDb"
# Clean up temp files
rm -f "${weatherDb}.tmp.user" "${weatherDb}.tmp.cache"
fi
) 200>"$weatherDbLock"
}
# Function to cache geocode result
@@ -106,10 +150,45 @@ cache_location() {
local cached
cached=$(get_cached_location "$query")
if [[ -z "$cached" ]]; then
# Use flock to prevent race conditions
(
flock -x 200
echo "CACHE|${queryLower}|${location}|${lat}|${lon}|${formatted}" >> "$weatherDb"
) 200>"$weatherDbLock"
# Maintain cache size after adding new entry
maintain_cache
fi
}
# Function to enforce Nominatim rate limit (1 request per second)
rate_limit_nominatim() {
local rateLimitLock="${nominatimRateLimitFile}.lock"
(
flock -x 200
# Check if rate limit file exists and read last request time
if [[ -f "$nominatimRateLimitFile" ]]; then
local lastRequest
lastRequest=$(cat "$nominatimRateLimitFile" 2>/dev/null || echo "0")
local currentTime
currentTime=$(date +%s)
local timeSinceLastRequest=$((currentTime - lastRequest))
# If less than 1 second has passed, sleep for the remaining time
if [[ $timeSinceLastRequest -lt 1 ]]; then
local sleepTime=$((1 - timeSinceLastRequest))
sleep "$sleepTime"
fi
fi
# Update last request time
date +%s > "$nominatimRateLimitFile"
) 200>"$rateLimitLock"
}
# Function to format location (City, State or City, Country)
format_location() {
local address="$1"
@@ -179,9 +258,27 @@ geocode_location() {
# URL encode the query (replace spaces with +)
local encodedQuery="${query// /+}"
# Check if query contains common US indicators (case-insensitive)
local countryCode=""
local queryLower="${query,,}"
# Common US state names and abbreviations
local usStates="alabama|alaska|arizona|arkansas|california|colorado|connecticut|delaware|florida|georgia|hawaii|idaho|illinois|indiana|iowa|kansas|kentucky|louisiana|maine|maryland|massachusetts|michigan|minnesota|mississippi|missouri|montana|nebraska|nevada|new hampshire|new jersey|new mexico|new york|north carolina|north dakota|ohio|oklahoma|oregon|pennsylvania|rhode island|south carolina|south dakota|tennessee|texas|utah|vermont|virginia|washington|west virginia|wisconsin|wyoming"
if [[ "$queryLower" =~ (usa|united states) ]] || \
[[ "$query" =~ [[:space:]][A-Z]{2}$ ]] || \
[[ "$queryLower" =~ [[:space:]](${usStates})$ ]] || \
[[ "$query" =~ ^[0-9]{5}([[:space:]]|$) ]]; then
# Query mentions USA, ends with state abbreviation, ends with state name, or starts with 5-digit zip
countryCode="&countrycodes=us"
fi
# Enforce rate limit before making API request
rate_limit_nominatim
response=$(curl -s --connect-timeout 5 --max-time 10 \
-H "User-Agent: ${userAgent}" \
"${url}?q=${encodedQuery}&format=json&limit=1&addressdetails=1")
"${url}?q=${encodedQuery}&format=json&limit=1&addressdetails=1${countryCode}")
if [[ -z "$response" || "$response" == "[]" ]]; then
return 1
@@ -217,7 +314,7 @@ get_weather() {
local url="https://api.open-meteo.com/v1/forecast"
local params="latitude=${lat}&longitude=${lon}"
params+="&current=temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m"
params+="&current=temperature_2m,apparent_temperature,relative_humidity_2m,weather_code,wind_speed_10m"
params+="&daily=weather_code,temperature_2m_max,temperature_2m_min"
params+="&timezone=auto&forecast_days=3&temperature_unit=fahrenheit&wind_speed_unit=mph"
@@ -239,17 +336,35 @@ format_weather() {
# Parse current weather
local temp
local feelsLike
local humidity
local windSpeed
local weatherCode
temp=$(echo "$weatherData" | jq -r '.current.temperature_2m // "N/A"')
feelsLike=$(echo "$weatherData" | jq -r '.current.apparent_temperature // "N/A"')
humidity=$(echo "$weatherData" | jq -r '.current.relative_humidity_2m // "N/A"')
windSpeed=$(echo "$weatherData" | jq -r '.current.wind_speed_10m // "N/A"')
weatherCode=$(echo "$weatherData" | jq -r '.current.weather_code // 0')
local conditions="${weatherCodes[$weatherCode]:-Unknown}"
# Build message
local message="Weather for ${locationName}: ${temp}°F, ${conditions}"
local message="Weather for ${locationName}: ${temp}°F"
# Add feels-like if different from actual temp (round to nearest degree for comparison)
if [[ "$feelsLike" != "N/A" && "$temp" != "N/A" ]]; then
local tempRounded
local feelsLikeRounded
tempRounded=$(printf "%.0f" "$temp" 2>/dev/null || echo "$temp")
feelsLikeRounded=$(printf "%.0f" "$feelsLike" 2>/dev/null || echo "$feelsLike")
# Only show feels-like if it differs by at least 3 degrees
local diff=$((tempRounded - feelsLikeRounded))
if [[ ${diff#-} -ge 3 ]]; then
message+=" (feels like ${feelsLike}°F)"
fi
fi
message+=", ${conditions}"
if [[ "$humidity" != "N/A" ]]; then
message+=", Humidity: ${humidity}%"
@@ -325,17 +440,12 @@ format_forecast() {
# Main command logic
subcommand="${1:-}"
# If subcommand is the module name itself (w or weather), treat as no argument
if [[ "$subcommand" == "w" || "$subcommand" == "weather" ]]; then
subcommand=""
fi
case "$subcommand" in
set)
# Set user's location
shift
if [[ $# -eq 0 ]]; then
msg "$channelName" "$name: Usage: weather -set <location>"
msg "$channelName" "$name: Usage: weather set <location>"
exit 0
fi
@@ -364,6 +474,7 @@ case "$subcommand" in
save_user_location "$name" "$fullAddress" "$lat" "$lon" "$formattedLocation"
msg "$channelName" "$name: Your location has been set to: ${formattedLocation}"
exit 0
;;
del|delete)