diff --git a/bot/handler/weather.go b/bot/handler/weather.go index 9cd6f89..a946ec1 100644 --- a/bot/handler/weather.go +++ b/bot/handler/weather.go @@ -1,70 +1,19 @@ package handler import ( - "encoding/json" "fmt" - "io" - "net/http" "strings" "git.kill0.net/chill9/beepboop/bot" - "git.kill0.net/chill9/beepboop/lib" + "git.kill0.net/chill9/beepboop/lib/weather" "github.com/bwmarrin/discordgo" + log "github.com/sirupsen/logrus" ) -const ( - OpenWeatherMapURI = "https://api.openweathermap.org" -) - -var ( - EndpointWeather = lib.BuildURI(OpenWeatherMapURI, "/data/2.5/weather") -) - -type ( - WeatherHandler struct { - Config bot.Config - Name string - } - - Temperature float32 - - Weather struct { - Main struct { - Temp Temperature `json:"temp"` - FeelsLike Temperature `json:"feels_like"` - TempMin Temperature `json:"temp_min"` - TempMax Temperature `json:"temp_max"` - Pressure float32 `json:"pressure"` - Humidity float32 `json:"humidity"` - } `json:"main"` - - Coord struct { - Lon float32 `json:"lon"` - Lat float32 `json:"lat"` - } `json:"coord"` - - Rain struct { - H1 float32 `json:"1h"` - H3 float32 `json:"3h"` - } `json:"rain"` - } - - WeatherError struct { - Message string `json:"message"` - } -) - -func (t *Temperature) Kelvin() float32 { - return float32(*t) -} - -func (t *Temperature) Fahrenheit() float32 { - return ((float32(*t) - 273.15) * (9.0 / 5)) + 32 -} - -func (t *Temperature) Celcius() float32 { - return float32(*t) - 273.15 +type WeatherHandler struct { + Config bot.Config + Name string } func NewWeatherHandler(s string) *WeatherHandler { @@ -79,9 +28,9 @@ func (h *WeatherHandler) SetConfig(config bot.Config) { func (h *WeatherHandler) Handle(s *discordgo.Session, m *discordgo.MessageCreate) { var ( - loc string - w Weather - werr WeatherError + err error + loc string + w weather.Weather ) if m.Author.ID == s.State.User.ID { @@ -106,51 +55,17 @@ func (h *WeatherHandler) Handle(s *discordgo.Session, m *discordgo.MessageCreate return } - req, err := http.NewRequest("GET", EndpointWeather, nil) + wc := weather.NewClient(h.Config.OpenWeatherMapToken) + + log.Debugf("weather requested for '%s'", loc) + + w, err = wc.Get(loc) if err != nil { - log.Errorf("failed to create new request: %s", err) + log.Errorf("weather client error: %v", err) return } - q := req.URL.Query() - q.Add("q", loc) - q.Add("appid", h.Config.OpenWeatherMapToken) - req.URL.RawQuery = q.Encode() - - resp, err := http.DefaultClient.Do(req) - if err != nil { - log.Errorf("HTTP request failed: %s", err) - return - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - log.Errorf("reading HTTP response failed: %s", err) - return - } - - if resp.StatusCode != 200 { - err = json.Unmarshal(body, &werr) - if err != nil { - log.Debugf("%s\n", body) - log.Errorf("unmarshaling JSON failed: %s", err) - return - } - log.Warnf("error: (%s) %s", resp.Status, werr.Message) - return - } - - log.Debugf("weather requested for '%s'\n", loc) - - err = json.Unmarshal(body, &w) - if err != nil { - log.Debugf("%s\n", body) - log.Errorf("unmarshaling JSON failed: %s", err) - return - } - - log.Debugf("weather returned for '%s': %+v\n", loc, w) + log.Debugf("weather returned for '%s': %+v", loc, w) s.ChannelMessageSend(m.ChannelID, fmt.Sprintf( "%s (%.1f, %.1f) — C:%.1f F:%.1f K:%.1f", diff --git a/lib/weather/structs.go b/lib/weather/structs.go new file mode 100644 index 0000000..9ba8fbd --- /dev/null +++ b/lib/weather/structs.go @@ -0,0 +1,42 @@ +package weather + +type ( + Temperature float32 + + Weather struct { + Main struct { + Temp Temperature `json:"temp"` + FeelsLike Temperature `json:"feels_like"` + TempMin Temperature `json:"temp_min"` + TempMax Temperature `json:"temp_max"` + Pressure float32 `json:"pressure"` + Humidity float32 `json:"humidity"` + } `json:"main"` + + Coord struct { + Lon float32 `json:"lon"` + Lat float32 `json:"lat"` + } `json:"coord"` + + Rain struct { + H1 float32 `json:"1h"` + H3 float32 `json:"3h"` + } `json:"rain"` + } + + WeatherError struct { + Message string `json:"message"` + } +) + +func (t *Temperature) Kelvin() float32 { + return float32(*t) +} + +func (t *Temperature) Fahrenheit() float32 { + return ((float32(*t) - 273.15) * (9.0 / 5)) + 32 +} + +func (t *Temperature) Celcius() float32 { + return float32(*t) - 273.15 +} diff --git a/lib/weather/weather.go b/lib/weather/weather.go new file mode 100644 index 0000000..9a9d990 --- /dev/null +++ b/lib/weather/weather.go @@ -0,0 +1,81 @@ +package weather + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + + "git.kill0.net/chill9/beepboop/lib" + + log "github.com/sirupsen/logrus" +) + +type ( + WeatherClient struct { + token string + } +) + +const ( + OpenWeatherMapURI = "https://api.openweathermap.org" +) + +var ( + EndpointWeather = lib.BuildURI(OpenWeatherMapURI, "/data/2.5/weather") +) + +func NewClient(token string) *WeatherClient { + return &WeatherClient{token} +} + +func (c *WeatherClient) Get(loc string) (w Weather, err error) { + var ( + werr WeatherError + ) + + req, err := http.NewRequest("GET", EndpointWeather, nil) + if err != nil { + err = fmt.Errorf("failed to create new request: %s", err) + return + } + + q := req.URL.Query() + q.Add("q", loc) + q.Add("appid", c.token) + req.URL.RawQuery = q.Encode() + + resp, err := http.DefaultClient.Do(req) + if err != nil { + err = fmt.Errorf("HTTP request failed: %s", err) + return + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + err = fmt.Errorf("reading HTTP response failed: %s", err) + return + } + + if resp.StatusCode != 200 { + err = json.Unmarshal(body, &werr) + if err != nil { + log.Debugf("%s", body) + err = fmt.Errorf("unmarshaling JSON failed: %s", err) + return + } + + err = fmt.Errorf("error: (%s) %s", resp.Status, werr.Message) + return + } + + err = json.Unmarshal(body, &w) + if err != nil { + log.Debugf("%s", body) + log.Errorf("unmarshaling JSON failed: %s", err) + return + } + + return +}