docs: Add docs

Signed-off-by: Tim Hårek Andreassen <tim@harek.no>
This commit is contained in:
Tim Hårek Andreassen 2024-10-05 23:36:31 +02:00
parent 7435512ffb
commit 97e085e2ad
No known key found for this signature in database
GPG key ID: E59C7734F0E10EB5
6 changed files with 31 additions and 8 deletions

View file

@ -2,6 +2,7 @@ package main
import "git.sr.ht/~timharek/yr/cmd" import "git.sr.ht/~timharek/yr/cmd"
// Execute CLI
func main() { func main() {
cmd.Execute() cmd.Execute()
} }

1
pkg/cache/cache.go vendored
View file

@ -14,6 +14,7 @@ type Cache[T any] struct {
Path string Path string
} }
// New Cache where default path is os.TempDir()
func New[T any](path string) *Cache[T] { func New[T any](path string) *Cache[T] {
if path == "" { if path == "" {
path = os.TempDir() path = os.TempDir()

View file

@ -1,3 +1,4 @@
// Access [Meteorologisk institutt's API](https://api.met.no)
package met package met
import ( import (
@ -12,6 +13,7 @@ type Met struct {
siteName string siteName string
} }
// Returns valid Met client or error if empty siteName is provided
func New(siteName string) (*Met, error) { func New(siteName string) (*Met, error) {
if siteName == "" { if siteName == "" {
return nil, fmt.Errorf("`siteName` must be defined.") return nil, fmt.Errorf("`siteName` must be defined.")
@ -22,6 +24,8 @@ func New(siteName string) (*Met, error) {
}, nil }, nil
} }
// Get LocationForecast from Met, returns error if Met doesn't answer or response is missing required headers
// API endpoint: https://api.met.no/weatherapi/locationforecast/2.0/documentation
func (m *Met) Forecast(lat, lon float64, alt *int) (*LocationForecastResult, error) { func (m *Met) Forecast(lat, lon float64, alt *int) (*LocationForecastResult, error) {
url := "https://api.met.no/weatherapi/locationforecast/2.0/complete" url := "https://api.met.no/weatherapi/locationforecast/2.0/complete"

View file

@ -24,6 +24,8 @@ func New(siteName string) (*Nominatim, error) {
}, nil }, nil
} }
// Search for coordinates based on q
// API endpoint: https://nominatim.openstreetmap.org/search
func (n *Nominatim) Search(q string) (*SearchResults, error) { func (n *Nominatim) Search(q string) (*SearchResults, error) {
url := fmt.Sprintf("https://nominatim.openstreetmap.org/search?q=%s&format=jsonv2", url.QueryEscape(q)) url := fmt.Sprintf("https://nominatim.openstreetmap.org/search?q=%s&format=jsonv2", url.QueryEscape(q))
@ -58,6 +60,8 @@ func (n *Nominatim) Search(q string) (*SearchResults, error) {
return &result, nil return &result, nil
} }
// Reverse search for location based on lat and lon
// API endpoint: https://nominatim.openstreetmap.org/reverse
func (n *Nominatim) Reverse(lat, lon float64) (*ReverseResult, error) { func (n *Nominatim) Reverse(lat, lon float64) (*ReverseResult, error) {
url := fmt.Sprintf("https://nominatim.openstreetmap.org/reverse?lat=%.16f&lon=%.16f&format=jsonv2", lat, lon) url := fmt.Sprintf("https://nominatim.openstreetmap.org/reverse?lat=%.16f&lon=%.16f&format=jsonv2", lat, lon)
@ -101,6 +105,7 @@ type LookupResult struct {
Location string `json:"location"` Location string `json:"location"`
} }
// Lookup location coordinates based on q
func (n *Nominatim) Lookup(q string) (*LookupResult, error) { func (n *Nominatim) Lookup(q string) (*LookupResult, error) {
r, err := n.Search(q) r, err := n.Search(q)
@ -132,6 +137,7 @@ func (n *Nominatim) Lookup(q string) (*LookupResult, error) {
}, nil }, nil
} }
// Lookup location name based on lat and lon
func (n *Nominatim) ReverseLookup(lat, lon float64) (*LookupResult, error) { func (n *Nominatim) ReverseLookup(lat, lon float64) (*LookupResult, error) {
r, err := n.Reverse(lat, lon) r, err := n.Reverse(lat, lon)
@ -148,6 +154,7 @@ func (n *Nominatim) ReverseLookup(lat, lon float64) (*LookupResult, error) {
}, nil }, nil
} }
// Check if all fields on s is nil
func allFieldsNil(s interface{}) bool { func allFieldsNil(s interface{}) bool {
v := reflect.ValueOf(s) v := reflect.ValueOf(s)

View file

@ -1,12 +1,13 @@
package direction package direction
// Cardinal direction in unicode arrow
const ( const (
NORTH = "↑" NORTH string = "↑"
SOUTH = "↓" SOUTH string = "↓"
WEST = "←" WEST string = "←"
EAST = "→" EAST string = "→"
NORTH_WEST = "↖" NORTH_WEST string = "↖"
NORTH_EAST = "↗" NORTH_EAST string = "↗"
SOUTH_WEST = "↙" SOUTH_WEST string = "↙"
SOUTH_EAST = "↘" SOUTH_EAST string = "↘"
) )

View file

@ -18,6 +18,7 @@ type Client struct {
cache cache.Cache[ForecastResult] cache cache.Cache[ForecastResult]
} }
// New default Yr client
func New() (*Client, error) { func New() (*Client, error) {
siteName := "git.sr.ht/~timharek/yr" siteName := "git.sr.ht/~timharek/yr"
met, err := met.New(siteName) met, err := met.New(siteName)
@ -38,6 +39,7 @@ type wind struct {
Direction float64 `json:"direction"` Direction float64 `json:"direction"`
} }
// Returns wind direction to an unicode arrow
func (w *wind) DirectionToString() string { func (w *wind) DirectionToString() string {
return windDirection(w.Direction) return windDirection(w.Direction)
} }
@ -68,6 +70,7 @@ func windDirection(d float64) string {
} }
} }
// A forecast
type Forecast struct { type Forecast struct {
nominatim.LookupResult nominatim.LookupResult
Time time.Time `json:"time"` Time time.Time `json:"time"`
@ -76,6 +79,7 @@ type Forecast struct {
Wind wind `json:"wind"` // In m/s Wind wind `json:"wind"` // In m/s
} }
// A forecast result with metadata
type ForecastResult struct { type ForecastResult struct {
Expires time.Time `json:"expires"` Expires time.Time `json:"expires"`
LastModified time.Time `json:"lastModified"` LastModified time.Time `json:"lastModified"`
@ -83,6 +87,7 @@ type ForecastResult struct {
Forecast []Forecast `json:"forecast"` Forecast []Forecast `json:"forecast"`
} }
// Current forecast for q
func (c *Client) Now(q string) (*ForecastResult, error) { func (c *Client) Now(q string) (*ForecastResult, error) {
cacheResult, err := c.cache.Get(q) cacheResult, err := c.cache.Get(q)
if err != nil { if err != nil {
@ -103,6 +108,7 @@ func (c *Client) Now(q string) (*ForecastResult, error) {
}, &coords.Location) }, &coords.Location)
} }
// Current forecast for coords
func (c *Client) NowCoords(coords *nominatim.Coordinates, location *string) (*ForecastResult, error) { func (c *Client) NowCoords(coords *nominatim.Coordinates, location *string) (*ForecastResult, error) {
result, err := c.ForecastCoords(coords, location) result, err := c.ForecastCoords(coords, location)
if err != nil { if err != nil {
@ -114,6 +120,7 @@ func (c *Client) NowCoords(coords *nominatim.Coordinates, location *string) (*Fo
return result, nil return result, nil
} }
// Forecast for q
func (c *Client) Forecast(q string) (*ForecastResult, error) { func (c *Client) Forecast(q string) (*ForecastResult, error) {
cacheResult, err := c.cache.Get(q) cacheResult, err := c.cache.Get(q)
if err != nil { if err != nil {
@ -134,6 +141,7 @@ func (c *Client) Forecast(q string) (*ForecastResult, error) {
}, &coords.Location) }, &coords.Location)
} }
// Forecast for coords
func (c *Client) ForecastCoords(coords *nominatim.Coordinates, location *string) (*ForecastResult, error) { func (c *Client) ForecastCoords(coords *nominatim.Coordinates, location *string) (*ForecastResult, error) {
coordCacheName := fmt.Sprintf("%.4f_%.4f", coords.Latitude, coords.Longitude) coordCacheName := fmt.Sprintf("%.4f_%.4f", coords.Latitude, coords.Longitude)
cacheResult, err := c.cache.Get(coordCacheName) cacheResult, err := c.cache.Get(coordCacheName)
@ -224,6 +232,7 @@ func (c *Client) ForecastCoords(coords *nominatim.Coordinates, location *string)
return &result, nil return &result, nil
} }
// Helper to sort met.Timeseries
func sortTimeSeries(a, b met.Timeseries) int { func sortTimeSeries(a, b met.Timeseries) int {
return cmp.Compare(a.Time.Unix(), b.Time.Unix()) return cmp.Compare(a.Time.Unix(), b.Time.Unix())
} }