Compare commits
26 Commits
b48165fa0a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| b26e11ac88 | |||
| 3d60361fa2 | |||
| f5fe993105 | |||
| b182c18d49 | |||
| 6930389a39 | |||
| d5f237e1f3 | |||
| c3d0451d62 | |||
| 950467bd2e | |||
| ba484557b8 | |||
| 1b15abb7f7 | |||
| f6ee57d25c | |||
| d22bf0a3b5 | |||
| 98e9eb44d3 | |||
| f6749f4e9e | |||
| 9ce4a9172a | |||
| 390ddd8c62 | |||
| 2ee81c19c8 | |||
| cb1bdab0af | |||
| 0d75d4a5ac | |||
| b8b53e8c5e | |||
| 6ec52ebca9 | |||
| b3c9157b3c | |||
| e55f1d3d97 | |||
| 27fab7155c | |||
| 5b5e1f2167 | |||
| a38926062f |
58
.drone.yml
58
.drone.yml
@@ -1,8 +1,30 @@
|
||||
kind: pipeline
|
||||
name: default
|
||||
name: notify-pipeline-start
|
||||
|
||||
steps:
|
||||
- name: docker
|
||||
- name: slack
|
||||
image: plugins/slack
|
||||
settings:
|
||||
webhook:
|
||||
from_secret: SLACK_WEBHOOK
|
||||
link_names: true
|
||||
template: >
|
||||
{{#if build.pull }}
|
||||
*Build started*: {{ repo.owner }}/{{ repo.name }} - <https://git.eeqj.de/{{ repo.owner }}/{{ repo.name }}/pull/{{ build.pull }}|Pull Request #{{ build.pull }}>
|
||||
{{else}}
|
||||
*Build started: {{ repo.owner }}/{{ repo.name }} - Build #{{ build.number }}* (type: `{{ build.event }}`)
|
||||
{{/if}}
|
||||
Commit: <https://git.eeqj.de/{{ repo.owner }}/{{ repo.name }}/commit/{{ build.commit }}|{{ truncate build.commit 8 }}>
|
||||
Branch: <https://git.eeqj.de/{{ repo.owner }}/{{ repo.name }}/commits/{{ build.branch }}|{{ build.branch }}>
|
||||
Author: {{ build.author }}
|
||||
<{{ build.link }}|Visit build page ↗>
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: test-docker-build
|
||||
|
||||
steps:
|
||||
- name: test-docker-build
|
||||
image: plugins/docker
|
||||
network_mode: bridge
|
||||
settings:
|
||||
@@ -11,3 +33,35 @@ steps:
|
||||
tags:
|
||||
- ${DRONE_COMMIT_SHA}
|
||||
- ${DRONE_BRANCH}
|
||||
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: notify-pipeline-end
|
||||
|
||||
steps:
|
||||
- name: slack
|
||||
image: plugins/slack
|
||||
settings:
|
||||
webhook:
|
||||
from_secret: SLACK_WEBHOOK
|
||||
link_names: true
|
||||
template: >
|
||||
{{#if build.pull }}
|
||||
*{{#success build.status}}✔{{ else }}✘{{/success}} {{ uppercasefirst build.status }}*: {{ repo.owner }}/{{ repo.name }} - <https://git.eeqj.de/{{ repo.owner }}/{{ repo.name }}/pull/{{ build.pull }}|Pull Request #{{ build.pull }}>
|
||||
{{else}}
|
||||
*{{#success build.status}}✔{{ else }}✘{{/success}} {{ uppercasefirst build.status }}: {{ repo.owner }}/{{ repo.name }} - Build #{{ build.number }}* (type: `{{ build.event }}`)
|
||||
{{/if}}
|
||||
Commit: <https://git.eeqj.de/{{ repo.owner }}/{{ repo.name }}/commit/{{ build.commit }}|{{ truncate build.commit 8 }}>
|
||||
Branch: <https://git.eeqj.de/{{ repo.owner }}/{{ repo.name }}/commits/{{ build.branch }}|{{ build.branch }}>
|
||||
Author: {{ build.author }}
|
||||
Duration: {{ since build.created }}
|
||||
<{{ build.link }}|Visit build page ↗>
|
||||
|
||||
depends_on:
|
||||
- test-docker-build
|
||||
|
||||
trigger:
|
||||
status:
|
||||
- success
|
||||
- failure
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
sco
|
||||
.DS_Store
|
||||
|
||||
7
Makefile
7
Makefile
@@ -29,6 +29,7 @@ default: fmt
|
||||
|
||||
fmt:
|
||||
go fmt ./...
|
||||
goimports -l -w .
|
||||
|
||||
docker-build:
|
||||
docker build -t $(IMAGENAME) .
|
||||
@@ -41,5 +42,9 @@ build: ./$(FN)
|
||||
go-get:
|
||||
cd cmd/$(FN) && go get -v
|
||||
|
||||
./$(FN): */*.go cmd/*/*.go go-get
|
||||
vet:
|
||||
go vet ./...
|
||||
bash -c 'test -z "$$(gofmt -l .)"'
|
||||
|
||||
./$(FN): */*.go cmd/*/*.go go-get vet
|
||||
cd cmd/$(FN) && go build -o ../../$(FN) $(GOFLAGS) .
|
||||
|
||||
17
README.md
17
README.md
@@ -2,6 +2,23 @@
|
||||
|
||||
Mattermost bot.
|
||||
|
||||
# Environment Variables
|
||||
|
||||
## for bot comms to mattermost server
|
||||
|
||||
* `SCO_API_URL`
|
||||
* `SCO_WEBSOCKET_URL`
|
||||
* `SCO_DEBUG_CHANNEL`
|
||||
* `SCO_ACCOUNT_EMAIL`
|
||||
* `SCO_ACCOUNT_PASSWORD`
|
||||
* `SCO_TEAM_NAME`
|
||||
* `SCO_ACCOUNT_USERNAME`
|
||||
|
||||
## remote stuff
|
||||
|
||||
* `METAR_API_TOKEN` for https://avwx.rest
|
||||
* `AIRNOW_API_KEY` for http://www.airnowapi.org
|
||||
|
||||
# status
|
||||
|
||||
[](https://drone.datavi.be/sneak/sco)
|
||||
|
||||
99
bot/aqi.go
Normal file
99
bot/aqi.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package bot
|
||||
|
||||
//import "github.com/kr/pretty"
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type AQIResponse struct {
|
||||
DateObserved string `json:"DateObserved"`
|
||||
HourObserved int `json:"HourObserved"`
|
||||
LocalTimeZone string `json:"LocalTimeZone"`
|
||||
ReportingArea string `json:"ReportingArea"`
|
||||
StateCode string `json:"StateCode"`
|
||||
Latitude float64 `json:"Latitude"`
|
||||
Longitude float64 `json:"Longitude"`
|
||||
ParameterName string `json:"ParameterName"`
|
||||
AQI int `json:"AQI"`
|
||||
Category struct {
|
||||
Number int `json:"Number"`
|
||||
Name string `json:"Name"`
|
||||
} `json:"Category"`
|
||||
}
|
||||
|
||||
func formatAQIResponse(input *[]AQIResponse, zip string) string {
|
||||
dinput := *input
|
||||
in := dinput[0]
|
||||
when := fmt.Sprintf("%s at %d:00 %s", in.DateObserved, in.HourObserved, in.LocalTimeZone)
|
||||
bytes, err := json.Marshal(input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
formatted := string(bytes)
|
||||
out := fmt.Sprintf("# AQI for %s as of %s:\n %s", zip, when, formatted)
|
||||
return out
|
||||
}
|
||||
|
||||
func (b *Bot) HandleAirQualityRequest(channelid string, postid string, message string) {
|
||||
|
||||
// we are using a very bare image with no CA cert bundle
|
||||
// actually if you docker bind mount the ca cert bundle in the right
|
||||
// place, golang will find it and use it.
|
||||
//http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
|
||||
log.Info().Msgf("aqi request received: `%s`", message)
|
||||
|
||||
r := regexp.MustCompile(`aqi\s+([0-9]{5})`)
|
||||
matches := r.FindStringSubmatch(message)
|
||||
if len(matches) < 2 {
|
||||
b.SendMsgToChannel("error, sorry", postid, channelid)
|
||||
}
|
||||
|
||||
zip := matches[1]
|
||||
|
||||
apikey := os.Getenv("AIRNOW_API_KEY")
|
||||
url := fmt.Sprintf("http://www.airnowapi.org/aq/observation/zipCode/current/?format=application/json&zipCode=%s&distance=25&API_KEY=%s", zip, apikey)
|
||||
|
||||
log.Info().Msgf("calculated url: `%s`", url)
|
||||
|
||||
client := http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
b.SendMsgToChannel(fmt.Sprintf("aqi fetch error: %s", err), postid, channelid)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
b.SendMsgToChannel(fmt.Sprintf("aqi fetch error: http status %d", resp.StatusCode), postid, channelid)
|
||||
return
|
||||
}
|
||||
|
||||
data, _ := ioutil.ReadAll(resp.Body)
|
||||
|
||||
var parsedAQIResponse []AQIResponse
|
||||
|
||||
log.Info().Msgf("aqi %s: %s", zip, data)
|
||||
|
||||
err = nil
|
||||
err = json.Unmarshal([]byte(data), &parsedAQIResponse)
|
||||
|
||||
if err != nil {
|
||||
b.SendMsgToChannel("error deserializing AQI data", postid, channelid)
|
||||
return
|
||||
}
|
||||
|
||||
msg := formatAQIResponse(&parsedAQIResponse, zip)
|
||||
b.SendMsgToChannel(msg, postid, channelid)
|
||||
}
|
||||
95
bot/bot.go
95
bot/bot.go
@@ -3,13 +3,15 @@ package bot
|
||||
//import "github.com/kr/pretty"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mattermost/mattermost-server/v5/model"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v5/model"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type Bot struct {
|
||||
@@ -42,13 +44,23 @@ func New(options ...func(s *Bot)) *Bot {
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bot) Main() int {
|
||||
func (b *Bot) identify() {
|
||||
log.Info().
|
||||
Str("version", b.Version).
|
||||
Str("buildarch", b.Buildarch).
|
||||
Str("commit", b.Commit).
|
||||
Msg("starting")
|
||||
}
|
||||
|
||||
func (b *Bot) Main() {
|
||||
println(b.BotName)
|
||||
|
||||
b.StartupUnixTime = time.Now().Unix()
|
||||
|
||||
b.SetupGracefulShutdown()
|
||||
|
||||
b.setupLogging()
|
||||
|
||||
b.client = model.NewAPIv4Client(b.APIURL)
|
||||
|
||||
// Lets test to see if the mattermost server is up and running
|
||||
@@ -71,7 +83,7 @@ func (b *Bot) Main() int {
|
||||
|
||||
// Lets create a bot channel for logging debug messages into
|
||||
b.CreateBotDebuggingChannelIfNeeded()
|
||||
msg := fmt.Sprintf("_**%s** has started up_\n\nrunning on version %s", b.BotName, b.Version)
|
||||
msg := fmt.Sprintf("_**%s** (version `%s`) is now starting up_", b.BotName, b.Version)
|
||||
b.SendMsgToDebuggingChannel(msg, "")
|
||||
|
||||
// Lets start listening to some channels via the websocket!
|
||||
@@ -95,7 +107,6 @@ func (b *Bot) Main() int {
|
||||
|
||||
// You can block forever with
|
||||
select {}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (b *Bot) MakeSureServerIsRunning() {
|
||||
@@ -210,6 +221,8 @@ func (b *Bot) HandleWebSocketResponse(event *model.WebSocketEvent) {
|
||||
return
|
||||
}
|
||||
|
||||
// FIXME check for parts and joins and whatnot and ignore those
|
||||
|
||||
// check to see if we have been addressed
|
||||
if matched, _ := regexp.MatchString(`^\s*`+b.BotName+`\s*`, post.Message); matched {
|
||||
println("i have been addressed in channel " + post.ChannelId)
|
||||
@@ -218,6 +231,13 @@ func (b *Bot) HandleWebSocketResponse(event *model.WebSocketEvent) {
|
||||
return
|
||||
}
|
||||
|
||||
if matched, _ := regexp.MatchString(`^\s*bot([\,]?)\s*`, post.Message); matched {
|
||||
println("i have been addressed in channel " + post.ChannelId)
|
||||
//b.SendMsgToDebuggingChannel("i have been addressed in channel "+post.ChannelId, "")
|
||||
b.HandleMsgFromChannel(event)
|
||||
return
|
||||
}
|
||||
|
||||
if event.Broadcast.ChannelId == b.debuggingChannel.Id {
|
||||
b.HandleMsgFromDebuggingChannel(event)
|
||||
return
|
||||
@@ -236,7 +256,15 @@ func (b *Bot) HandleMsgFromChannel(event *model.WebSocketEvent) {
|
||||
return
|
||||
}
|
||||
|
||||
//pretty.Print(post)
|
||||
if matched, _ := regexp.MatchString(`metar\s+[^\s]+`, post.Message); matched {
|
||||
b.HandleWeatherRequest(post.ChannelId, post.Id, post.Message)
|
||||
return
|
||||
}
|
||||
|
||||
if matched, _ := regexp.MatchString(`aqi\s+[^\s]+`, post.Message); matched {
|
||||
b.HandleAirQualityRequest(post.ChannelId, post.Id, post.Message)
|
||||
return
|
||||
}
|
||||
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)alive(?:$|\W)`, post.Message); matched {
|
||||
b.SendMsgToChannel("yes I'm running", post.Id, post.ChannelId)
|
||||
@@ -267,37 +295,42 @@ func (b *Bot) HandleMsgFromDebuggingChannel(event *model.WebSocketEvent) {
|
||||
println("responding to debugging channel msg")
|
||||
|
||||
post := model.PostFromJson(strings.NewReader(event.Data["post"].(string)))
|
||||
if post != nil {
|
||||
if post == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// ignore my events
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)shutdown(?:$|\W)`, post.Message); matched {
|
||||
b.Shutdown()
|
||||
return
|
||||
}
|
||||
if post.Message == "" {
|
||||
// null message, we can probably ignore it.
|
||||
return
|
||||
}
|
||||
|
||||
// if you see any word matching 'alive' then respond
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)alive(?:$|\W)`, post.Message); matched {
|
||||
b.SendMsgToDebuggingChannel("Yes I'm running", post.Id)
|
||||
return
|
||||
}
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)shutdown(?:$|\W)`, post.Message); matched {
|
||||
b.Shutdown()
|
||||
return
|
||||
}
|
||||
|
||||
// if you see any word matching 'up' then respond
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)up(?:$|\W)`, post.Message); matched {
|
||||
b.SendMsgToDebuggingChannel("Yes I'm running", post.Id)
|
||||
return
|
||||
}
|
||||
// if you see any word matching 'alive' then respond
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)alive(?:$|\W)`, post.Message); matched {
|
||||
b.SendMsgToDebuggingChannel("Yes I'm running", post.Id)
|
||||
return
|
||||
}
|
||||
|
||||
// if you see any word matching 'running' then respond
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)running(?:$|\W)`, post.Message); matched {
|
||||
b.SendMsgToDebuggingChannel("Yes I'm running", post.Id)
|
||||
return
|
||||
}
|
||||
// if you see any word matching 'up' then respond
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)up(?:$|\W)`, post.Message); matched {
|
||||
b.SendMsgToDebuggingChannel("Yes I'm running", post.Id)
|
||||
return
|
||||
}
|
||||
|
||||
// if you see any word matching 'hello' then respond
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)hello(?:$|\W)`, post.Message); matched {
|
||||
b.SendMsgToDebuggingChannel("Yes I'm running", post.Id)
|
||||
return
|
||||
}
|
||||
// if you see any word matching 'running' then respond
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)running(?:$|\W)`, post.Message); matched {
|
||||
b.SendMsgToDebuggingChannel("Yes I'm running", post.Id)
|
||||
return
|
||||
}
|
||||
|
||||
// if you see any word matching 'hello' then respond
|
||||
if matched, _ := regexp.MatchString(`(?:^|\W)hello(?:$|\W)`, post.Message); matched {
|
||||
b.SendMsgToDebuggingChannel("Yes I'm running", post.Id)
|
||||
return
|
||||
}
|
||||
|
||||
b.SendMsgToChannel("I did not understand your command, sorry", post.Id, post.ChannelId)
|
||||
|
||||
39
bot/logger.go
Normal file
39
bot/logger.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package bot
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (b *Bot) setupLogging() {
|
||||
|
||||
log.Logger = log.With().Caller().Logger()
|
||||
|
||||
tty := isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd())
|
||||
|
||||
if tty {
|
||||
out := zerolog.NewConsoleWriter(
|
||||
func(w *zerolog.ConsoleWriter) {
|
||||
// Customize time format
|
||||
w.TimeFormat = time.RFC3339
|
||||
},
|
||||
)
|
||||
log.Logger = log.Output(out)
|
||||
}
|
||||
|
||||
// always log in UTC
|
||||
zerolog.TimestampFunc = func() time.Time {
|
||||
return time.Now().UTC()
|
||||
}
|
||||
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
//zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
//if viper.GetBool("debug") {
|
||||
//}
|
||||
|
||||
b.identify()
|
||||
}
|
||||
144
bot/metar.go
Normal file
144
bot/metar.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package bot
|
||||
|
||||
//import "github.com/kr/pretty"
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type MetarResponse struct {
|
||||
Meta struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
StationsUpdated string `json:"stations_updated"`
|
||||
} `json:"meta"`
|
||||
Altimeter struct {
|
||||
Repr string `json:"repr"`
|
||||
Value float64 `json:"value"`
|
||||
Spoken string `json:"spoken"`
|
||||
} `json:"altimeter"`
|
||||
Clouds []interface{} `json:"clouds"`
|
||||
FlightRules string `json:"flight_rules"`
|
||||
Other []interface{} `json:"other"`
|
||||
Sanitized string `json:"sanitized"`
|
||||
Visibility struct {
|
||||
Repr string `json:"repr"`
|
||||
Value int `json:"value"`
|
||||
Spoken string `json:"spoken"`
|
||||
} `json:"visibility"`
|
||||
WindDirection struct {
|
||||
Repr string `json:"repr"`
|
||||
Value int `json:"value"`
|
||||
Spoken string `json:"spoken"`
|
||||
} `json:"wind_direction"`
|
||||
WindGust struct {
|
||||
Repr string `json:"repr"`
|
||||
Value int `json:"value"`
|
||||
Spoken string `json:"spoken"`
|
||||
} `json:"wind_gust"`
|
||||
WindSpeed struct {
|
||||
Repr string `json:"repr"`
|
||||
Value int `json:"value"`
|
||||
Spoken string `json:"spoken"`
|
||||
} `json:"wind_speed"`
|
||||
WxCodes []interface{} `json:"wx_codes"`
|
||||
Raw string `json:"raw"`
|
||||
Station string `json:"station"`
|
||||
Time struct {
|
||||
Repr string `json:"repr"`
|
||||
Dt time.Time `json:"dt"`
|
||||
} `json:"time"`
|
||||
Remarks string `json:"remarks"`
|
||||
Dewpoint struct {
|
||||
Repr string `json:"repr"`
|
||||
Value int `json:"value"`
|
||||
Spoken string `json:"spoken"`
|
||||
} `json:"dewpoint"`
|
||||
RemarksInfo struct {
|
||||
DewpointDecimal struct {
|
||||
Repr string `json:"repr"`
|
||||
Value float64 `json:"value"`
|
||||
Spoken string `json:"spoken"`
|
||||
} `json:"dewpoint_decimal"`
|
||||
TemperatureDecimal struct {
|
||||
Repr string `json:"repr"`
|
||||
Value float64 `json:"value"`
|
||||
Spoken string `json:"spoken"`
|
||||
} `json:"temperature_decimal"`
|
||||
} `json:"remarks_info"`
|
||||
RunwayVisibility []interface{} `json:"runway_visibility"`
|
||||
Temperature struct {
|
||||
Repr string `json:"repr"`
|
||||
Value int `json:"value"`
|
||||
Spoken string `json:"spoken"`
|
||||
} `json:"temperature"`
|
||||
WindVariableDirection []interface{} `json:"wind_variable_direction"`
|
||||
Units struct {
|
||||
Altimeter string `json:"altimeter"`
|
||||
Altitude string `json:"altitude"`
|
||||
Temperature string `json:"temperature"`
|
||||
Visibility string `json:"visibility"`
|
||||
WindSpeed string `json:"wind_speed"`
|
||||
} `json:"units"`
|
||||
}
|
||||
|
||||
func (b *Bot) HandleWeatherRequest(channelid string, postid string, message string) {
|
||||
|
||||
// we are using a very bare image with no CA cert bundle
|
||||
// actually if you docker bind mount the ca cert bundle in the right
|
||||
// place, golang will find it and use it.
|
||||
//http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
|
||||
log.Info().Msgf("weather request received: `%s`", message)
|
||||
|
||||
r := regexp.MustCompile(`metar\s+([A-Za-z]{4})`)
|
||||
matches := r.FindStringSubmatch(message)
|
||||
if len(matches) < 2 {
|
||||
b.SendMsgToChannel("error, sorry", postid, channelid)
|
||||
}
|
||||
|
||||
loc := matches[1]
|
||||
|
||||
token := os.Getenv("METAR_API_TOKEN")
|
||||
url := fmt.Sprintf("https://avwx.rest/api/metar/%s?options=&airport=true&reporting=true&format=json&onfail=cache", loc)
|
||||
|
||||
log.Info().Msgf("calculated url: `%s`", url)
|
||||
|
||||
client := http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
req.Header.Add("Authorization", `Token `+token)
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
b.SendMsgToChannel(fmt.Sprintf("weather fetch error: %s", err), postid, channelid)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
b.SendMsgToChannel(fmt.Sprintf("weather fetch error: http status %d", resp.StatusCode), postid, channelid)
|
||||
return
|
||||
}
|
||||
|
||||
data, _ := ioutil.ReadAll(resp.Body)
|
||||
|
||||
var parsedMetarResponse MetarResponse
|
||||
|
||||
log.Info().Msgf("weather %s: %s", loc, data)
|
||||
|
||||
err = nil
|
||||
err = json.Unmarshal([]byte(data), &parsedMetarResponse)
|
||||
|
||||
if err != nil {
|
||||
b.SendMsgToChannel("error deserializing metar data", postid, channelid)
|
||||
return
|
||||
}
|
||||
b.SendMsgToChannel(fmt.Sprintf("weather for `%s`: \n```\n%+v\n```\n", loc, parsedMetarResponse), postid, channelid)
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
package main
|
||||
|
||||
import "os"
|
||||
import "git.eeqj.de/sneak/sco/bot"
|
||||
import (
|
||||
"os"
|
||||
|
||||
"git.eeqj.de/sneak/sco/bot"
|
||||
)
|
||||
|
||||
var Version string
|
||||
var Commit string
|
||||
|
||||
var Buildarch string
|
||||
|
||||
func main() {
|
||||
@@ -23,5 +27,5 @@ func main() {
|
||||
b.AccountFirstname = "LSV"
|
||||
b.AccountLastname = "Serious Callers Only"
|
||||
})
|
||||
os.Exit(mybot.Main())
|
||||
mybot.Main()
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -5,4 +5,6 @@ go 1.15
|
||||
require (
|
||||
github.com/kr/pretty v0.1.0
|
||||
github.com/mattermost/mattermost-server/v5 v5.26.2
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/rs/zerolog v1.19.0
|
||||
)
|
||||
|
||||
6
go.sum
6
go.sum
@@ -332,6 +332,7 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
@@ -443,6 +444,9 @@ github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qq
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.19.0 h1:hYz4ZVdUgjXTBUmrkrw55j1nHx68LfOKIQk5IYtyScg=
|
||||
github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
|
||||
github.com/rudderlabs/analytics-go v3.2.1+incompatible/go.mod h1:LF8/ty9kUX4PTY3l5c97K3nZZaX5Hwsvt+NBaRL/f30=
|
||||
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
@@ -674,6 +678,7 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -698,6 +703,7 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
||||
Reference in New Issue
Block a user