98 lines
3.2 KiB
Markdown
98 lines
3.2 KiB
Markdown
# Imperial Units Implementation
|
||
|
||
## Overview
|
||
|
||
The application automatically selects between metric and imperial (USCS) units based on the request context, matching the behavior of the original Python implementation.
|
||
|
||
## Unit Selection Priority
|
||
|
||
The system determines which units to use in the following priority order:
|
||
|
||
1. **Explicit query parameter** (highest priority)
|
||
- `?u` - Force imperial units (°F, mph, inches, inHg)
|
||
- `?m` - Force metric units (°C, km/h, mm, hPa)
|
||
|
||
2. **Language parameter**
|
||
- `?lang=us` - Use imperial units (for us.wttr.in subdomain)
|
||
|
||
3. **Client IP geolocation**
|
||
- Requests from US IP addresses automatically use imperial units
|
||
- Uses GeoIP database to detect country code
|
||
|
||
4. **Default**
|
||
- Metric units for all other cases
|
||
|
||
## Implementation Details
|
||
|
||
### Code Changes
|
||
|
||
1. **GeoIP Module** (`src/location/geoip.zig`)
|
||
- Added `isUSIP()` method to detect US IP addresses
|
||
- Queries MaxMind database for country ISO code
|
||
- Returns `true` if country code is "US"
|
||
|
||
2. **Handler** (`src/http/handler.zig`)
|
||
- Added `geoip` to `HandleWeatherOptions`
|
||
- Implements priority logic for unit selection
|
||
- Extracts client IP from headers (X-Forwarded-For, X-Real-IP)
|
||
- Passes `use_imperial` flag to all renderers
|
||
|
||
3. **Renderers** (all updated to support imperial units)
|
||
- `ansi.zig` - Shows °F instead of °C
|
||
- `line.zig` - Shows °F and mph for formats 1-4
|
||
- `custom.zig` - Converts all units (temp, wind, precip, pressure)
|
||
- `v2.zig` - Shows imperial units in detailed format
|
||
- `json.zig` - Already outputs both units (no changes needed)
|
||
|
||
### Conversions
|
||
|
||
- Temperature: `°F = °C × 9/5 + 32`
|
||
- Wind speed: `mph = km/h × 0.621371`
|
||
- Precipitation: `inches = mm × 0.0393701`
|
||
- Pressure: `inHg = hPa × 0.02953`
|
||
|
||
## Testing
|
||
|
||
### Unit Tests
|
||
|
||
All renderers have unit tests verifying imperial units:
|
||
- `test "render with imperial units"` in ansi.zig
|
||
- `test "format 2 with imperial units"` in line.zig
|
||
- `test "render custom format with imperial units"` in custom.zig
|
||
- `test "render v2 format with imperial units"` in v2.zig
|
||
- `test "imperial units selection logic"` in handler.zig
|
||
- `test "isUSIP detects US IPs"` in geoip.zig
|
||
|
||
### Integration Testing
|
||
|
||
```bash
|
||
# Test with lang=us
|
||
curl "http://localhost:8002/London?lang=us&format=2"
|
||
# Output: 51.5074,-0.1278: ☁️ 54°F 🌬️SW19mph
|
||
|
||
# Test with explicit ?u
|
||
curl "http://localhost:8002/London?format=2&u"
|
||
# Output: 51.5074,-0.1278: ☁️ 54°F 🌬️SW19mph
|
||
|
||
# Test metric override
|
||
curl "http://localhost:8002/London?lang=us&format=2&m"
|
||
# Output: 51.5074,-0.1278: ☁️ 12°C 🌬️SW30km/h
|
||
|
||
# Test from US IP (automatic detection)
|
||
curl -H "X-Forwarded-For: 8.8.8.8" "http://localhost:8002/London?format=2"
|
||
# Output: Uses imperial if 8.8.8.8 is detected as US IP
|
||
```
|
||
|
||
## Documentation Updates
|
||
|
||
- **API_ENDPOINTS.md** - Added "Unit System Defaults" section explaining priority
|
||
- **README.md** - Updated "Implemented Features" to mention auto-detection
|
||
- **IMPERIAL_UNITS.md** - This document
|
||
|
||
## Compatibility
|
||
|
||
This implementation matches the original Python behavior in `lib/parse_query.py`:
|
||
- Same priority order
|
||
- Same detection logic
|
||
- Same unit conversions
|
||
- Compatible with existing clients and scripts
|