diff --git a/bot.go b/bot.go
index 319eca1..5f68502 100644
--- a/bot.go
+++ b/bot.go
@@ -4,10 +4,14 @@ import (
"fmt"
"html"
"math"
+ "regexp"
+ "strconv"
"strings"
"text/tabwriter"
"time"
+ "git.gensokyo.cafe/kkyy/mycurrencynet"
+ "github.com/dustin/go-humanize"
"github.com/go-errors/errors"
"github.com/samber/lo"
tele "gopkg.in/telebot.v3"
@@ -49,6 +53,7 @@ func initBot() (*tele.Bot, error) {
b.Handle("/me", handleUserInfoCmd)
b.Handle("/chat", handleChatInfoCmd)
b.Handle("/year_progress", handleYearProgressCmd)
+ b.Handle("/xr", handleExchangeRateCmd)
b.Handle(tele.OnText, handleGeneralMessage)
b.Handle(tele.OnSticker, handleGeneralMessage)
@@ -95,12 +100,12 @@ func handleStartCmd(c tele.Context) error {
func handleTrafficCmd(c tele.Context) error {
dailyTraffic, err := stats.VnstatDailyTraffic(config.WatchedInterface)
if err != nil {
- _ = c.Reply(stickerFromID(stickerPanic))
+ _ = c.Reply(stickerFromID(stickerPanic), tele.Silent)
return err
}
monthlyTraffic, err := stats.VnstatMonthlyTraffic(config.WatchedInterface)
if err != nil {
- _ = c.Reply(stickerFromID(stickerPanic))
+ _ = c.Reply(stickerFromID(stickerPanic), tele.Silent)
return err
}
@@ -137,7 +142,7 @@ func handleTrafficCmd(c tele.Context) error {
respText = strings.Join(responseParts, "\n")
}
- return c.Reply(respText, &tele.SendOptions{ParseMode: tele.ModeMarkdown})
+ return c.Reply(respText, &tele.SendOptions{ParseMode: tele.ModeMarkdown}, tele.Silent)
}
func fmtTraffic(r stats.VnstatTrafficRecord) string {
@@ -148,7 +153,7 @@ func fmtTraffic(r stats.VnstatTrafficRecord) string {
func handleUserInfoCmd(c tele.Context) error {
u := c.Sender()
if u == nil {
- return c.Reply("Unknown.")
+ return c.Reply("Unknown.", tele.Silent)
}
replyText := []string{
@@ -163,13 +168,13 @@ func handleUserInfoCmd(c tele.Context) error {
fmt.Sprintf(`IsPremium: %t`, u.IsPremium),
"```",
}
- return c.Reply(strings.Join(replyText, "\n"), &tele.SendOptions{ParseMode: tele.ModeMarkdown})
+ return c.Reply(strings.Join(replyText, "\n"), &tele.SendOptions{ParseMode: tele.ModeMarkdown}, tele.Silent)
}
func handleChatInfoCmd(c tele.Context) error {
chat := c.Chat()
if chat == nil {
- return c.Reply("Unknown.")
+ return c.Reply("Unknown.", tele.Silent)
}
loc := ""
if chat.ChatLocation != nil {
@@ -195,7 +200,7 @@ func handleChatInfoCmd(c tele.Context) error {
fmt.Sprintf(`NoVoiceAndVideo: %t`, chat.NoVoiceAndVideo),
"```",
}
- return c.Reply(strings.Join(replyText, "\n"), &tele.SendOptions{ParseMode: tele.ModeMarkdown})
+ return c.Reply(strings.Join(replyText, "\n"), &tele.SendOptions{ParseMode: tele.ModeMarkdown}, tele.Silent)
}
func drawBar(progress float64, length int) string {
@@ -220,7 +225,7 @@ func drawBarForTrafficRecord(r stats.VnstatTrafficRecord) string {
effective := lo.Max([]uint64{r.Rx, r.Tx})
max := config.MonthlyTrafficLimitGiB
ratio := float64(effective) / 1024 / 1024 / 1024 / float64(max)
- return fmt.Sprintf("`%s %2.0f%%`", drawBar(ratio, 25), ratio*100)
+ return fmt.Sprintf("`%s %2.0f%%`", drawBar(ratio, 16), ratio*100)
}
func handleYearProgressCmd(c tele.Context) error {
@@ -232,9 +237,9 @@ func handleYearProgressCmd(c tele.Context) error {
replyText := fmt.Sprintf(
"\n%d is %2.0f%% complete.\n
%s
",
- time.Now().Year(), ratio*100, drawBar(ratio, 25),
+ time.Now().Year(), ratio*100, drawBar(ratio, 20),
)
- return c.Reply(replyText, &tele.SendOptions{ParseMode: tele.ModeHTML})
+ return c.Reply(replyText, &tele.SendOptions{ParseMode: tele.ModeHTML}, tele.Silent)
}
func handleGeneralMessage(_ tele.Context) error {
@@ -258,12 +263,16 @@ func handleDigCmd(c tele.Context) error {
req, err := cmds.NewDigRequest(msg.Payload)
if err != nil {
- return c.Reply("Invalid arguments.\nUsage: `/dig [type]`", &tele.SendOptions{ParseMode: tele.ModeMarkdown})
+ return c.Reply(
+ "Invalid arguments.\nUsage: `/dig [type]`",
+ &tele.SendOptions{ParseMode: tele.ModeMarkdown},
+ tele.Silent,
+ )
}
resp, err := cmds.Dig(req)
if err != nil {
- _ = c.Reply(stickerFromID(stickerPanic))
+ _ = c.Reply(stickerFromID(stickerPanic), tele.Silent)
return err
}
@@ -286,5 +295,161 @@ func handleDigCmd(c tele.Context) error {
html.EscapeString(replyBuf.String()),
"",
}
- return c.Reply(strings.Join(replyText, ""), &tele.SendOptions{ParseMode: tele.ModeHTML})
+ return c.Reply(strings.Join(replyText, ""), &tele.SendOptions{ParseMode: tele.ModeHTML}, tele.Silent)
+}
+
+func handleExchangeRateCmd(c tele.Context) error {
+ msg := c.Message()
+ if msg == nil {
+ return nil
+ }
+
+ if msg.Payload == "" {
+ return c.Reply("Usage: `/xr [ ...] [to] `",
+ &tele.SendOptions{ParseMode: tele.ModeMarkdown},
+ tele.Silent,
+ )
+ }
+
+ from, to, err := parseXrRequest(msg.Payload)
+ if err != nil {
+ return c.Reply(err.Error(), tele.Silent)
+ }
+ codes := append([]string{to.Code}, lo.Map(from, func(i xrCurrency, _ int) string { return i.Code })...)
+ currencies, err := exchangeRates.Get(codes...)
+ if err != nil {
+ return c.Reply(err.Error(), tele.Silent)
+ }
+ toCur := currencies[0]
+
+ // format reply
+ var replyLines []string
+ for i, fromItem := range from {
+ fromCur := currencies[i+1]
+ replyLines = append(replyLines, fmtXrPair(fromCur, toCur, fromItem.Amount))
+ }
+
+ return c.Reply(strings.Join(replyLines, "\n"), &tele.SendOptions{ParseMode: tele.ModeMarkdown}, tele.Silent)
+}
+
+type xrCurrency struct {
+ Code string
+ Amount float64
+}
+
+func parseXrRequest(input string) (from []xrCurrency, to xrCurrency, err error) {
+ args := strings.Fields(input)
+
+ var tmpTo *xrCurrency = nil
+ fillFrom := true
+
+ c := xrCurrency{Amount: -1}
+ for _, arg := range args {
+ arg = strings.ToUpper(arg)
+
+ switch {
+ case arg == "TO":
+ fillFrom = false
+ continue
+
+ case fillFrom:
+ num, sym, tErr := parseXrToken(arg)
+ if tErr != nil {
+ err = tErr
+ return
+ }
+ if num != -1 {
+ if c.Amount != -1 {
+ err = errors.New("invalid input")
+ return
+ }
+ c.Amount = num
+ }
+ if c.Amount == -1 {
+ c.Amount = 1
+ }
+
+ if sym != "" {
+ c.Code = sym
+ from = append(from, c)
+ c = xrCurrency{Amount: -1}
+ }
+
+ case !fillFrom:
+ if tmpTo != nil {
+ err = errors.New("invalid input")
+ return
+ }
+ tmpTo = &xrCurrency{Code: arg}
+
+ default:
+ err = errors.New("invalid input")
+ return
+ }
+ }
+
+ if len(from) < 1 || len(from) > 10 {
+ err = errors.New("invalid input")
+ return
+ }
+
+ if fillFrom {
+ if len(from) < 2 {
+ err = errors.New("invalid input")
+ return
+ }
+ tmpTo = &from[len(from)-1]
+ from = from[:len(from)-1]
+ }
+
+ if tmpTo == nil {
+ err = errors.New("invalid input")
+ return
+ }
+ to = *tmpTo
+
+ return
+}
+
+var xrTokenRe = regexp.MustCompile(`^([0-9.]+)?([A-Z]{3,})?$`)
+
+func parseXrToken(token string) (num float64, sym string, err error) {
+ num = -1
+ matches := xrTokenRe.FindStringSubmatch(token)
+ if len(matches) != 3 {
+ err = errors.New("invalid input")
+ return
+ }
+
+ if matches[1] != "" {
+ num, err = strconv.ParseFloat(matches[1], 64)
+ if err != nil {
+ return
+ }
+ if num <= 0 {
+ err = errors.New("invalid input: amount must be positive")
+ return
+ }
+ }
+
+ sym = matches[2]
+ if num == 0 && sym == "" {
+ err = errors.New("invalid input")
+ }
+ return
+}
+
+func fmtXrPair(from, to *mycurrencynet.Currency, amount float64) string {
+ rate := from.To(to) * amount
+ fromInfo := fmt.Sprintf("%s (%s)", from.Name, from.Code)
+ toInfo := fmt.Sprintf("%s (%s)", to.Name, to.Code)
+
+ return fmt.Sprintf("*%s* %s\n= *%s* %s\n", fmtXrFloat(amount), fromInfo, fmtXrFloat(rate), toInfo)
+}
+
+func fmtXrFloat(num float64) string {
+ if num < 100 {
+ return fmt.Sprintf("%.4g", num)
+ }
+ return humanize.CommafWithDigits(num, 2)
}
diff --git a/go.mod b/go.mod
index d2f6cfa..5077a03 100644
--- a/go.mod
+++ b/go.mod
@@ -3,17 +3,22 @@ module git.gensokyo.cafe/kkyy/tgbot_misaka_5882f7
go 1.19
require (
+ git.gensokyo.cafe/kkyy/mycurrencynet v0.0.0-20221206125603-704d2e03300e
+ github.com/dustin/go-humanize v1.0.0
github.com/go-errors/errors v1.4.2
- github.com/goccy/go-json v0.9.11
- github.com/samber/lo v1.35.0
- go.uber.org/zap v1.23.0
- golang.org/x/net v0.2.0
+ github.com/goccy/go-json v0.10.0
+ github.com/samber/lo v1.36.0
+ go.uber.org/zap v1.24.0
+ golang.org/x/net v0.3.0
gopkg.in/telebot.v3 v3.1.2
)
require (
+ github.com/PuerkitoBio/goquery v1.8.0 // indirect
+ github.com/andybalholm/cascadia v1.3.1 // indirect
+ github.com/go-resty/resty/v2 v2.7.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
- golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
- golang.org/x/text v0.4.0 // indirect
+ golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
+ golang.org/x/text v0.5.0 // indirect
)
diff --git a/go.sum b/go.sum
index 9d2adf4..e02271a 100644
--- a/go.sum
+++ b/go.sum
@@ -54,15 +54,21 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+git.gensokyo.cafe/kkyy/mycurrencynet v0.0.0-20221206125603-704d2e03300e h1:hIWknUNDWU6BziRsOkf7Hn1IhLOuaUF3bduOyVH0r+4=
+git.gensokyo.cafe/kkyy/mycurrencynet v0.0.0-20221206125603-704d2e03300e/go.mod h1:x6pYa04dntzpOwjsXU0HIglz9D4Ce37BJMxLxZDQRrg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
+github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
+github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -98,6 +104,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -131,9 +138,11 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
+github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
+github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
-github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
+github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -337,8 +346,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8=
-github.com/samber/lo v1.35.0 h1:GlT8CV1GE+v97Y7MLF1wXvX6mjoxZ+hi61tj/ZcQwY0=
-github.com/samber/lo v1.35.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
+github.com/samber/lo v1.36.0 h1:4LaOxH1mHnbDGhTVE0i1z8v/lWaQW8AIfOD3HU4mSaw=
+github.com/samber/lo v1.36.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -390,8 +399,8 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
-go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
+go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
+go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -412,8 +421,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
-golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
+golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
+golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -479,6 +488,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@@ -486,8 +497,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -609,8 +620,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/main.go b/main.go
index ca67af9..a3c87c3 100644
--- a/main.go
+++ b/main.go
@@ -4,7 +4,9 @@ import (
"os"
"os/signal"
"syscall"
+ "time"
+ "git.gensokyo.cafe/kkyy/mycurrencynet"
"go.uber.org/zap"
tele "gopkg.in/telebot.v3"
@@ -22,6 +24,25 @@ func initLogger() {
logger = l.Sugar()
}
+var exchangeRates = mycurrencynet.New()
+
+func initExchangeRates() {
+ if err := exchangeRates.Update(); err != nil {
+ logger.Panicw("Failed to update exchange rates", "err", err)
+ }
+ logger.Info("Exchange rates updated")
+
+ go exchangeRates.UpdateEvery(
+ time.Hour,
+ func(err error) {
+ logger.Errorw("Failed to update exchange rates", "err", err)
+ },
+ func() {
+ logger.Info("Exchange rates updated")
+ },
+ )
+}
+
func runBot() {
logger.Info("Bot initializing...")
bot, err := initBot()
@@ -37,6 +58,7 @@ func runBot() {
{Text: "traffic", Description: "Show traffic usage."},
{Text: "dig", Description: "Diggy diggy dig."},
{Text: "year_progress", Description: "Time doesn't wait."},
+ {Text: "xr", Description: "Currency exchange rates"},
}); err != nil {
logger.Fatalw("Failed to announce commands", "err", err)
}
@@ -45,6 +67,8 @@ func runBot() {
botFinCh := utils.WaitFor(bot.Start)
logger.Infow("Bot started", "username", bot.Me.Username)
+ go initExchangeRates()
+
// listen for shutdown signal
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)