-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathircbot_weather.go
121 lines (112 loc) · 2.7 KB
/
ircbot_weather.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"strings"
"time"
"gitea.demsh.org/demsh/ircfw"
"gopkg.in/tomb.v2"
)
const (
weatherURL = "https://api.openweathermap.org/data/2.5/weather?units=metric&lang=ru&APPID=%s&q=%s"
mmHgMagic = 0.750062
)
type weather struct {
Weather []struct {
Description string `json:"description"`
} `json:"weather"`
Main struct {
Temp float64 `json:"temp"`
Pressure float64 `json:"pressure"`
Humidity int `json:"humidity"`
TempMin float64 `json:"temp_min"`
TempMax float64 `json:"temp_max"`
} `json:"main"`
Wind struct {
Speed float64 `json:"speed"`
Deg float64 `json:"deg"`
} `json:"wind"`
Sys struct {
Country string `json:"country"`
} `json:"sys"`
CityID int `json:"id"`
Name string `json:"name"`
Cod int `json:"cod"`
created time.Time
}
func (w weather) expired() bool {
return time.Since(w.created) > 10*time.Minute
}
func (w weather) String() string {
return fmt.Sprintf("%s/%s: %s; температура: %.1f °C; давление: %.1f мм рт.ст; ветер %.1f м/с, относ. влаж.: %d%%",
w.Name, w.Sys.Country, w.Weather[0].Description,
w.Main.Temp, w.Main.Pressure*mmHgMagic, w.Wind.Speed,
w.Main.Humidity)
}
func handleWeather(ctx context.Context, bot *ircbot, msg ircfw.Msg) {
params := strings.Split(removeCmd(msg.Text(), cmdWeather)[0], " ")
if len(params) < 1 {
return
}
city := strings.ToLower(params[0])
weather, err := getWeather(ctx, bot, city)
if err != nil {
bot.Logf("Weather for %q: %q", city, err)
return
}
msg.Reply(ctx, []string{weather.String()})
}
func getWeather(ctx context.Context, bot *ircbot, alias string) (result weather, err error) {
var (
city, country string
)
err = bot.stmts[fetchCity].QueryRowContext(ctx, alias).Scan(&city, &country)
if err != nil {
return
}
city = fmt.Sprintf("%s,%s", city, country)
bot.mu.Lock()
result, ok := bot.weatherCache[city]
bot.mu.Unlock()
if ok {
return
}
body, _, err := get(ctx, fmt.Sprintf(weatherURL, bot.config.weatherToken, city), "application/json", bot.config.userAgent)
if err != nil {
return
}
defer body.Close()
b, err := ioutil.ReadAll(body)
if err != nil {
return
}
err = json.Unmarshal(b, &result)
if err != nil {
return
}
bot.mu.Lock()
bot.weatherCache[city] = result
bot.mu.Unlock()
return
}
func (b *ircbot) pruneWeatherCache() error {
b.weatherCache = make(map[string]weather)
ticker := time.NewTicker(time.Minute)
for {
select {
case <-b.tomb.Dying():
ticker.Stop()
return tomb.ErrDying
case <-ticker.C:
}
b.mu.Lock()
for city, weather := range b.weatherCache {
if weather.expired() {
delete(b.weatherCache, city)
}
}
b.mu.Unlock()
}
}