From 6a4b478eeb3328f5ef3b052ff10278073aedd449 Mon Sep 17 00:00:00 2001 From: Mark Jung Date: Mon, 29 Apr 2019 21:49:45 -0500 Subject: [PATCH 01/30] initial verson done --- bees/youtubebee/youtube.go | 140 ++++++++++++++++++++++++++++++ bees/youtubebee/youtubefactory.go | 113 ++++++++++++++++++++++++ hives.go | 2 + 3 files changed, 255 insertions(+) create mode 100644 bees/youtubebee/youtube.go create mode 100644 bees/youtubebee/youtubefactory.go diff --git a/bees/youtubebee/youtube.go b/bees/youtubebee/youtube.go new file mode 100644 index 00000000..baffd027 --- /dev/null +++ b/bees/youtubebee/youtube.go @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2014 Daniel 'grindhold' Brendle + * 2014-2017 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * Daniel 'grindhold' Brendle + * Christian Muehlhaeuser + */ + +// Package youtubebee is a Bee for tunneling Youtube push notifications. +package youtube + +import ( + "encoding/xml" + "net" + "net/http" + "net/url" + + "github.com/muesli/beehive/bees" +) + +// YoutubeBee is a Bee for handling Youtube push notifications. +type YoutubeBee struct { + bees.Bee + + url string + + addr string + + eventChan chan bees.Event +} + +// Run executes the Bee's event loop. +func (mod *YoutubeBee) Run(eventChan chan bees.Event) { + mod.eventChan = eventChan + subscriptionLink := "https://pubsubhubbub.appspot.com/subscribe" + channelID := mod.url.split("/") + channelID = challenge[len(channelID)-1] + topic := "https://www.youtube.com/xml/feeds/videos.xml?channel_id=" + channelID + + srv := &http.Server{Addr: mod.addr, Handler: mod} + l, err := net.Listen("tcp", mod.addr) + if err != nil { + mod.LogErrorf("Can't listen on %s", mod.addr) + return + } + defer l.Close() + + go func() { + err := srv.Serve(l) + if err != nil { + mod.LogErrorf("Server error: %v", err) + } + // Go 1.8+: srv.Close() + // send POST to Google's pubsubhubbub to subscribe + resp, err := http.PostForm(subscriptionLink, + url.Values{ + "hub.mode": {"subscribe"}, + "hub.topic": {topic}, + "hub.callback": {mod.addr}, + }) + }() + + select { + case <-mod.SigChan: + return + } +} + +func (mod *YoutubeBee) ServeHTTP(w http.ResponseWriter, req *http.Request) { + if req.Method == "POST" { + ev := bees.Event{ + Bee: mod.Name(), + } + ev.Name = "push" + type Feed struct { + XMLName xml.Name `xml:"feed"` + Text string `xml:",chardata"` + Yt string `xml:"yt,attr"` + Xmlns string `xml:"xmlns,attr"` + Link []struct { + Text string `xml:",chardata"` + Rel string `xml:"rel,attr"` + Href string `xml:"href,attr"` + } `xml:"link"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Entry struct { + Text string `xml:",chardata"` + ID string `xml:"id"` + VideoId string `xml:"videoId"` + ChannelId string `xml:"channelId"` + Title string `xml:"title"` + Link struct { + Text string `xml:",chardata"` + Rel string `xml:"rel,attr"` + Href string `xml:"href,attr"` + } `xml:"link"` + Author struct { + Text string `xml:",chardata"` + Name string `xml:"name"` + URI string `xml:"uri"` + } `xml:"author"` + Published string `xml:"published"` + Updated string `xml:"updated"` + } `xml:"entry"` + } + var feed Feed + xml.Unmarshal([]byte(realdata), &feed) + for _, link := range feed.Link { + if link.Rel == "self" { + ev.Options.SetValue("channelUrl", "string", link.Href) + } + } + ev.Options.SetValue("vidUrl", "string", feed.Entry.Link.Href) + + mod.eventChan <- ev + } +} + +// ReloadOptions parses the config options and initializes the Bee. +func (mod *YoutubeBee) ReloadOptions(options bees.BeeOptions) { + mod.SetOptions(options) + + options.Bind("address", &mod.addr) + options.Bind("channel", &mod.url) +} diff --git a/bees/youtubebee/youtubefactory.go b/bees/youtubebee/youtubefactory.go new file mode 100644 index 00000000..f8cdc7ec --- /dev/null +++ b/bees/youtubebee/youtubefactory.go @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014-2017 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * Christian Muehlhaeuser + */ + +package youtubebee + +import ( + "github.com/muesli/beehive/bees" +) + +// WebBeeFactory is a factory for WebBees. +type YoutubeBeeFactory struct { + bees.BeeFactory +} + +// New returns a new Bee instance configured with the supplied options. +func (factory *YoutubeBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { + bee := YoutubeBee{ + Bee: bees.NewBee(name, factory.ID(), description, options), + } + bee.ReloadOptions(options) + + return &bee +} + +// ID returns the ID of this Bee. +func (factory *YoutubeBeeFactory) ID() string { + return "youtubebee" +} + +// Name returns the name of this Bee. +func (factory *YoutubeBeeFactory) Name() string { + return "Youtube Bee" +} + +// Description returns the description of this Bee. +func (factory *YoutubeBeeFactory) Description() string { + return "HTTP Server that listens to a Youtube channel" +} + +// Image returns the filename of an image for this Bee. +func (factory *YoutubeBeeFactory) Image() string { + return factory.ID() + ".png" +} + +// LogoColor returns the preferred logo background color (used by the admin interface). +func (factory *YoutubeBeeFactory) LogoColor() string { + return "#ff0000" +} + +// Options returns the options available to configure this Bee. +func (factory *YoutubeBeeFactory) Options() []bees.BeeOptionDescriptor { + opts := []bees.BeeOptionDescriptor{ + { + Name: "address", + Description: "Which addr to listen on, eg: 0.0.0.0:12345", + Type: "address", + Mandatory: true, + }, + { + Name: "channel", + Description: "What is the link of the channel you want to receive push notifications for?", + Type: "url", + Mandatory: true, + }, + } + return opts +} + +// Events describes the available events provided by this Bee. +func (factory *YoutubeBeeFactory) Events() []bees.EventDescriptor { + events := []bees.EventDescriptor{ + { + Namespace: factory.Name(), + Name: "push", + Description: "A push notification was sent by the Youtube channel", + Options: []bees.PlaceholderDescriptor{ + { + Name: "channelUrl", + Description: "The url of the channel push notification was sent from", + Type: "url", + }, + { + Name: "vidUrl", + Description: "The url of the video relevant to the push notification", + Type: "url", + }, + }, + }, + } + return events +} + +func init() { + f := YoutubeBeeFactory{} + bees.RegisterFactory(&f) +} diff --git a/hives.go b/hives.go index 82032d3c..68268af4 100644 --- a/hives.go +++ b/hives.go @@ -21,6 +21,8 @@ package main import ( + _ "github.com/MarkJung/beehive/bees/youtubebee" + _ "github.com/muesli/beehive/bees/alertoverbee" _ "github.com/muesli/beehive/bees/anelpowerctrlbee" _ "github.com/muesli/beehive/bees/cleverbotbee" From bd378895f6d36b5ce49249ed96da1489d33404cc Mon Sep 17 00:00:00 2001 From: Mark Jung Date: Mon, 29 Apr 2019 22:12:50 -0500 Subject: [PATCH 02/30] error messages --- hives.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hives.go b/hives.go index 68268af4..12ad1af1 100644 --- a/hives.go +++ b/hives.go @@ -21,8 +21,6 @@ package main import ( - _ "github.com/MarkJung/beehive/bees/youtubebee" - _ "github.com/muesli/beehive/bees/alertoverbee" _ "github.com/muesli/beehive/bees/anelpowerctrlbee" _ "github.com/muesli/beehive/bees/cleverbotbee" @@ -63,4 +61,5 @@ import ( _ "github.com/muesli/beehive/bees/twiliobee" _ "github.com/muesli/beehive/bees/twitterbee" _ "github.com/muesli/beehive/bees/webbee" + _ "github.com/muesli/beehive/bees/youtubebee" ) From 0529378e8bcdd68debb13172ec8e7e8065b48a86 Mon Sep 17 00:00:00 2001 From: Mark Jung Date: Tue, 14 May 2019 18:59:39 -0500 Subject: [PATCH 03/30] done with youtube bee; --- bees/youtubebee/youtube.go | 54 ++++++++++++++++++++++--------- bees/youtubebee/youtubefactory.go | 2 +- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/bees/youtubebee/youtube.go b/bees/youtubebee/youtube.go index baffd027..cac96b54 100644 --- a/bees/youtubebee/youtube.go +++ b/bees/youtubebee/youtube.go @@ -21,13 +21,18 @@ */ // Package youtubebee is a Bee for tunneling Youtube push notifications. -package youtube +package youtubebee import ( "encoding/xml" + "fmt" + "io/ioutil" + "log" "net" "net/http" "net/url" + "strconv" + "strings" "github.com/muesli/beehive/bees" ) @@ -47,12 +52,13 @@ type YoutubeBee struct { func (mod *YoutubeBee) Run(eventChan chan bees.Event) { mod.eventChan = eventChan subscriptionLink := "https://pubsubhubbub.appspot.com/subscribe" - channelID := mod.url.split("/") - channelID = challenge[len(channelID)-1] + channelURLTokens := strings.Split(mod.url, "/") + channelID := channelURLTokens[len(channelURLTokens)-1] topic := "https://www.youtube.com/xml/feeds/videos.xml?channel_id=" + channelID + hardcodedAddress := "0.0.0.0:5050" // should be mod.addr - srv := &http.Server{Addr: mod.addr, Handler: mod} - l, err := net.Listen("tcp", mod.addr) + srv := &http.Server{Addr: hardcodedAddress, Handler: mod} + l, err := net.Listen("tcp", hardcodedAddress) if err != nil { mod.LogErrorf("Can't listen on %s", mod.addr) return @@ -66,12 +72,22 @@ func (mod *YoutubeBee) Run(eventChan chan bees.Event) { } // Go 1.8+: srv.Close() // send POST to Google's pubsubhubbub to subscribe - resp, err := http.PostForm(subscriptionLink, - url.Values{ - "hub.mode": {"subscribe"}, - "hub.topic": {topic}, - "hub.callback": {mod.addr}, - }) + // need to be in form-data format + data := url.Values{} + data.Set("hub.mode", "subscribe") + data.Set("hub.topic", topic) + data.Set("hub.callback", mod.addr) + client := &http.Client{} + r, _ := http.NewRequest("POST", subscriptionLink, strings.NewReader(data.Encode())) // URL-encoded payload + r.Header.Add("Content-Type", "application/x-www-form-urlencoded") + r.Header.Add("Content-Length", strconv.Itoa(len(data.Encode()))) + + resp, _ := client.Do(r) + for resp.Status != "202 Accepted" { + // redo until success + resp, _ = client.Do(r) + } + }() select { @@ -119,15 +135,21 @@ func (mod *YoutubeBee) ServeHTTP(w http.ResponseWriter, req *http.Request) { } `xml:"entry"` } var feed Feed - xml.Unmarshal([]byte(realdata), &feed) - for _, link := range feed.Link { - if link.Rel == "self" { - ev.Options.SetValue("channelUrl", "string", link.Href) - } + body, err := ioutil.ReadAll(req.Body) + if err != nil { + log.Printf("Error reading body: %v", err) + http.Error(w, "can't read body", http.StatusBadRequest) } + xml.Unmarshal([]byte(body), &feed) + ev.Options.SetValue("channelUrl", "string", feed.Entry.Author.URI) ev.Options.SetValue("vidUrl", "string", feed.Entry.Link.Href) mod.eventChan <- ev + } else if req.Method == "GET" { + challenge := req.URL.Query().Get("hub.challenge") + if challenge != "" { + fmt.Fprintf(w, challenge) + } } } diff --git a/bees/youtubebee/youtubefactory.go b/bees/youtubebee/youtubefactory.go index f8cdc7ec..e0d81892 100644 --- a/bees/youtubebee/youtubefactory.go +++ b/bees/youtubebee/youtubefactory.go @@ -46,7 +46,7 @@ func (factory *YoutubeBeeFactory) ID() string { // Name returns the name of this Bee. func (factory *YoutubeBeeFactory) Name() string { - return "Youtube Bee" + return "Youtube" } // Description returns the description of this Bee. From 690444611381fd6c021b9bf77b9e0a6974d48576 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 29 Apr 2019 11:10:48 +0200 Subject: [PATCH 04/30] Added logs API end-point, which lets you retrieve Beehive's logs --- api/api.go | 2 + api/resources/logs/logs.go | 54 +++++++++++++++++++ api/resources/logs/logs_get.go | 77 ++++++++++++++++++++++++++ api/resources/logs/logs_response.go | 84 +++++++++++++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 api/resources/logs/logs.go create mode 100644 api/resources/logs/logs_get.go create mode 100644 api/resources/logs/logs_response.go diff --git a/api/api.go b/api/api.go index 0c3ce0bf..e9edfdac 100644 --- a/api/api.go +++ b/api/api.go @@ -42,6 +42,7 @@ import ( "github.com/muesli/beehive/api/resources/bees" "github.com/muesli/beehive/api/resources/chains" "github.com/muesli/beehive/api/resources/hives" + "github.com/muesli/beehive/api/resources/logs" "github.com/muesli/beehive/app" ) @@ -191,6 +192,7 @@ func Run() { &bees.BeeResource{}, &chains.ChainResource{}, &actions.ActionResource{}, + &logs.LogResource{}, ) server := &http.Server{Addr: bind, Handler: wsContainer} diff --git a/api/resources/logs/logs.go b/api/resources/logs/logs.go new file mode 100644 index 00000000..bba70a33 --- /dev/null +++ b/api/resources/logs/logs.go @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017-2019 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * Christian Muehlhaeuser + */ + +package logs + +import ( + "github.com/emicklei/go-restful" + "github.com/muesli/smolder" +) + +// LogResource is the resource responsible for /logs +type LogResource struct { + smolder.Resource +} + +var ( + // _ smolder.GetIDSupported = &LogResource{} + _ smolder.GetSupported = &LogResource{} +) + +// Register this resource with the container to setup all the routes +func (r *LogResource) Register(container *restful.Container, config smolder.APIConfig, context smolder.APIContextFactory) { + r.Name = "LogResource" + r.TypeName = "log" + r.Endpoint = "logs" + r.Doc = "Manage logs" + + r.Config = config + r.Context = context + + r.Init(container, r) +} + +// Returns returns the model that will be returned +func (r *LogResource) Returns() interface{} { + return LogResponse{} +} diff --git a/api/resources/logs/logs_get.go b/api/resources/logs/logs_get.go new file mode 100644 index 00000000..1de9b81f --- /dev/null +++ b/api/resources/logs/logs_get.go @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2017-2019 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * Christian Muehlhaeuser + */ + +package logs + +import ( + "github.com/muesli/beehive/bees" + + "github.com/emicklei/go-restful" + "github.com/muesli/smolder" +) + +// GetAuthRequired returns true because all requests need authentication +func (r *LogResource) GetAuthRequired() bool { + return false +} + +// GetByIDsAuthRequired returns true because all requests need authentication +func (r *LogResource) GetByIDsAuthRequired() bool { + return false +} + +// GetDoc returns the description of this API endpoint +func (r *LogResource) GetDoc() string { + return "retrieve logs" +} + +// GetParams returns the parameters supported by this API endpoint +func (r *LogResource) GetParams() []*restful.Parameter { + params := []*restful.Parameter{} + params = append(params, restful.QueryParameter("bee", "id of a bee").DataType("string")) + + return params +} + +// GetByIDs sends out all items matching a set of IDs +/* +func (r *LogResource) GetByIDs(ctx smolder.APIContext, request *restful.Request, response *restful.Response, ids []string) { + resp := LogResponse{} + resp.Init(ctx) + + resp.Send(response) +} +*/ + +// Get sends out items matching the query parameters +func (r *LogResource) Get(ctx smolder.APIContext, request *restful.Request, response *restful.Response, params map[string][]string) { + // ctxapi := ctx.(*context.APIContext) + bee := request.QueryParameter("bee") + + resp := LogResponse{} + resp.Init(ctx) + + logs := bees.GetLogs(bee) + for _, log := range logs { + resp.AddLog(&log) + } + + resp.Send(response) +} diff --git a/api/resources/logs/logs_response.go b/api/resources/logs/logs_response.go new file mode 100644 index 00000000..2dc98c7c --- /dev/null +++ b/api/resources/logs/logs_response.go @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015-2019 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * Christian Muehlhaeuser + */ + +package logs + +import ( + "time" + + "github.com/muesli/beehive/bees" + + "github.com/muesli/smolder" +) + +// LogResponse is the common response to 'log' requests +type LogResponse struct { + smolder.Response + + Logs []logInfoResponse `json:"logs,omitempty"` + logs []*bees.LogMessage +} + +type logInfoResponse struct { + ID string `json:"id"` + Bee string `json:"bee"` + Level int64 `json:"level"` + Message string `json:"message"` + Timestamp time.Time `json:"timestamp"` +} + +// Init a new response +func (r *LogResponse) Init(context smolder.APIContext) { + r.Parent = r + r.Context = context + + r.Logs = []logInfoResponse{} +} + +// AddLog adds a log to the response +func (r *LogResponse) AddLog(log *bees.LogMessage) { + r.logs = append(r.logs, log) + r.Logs = append(r.Logs, prepareLogResponse(r.Context, log)) +} + +// EmptyResponse returns an empty API response for this endpoint if there's no data to respond with +func (r *LogResponse) EmptyResponse() interface{} { + if len(r.logs) == 0 { + var out struct { + Logs interface{} `json:"logs"` + } + out.Logs = []logInfoResponse{} + return out + } + return nil +} + +func prepareLogResponse(context smolder.APIContext, log *bees.LogMessage) logInfoResponse { + // ctx := context.(*context.APIContext) + resp := logInfoResponse{ + ID: (*log).ID, + Bee: (*log).Bee, + Level: int64((*log).MessageType), + Message: (*log).Message, + Timestamp: (*log).Timestamp, + } + + return resp +} From 095472f8db7c295cb408b62a32f03fc015d71b58 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 29 Apr 2019 11:11:12 +0200 Subject: [PATCH 05/30] Reverse ordering in LogSorter --- bees/logs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bees/logs.go b/bees/logs.go index bdfe3d92..82a421b0 100644 --- a/bees/logs.go +++ b/bees/logs.go @@ -46,7 +46,7 @@ type LogSorter []LogMessage func (a LogSorter) Len() int { return len(a) } func (a LogSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a LogSorter) Less(i, j int) bool { return a[i].Timestamp.Before(a[j].Timestamp) } +func (a LogSorter) Less(i, j int) bool { return !a[i].Timestamp.Before(a[j].Timestamp) } // NewLogMessage returns a newly composed LogMessage func NewLogMessage(bee string, message string, messageType uint) LogMessage { From 022293fb0b4074ed7fc433537f98f97f107e67ef Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 29 Apr 2019 11:35:15 +0200 Subject: [PATCH 06/30] Sideload Hives in API requests to /bees --- api/resources/bees/bees_response.go | 17 +++++++++++++++-- api/resources/hives/hives_response.go | 12 ++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/api/resources/bees/bees_response.go b/api/resources/bees/bees_response.go index 8159acd2..8c165836 100644 --- a/api/resources/bees/bees_response.go +++ b/api/resources/bees/bees_response.go @@ -25,9 +25,10 @@ import ( "time" restful "github.com/emicklei/go-restful" - "github.com/muesli/beehive/bees" - "github.com/muesli/smolder" + + "github.com/muesli/beehive/api/resources/hives" + "github.com/muesli/beehive/bees" ) // BeeResponse is the common response to 'bee' requests @@ -36,6 +37,9 @@ type BeeResponse struct { Bees []beeInfoResponse `json:"bees,omitempty"` bees map[string]*bees.BeeInterface + + Hives []hives.HiveInfoResponse `json:"hives,omitempty"` + hives map[string]*bees.BeeFactoryInterface } type beeInfoResponse struct { @@ -55,11 +59,20 @@ func (r *BeeResponse) Init(context smolder.APIContext) { r.Context = context r.bees = make(map[string]*bees.BeeInterface) + r.hives = make(map[string]*bees.BeeFactoryInterface) } // AddBee adds a bee to the response func (r *BeeResponse) AddBee(bee *bees.BeeInterface) { r.bees[(*bee).Name()] = bee + + hive := bees.GetFactory((*bee).Namespace()) + if hive == nil { + panic("Hive for Bee not found") + } + + r.hives[(*hive).Name()] = hive + r.Hives = append(r.Hives, hives.PrepareHiveResponse(r.Context, hive)) } // Send responds to a request with http.StatusOK diff --git a/api/resources/hives/hives_response.go b/api/resources/hives/hives_response.go index ebadd1b4..19acd40a 100644 --- a/api/resources/hives/hives_response.go +++ b/api/resources/hives/hives_response.go @@ -36,11 +36,11 @@ import ( type HiveResponse struct { smolder.Response - Hives []hiveInfoResponse `json:"hives,omitempty"` + Hives []HiveInfoResponse `json:"hives,omitempty"` hives map[string]*bees.BeeFactoryInterface } -type hiveInfoResponse struct { +type HiveInfoResponse struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description"` @@ -73,7 +73,7 @@ func (r *HiveResponse) Send(response *restful.Response) { sort.Strings(keys) for _, k := range keys { - r.Hives = append(r.Hives, prepareHiveResponse(r.Context, r.hives[k])) + r.Hives = append(r.Hives, PrepareHiveResponse(r.Context, r.hives[k])) } r.Response.Send(response) @@ -85,17 +85,17 @@ func (r *HiveResponse) EmptyResponse() interface{} { var out struct { Hives interface{} `json:"hives"` } - out.Hives = []hiveInfoResponse{} + out.Hives = []HiveInfoResponse{} return out } return nil } -func prepareHiveResponse(ctx smolder.APIContext, hive *bees.BeeFactoryInterface) hiveInfoResponse { +func PrepareHiveResponse(ctx smolder.APIContext, hive *bees.BeeFactoryInterface) HiveInfoResponse { u, _ := url.Parse(ctx.(*context.APIContext).Config.BaseURL) u.Path = path.Join(u.Path, "images", (*hive).Image()) - resp := hiveInfoResponse{ + resp := HiveInfoResponse{ ID: (*hive).ID(), Name: (*hive).Name(), Description: (*hive).Description(), From 6511f3887f02c28838075c54d07b2655118abf13 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 29 Apr 2019 13:28:30 +0200 Subject: [PATCH 07/30] Bees can now expose their state This allows Bees to store a state independent from event parameters. Those states can be checked in filters or used as action parameters like other values. Just as examples, Bees could store whether they're currently connected, the latest sensor read-out, or the timestamp of the most recent sync as their states. In Filters you could then check their state: {{test eq .context.irc.connected true}} --- api/resources/hives/hives_response.go | 2 + bees/chains.go | 1 + bees/context.go | 63 +++++++++++++++++++++++++++ bees/descriptors.go | 7 +++ bees/factories.go | 7 +++ 5 files changed, 80 insertions(+) create mode 100644 bees/context.go diff --git a/api/resources/hives/hives_response.go b/api/resources/hives/hives_response.go index 19acd40a..2c3e4082 100644 --- a/api/resources/hives/hives_response.go +++ b/api/resources/hives/hives_response.go @@ -47,6 +47,7 @@ type HiveInfoResponse struct { Image string `json:"image"` LogoColor string `json:"logocolor"` Options []bees.BeeOptionDescriptor `json:"options"` + States []bees.StateDescriptor `json:"states"` Events []bees.EventDescriptor `json:"events"` Actions []bees.ActionDescriptor `json:"actions"` } @@ -102,6 +103,7 @@ func PrepareHiveResponse(ctx smolder.APIContext, hive *bees.BeeFactoryInterface) Image: u.String(), LogoColor: (*hive).LogoColor(), Options: (*hive).Options(), + States: (*hive).States(), Events: (*hive).Events(), Actions: (*hive).Actions(), } diff --git a/bees/chains.go b/bees/chains.go index 7a586992..6f1bd429 100644 --- a/bees/chains.go +++ b/bees/chains.go @@ -94,6 +94,7 @@ func execChains(event *Event) { for _, opt := range event.Options { m[opt.Name] = opt.Value } + ctx.FillMap(m) failed := false log.Println("Executing chain:", c.Name, "-", c.Description) diff --git a/bees/context.go b/bees/context.go new file mode 100644 index 00000000..15c6f111 --- /dev/null +++ b/bees/context.go @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * Christian Muehlhaeuser + */ + +// Package bees is Beehive's central module system. +package bees + +var ( + ctx = NewContext() +) + +type Context struct { + state map[*Bee]map[string]interface{} +} + +func NewContext() *Context { + return &Context{ + state: make(map[*Bee]map[string]interface{}), + } +} + +func (c *Context) Set(bee *Bee, key string, value interface{}) { + if _, ok := c.state[bee]; !ok { + c.state[bee] = make(map[string]interface{}) + } + c.state[bee][key] = value +} + +func (c *Context) Value(bee *Bee, key string) interface{} { + return c.state[bee][key] +} + +func (c *Context) FillMap(m map[string]interface{}) { + cd := make(map[string]interface{}) + for bee, d := range c.state { + cd[bee.Name()] = d + } + m["context"] = cd +} + +func (bee *Bee) ContextSet(key string, value interface{}) { + ctx.Set(bee, key, value) +} + +func (bee *Bee) ContextValue(key string) interface{} { + return ctx.Value(bee, key) +} diff --git a/bees/descriptors.go b/bees/descriptors.go index e57e91b1..916e3974 100644 --- a/bees/descriptors.go +++ b/bees/descriptors.go @@ -54,6 +54,13 @@ type BeeOptionDescriptor struct { Mandatory bool } +// StateDescriptor describes a State provided by a Bee. +type StateDescriptor struct { + Name string + Description string + Type string +} + // GetActionDescriptor returns the ActionDescriptor matching an action. func GetActionDescriptor(action *Action) ActionDescriptor { bee := GetBee(action.Bee) diff --git a/bees/factories.go b/bees/factories.go index b5b716b6..83297908 100644 --- a/bees/factories.go +++ b/bees/factories.go @@ -51,6 +51,11 @@ func (factory *BeeFactory) Options() []BeeOptionDescriptor { return []BeeOptionDescriptor{} } +// States returns the default empty states set. +func (factory *BeeFactory) States() []StateDescriptor { + return []StateDescriptor{} +} + // Events returns the default empty events set. func (factory *BeeFactory) Events() []EventDescriptor { return []EventDescriptor{} @@ -79,6 +84,8 @@ type BeeFactoryInterface interface { // Options supported by module Options() []BeeOptionDescriptor + // States provided by module + States() []StateDescriptor // Events defined by module Events() []EventDescriptor // Actions supported by module From 2d82826baaa82a9466e78ea0a80fcd49fb130eed Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 29 Apr 2019 13:51:21 +0200 Subject: [PATCH 08/30] Support states in IRCBee --- bees/ircbee/ircbee.go | 16 ++++++++++------ bees/ircbee/ircbeefactory.go | 19 ++++++++++++++++++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/bees/ircbee/ircbee.go b/bees/ircbee/ircbee.go index fbea69e4..0a2ac4a5 100644 --- a/bees/ircbee/ircbee.go +++ b/bees/ircbee/ircbee.go @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2017 Christian Muehlhaeuser + * Copyright (C) 2014-2019 Christian Muehlhaeuser * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -255,12 +255,14 @@ func (mod *IrcBee) Run(eventChan chan bees.Event) { eventChan <- ev }) - connecting := false - disconnected := true waitForDisconnect := false + connecting := false + connected := false + mod.ContextSet("connected", &connected) + for { // loop on IRC connection events - if disconnected { + if !connected { if waitForDisconnect { return } @@ -280,12 +282,12 @@ func (mod *IrcBee) Run(eventChan chan bees.Event) { if status { mod.Logln("Connected to IRC:", mod.server) connecting = false - disconnected = false + connected = true mod.rejoin() } else { mod.Logln("Disconnected from IRC:", mod.server) connecting = false - disconnected = true + connected = false } case <-mod.SigChan: @@ -309,4 +311,6 @@ func (mod *IrcBee) ReloadOptions(options bees.BeeOptions) { options.Bind("password", &mod.password) options.Bind("ssl", &mod.ssl) options.Bind("channels", &mod.channels) + + mod.ContextSet("channels", &mod.channels) } diff --git a/bees/ircbee/ircbeefactory.go b/bees/ircbee/ircbeefactory.go index f4a5575c..5afc52c9 100644 --- a/bees/ircbee/ircbeefactory.go +++ b/bees/ircbee/ircbeefactory.go @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2017 Christian Muehlhaeuser + * Copyright (C) 2014-2019 Christian Muehlhaeuser * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -101,6 +101,23 @@ func (factory *IrcBeeFactory) Options() []bees.BeeOptionDescriptor { return opts } +// States returns the state values provided by this Bee. +func (factory *IrcBeeFactory) States() []bees.StateDescriptor { + opts := []bees.StateDescriptor{ + { + Name: "connected", + Description: "Whether this bee is currently connected to IRC", + Type: "bool", + }, + { + Name: "channels", + Description: "Which channels this bee is currently connected to", + Type: "[]string", + }, + } + return opts +} + // Events describes the available events provided by this Bee. func (factory *IrcBeeFactory) Events() []bees.EventDescriptor { events := []bees.EventDescriptor{ From a896302371bf2d38b9a557eb713bc5a9bad4ced5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 30 Apr 2019 11:42:27 +0200 Subject: [PATCH 09/30] Fixed converting strong to float64 in ConvertValue --- bees/placeholders.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bees/placeholders.go b/bees/placeholders.go index 3175a0ca..79801cdd 100644 --- a/bees/placeholders.go +++ b/bees/placeholders.go @@ -167,7 +167,7 @@ func ConvertValue(v interface{}, dst interface{}) error { case float32: *d = float64(vt) case string: - x, _ := strconv.Atoi(vt) + x, _ := strconv.ParseFloat(vt, 64) *d = float64(x) default: panic(fmt.Sprintf("Unhandled type %+v for float64 conversion", reflect.TypeOf(vt))) @@ -214,9 +214,9 @@ func ConvertValue(v interface{}, dst interface{}) error { case int64: *d = time.Unix(vt, 0) default: - panic(fmt.Sprintf("Unhandled type %+v for time.Time conversion", reflect.TypeOf(vt))) + panic(fmt.Sprintf("Unhandled type %+v for time.Time conversion", reflect.TypeOf(vt))) } - + case *url.Values: switch vt := v.(type) { case string: From 20081f0afb9986ccd72cd48e0a795069f07e76ea Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 1 May 2019 14:08:51 +0200 Subject: [PATCH 10/30] Go mod tidy our module deps --- go.mod | 76 +++++++++++++++++++++++++++++++--------------------------- go.sum | 76 +++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 101 insertions(+), 51 deletions(-) diff --git a/go.mod b/go.mod index 1aca475a..e0675e49 100644 --- a/go.mod +++ b/go.mod @@ -4,58 +4,56 @@ go 1.12 require ( github.com/ChimeraCoder/anaconda v2.0.0+incompatible - github.com/ChimeraCoder/tokenbucket v0.0.0-20131201223612-c5a927568de7 + github.com/ChimeraCoder/tokenbucket v0.0.0-20131201223612-c5a927568de7 // indirect github.com/CleverbotIO/go-cleverbot.io v0.0.0-20170417080108-d24926702e8d github.com/MariaTerzieva/gotumblr v0.0.0-20170505145609-93ca5e50a3fd github.com/Profpatsch/GoOse v0.0.0-20181012194242-da5de31b9bd2 github.com/PuerkitoBio/goquery v1.3.0 - github.com/advancedlogic/goquery v0.0.0-20150328072103-aeb03ad57afc github.com/akashshinde/go_cricket v0.0.0-20170322162016-01a06b2c3f22 - github.com/andybalholm/cascadia v1.0.0 + github.com/andybalholm/cascadia v1.0.0 // indirect github.com/araddon/dateparse v0.0.0-20190329160016-74dc0e29b01f // indirect - github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 - github.com/bjarneh/latinx v0.0.0-20120329061922-4dfe9ba2a293 + github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 // indirect github.com/briandowns/openweathermap v0.0.0-20171018182829-64ca52ee34ca github.com/carlosdp/twiliogo v0.0.0-20140102225436-f61c8230fa91 - github.com/davecgh/go-spew v1.1.0 + github.com/davecgh/go-spew v1.1.0 // indirect github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb - github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4 - github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc - github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad + github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect + github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect github.com/emicklei/go-restful v2.6.0+incompatible github.com/fatih/set v0.2.1 // indirect github.com/fluffle/goirc v0.0.0-20180216210456-fc1dfa1ceb88 github.com/fsnotify/fsnotify v1.4.7 - github.com/garyburd/go-oauth v0.0.0-20171004151416-4cff9ef7b700 + github.com/garyburd/go-oauth v0.0.0-20171004151416-4cff9ef7b700 // indirect github.com/gigawattio/window v0.0.0-20180317192513-0f5467e35573 // indirect github.com/glaxx/go_pastebin v0.0.0-20170619211819-7e72d56770d0 - github.com/go-ini/ini v1.32.0 + github.com/go-ini/ini v1.32.0 // indirect github.com/go-mail/mail v0.0.0-20180301192024-63235f23494b github.com/go-telegram-bot-api/telegram-bot-api v4.6.1+incompatible - github.com/golang/mock v1.0.0 - github.com/golang/protobuf v1.0.0 + github.com/golang/mock v1.0.0 // indirect github.com/google/go-github v15.0.0+incompatible - github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 - github.com/gorilla/websocket v1.2.0 + github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect + github.com/gorilla/websocket v1.2.0 // indirect github.com/guelfey/go.dbus v0.0.0-20131113121618-f6a3a2366cc3 github.com/huandu/facebook v2.1.2+incompatible github.com/jacobsa/go-serial v0.0.0-20180131005756-15cf729a72d4 github.com/jayeshsolanki93/devgorant v0.0.0-20160810172004-69fb03e5c3b1 github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43 // indirect github.com/kr/pretty v0.0.0-20160823170715-cfb55aafdaf3 - github.com/kr/text v0.0.0-20160504234017-7cafcd837844 - github.com/kurrik/oauth1a v0.0.0-20151019171716-cb1b80e32dd4 + github.com/kr/text v0.0.0-20160504234017-7cafcd837844 // indirect + github.com/kurrik/oauth1a v0.0.0-20151019171716-cb1b80e32dd4 // indirect + github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect + github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018 // indirect github.com/mattn/go-colorable v0.0.9 - github.com/mattn/go-isatty v0.0.3 + github.com/mattn/go-isatty v0.0.3 // indirect github.com/mattn/go-mastodon v0.0.3 github.com/mattn/go-runewidth v0.0.4 // indirect github.com/mattn/go-xmpp v0.0.0-20180131083630-7ec2b8b7def6 - github.com/minio/minio-go v0.0.0-20180223024044-c645fb54e4d1 - github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747 - github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 - github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff + github.com/minio/minio-go v6.0.14+incompatible + github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747 // indirect + github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 // indirect + github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect github.com/muesli/go-pkg-rss v0.0.0-20180307042412-3bef0f3126ec - github.com/muesli/go-pkg-xmlx v0.0.0-20151201012946-76f54ee73233 + github.com/muesli/go-pkg-xmlx v0.0.0-20151201012946-76f54ee73233 // indirect github.com/muesli/go.hue v0.0.0-20140802040715-8aefcc693caf github.com/muesli/goefa v0.0.0-20180221033339-ae75724b4510 github.com/muesli/smolder v0.0.0-20181113094957-e6752d792454 @@ -63,24 +61,32 @@ require ( github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7 github.com/olekukonko/tablewriter v0.0.1 // indirect + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect github.com/pkg/errors v0.8.1 // indirect - github.com/pmezard/go-difflib v1.0.0 - github.com/rogpeppe/go-charset v0.0.0-20150615172532-e9ff06f347d3 + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-charset v0.0.0-20150615172532-e9ff06f347d3 // indirect github.com/simplepush/simplepush-go v0.0.0-20170125185443-9b5259670030 + github.com/simplereach/timeutils v1.2.0 // indirect github.com/sirupsen/logrus v1.0.4 + github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect github.com/sromku/go-gitter v0.0.0-20170828210750-70f7030a94a6 github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect - github.com/stretchr/objx v0.1.0 - github.com/stretchr/testify v1.2.1 - github.com/technoweenie/multipartstreamer v1.0.1 + github.com/stretchr/objx v0.1.0 // indirect + github.com/stretchr/testify v1.2.1 // indirect + github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect - golang.org/x/crypto v0.0.0-20180228161326-91a49db82a88 - golang.org/x/net v0.0.0-20180306060152-d25186b37f34 + golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 // indirect golang.org/x/oauth2 v0.0.0-20180228173056-2f32c3ac0fa4 - golang.org/x/sys v0.0.0-20180302081741-dd2ff4accc09 - golang.org/x/text v0.3.0 - google.golang.org/appengine v1.0.0 - gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc - gopkg.in/fatih/set.v0 v0.1.0 + golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect + google.golang.org/appengine v1.0.0 // indirect + gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect + gopkg.in/ini.v1 v1.42.0 // indirect + gopkg.in/mail.v2 v2.3.1 // indirect + gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect layeh.com/gumble v0.0.0-20180224004502-127dae0a3703 ) diff --git a/go.sum b/go.sum index 56a8925d..870f7701 100644 --- a/go.sum +++ b/go.sum @@ -10,7 +10,6 @@ github.com/Profpatsch/GoOse v0.0.0-20181012194242-da5de31b9bd2 h1:bul/2q+F+e8bZq github.com/Profpatsch/GoOse v0.0.0-20181012194242-da5de31b9bd2/go.mod h1:f5uOYEWPJji9Y6mwXULhr/sETrGWcW6D+bg9nRCA310= github.com/PuerkitoBio/goquery v1.3.0 h1:2LzdaeRwZjIMW7iKEei51jiCPB33mou4AI7QCzS4NgE= github.com/PuerkitoBio/goquery v1.3.0/go.mod h1:T9ezsOHcCrDCgA8aF1Cqr3sSYbO/xgdy8/R/XiIMAhA= -github.com/advancedlogic/goquery v0.0.0-20150328072103-aeb03ad57afc/go.mod h1:eK/K8AfetLcpConguBp2wpQRKWN+rmGrvAK1pSHtY0U= github.com/akashshinde/go_cricket v0.0.0-20170322162016-01a06b2c3f22 h1:2jzZwBlEdGUf34//31M7m+J1k8Iln8yNeVK0FpnZXOY= github.com/akashshinde/go_cricket v0.0.0-20170322162016-01a06b2c3f22/go.mod h1:22G9EQ6wpT/k35p9F2xHsbqfH5uL3bQcjJIjPJ+J6xU= github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= @@ -19,7 +18,6 @@ github.com/araddon/dateparse v0.0.0-20190329160016-74dc0e29b01f h1:wK+B1a8vR5Ew0 github.com/araddon/dateparse v0.0.0-20190329160016-74dc0e29b01f/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 h1:ekDALXAVvY/Ub1UtNta3inKQwZ/jMB/zpOtD8rAYh78= github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330/go.mod h1:nH+k0SvAt3HeiYyOlJpLLv1HG1p7KWP7qU9QPp2/pCo= -github.com/bjarneh/latinx v0.0.0-20120329061922-4dfe9ba2a293/go.mod h1:HdstVrPoCN+CT+wHjeU6juUog6IM+EShcDoARBbc7cU= github.com/briandowns/openweathermap v0.0.0-20171018182829-64ca52ee34ca h1:d4L/k7PUsGcGUY7WK+JgQ3rOeLST3xHivi/Bz5jxBt4= github.com/briandowns/openweathermap v0.0.0-20171018182829-64ca52ee34ca/go.mod h1:8g1Bgq9PbPpXIA3sdlWmWf2JpiWGJee/O4Q+ddYO6+k= github.com/carlosdp/twiliogo v0.0.0-20140102225436-f61c8230fa91 h1:fIflfwVZsOHJD5nWJXEmdGrHnhVGVWtvVZAXMsHlCDU= @@ -28,7 +26,6 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb h1:6S+TKObz6+Io2c8IOkcbK4Sz7nj6RpEVU7TkvmsZZcw= github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb/go.mod h1:wf3nKtOnQqCp7kp9xB7hHnNlZ6m3NoiOxjrB9hFRq4Y= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc h1:tP7tkU+vIsEOKiK+l/NSLN4uUtkyuxc6hgYpQeCWAeI= github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc/go.mod h1:ORH5Qp2bskd9NzSfKqAF7tKfONsEkCarTE5ESr/RVBw= github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad h1:Qk76DOWdOp+GlyDKBAG3Klr9cn7N+LcYc82AZ2S7+cA= @@ -55,16 +52,20 @@ github.com/go-telegram-bot-api/telegram-bot-api v4.6.1+incompatible h1:KWd4+1Z6h github.com/go-telegram-bot-api/telegram-bot-api v4.6.1+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/golang/mock v1.0.0 h1:HzcpUG60pfl43n9d2qbdi/3l1uKpAmxlfWEPWtV/QxM= github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.0.0 h1:lsek0oXi8iFE9L+EXARyHIjU5rlWIhhTkjDz3vHhWWQ= -github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-github v15.0.0+incompatible h1:jlPg2Cpsxb/FyEV/MFiIE9tW/2RAevQNZDPeHbf5a94= github.com/google/go-github v15.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/guelfey/go.dbus v0.0.0-20131113121618-f6a3a2366cc3 h1:fngCxKbvZdctIsWj2hYijhAt4iK0JXSSA78B36xP0yI= github.com/guelfey/go.dbus v0.0.0-20131113121618-f6a3a2366cc3/go.mod h1:0CNX5Cvi77WEH8llpfZ/ieuqyceb1cnO5//b5zzsnF8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/facebook v2.1.2+incompatible h1:APtODfdBm89WyxkAhP2rZlDvPFJv21fQccS1dRFkTdU= github.com/huandu/facebook v2.1.2+incompatible/go.mod h1:wJogp9rhXUUjDuhx6ZaR5Eylx3dsJmy0zyFRaPYUq5g= github.com/jacobsa/go-serial v0.0.0-20180131005756-15cf729a72d4 h1:G2ztCwXov8mRvP0ZfjE6nAlaCX2XbykaeHdbT6KwDz0= @@ -73,12 +74,18 @@ github.com/jayeshsolanki93/devgorant v0.0.0-20160810172004-69fb03e5c3b1 h1:+rPUG github.com/jayeshsolanki93/devgorant v0.0.0-20160810172004-69fb03e5c3b1/go.mod h1:C2TzmYXoz+ck9q8+lWXSkyba/l+eyKC39pw98R9MrhA= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43 h1:jTkyeF7NZ5oIr0ESmcrpiDgAfoidCBF4F5kJhjtaRwE= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kr/pretty v0.0.0-20160823170715-cfb55aafdaf3 h1:dhwb1Ev84SKKVBfLuhR4bw/29yYHzwtTyTLUWWnvYxI= github.com/kr/pretty v0.0.0-20160823170715-cfb55aafdaf3/go.mod h1:Bvhd+E3laJ0AVkG0c9rmtZcnhV0HQ3+c3YxxqTvc/gA= github.com/kr/text v0.0.0-20160504234017-7cafcd837844 h1:kpzneEBeC0dMewP3gr/fADv1OlblH9r1goWVwpOt3TU= github.com/kr/text v0.0.0-20160504234017-7cafcd837844/go.mod h1:sjUstKUATFIcff4qlB53Kml0wQPtJVc/3fWrmuUmcfA= github.com/kurrik/oauth1a v0.0.0-20151019171716-cb1b80e32dd4 h1:hGX8e8fDuWmCOQEneaHtuiqiy1NsBnZW2G6lxitngus= github.com/kurrik/oauth1a v0.0.0-20151019171716-cb1b80e32dd4/go.mod h1:8buhLMuecANgNgxrsQynWlNt03oXr1B/v2xbuRSrnEc= +github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 h1:AsEBgzv3DhuYHI/GiQh2HxvTP71HCCE9E/tzGUzGdtU= +github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0= +github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018 h1:MNApn+Z+fIT4NPZopPfCc1obT6aY3SVM6DOctz1A9ZU= +github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg= github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= @@ -89,8 +96,8 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-xmpp v0.0.0-20180131083630-7ec2b8b7def6 h1:iFTAHAY8qacRrQUn56r3lW6+5mfp4Hjx2gHzwlcdAhE= github.com/mattn/go-xmpp v0.0.0-20180131083630-7ec2b8b7def6/go.mod h1:Cs5mF0OsrRRmhkyOod//ldNPOwJsrBvJ+1WRspv0xoc= -github.com/minio/minio-go v0.0.0-20180223024044-c645fb54e4d1 h1:LjDbsj1xwnrXvRWBvqZBMiZ/1Y3gwhm+S1PWi1W7Y1A= -github.com/minio/minio-go v0.0.0-20180223024044-c645fb54e4d1/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8= +github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o= +github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8= github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747 h1:eQox4Rh4ewJF+mqYPxCkmBAirRnPaHEB26UkNuPyjlk= github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 h1:oKIteTqeSpenyTrOVj5zkiyCaflLa8B+CD0324otT+o= @@ -107,8 +114,6 @@ github.com/muesli/goefa v0.0.0-20180221033339-ae75724b4510 h1:byNlAG5gQPj+hvyx2I github.com/muesli/goefa v0.0.0-20180221033339-ae75724b4510/go.mod h1:cbhVWIL28EF8sTH71/qsU+TeEEmYC33MES0J7Ul0TFI= github.com/muesli/smolder v0.0.0-20181113094957-e6752d792454 h1:M4sPHl3GXRrWLL4gQHzjf0pIiy3LyqCHqNfbGWNA7OI= github.com/muesli/smolder v0.0.0-20181113094957-e6752d792454/go.mod h1:vBtOJlVGxLheofBQdKVQGaG40aJQUwr6Lh4PVliqebY= -github.com/nlopes/slack v0.2.0 h1:ygNVH3HWrOPFbzFoAmRKPcMcmYMmsLf+vPV9DhJdqJI= -github.com/nlopes/slack v0.2.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0= github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= @@ -117,6 +122,11 @@ github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7 h1:NZz8yuBWWG4 github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7/go.mod h1:geyfqmhRrxMwbEo5RPwf5rw5vITQHHQlA7+azUQSIJM= github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -125,8 +135,14 @@ github.com/rogpeppe/go-charset v0.0.0-20150615172532-e9ff06f347d3 h1:t0lav+WB8mT github.com/rogpeppe/go-charset v0.0.0-20150615172532-e9ff06f347d3/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/simplepush/simplepush-go v0.0.0-20170125185443-9b5259670030 h1:uM9h9hFHksg0mDTOst9h9QIyL2YiIi+CriSf8agWrwU= github.com/simplepush/simplepush-go v0.0.0-20170125185443-9b5259670030/go.mod h1:3SZdv/t76bM6vmmSa251/VnQMn9S8gRuZcRFy2Ack9A= +github.com/simplereach/timeutils v1.2.0 h1:btgOAlu9RW6de2r2qQiONhjgxdAG7BL6je0G6J/yPnA= +github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8= github.com/sirupsen/logrus v1.0.4 h1:gzbtLsZC3Ic5PptoRG+kQj4L60qjK7H7XszrU163JNQ= github.com/sirupsen/logrus v1.0.4/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/sromku/go-gitter v0.0.0-20170828210750-70f7030a94a6 h1:7AV47xvYbuwoNxR9LDhkRwqzZsySCX5H8WVM4zrDmME= github.com/sromku/go-gitter v0.0.0-20170828210750-70f7030a94a6/go.mod h1:P2BoF5QlNE1UcKtYKP8xa8B9I5eALYU5JpRdCqLddL4= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= @@ -139,19 +155,47 @@ github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQ github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= -golang.org/x/crypto v0.0.0-20180228161326-91a49db82a88 h1:jLkAo/qlT9whgCLYC5GAJ9kcKrv3Wj8VCc4N+KJ4wpw= -golang.org/x/crypto v0.0.0-20180228161326-91a49db82a88/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180306060152-d25186b37f34 h1:iFnCuNSN/vI6MpVNGKchMAS+XtQqe4z/g9mSPtIKy8E= -golang.org/x/net v0.0.0-20180306060152-d25186b37f34/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYRuq8JQ1aa7LJt8EXVyo= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180228173056-2f32c3ac0fa4 h1:Q6d4fL/kGYXpYk4o7Und88I/5k3ZSDFQVqgvpE2P34o= golang.org/x/oauth2 v0.0.0-20180228173056-2f32c3ac0fa4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sys v0.0.0-20180302081741-dd2ff4accc09 h1:wNPZbZUOH0tyqngVRXeF2iQm19+ssqyebJTCFBvxsow= -golang.org/x/sys v0.0.0-20180302081741-dd2ff4accc09/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +google.golang.org/appengine v1.0.0 h1:dN4LljjBKVChsv0XCSI+zbyzdqrkEwX5LQFUMRSGqOc= google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= -gopkg.in/fatih/set.v0 v0.1.0/go.mod h1:5eLWEndGL4zGGemXWrKuts+wTJR0y+w+auqUJZbmyBg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= +gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= layeh.com/gumble v0.0.0-20180224004502-127dae0a3703 h1:CZ84uK0lSV2j5whBLgMf7s4qd/mIZTpXKWDwIAUpw4I= layeh.com/gumble v0.0.0-20180224004502-127dae0a3703/go.mod h1:ZWnZxbDNsg1uFq6Zu7mRdCi7xechwiqWYsFdedd0GUc= From d9e2b63edd153077baaa1d06f562fdeee7923af8 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 1 May 2019 14:19:53 +0200 Subject: [PATCH 11/30] Bumped dependencies to latest compatible releases --- go.mod | 76 ++++++++++++------------ go.sum | 181 ++++++++++++++++++++++++++++++++------------------------- 2 files changed, 140 insertions(+), 117 deletions(-) diff --git a/go.mod b/go.mod index e0675e49..d973f754 100644 --- a/go.mod +++ b/go.mod @@ -8,85 +8,85 @@ require ( github.com/CleverbotIO/go-cleverbot.io v0.0.0-20170417080108-d24926702e8d github.com/MariaTerzieva/gotumblr v0.0.0-20170505145609-93ca5e50a3fd github.com/Profpatsch/GoOse v0.0.0-20181012194242-da5de31b9bd2 - github.com/PuerkitoBio/goquery v1.3.0 + github.com/PuerkitoBio/goquery v1.5.0 github.com/akashshinde/go_cricket v0.0.0-20170322162016-01a06b2c3f22 - github.com/andybalholm/cascadia v1.0.0 // indirect - github.com/araddon/dateparse v0.0.0-20190329160016-74dc0e29b01f // indirect + github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83 // indirect github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 // indirect - github.com/briandowns/openweathermap v0.0.0-20171018182829-64ca52ee34ca - github.com/carlosdp/twiliogo v0.0.0-20140102225436-f61c8230fa91 - github.com/davecgh/go-spew v1.1.0 // indirect + github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d + github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1 github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect - github.com/emicklei/go-restful v2.6.0+incompatible + github.com/emicklei/go-restful v2.9.3+incompatible github.com/fatih/set v0.2.1 // indirect - github.com/fluffle/goirc v0.0.0-20180216210456-fc1dfa1ceb88 + github.com/fluffle/goirc v1.0.1 github.com/fsnotify/fsnotify v1.4.7 - github.com/garyburd/go-oauth v0.0.0-20171004151416-4cff9ef7b700 // indirect + github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 // indirect github.com/gigawattio/window v0.0.0-20180317192513-0f5467e35573 // indirect github.com/glaxx/go_pastebin v0.0.0-20170619211819-7e72d56770d0 - github.com/go-ini/ini v1.32.0 // indirect - github.com/go-mail/mail v0.0.0-20180301192024-63235f23494b - github.com/go-telegram-bot-api/telegram-bot-api v4.6.1+incompatible - github.com/golang/mock v1.0.0 // indirect - github.com/google/go-github v15.0.0+incompatible - github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect - github.com/gorilla/websocket v1.2.0 // indirect + github.com/go-ini/ini v1.42.0 // indirect + github.com/go-mail/mail v2.3.1+incompatible + github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible + github.com/golang/mock v1.2.0 // indirect + github.com/golang/protobuf v1.3.1 // indirect + github.com/google/go-github v17.0.0+incompatible + github.com/google/go-querystring v1.0.0 // indirect + github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect + github.com/gorilla/websocket v1.4.0 // indirect github.com/guelfey/go.dbus v0.0.0-20131113121618-f6a3a2366cc3 - github.com/huandu/facebook v2.1.2+incompatible + github.com/huandu/facebook v2.3.1+incompatible github.com/jacobsa/go-serial v0.0.0-20180131005756-15cf729a72d4 github.com/jayeshsolanki93/devgorant v0.0.0-20160810172004-69fb03e5c3b1 github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43 // indirect - github.com/kr/pretty v0.0.0-20160823170715-cfb55aafdaf3 - github.com/kr/text v0.0.0-20160504234017-7cafcd837844 // indirect + github.com/json-iterator/go v1.1.6 // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/kr/pretty v0.1.0 github.com/kurrik/oauth1a v0.0.0-20151019171716-cb1b80e32dd4 // indirect github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018 // indirect - github.com/mattn/go-colorable v0.0.9 - github.com/mattn/go-isatty v0.0.3 // indirect + github.com/mattn/go-colorable v0.1.1 + github.com/mattn/go-isatty v0.0.7 // indirect github.com/mattn/go-mastodon v0.0.3 github.com/mattn/go-runewidth v0.0.4 // indirect - github.com/mattn/go-xmpp v0.0.0-20180131083630-7ec2b8b7def6 + github.com/mattn/go-xmpp v0.0.0-20190124093244-6093f50721ed github.com/minio/minio-go v6.0.14+incompatible - github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 // indirect github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect github.com/muesli/go-pkg-rss v0.0.0-20180307042412-3bef0f3126ec github.com/muesli/go-pkg-xmlx v0.0.0-20151201012946-76f54ee73233 // indirect github.com/muesli/go.hue v0.0.0-20140802040715-8aefcc693caf - github.com/muesli/goefa v0.0.0-20180221033339-ae75724b4510 + github.com/muesli/goefa v0.0.0-20180507204150-08d8ee2555d2 github.com/muesli/smolder v0.0.0-20181113094957-e6752d792454 github.com/nlopes/slack v0.5.0 github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7 github.com/olekukonko/tablewriter v0.0.1 // indirect - github.com/onsi/ginkgo v1.8.0 // indirect - github.com/onsi/gomega v1.5.0 // indirect github.com/pkg/errors v0.8.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-charset v0.0.0-20150615172532-e9ff06f347d3 // indirect - github.com/simplepush/simplepush-go v0.0.0-20170125185443-9b5259670030 + github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 // indirect + github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02 github.com/simplereach/timeutils v1.2.0 // indirect - github.com/sirupsen/logrus v1.0.4 + github.com/sirupsen/logrus v1.4.1 + github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 // indirect github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect github.com/sromku/go-gitter v0.0.0-20170828210750-70f7030a94a6 github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect - github.com/stretchr/objx v0.1.0 // indirect - github.com/stretchr/testify v1.2.1 // indirect + github.com/stretchr/objx v0.2.0 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect + golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 // indirect golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 // indirect - golang.org/x/oauth2 v0.0.0-20180228173056-2f32c3ac0fa4 - golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect - google.golang.org/appengine v1.0.0 // indirect - gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect + golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a + golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872 // indirect + golang.org/x/text v0.3.2 // indirect + google.golang.org/appengine v1.5.0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect gopkg.in/ini.v1 v1.42.0 // indirect gopkg.in/mail.v2 v2.3.1 // indirect gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect gopkg.in/yaml.v2 v2.2.2 // indirect - layeh.com/gumble v0.0.0-20180224004502-127dae0a3703 + layeh.com/gumble v0.0.0-20180508205105-1ea1159c4956 ) diff --git a/go.sum b/go.sum index 870f7701..0a75bdb3 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/ChimeraCoder/anaconda v2.0.0+incompatible h1:F0eD7CHXieZ+VLboCD5UAqCeAzJZxcr90zSCcuJopJs= github.com/ChimeraCoder/anaconda v2.0.0+incompatible/go.mod h1:TCt3MijIq3Qqo9SBtuW/rrM4x7rDfWqYWHj8T7hLcLg= github.com/ChimeraCoder/tokenbucket v0.0.0-20131201223612-c5a927568de7 h1:r+EmXjfPosKO4wfiMLe1XQictsIlhErTufbWUsjOTZs= @@ -8,98 +9,116 @@ github.com/MariaTerzieva/gotumblr v0.0.0-20170505145609-93ca5e50a3fd h1:KddRLg9z github.com/MariaTerzieva/gotumblr v0.0.0-20170505145609-93ca5e50a3fd/go.mod h1:QSx6VAxYnm/tN1N2icODlufKb0b5OuBkXDzFJWD7nlM= github.com/Profpatsch/GoOse v0.0.0-20181012194242-da5de31b9bd2 h1:bul/2q+F+e8bZqgNmh/rQSxZK8F4XXw24SCi1GUJ2i4= github.com/Profpatsch/GoOse v0.0.0-20181012194242-da5de31b9bd2/go.mod h1:f5uOYEWPJji9Y6mwXULhr/sETrGWcW6D+bg9nRCA310= -github.com/PuerkitoBio/goquery v1.3.0 h1:2LzdaeRwZjIMW7iKEei51jiCPB33mou4AI7QCzS4NgE= -github.com/PuerkitoBio/goquery v1.3.0/go.mod h1:T9ezsOHcCrDCgA8aF1Cqr3sSYbO/xgdy8/R/XiIMAhA= +github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk= +github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/akashshinde/go_cricket v0.0.0-20170322162016-01a06b2c3f22 h1:2jzZwBlEdGUf34//31M7m+J1k8Iln8yNeVK0FpnZXOY= github.com/akashshinde/go_cricket v0.0.0-20170322162016-01a06b2c3f22/go.mod h1:22G9EQ6wpT/k35p9F2xHsbqfH5uL3bQcjJIjPJ+J6xU= github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/araddon/dateparse v0.0.0-20190329160016-74dc0e29b01f h1:wK+B1a8vR5Ew04VA3qxBfXC8E8NghEREybZfotsfHp8= -github.com/araddon/dateparse v0.0.0-20190329160016-74dc0e29b01f/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= +github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83 h1:ukTLOeMC0aVxbJWVg6hOsVJ0VPIo8w++PbNsze/pqF8= +github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 h1:ekDALXAVvY/Ub1UtNta3inKQwZ/jMB/zpOtD8rAYh78= github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330/go.mod h1:nH+k0SvAt3HeiYyOlJpLLv1HG1p7KWP7qU9QPp2/pCo= -github.com/briandowns/openweathermap v0.0.0-20171018182829-64ca52ee34ca h1:d4L/k7PUsGcGUY7WK+JgQ3rOeLST3xHivi/Bz5jxBt4= -github.com/briandowns/openweathermap v0.0.0-20171018182829-64ca52ee34ca/go.mod h1:8g1Bgq9PbPpXIA3sdlWmWf2JpiWGJee/O4Q+ddYO6+k= -github.com/carlosdp/twiliogo v0.0.0-20140102225436-f61c8230fa91 h1:fIflfwVZsOHJD5nWJXEmdGrHnhVGVWtvVZAXMsHlCDU= -github.com/carlosdp/twiliogo v0.0.0-20140102225436-f61c8230fa91/go.mod h1:pAxCBpjl/0JxYZlWGP/Dyi8f/LQSCQD2WAsG/iNzqQ8= +github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d h1:28xWzPQ9bdGxKAAwQpZipZZ9Xz8kQcgMPF9cZnvMeuI= +github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d/go.mod h1:8g1Bgq9PbPpXIA3sdlWmWf2JpiWGJee/O4Q+ddYO6+k= +github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1 h1:hXakhQtPnXH839q1pBl/GqfTSchqE+R5Fqn98Iu7UQM= +github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1/go.mod h1:pAxCBpjl/0JxYZlWGP/Dyi8f/LQSCQD2WAsG/iNzqQ8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 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/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb h1:6S+TKObz6+Io2c8IOkcbK4Sz7nj6RpEVU7TkvmsZZcw= github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb/go.mod h1:wf3nKtOnQqCp7kp9xB7hHnNlZ6m3NoiOxjrB9hFRq4Y= github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc h1:tP7tkU+vIsEOKiK+l/NSLN4uUtkyuxc6hgYpQeCWAeI= github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc/go.mod h1:ORH5Qp2bskd9NzSfKqAF7tKfONsEkCarTE5ESr/RVBw= github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad h1:Qk76DOWdOp+GlyDKBAG3Klr9cn7N+LcYc82AZ2S7+cA= github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad/go.mod h1:mPKfmRa823oBIgl2r20LeMSpTAteW5j7FLkc0vjmzyQ= -github.com/emicklei/go-restful v2.6.0+incompatible h1:luAX89wpjId5gV+GJV11MFD56GpAJTG2eUqCeDDgB98= -github.com/emicklei/go-restful v2.6.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.3+incompatible h1:2OwhVdhtzYUp5P5wuGsVDPagKSRd9JK72sJCHVCXh5g= +github.com/emicklei/go-restful v2.9.3+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA= github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= -github.com/fluffle/goirc v0.0.0-20180216210456-fc1dfa1ceb88 h1:u4MUgj6o/rJ/KkV+v4gk5PQhX844bGzbCv2LY3mMXeI= -github.com/fluffle/goirc v0.0.0-20180216210456-fc1dfa1ceb88/go.mod h1:XSqSOq5nTMabnZQgLQMKdkleBiUntueKLNTb0PpSOZw= +github.com/fluffle/goirc v1.0.1 h1:YHBfWIXSFgABz8dbijvOIKucFejnbHdk78+r2z/6B/Q= +github.com/fluffle/goirc v1.0.1/go.mod h1:bm91JNJ5r070PbWm8uG9UDcy9GJxvB6fmVuHDttWwR4= +github.com/fluffle/golog v1.0.2/go.mod h1:TKZoUh/MNb9worAhWP158Ol0TXc5EfhMJK/qB/7j+Ko= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/garyburd/go-oauth v0.0.0-20171004151416-4cff9ef7b700 h1:keDwpc5ecCjVkZypVCT1QpyVHD9UeCcaWaJrcpqb8XM= -github.com/garyburd/go-oauth v0.0.0-20171004151416-4cff9ef7b700/go.mod h1:HfkOCN6fkKKaPSAeNq/er3xObxTW4VLeY6UUK895gLQ= +github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 h1:GOfMz6cRgTJ9jWV0qAezv642OhPnKEG7gtUjJSdStHE= +github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17/go.mod h1:HfkOCN6fkKKaPSAeNq/er3xObxTW4VLeY6UUK895gLQ= github.com/gigawattio/window v0.0.0-20180317192513-0f5467e35573 h1:u8AQ9bPa9oC+8/A/jlWouakhIvkFfuxgIIRjiy8av7I= github.com/gigawattio/window v0.0.0-20180317192513-0f5467e35573/go.mod h1:eBvb3i++NHDH4Ugo9qCvMw8t0mTSctaEa5blJbWcNxs= github.com/glaxx/go_pastebin v0.0.0-20170619211819-7e72d56770d0 h1:EdszNpwFiRjmOMBc8VWyoaydQLCMvXCTO1JGhOPN8J0= github.com/glaxx/go_pastebin v0.0.0-20170619211819-7e72d56770d0/go.mod h1:R7D2HdGrozpSe4V0ZuxAH7RKteG/vcpPpPsghEHo2+Y= -github.com/go-ini/ini v1.32.0 h1:/MArBHSS0TFR28yPPDK1vPIjt4wUnPBfb81i6iiyKvA= -github.com/go-ini/ini v1.32.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-mail/mail v0.0.0-20180301192024-63235f23494b h1:m35QDmGg5Pnb8U7OP/pETlSu9njctBR/SLucC28Wy6g= -github.com/go-mail/mail v0.0.0-20180301192024-63235f23494b/go.mod h1:VPWjmmNyRsWXQZHVHT3g0YbIINUkSmuKOiLIDkWbL6M= -github.com/go-telegram-bot-api/telegram-bot-api v4.6.1+incompatible h1:KWd4+1Z6hk4FqQPCvPBSMCTCy0vjTVJmq0JdkflLxy8= -github.com/go-telegram-bot-api/telegram-bot-api v4.6.1+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= -github.com/golang/mock v1.0.0 h1:HzcpUG60pfl43n9d2qbdi/3l1uKpAmxlfWEPWtV/QxM= -github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/go-ini/ini v1.42.0 h1:TWr1wGj35+UiWHlBA8er89seFXxzwFn11spilrrj+38= +github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-mail/mail v2.3.1+incompatible h1:UzNOn0k5lpfVtO31cK3hn6I4VEVGhe3lX8AJBAxXExM= +github.com/go-mail/mail v2.3.1+incompatible/go.mod h1:VPWjmmNyRsWXQZHVHT3g0YbIINUkSmuKOiLIDkWbL6M= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-github v15.0.0+incompatible h1:jlPg2Cpsxb/FyEV/MFiIE9tW/2RAevQNZDPeHbf5a94= -github.com/google/go-github v15.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= -github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= -github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/guelfey/go.dbus v0.0.0-20131113121618-f6a3a2366cc3 h1:fngCxKbvZdctIsWj2hYijhAt4iK0JXSSA78B36xP0yI= github.com/guelfey/go.dbus v0.0.0-20131113121618-f6a3a2366cc3/go.mod h1:0CNX5Cvi77WEH8llpfZ/ieuqyceb1cnO5//b5zzsnF8= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/facebook v2.1.2+incompatible h1:APtODfdBm89WyxkAhP2rZlDvPFJv21fQccS1dRFkTdU= -github.com/huandu/facebook v2.1.2+incompatible/go.mod h1:wJogp9rhXUUjDuhx6ZaR5Eylx3dsJmy0zyFRaPYUq5g= +github.com/huandu/facebook v2.3.1+incompatible h1:+F6kUqKx5TifzMg2fXYZFdA/3VVNphdNK8G4PF2ui74= +github.com/huandu/facebook v2.3.1+incompatible/go.mod h1:wJogp9rhXUUjDuhx6ZaR5Eylx3dsJmy0zyFRaPYUq5g= github.com/jacobsa/go-serial v0.0.0-20180131005756-15cf729a72d4 h1:G2ztCwXov8mRvP0ZfjE6nAlaCX2XbykaeHdbT6KwDz0= github.com/jacobsa/go-serial v0.0.0-20180131005756-15cf729a72d4/go.mod h1:2RvX5ZjVtsznNZPEt4xwJXNJrM3VTZoQf7V6gk0ysvs= github.com/jayeshsolanki93/devgorant v0.0.0-20160810172004-69fb03e5c3b1 h1:+rPUGcMtKybxck9IKclxodfetCoCD2eSBEzPMZgc2ZA= github.com/jayeshsolanki93/devgorant v0.0.0-20160810172004-69fb03e5c3b1/go.mod h1:C2TzmYXoz+ck9q8+lWXSkyba/l+eyKC39pw98R9MrhA= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43 h1:jTkyeF7NZ5oIr0ESmcrpiDgAfoidCBF4F5kJhjtaRwE= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/kr/pretty v0.0.0-20160823170715-cfb55aafdaf3 h1:dhwb1Ev84SKKVBfLuhR4bw/29yYHzwtTyTLUWWnvYxI= -github.com/kr/pretty v0.0.0-20160823170715-cfb55aafdaf3/go.mod h1:Bvhd+E3laJ0AVkG0c9rmtZcnhV0HQ3+c3YxxqTvc/gA= -github.com/kr/text v0.0.0-20160504234017-7cafcd837844 h1:kpzneEBeC0dMewP3gr/fADv1OlblH9r1goWVwpOt3TU= -github.com/kr/text v0.0.0-20160504234017-7cafcd837844/go.mod h1:sjUstKUATFIcff4qlB53Kml0wQPtJVc/3fWrmuUmcfA= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kurrik/oauth1a v0.0.0-20151019171716-cb1b80e32dd4 h1:hGX8e8fDuWmCOQEneaHtuiqiy1NsBnZW2G6lxitngus= github.com/kurrik/oauth1a v0.0.0-20151019171716-cb1b80e32dd4/go.mod h1:8buhLMuecANgNgxrsQynWlNt03oXr1B/v2xbuRSrnEc= github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 h1:AsEBgzv3DhuYHI/GiQh2HxvTP71HCCE9E/tzGUzGdtU= github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0= github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018 h1:MNApn+Z+fIT4NPZopPfCc1obT6aY3SVM6DOctz1A9ZU= github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg= -github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-mastodon v0.0.3 h1:FVp4vNXmeHhfvCSHTvfhCgrrC9UQzqx2dSisOzzjsJk= github.com/mattn/go-mastodon v0.0.3/go.mod h1:/OSOSDJyV0OUlBuDV0Qrllizt3BJNj4Ir5xhckYRVmg= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-xmpp v0.0.0-20180131083630-7ec2b8b7def6 h1:iFTAHAY8qacRrQUn56r3lW6+5mfp4Hjx2gHzwlcdAhE= -github.com/mattn/go-xmpp v0.0.0-20180131083630-7ec2b8b7def6/go.mod h1:Cs5mF0OsrRRmhkyOod//ldNPOwJsrBvJ+1WRspv0xoc= +github.com/mattn/go-xmpp v0.0.0-20190124093244-6093f50721ed h1:A1hEQg5M0b3Wg06pm3q/B0wdZsPjVQ/a2IgauQ8wCZo= +github.com/mattn/go-xmpp v0.0.0-20190124093244-6093f50721ed/go.mod h1:Cs5mF0OsrRRmhkyOod//ldNPOwJsrBvJ+1WRspv0xoc= github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o= github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8= -github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747 h1:eQox4Rh4ewJF+mqYPxCkmBAirRnPaHEB26UkNuPyjlk= -github.com/mitchellh/go-homedir v0.0.0-20161203194507-b8bc1bf76747/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 h1:oKIteTqeSpenyTrOVj5zkiyCaflLa8B+CD0324otT+o= github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff h1:HLGD5/9UxxfEuO9DtP8gnTmNtMxbPyhYltfxsITel8g= @@ -110,8 +129,8 @@ github.com/muesli/go-pkg-xmlx v0.0.0-20151201012946-76f54ee73233 h1:BpRRQx7DiGCv github.com/muesli/go-pkg-xmlx v0.0.0-20151201012946-76f54ee73233/go.mod h1:fuQ3qbkN+TpT4HAUW6IoYwf5qJHU/Mac+jPoTMb1i/4= github.com/muesli/go.hue v0.0.0-20140802040715-8aefcc693caf h1:LxZj9OgYtTw5bQWoHaBuCSc+bLKuWq0khkGyfbBvALQ= github.com/muesli/go.hue v0.0.0-20140802040715-8aefcc693caf/go.mod h1:kbCdPkiPQGNQW+m9a1XHIrOCT4/FtfpqBF2bVkwZjMg= -github.com/muesli/goefa v0.0.0-20180221033339-ae75724b4510 h1:byNlAG5gQPj+hvyx2IONpv19srMxb1Z4RkLR4oa2VNA= -github.com/muesli/goefa v0.0.0-20180221033339-ae75724b4510/go.mod h1:cbhVWIL28EF8sTH71/qsU+TeEEmYC33MES0J7Ul0TFI= +github.com/muesli/goefa v0.0.0-20180507204150-08d8ee2555d2 h1:A0yDQZg4PVcBvzH9IYGydylu0ytfiTK8LaHOH5eJrLY= +github.com/muesli/goefa v0.0.0-20180507204150-08d8ee2555d2/go.mod h1:cbhVWIL28EF8sTH71/qsU+TeEEmYC33MES0J7Ul0TFI= github.com/muesli/smolder v0.0.0-20181113094957-e6752d792454 h1:M4sPHl3GXRrWLL4gQHzjf0pIiy3LyqCHqNfbGWNA7OI= github.com/muesli/smolder v0.0.0-20181113094957-e6752d792454/go.mod h1:vBtOJlVGxLheofBQdKVQGaG40aJQUwr6Lh4PVliqebY= github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0= @@ -122,25 +141,22 @@ github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7 h1:NZz8yuBWWG4 github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7/go.mod h1:geyfqmhRrxMwbEo5RPwf5rw5vITQHHQlA7+azUQSIJM= github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-charset v0.0.0-20150615172532-e9ff06f347d3 h1:t0lav+WB8mTCXXjf4FPHYQ0VcGRP/9ScnHL+I/P2Z9Y= -github.com/rogpeppe/go-charset v0.0.0-20150615172532-e9ff06f347d3/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= -github.com/simplepush/simplepush-go v0.0.0-20170125185443-9b5259670030 h1:uM9h9hFHksg0mDTOst9h9QIyL2YiIi+CriSf8agWrwU= -github.com/simplepush/simplepush-go v0.0.0-20170125185443-9b5259670030/go.mod h1:3SZdv/t76bM6vmmSa251/VnQMn9S8gRuZcRFy2Ack9A= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 h1:BN/Nyn2nWMoqGRA7G7paDNDqTXE30mXGqzzybrfo05w= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02 h1:1wFJqw2JrDwoJRJmq/NtlZHRRUGTt7W9uHbWjJ6X2bE= +github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02/go.mod h1:3SZdv/t76bM6vmmSa251/VnQMn9S8gRuZcRFy2Ack9A= github.com/simplereach/timeutils v1.2.0 h1:btgOAlu9RW6de2r2qQiONhjgxdAG7BL6je0G6J/yPnA= github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8= -github.com/sirupsen/logrus v1.0.4 h1:gzbtLsZC3Ic5PptoRG+kQj4L60qjK7H7XszrU163JNQ= -github.com/sirupsen/logrus v1.0.4/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 h1:hBSHahWMEgzwRyS6dRpxY0XyjZsHyQ61s084wo5PJe0= +github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/sromku/go-gitter v0.0.0-20170828210750-70f7030a94a6 h1:7AV47xvYbuwoNxR9LDhkRwqzZsySCX5H8WVM4zrDmME= @@ -149,53 +165,60 @@ github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cma github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U= -github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYRuq8JQ1aa7LJt8EXVyo= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180228173056-2f32c3ac0fa4 h1:Q6d4fL/kGYXpYk4o7Und88I/5k3ZSDFQVqgvpE2P34o= -golang.org/x/oauth2 v0.0.0-20180228173056-2f32c3ac0fa4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872 h1:cGjJzUd8RgBw428LXP65YXni0aiGNA4Bl+ls8SmLOm8= +golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -google.golang.org/appengine v1.0.0 h1:dN4LljjBKVChsv0XCSI+zbyzdqrkEwX5LQFUMRSGqOc= -google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -layeh.com/gumble v0.0.0-20180224004502-127dae0a3703 h1:CZ84uK0lSV2j5whBLgMf7s4qd/mIZTpXKWDwIAUpw4I= -layeh.com/gumble v0.0.0-20180224004502-127dae0a3703/go.mod h1:ZWnZxbDNsg1uFq6Zu7mRdCi7xechwiqWYsFdedd0GUc= +layeh.com/gumble v0.0.0-20180508205105-1ea1159c4956 h1:TaQ2ECrcAom2bkjRvOxhsUkD6l5iiCJ/++lHHZ42zII= +layeh.com/gumble v0.0.0-20180508205105-1ea1159c4956/go.mod h1:ZWnZxbDNsg1uFq6Zu7mRdCi7xechwiqWYsFdedd0GUc= From ac93554b6b14924e10c7bfb080ae753ab0f41787 Mon Sep 17 00:00:00 2001 From: CalmBit Date: Wed, 1 May 2019 16:32:11 -0400 Subject: [PATCH 12/30] Added Prometheus Bee (#231) --- .gitignore | 1 + assets/bees/prometheusbee.png | Bin 0 -> 2921 bytes bees/prometheusbee/prometheusbee.go | 253 ++++++++++++++++++ bees/prometheusbee/prometheusbeefactory.go | 286 +++++++++++++++++++++ hives.go | 1 + 5 files changed, 541 insertions(+) create mode 100644 assets/bees/prometheusbee.png create mode 100644 bees/prometheusbee/prometheusbee.go create mode 100644 bees/prometheusbee/prometheusbeefactory.go diff --git a/.gitignore b/.gitignore index 6bc7bb21..9b3f7d09 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ beehive.conf # Embedded assets api/bindata.go + diff --git a/assets/bees/prometheusbee.png b/assets/bees/prometheusbee.png new file mode 100644 index 0000000000000000000000000000000000000000..2ef61724233b836669875513f823cc78873c77fe GIT binary patch literal 2921 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 Tdpd$V00000NkvXXu0mjf>~L#4 literal 0 HcmV?d00001 diff --git a/bees/prometheusbee/prometheusbee.go b/bees/prometheusbee/prometheusbee.go new file mode 100644 index 00000000..60fef147 --- /dev/null +++ b/bees/prometheusbee/prometheusbee.go @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2019 CalmBit + * 2014-2019 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * CalmBit + * Christian Muehlhaeuser + */ + +// Package prometheusbee is a bee designed to expose metrics for scraping +// by Prometheus. +package prometheusbee + +import ( + "github.com/muesli/beehive/bees" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "net/http" +) + +// PrometheusBee is a bee designed to expose metrics for scraping +// by Prometheus. +type PrometheusBee struct { + bees.Bee + + addr string + + counterVecName string + gaugeVecName string + histogramVecName string + summaryVecName string + + counter *prometheus.CounterVec + gauge *prometheus.GaugeVec + histogram *prometheus.HistogramVec + summary *prometheus.SummaryVec +} + +// Run executes the Bee's event loop. +func (mod *PrometheusBee) Run(eventChan chan bees.Event) { + + // Counter vector registration + + mod.counter = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: mod.counterVecName, + Help: "Collection of all counter variables being iterated by hives", + }, + []string{"name"}, + ) + err := prometheus.Register(mod.counter) + if err != nil { + mod.LogErrorf("Error registering counter vector: %v", err) + panic("Unable to start Prometheus due to counter initialization failure") + } + + // Gauge vector registration + + mod.gauge = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: mod.gaugeVecName, + Help: "Collection of all gauge variables being iterated by hives", + }, + []string{"name"}, + ) + err = prometheus.Register(mod.gauge) + if err != nil { + mod.LogErrorf("Error registering gauge vector: %v", err) + panic("Unable to start Prometheus due to gauge initialization failure") + } + + // Histogram vector registration + + mod.histogram = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: mod.histogramVecName, + Help: "Collection of all histogram variables being iterated by hives", + }, + []string{"name"}, + ) + err = prometheus.Register(mod.histogram) + if err != nil { + mod.LogErrorf("Error registering histogram vector: %v", err) + panic("Unable to start Prometheus due to histogram initialization failure") + } + + // Summary vector registration + + mod.summary = prometheus.NewSummaryVec( + prometheus.SummaryOpts{ + Name: mod.summaryVecName, + Help: "Collection of all summary variables being iterated by hives", + }, + []string{"name"}, + ) + err = prometheus.Register(mod.summary) + if err != nil { + mod.LogErrorf("Error registering summary vector: %v", err) + panic("Unable to start Prometheus due to summary initialization failure") + } + + // Now, to serve everything up: + + go func() { + http.Handle("/metrics", promhttp.Handler()) + err := http.ListenAndServe(":2112", nil) + if err != nil { + mod.LogErrorf("Error running prometheus metric handler: %v", err) + } + }() + + select { + case <-mod.SigChan: + return + } +} + +// Action triggers the action passed to it. +func (mod *PrometheusBee) Action(action bees.Action) []bees.Placeholder { + outs := []bees.Placeholder{} + switch action.Name { + case "counter_inc": + var label string + action.Options.Bind("label", &label) + c, err := mod.counter.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error incrementing counter: %v", err) + } else { + c.Inc() + } + case "counter_add": + var label string + var value float64 + action.Options.Bind("label", &label) + action.Options.Bind("value", &value) + c, err := mod.counter.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error adding to counter: %v", err) + } else { + c.Add(value) + } + case "gauge_set": + var label string + var value float64 + action.Options.Bind("label", &label) + action.Options.Bind("value", &value) + g, err := mod.gauge.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error setting gauge: %v", err) + } else { + g.Set(value) + } + case "gauge_inc": + var label string + action.Options.Bind("label", &label) + g, err := mod.gauge.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error incrementing gauge: %v", err) + } else { + g.Inc() + } + case "gauge_dec": + var label string + action.Options.Bind("label", &label) + g, err := mod.gauge.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error decrementing gauge: %v", err) + } else { + g.Dec() + } + case "gauge_add": + var label string + var value float64 + action.Options.Bind("label", &label) + action.Options.Bind("value", &value) + g, err := mod.gauge.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error adding to gauge: %v", err) + } else { + g.Add(value) + } + case "gauge_sub": + var label string + var value float64 + action.Options.Bind("label", &label) + action.Options.Bind("value", &value) + g, err := mod.gauge.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error subtracting from gauge: %v", err) + } else { + g.Sub(value) + } + case "gauge_set_to_current_time": + var label string + action.Options.Bind("label", &label) + g, err := mod.gauge.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error setting gauge to current time: %v", err) + } else { + g.SetToCurrentTime() + } + case "histogram_observe": + var label string + var value float64 + action.Options.Bind("label", &label) + action.Options.Bind("value", &value) + h, err := mod.histogram.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error observing value for histogram: %v", err) + } else { + h.Observe(value) + } + case "summary_observe": + var label string + var value float64 + action.Options.Bind("label", &label) + action.Options.Bind("value", &value) + s, err := mod.summary.GetMetricWithLabelValues(label) + if err != nil { + mod.LogErrorf("Error observing value for summary: %v", err) + } else { + s.Observe(value) + } + default: + panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) + } + + return outs +} + +// ReloadOptions parses the config options and initializes the Bee. +func (mod *PrometheusBee) ReloadOptions(options bees.BeeOptions) { + mod.SetOptions(options) + + options.Bind("address", &mod.addr) + options.Bind("counter_vec_name", &mod.counterVecName) + options.Bind("gauge_vec_name", &mod.gaugeVecName) + options.Bind("histogram_vec_name", &mod.histogramVecName) + options.Bind("summary_vec_name", &mod.summaryVecName) +} diff --git a/bees/prometheusbee/prometheusbeefactory.go b/bees/prometheusbee/prometheusbeefactory.go new file mode 100644 index 00000000..cd5a3b4b --- /dev/null +++ b/bees/prometheusbee/prometheusbeefactory.go @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2019 CalmBit + * 2014-2019 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * CalmBit + * Christian Muehlhaeuser + */ + +package prometheusbee + +import ( + "github.com/muesli/beehive/bees" +) + +// PrometheusBeeFactory is a factory for PrometheusBees. +type PrometheusBeeFactory struct { + bees.BeeFactory +} + +// New returns a new Bee instance configured with the supplied options. +func (factory *PrometheusBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { + bee := PrometheusBee{ + Bee: bees.NewBee(name, factory.ID(), description, options), + } + bee.ReloadOptions(options) + + return &bee +} + +// ID returns the ID of this Bee. +func (factory *PrometheusBeeFactory) ID() string { + return "prometheusbee" +} + +// Name returns the name of this Bee. +func (factory *PrometheusBeeFactory) Name() string { + return "Prometheus" +} + +// Description returns the description of this Bee. +func (factory *PrometheusBeeFactory) Description() string { + return "Allows for the export of data to Prometheus" +} + +// Image returns the filename of an image for this Bee. +func (factory *PrometheusBeeFactory) Image() string { + return factory.ID() + ".png" +} + +// LogoColor returns the preferred logo background color (used by the admin interface). +func (factory *PrometheusBeeFactory) LogoColor() string { + return "#e59030" +} + +// Options returns the options available to configure this Bee. +func (factory *PrometheusBeeFactory) Options() []bees.BeeOptionDescriptor { + opts := []bees.BeeOptionDescriptor{ + { + Name: "address", + Description: "Which addr to listen on, eg: 0.0.0.0:2112", + Type: "address", + Mandatory: true, + }, + { + Name: "counter_vec_name", + Description: "The name of the counter vector", + Type: "string", + Mandatory: true, + Default: "counter_vec", + }, + { + Name: "gauge_vec_name", + Description: "The name of the gauge vector", + Type: "string", + Mandatory: true, + Default: "gauge_vec", + }, + { + Name: "histogram_vec_name", + Description: "The name of the histogram vector", + Type: "string", + Mandatory: true, + Default: "histogram_vec", + }, + { + Name: "summary_vec_name", + Description: "The name of the summary vector", + Type: "string", + Mandatory: true, + Default: "summary_vec", + }, + } + return opts +} + +// Actions describes the available actions provided by this Bee. +func (factory *PrometheusBeeFactory) Actions() []bees.ActionDescriptor { + actions := []bees.ActionDescriptor{ + { + Namespace: factory.Name(), + Name: "counter_inc", + Description: "Increments the value of a counter by 1", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the counter to increment", + Type: "string", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "counter_add", + Description: "Adds an arbitrary, positive value to a counter", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the counter to add to", + Type: "string", + Mandatory: true, + }, + { + Name: "value", + Description: "Value to add to the counter", + Type: "float64", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "gauge_set", + Description: "Sets a gauge's value to an arbitrary value", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the gauge to set", + Type: "string", + Mandatory: true, + }, + { + Name: "value", + Description: "New value for the gauge", + Type: "float64", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "gauge_inc", + Description: "Increments the value of a gauge by 1", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the gauge to increment", + Type: "string", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "gauge_dec", + Description: "Decrements the value of a gauge by 1", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the gauge to decrement", + Type: "string", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "gauge_add", + Description: "Adds an arbitrary value to a gauge", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the gauge to add to", + Type: "string", + Mandatory: true, + }, + { + Name: "value", + Description: "Value to add to the counter", + Type: "float64", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "gauge_sub", + Description: "Subtracts an arbitrary value from a gauge", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the gauge to subtract from", + Type: "string", + Mandatory: true, + }, + { + Name: "value", + Description: "Value to subtract from the gauge", + Type: "float64", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "gauge_set_to_current_time", + Description: "Sets a gauge's value to the current time as a unix timestamp", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the gauge to set", + Type: "string", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "histogram_observe", + Description: "Records an observation in a histogram", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the histogram to add an observation to", + Type: "string", + Mandatory: true, + }, + { + Name: "value", + Description: "Value to observe", + Type: "float64", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "summary_observe", + Description: "Records an observation in a summary", + Options: []bees.PlaceholderDescriptor{ + { + Name: "label", + Description: "Label of the summary to add an observation to", + Type: "string", + Mandatory: true, + }, + { + Name: "value", + Description: "Value to observe", + Type: "float64", + Mandatory: true, + }, + }, + }, + } + return actions +} + +func init() { + f := PrometheusBeeFactory{} + bees.RegisterFactory(&f) +} diff --git a/hives.go b/hives.go index 12ad1af1..21a8e73a 100644 --- a/hives.go +++ b/hives.go @@ -46,6 +46,7 @@ import ( _ "github.com/muesli/beehive/bees/nagiosbee" _ "github.com/muesli/beehive/bees/openweathermapbee" _ "github.com/muesli/beehive/bees/pastebinbee" + _ "github.com/muesli/beehive/bees/prometheusbee" _ "github.com/muesli/beehive/bees/pushoverbee" _ "github.com/muesli/beehive/bees/rssbee" _ "github.com/muesli/beehive/bees/s3bee" From 7960d0141f468658f21faf119f5080e86803f537 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 1 May 2019 22:46:46 +0200 Subject: [PATCH 13/30] Updated Go module definitions --- go.mod | 1 + go.sum | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/go.mod b/go.mod index d973f754..a949b5ca 100644 --- a/go.mod +++ b/go.mod @@ -65,6 +65,7 @@ require ( github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7 github.com/olekukonko/tablewriter v0.0.1 // indirect github.com/pkg/errors v0.8.1 // indirect + github.com/prometheus/client_golang v0.9.2 github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 // indirect github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02 github.com/simplereach/timeutils v1.2.0 // indirect diff --git a/go.sum b/go.sum index 0a75bdb3..0e783b31 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83 h1:ukTLOeMC0aVxb github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 h1:ekDALXAVvY/Ub1UtNta3inKQwZ/jMB/zpOtD8rAYh78= github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330/go.mod h1:nH+k0SvAt3HeiYyOlJpLLv1HG1p7KWP7qU9QPp2/pCo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d h1:28xWzPQ9bdGxKAAwQpZipZZ9Xz8kQcgMPF9cZnvMeuI= github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d/go.mod h1:8g1Bgq9PbPpXIA3sdlWmWf2JpiWGJee/O4Q+ddYO6+k= github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1 h1:hXakhQtPnXH839q1pBl/GqfTSchqE+R5Fqn98Iu7UQM= @@ -111,6 +113,8 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-xmpp v0.0.0-20190124093244-6093f50721ed h1:A1hEQg5M0b3Wg06pm3q/B0wdZsPjVQ/a2IgauQ8wCZo= github.com/mattn/go-xmpp v0.0.0-20190124093244-6093f50721ed/go.mod h1:Cs5mF0OsrRRmhkyOod//ldNPOwJsrBvJ+1WRspv0xoc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o= github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -145,6 +149,14 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 h1:BN/Nyn2nWMoqGRA7G7paDNDqTXE30mXGqzzybrfo05w= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02 h1:1wFJqw2JrDwoJRJmq/NtlZHRRUGTt7W9uHbWjJ6X2bE= @@ -183,6 +195,7 @@ golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -190,6 +203,7 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09 h1:KaQtG+aDELoNmXYas3TVkGNYR golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= From 7d52298ddd383d724d0f89f961263e03ed56e091 Mon Sep 17 00:00:00 2001 From: Matthias Krauser Date: Thu, 2 May 2019 19:38:04 +0200 Subject: [PATCH 14/30] fix handling of boolean config values --- bees/placeholders.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bees/placeholders.go b/bees/placeholders.go index 79801cdd..1f99cc6a 100644 --- a/bees/placeholders.go +++ b/bees/placeholders.go @@ -125,6 +125,8 @@ func ConvertValue(v interface{}, dst interface{}) error { vt = strings.ToLower(vt) if vt == "true" || vt == "on" || vt == "yes" || vt == "1" || vt == "t" { *d = true + } else { + *d = false } case int64: *d = vt > 0 From 1c9af592cbd98760f48111c673ccf389d90ea89b Mon Sep 17 00:00:00 2001 From: CalmBit Date: Fri, 3 May 2019 02:39:12 -0400 Subject: [PATCH 15/30] Cronbee fix --- bees/cronbee/cronbee.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bees/cronbee/cronbee.go b/bees/cronbee/cronbee.go index c6bc511f..77e1ccd4 100644 --- a/bees/cronbee/cronbee.go +++ b/bees/cronbee/cronbee.go @@ -54,7 +54,7 @@ func (mod *CronBee) Run(eventChan chan bees.Event) { { Name: "timestamp", Type: "string", - Value: timer.GetNextEvent(), + Value: timer.GetNextEvent().Format(time.RFC3339), }, }, } From 714db01e3dbde2beea7d3ecd93f7fc80ab8fd301 Mon Sep 17 00:00:00 2001 From: CalmBit Date: Fri, 3 May 2019 19:36:06 -0400 Subject: [PATCH 16/30] LogDebugF --- beehive.go | 2 ++ bees/bees.go | 15 +++++++++++---- bees/logs.go | 23 ++++++++++++++++++++--- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/beehive.go b/beehive.go index 562be002..d747466e 100644 --- a/beehive.go +++ b/beehive.go @@ -107,6 +107,8 @@ func main() { api.Run() + log.SetLevel(log.InfoLevel) + log.Println() log.Println("Beehive is buzzing...") diff --git a/bees/bees.go b/bees/bees.go index 585980d8..31f407e7 100644 --- a/bees/bees.go +++ b/bees/bees.go @@ -338,21 +338,28 @@ func (bee *Bee) Logln(args ...interface{}) { } log.Println(a...) - Log(bee.Name(), fmt.Sprintln(args...), 0) + Log(bee.Name(), fmt.Sprintln(args...), LogInfo) } // Logf logs a formatted string func (bee *Bee) Logf(format string, args ...interface{}) { s := fmt.Sprintf(format, args...) log.Printf("[%s]: %s", bee.Name(), s) - Log(bee.Name(), s, 0) + Log(bee.Name(), s, LogInfo) } // LogErrorf logs a formatted error string func (bee *Bee) LogErrorf(format string, args ...interface{}) { s := fmt.Sprintf(format, args...) log.Errorf("[%s]: %s", bee.Name(), s) - Log(bee.Name(), s, 1) + Log(bee.Name(), s, LogError) +} + +// LogDebugf logs a formatted debug string +func (bee *Bee) LogDebugf(format string, args ...interface{}) { + s := fmt.Sprintf(format, args...) + log.Debugf("[%s]: %s", bee.Name(), s) + Log(bee.Name(), s, LogDebug) } // LogFatal logs a fatal error @@ -362,7 +369,7 @@ func (bee *Bee) LogFatal(args ...interface{}) { a = append(a, v) } log.Panicln(a...) - Log(bee.Name(), fmt.Sprintln(args...), 2) + Log(bee.Name(), fmt.Sprintln(args...), LogFatal) } // UUID generates a new unique ID. diff --git a/bees/logs.go b/bees/logs.go index 82a421b0..b7fce1b1 100644 --- a/bees/logs.go +++ b/bees/logs.go @@ -41,6 +41,23 @@ var ( logMutex sync.RWMutex ) +// MessageType defines the log level of the log entry we're dealing with +type MessageType uint + +const ( + // LogInfo is for info-level log entries + LogInfo MessageType = iota + + // LogError is for error-level log entries + LogError MessageType = iota + + // LogFatal is for fatal-level log entries + LogFatal MessageType = iota + + // LogDebug is for debug-level log entries + LogDebug MessageType = iota +) + // LogSorter is used for sorting an array of LogMessages by their timestamp type LogSorter []LogMessage @@ -49,18 +66,18 @@ func (a LogSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a LogSorter) Less(i, j int) bool { return !a[i].Timestamp.Before(a[j].Timestamp) } // NewLogMessage returns a newly composed LogMessage -func NewLogMessage(bee string, message string, messageType uint) LogMessage { +func NewLogMessage(bee string, message string, messageType MessageType) LogMessage { return LogMessage{ ID: UUID(), Bee: bee, Message: message, - MessageType: messageType, + MessageType: uint(messageType), Timestamp: time.Now(), } } // Log adds a new LogMessage to the log -func Log(bee string, message string, messageType uint) { +func Log(bee string, message string, messageType MessageType) { logMutex.Lock() defer logMutex.Unlock() From f15c349208aec4af17261dbe730a8498b9bfdd0e Mon Sep 17 00:00:00 2001 From: CalmBit Date: Sat, 4 May 2019 05:25:38 -0400 Subject: [PATCH 17/30] TravisCI Bee (#234) --- assets/bees/travisbee.png | Bin 0 -> 26749 bytes bees/travisbee/travisbee.go | 233 +++++++++++++++++++++++++++++ bees/travisbee/travisbeefactory.go | 185 +++++++++++++++++++++++ go.mod | 1 + go.sum | 4 + hives.go | 1 + 6 files changed, 424 insertions(+) create mode 100644 assets/bees/travisbee.png create mode 100644 bees/travisbee/travisbee.go create mode 100644 bees/travisbee/travisbeefactory.go diff --git a/assets/bees/travisbee.png b/assets/bees/travisbee.png new file mode 100644 index 0000000000000000000000000000000000000000..94f255ec9ef016e18e94f7fedb6bb04105ae4aa7 GIT binary patch literal 26749 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

ak<2AIA!{{F87&q>sx_$WcF+D1SEnsUiAvXH$1 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

#3$RpaHpFsInJ z%)l~`DYR|$8JI+u!{ddZPw(u~i%N!YIQ!smB~;rol(_-BM{+vIww93 zE^uUK?a$>G1guNls@n-sLXe~+9Irn$!QL6T-K#bL{$0EF1Hoh=awm+d@`X8ow*NM; zEL)X1WMhHjBY95gQr42wSNqJ9!7knq zOXgSKee>c2NX6Dnafr#M*o{@Y^tiH5;<;#KBt<{2}x@VsTCLaAyp@yxcB?QGO%`EJNVy$O7Z30jFz*J z_zVI0!yf}7YUBu?o#sluV_(mqJrBT|a)x6RCce9~*(N3t`YvFt-PPQa9mm8HCei5Z z$dDI-hhGL-E>H8NZ!YyW1GehqNO~~qI?ZTX6T9^P~)Q0MZ_D z;nJoB*#-aLUB?xdD&bXMmbyy+@-SE-+-tf1rVYP3L&!l&w9c@5$3A(?!4Gpq^k|Ee;WDK)1adYf}x#Y)RZ=b4ZZ~5_n1pBn(gFFZT30 zI;1U6|Lt|LFkyF@0|uw{OqL_w-OOJ3CtlsOZvJ1D$m`ddx3InC0nPiREf;royKa%I zyDF+H2JN;w>)}>ZIDPwVL5dFG>8YVrdxvs~+;pLVb}V1`%Vooqti-0^@RGW$G()SF21 zyVbD>ruM)mA16hSu5CXbF;K`wv_CyzoJUyH2I-mQ=W6Xmrb1_L z8rHnKkjTPMeE~}MUqWa%{gdqi*9Nv96E%*llULp{eR$K#L>JAF>Pt|qhpa1t!FE68 zoko&;kFBe-;g{^mK`Xv9j{_W1H@VpZ!c;`}idSE#UDhB{M*ha;xKe1&#-~+^Tzp&n_iulDmUNtT)3$_tje. + * + * Authors: + * CalmBit + * Christian Muehlhaeuser + */ + +// Package travisbee is a bee for monitoring and reacting to the status of +// TravisCI builds. +package travisbee + +import ( + "context" + "time" + + "github.com/muesli/beehive/bees" + "github.com/shuheiktgw/go-travis" +) + +// TravisBee is a bee for monitoring and reacting to the status of +// TravisCI builds. +type TravisBee struct { + bees.Bee + + eventChan chan bees.Event + client *travis.Client + apiToken string + builds map[uint]BuildTracker +} + +// BuildTracker is a marker struct to denote "tracked builds" that TravisBee +// cares about. +type BuildTracker struct { + id uint + state string + lastTime time.Time +} + +// Run executes the Bee's event loop. +func (mod *TravisBee) Run(eventChan chan bees.Event) { + + mod.eventChan = eventChan + mod.client = travis.NewClient(travis.ApiOrgUrl, mod.apiToken) + mod.builds = make(map[uint]BuildTracker) + + since := time.Now() + timeout := time.Duration(time.Second * 10) + for { + select { + case <-mod.SigChan: + return + case <-time.After(timeout): + mod.getBuilds(since) + + } + since = time.Now() + timeout = time.Duration(time.Minute) + } +} + +func (mod *TravisBee) getBuilds(since time.Time) { + var opt = travis.BuildsOption{Limit: 10, Offset: 0, SortBy: "started_at:desc"} + builds, _, err := mod.client.Builds.List(context.Background(), &opt) + if err != nil { + mod.LogFatal("Error getting builds from travis-ci: ", err) + } + + for i, currentBuild := range builds { + if b, ok := mod.builds[currentBuild.Id]; ok { + b.lastTime = time.Now() + if b.state != currentBuild.State { + mod.handleStateChange(&b, currentBuild) + b.state = currentBuild.State + } + mod.builds[currentBuild.Id] = b + } else { + mod.LogDebugf("[%d] %d - %s / %s", i, currentBuild.Id, currentBuild.StartedAt, currentBuild.State) + + // If a build was just barely created (i.e. hasn't moved into any other + // stage yet) then we can't even get a started_at time - instead, let's + // just make it a new build, figuring it's obviously something we havent + // seen before. + if currentBuild.State == "created" { + mod.handleNewBuild(currentBuild, since) + } else { + t, err := time.Parse(time.RFC3339, currentBuild.StartedAt) + if err != nil { + mod.LogErrorf("Error parsing time %s - %v", currentBuild.StartedAt, err) + } + if t.After(since) { + mod.handleNewBuild(currentBuild, since) + } + } + } + } +} + +func (mod *TravisBee) handleNewBuild(build *travis.Build, since time.Time) { + mod.builds[build.Id] = BuildTracker{id: build.Id, state: build.State, lastTime: time.Now()} + mod.LogDebugf("Tracking build %d - state %s", build.Id, build.State) + + ev := bees.Event{ + Bee: mod.Name(), + Name: "build_started", + Options: []bees.Placeholder{ + { + Name: "id", + Type: "uint", + Value: build.Id, + }, + { + Name: "state", + Type: "string", + Value: build.State, + }, + { + Name: "repo_slug", + Type: "string", + Value: build.Repository.Slug, + }, + { + Name: "duration", + Type: "uint", + Value: build.Duration, + }, + }, + } + + mod.eventChan <- ev +} + +func (mod *TravisBee) handleStateChange(bt *BuildTracker, build *travis.Build) { + mod.LogDebugf("State changed! (was %s, is now %s)", bt.state, build.State) + + ev := bees.Event{ + Bee: mod.Name(), + Name: "build_status_change", + Options: []bees.Placeholder{ + { + Name: "id", + Type: "uint", + Value: build.Id, + }, + { + Name: "state", + Type: "string", + Value: build.State, + }, + { + Name: "last_state", + Type: "string", + Value: bt.state, + }, + { + Name: "repo_slug", + Type: "string", + Value: build.Repository.Slug, + }, + { + Name: "duration", + Type: "uint", + Value: build.Duration, + }, + }, + } + + mod.eventChan <- ev + + if build.State == "canceled" || build.State == "passed" || + build.State == "failed" || build.State == "errored" { + mod.handleBuildFinish(bt, build) + } +} + +func (mod *TravisBee) handleBuildFinish(bt *BuildTracker, build *travis.Build) { + mod.LogDebugf("Build %d has finished with state %s", build.Id, build.State) + ev := bees.Event{ + Bee: mod.Name(), + Name: "build_finished", + Options: []bees.Placeholder{ + { + Name: "id", + Type: "uint", + Value: build.Id, + }, + { + Name: "state", + Type: "string", + Value: build.State, + }, + { + Name: "previous_state", + Type: "string", + Value: build.PreviousState, + }, + { + Name: "repo_slug", + Type: "string", + Value: build.Repository.Slug, + }, + { + Name: "duration", + Type: "uint", + Value: build.Duration, + }, + }, + } + mod.eventChan <- ev + mod.LogDebugf("Now untracking build %d", bt.id) + delete(mod.builds, bt.id) +} + +// ReloadOptions parses the config options and initializes the Bee. +func (mod *TravisBee) ReloadOptions(options bees.BeeOptions) { + mod.SetOptions(options) + + options.Bind("api_key", &mod.apiToken) +} diff --git a/bees/travisbee/travisbeefactory.go b/bees/travisbee/travisbeefactory.go new file mode 100644 index 00000000..8f2a9108 --- /dev/null +++ b/bees/travisbee/travisbeefactory.go @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2019 CalmBit + * 2014-2019 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * CalmBit + * Christian Muehlhaeuser + */ + +package travisbee + +import ( + "github.com/muesli/beehive/bees" +) + +// TravisBeeFactory is a factory for TravisBees. +type TravisBeeFactory struct { + bees.BeeFactory + + lastBuilds map[string]string +} + +// New returns a new Bee instance configured with the supplied options. +func (factory *TravisBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { + bee := TravisBee{ + Bee: bees.NewBee(name, factory.ID(), description, options), + } + bee.ReloadOptions(options) + + return &bee +} + +// ID returns the ID of this Bee. +func (factory *TravisBeeFactory) ID() string { + return "travisbee" +} + +// Name returns the name of this Bee. +func (factory *TravisBeeFactory) Name() string { + return "Travis CI" +} + +// Description returns the description of this Bee. +func (factory *TravisBeeFactory) Description() string { + return "Allows for monitoring Travis CI jobs" +} + +// Image returns the filename of an image for this Bee. +func (factory *TravisBeeFactory) Image() string { + return factory.ID() + ".png" +} + +// LogoColor returns the preferred logo background color (used by the admin interface). +func (factory *TravisBeeFactory) LogoColor() string { + return "#3EAAAF" +} + +// Options returns the options available to configure this Bee. +func (factory *TravisBeeFactory) Options() []bees.BeeOptionDescriptor { + opts := []bees.BeeOptionDescriptor{ + { + Name: "api_key", + Description: "Your travis-ci.org API key", + Type: "string", + Mandatory: true, + }, + } + return opts +} + +// Events describes the available events provided by this Bee. +func (factory *TravisBeeFactory) Events() []bees.EventDescriptor { + events := []bees.EventDescriptor{ + { + Namespace: factory.Name(), + Name: "build_started", + Description: "is triggered when a build has been started", + Options: []bees.PlaceholderDescriptor{ + { + Name: "id", + Description: "The id of the build", + Type: "uint", + }, + { + Name: "state", + Description: "The current state of the build", + Type: "string", + }, + { + Name: "previous_state", + Description: "The final state of the previous build", + Type: "string", + }, + { + Name: "repo_slug", + Description: "The slug of the repo being built", + Type: "string", + }, + { + Name: "duration", + Description: "The current duration of the build in seconds", + Type: "uint", + }, + }, + }, + { + Namespace: factory.Name(), + Name: "build_status_change", + Description: "is triggered when a currently active build changes status", + Options: []bees.PlaceholderDescriptor{ + { + Name: "id", + Description: "The id of the build", + Type: "uint", + }, + { + Name: "state", + Description: "The current state of the build", + Type: "string", + }, + { + Name: "last_state", + Description: "The last state of the build", + Type: "string", + }, + { + Name: "repo_slug", + Description: "The slug of the repo being built", + Type: "string", + }, + { + Name: "duration", + Description: "The current duration of the build in seconds", + Type: "uint", + }, + }, + }, + { + Namespace: factory.Name(), + Name: "build_finished", + Description: "is triggered when a build enters any terminal state (canceled/errored/passed/failed)", + Options: []bees.PlaceholderDescriptor{ + { + Name: "id", + Description: "The id of the build", + Type: "uint", + }, + { + Name: "state", + Description: "The final state of the build", + Type: "string", + }, + { + Name: "repo_slug", + Description: "The slug of the repo being built", + Type: "string", + }, + { + Name: "duration", + Description: "The duration of the build in seconds", + Type: "uint", + }, + }, + }, + } + return events +} + +func init() { + f := TravisBeeFactory{} + bees.RegisterFactory(&f) +} diff --git a/go.mod b/go.mod index a949b5ca..ea862ed8 100644 --- a/go.mod +++ b/go.mod @@ -67,6 +67,7 @@ require ( github.com/pkg/errors v0.8.1 // indirect github.com/prometheus/client_golang v0.9.2 github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 // indirect + github.com/shuheiktgw/go-travis v0.1.10-0.20190502100712-2d0b3e9898f0 github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02 github.com/simplereach/timeutils v1.2.0 // indirect github.com/sirupsen/logrus v1.4.1 diff --git a/go.sum b/go.sum index 0e783b31..845165bf 100644 --- a/go.sum +++ b/go.sum @@ -159,6 +159,10 @@ github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nL github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4 h1:BN/Nyn2nWMoqGRA7G7paDNDqTXE30mXGqzzybrfo05w= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/shuheiktgw/go-travis v0.1.9 h1:qfu71EtAGkloDGS4jIA0f19g6goejqw782qParyaLPw= +github.com/shuheiktgw/go-travis v0.1.9/go.mod h1:QJJOek1pLVgh75HK4mUDw99bME0MIyam8+fH6Ebnjq4= +github.com/shuheiktgw/go-travis v0.1.10-0.20190502100712-2d0b3e9898f0 h1:+VL5INItDu3Gf4Wak1XZRgsmSTI482GzkTc7Rf2DjI8= +github.com/shuheiktgw/go-travis v0.1.10-0.20190502100712-2d0b3e9898f0/go.mod h1:QJJOek1pLVgh75HK4mUDw99bME0MIyam8+fH6Ebnjq4= github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02 h1:1wFJqw2JrDwoJRJmq/NtlZHRRUGTt7W9uHbWjJ6X2bE= github.com/simplepush/simplepush-go v0.0.0-20170307205831-8980e96b7b02/go.mod h1:3SZdv/t76bM6vmmSa251/VnQMn9S8gRuZcRFy2Ack9A= github.com/simplereach/timeutils v1.2.0 h1:btgOAlu9RW6de2r2qQiONhjgxdAG7BL6je0G6J/yPnA= diff --git a/hives.go b/hives.go index 21a8e73a..6d290bcc 100644 --- a/hives.go +++ b/hives.go @@ -58,6 +58,7 @@ import ( _ "github.com/muesli/beehive/bees/telegrambee" _ "github.com/muesli/beehive/bees/timebee" _ "github.com/muesli/beehive/bees/transmissionbee" + _ "github.com/muesli/beehive/bees/travisbee" _ "github.com/muesli/beehive/bees/tumblrbee" _ "github.com/muesli/beehive/bees/twiliobee" _ "github.com/muesli/beehive/bees/twitterbee" From fc99c8f5cba473fc7f1971ff07ec1fae8f1c468e Mon Sep 17 00:00:00 2001 From: Matthias Krauser Date: Thu, 2 May 2019 22:36:42 +0200 Subject: [PATCH 18/30] added email server bee --- assets/bees/emailserverbee.png | Bin 0 -> 9216 bytes bees/emailserverbee/emailserverbee.go | 190 ++++++++++++++++++ bees/emailserverbee/emailserverbeefactory.go | 199 +++++++++++++++++++ bees/events.go | 15 +- go.mod | 2 + go.sum | 4 + hives.go | 1 + 7 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 assets/bees/emailserverbee.png create mode 100644 bees/emailserverbee/emailserverbee.go create mode 100644 bees/emailserverbee/emailserverbeefactory.go diff --git a/assets/bees/emailserverbee.png b/assets/bees/emailserverbee.png new file mode 100644 index 0000000000000000000000000000000000000000..3fa7dddd9c66e26c091c45a95c2ff217c5dc898f GIT binary patch literal 9216 zcmd6MS5#A9^yW$Vv?DOq#rs#7KvM?h+jU01SG%nq~k11tAom zfrI~S{ki-B0G1JEekaJxAsFEo;Opw)?Scpj^>abEgm}0DK*;2lrA_8Ef}XU>stCK1EX*1|C$_g$MC7ct=oiO{u5O9Xs z_R%Eeo>fRhieyy-I`iVB*A9V_j?%V7#$7JeSoj|5!d#Yq^+L;#Y(prs_jNn|$DdY) z?{n>6j8fQ4R7ZQaO|RdHdhPL9u;jne{rhAA1IhE}XJrTmnw2wVpB8+ROL~yse|bJW z7xY>6g_p>92aZ~ajq|+teD#}gZz}QQ4MwI}>8~phouwM|ug_3zn0t&U9><(R(MJSm z3`e{%w9D;^OB2?AqaBkKqjpcGQK<}z8&nXJBU~IvaONmbcHm=)KL0z!{rAM~!~v5# zy=dUoQs27}Hk5iYA;}cK-!xi240>h*|Y?RHo^{`32|yrr!&Wat-tk zq%2cuJl9kanczk|z7QS%cvZYSw&vDoS&eCytGIP}7t^)w{AaIjUDKn}yJaZ6Y;HD~ zdE*;bV83GC-Lq`%GF7j;GW8`Yza&*$Gw-Tlx0`pLu86A=|L;qH=qqlaQeLjGF5b&T zA)T%1N+()B)q^jAk}V}c&$5U7HaLcZRvNGm%D%-XO9gdhXmh)KDe|=Ws`IrZ=lIUG z$(mi({_e_;o_^IqaR?iuFLE)CTr^37w*acas)AuwXi-2_fuxv`CWp}1u65_6>+OEb zn`K20gO`7P9gLbme@&S+8!8BzeTtP`w-q|HZc;Gcd?3*zLsehRgmsK#Re8kjx61>E0Ux(ZtHguaE0kMIkD@zUl7k=Vv0?&JRlla zU9YW%++FDyf=C)*ry8+lCR2UrcTM*h4kQkqzD>Up{Ct}eMML9RdY&!!LVx7tf#`+5 z^tK`oYyG0B20S>NoRGh5pYh>JC;d z$IKU7zdxQ@R(a{{HqC$0mEje%Re}eRWT~inq4GGj=D!yoJj8|7V!siHNiO@9PM;=M$tnbYGp(@~B56tW)LwSK zj5a#nB>kDP^%Hu;r0k#Dvmm%@g#8>p=#yT#xYjd1?W))(Ids$RT}qF1^%0VuUG{2a z74P6z#SRza4O8X-V=ca$dS8m%t5&ql`}!79Us%@V#Y1gwmegfOsc7%X&;~p2$%W=q zPHc~nUh=O}JkIAjj2D_tbYA(S-l5O)t;Avd1Haeq;gq%OwChT#F9{kwY$C%|h!{X#I4p0s-JG%jp*a6k^%I!81X6H?__zQb8Gc#9QPto&o^(XFbj9 z=3uLv3D3Sq<*>cGt+t8}7pUuV(um)YVxgHo5phK6pRfGS5?9$MQv1!e`J$*v&d0_k zA%hPi%dc#0teMP3SVdWFUf&LF+B?@@qzmO!$wDz_>Io1YVH>u2=Hr1*e4q1n?SCRy@9M7)Il&uKHOfZCPgw;rkdDvUz3w z%) zB}@?eiVdlQz`>8CP?5wFI59!)^OASkx4854d+(B~{;t{?q(OdlG9E>y8Sp=gd3oe6 zPSWyRuV~JCX^3GipyXg}Ing}6nWDg4vy zqQ#JU5d_oHj4fAjT_!bf0LWOcQ?c7HAfXUYr2L}B!F!2rN`L@rNPQe41*$9fzp7(F ztd_0=`QVb8vp8+}A`sM4&rwNKDUZQP>6P4z0pzdeF__I}#2B2bd$ysjr@8x@`T{Xc z+8a3d^5-tQ2h?cgSOB${-yM9lm?C7kW8-_OkO)63T8nNeF~;P@az

)c`K(f@{DG$knjFKGS^ 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. + * + * Authors: + * Matthias Krauser + */ + +package emailserverbee + +import ( + "github.com/flashmob/go-guerrilla" + "github.com/flashmob/go-guerrilla/backends" + "github.com/flashmob/go-guerrilla/mail" + + //"github.com/flashmob/go-guerrilla/response" + + "github.com/muesli/beehive/bees" +) + +// EmailServerBee is a Bee that starts an SMTP server and fires events for incoming +// Emails. +type EmailServerBee struct { + bees.Bee + + address string + allowedHosts []string + hostname string + maxSize int64 + timeout int + maxClients int + startTLSOn bool + tlsAlwaysOn bool + privateKeyFile string + publicKeyFile string + + eventChan chan bees.Event +} + +func (mod *EmailServerBee) mailProcessor() func() backends.Decorator { + return func() backends.Decorator { + return func(p backends.Processor) backends.Processor { + return backends.ProcessWith( + func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) { + if task == backends.TaskSaveMail { + + recipients := make([]string, len(e.RcptTo)) + + for index, rcpt := range e.RcptTo { + recipients[index] = rcpt.String() + } + + /*headers := make([]string, len(e.Header)) + + i := 0 + for name, value := range e.Header { + headers[i] = name + ": " + value + i += 1 + }*/ + + // create events and send it to cin + ev := bees.Event{ + Bee: mod.Name(), + Options: []bees.Placeholder{ + { + Name: "sender", + Type: "string", + Value: e.MailFrom.String(), + }, + { + Name: "remote_ip", + Type: "string", + Value: e.RemoteIP, + }, + { + Name: "recipients", + Type: "[]string", + Value: recipients, + }, + { + Name: "subject", + Type: "string", + Value: e.Subject, + }, + { + Name: "tls", + Type: "boolean", + Value: e.TLS, + }, + { + Name: "headers", + Type: "[]string", + Value: e.Header, + }, + { + Name: "body", + Type: "string", + Value: e.Data.String(), + }, + }, + } + + mod.eventChan <- ev + } + + return p.Process(e, task) + }, + ) + } + } +} + +// Run executes the Bee's event loop. +func (mod *EmailServerBee) Run(cin chan bees.Event) { + mod.eventChan = cin + + // see https://github.com/flashmob/go-guerrilla/wiki/Using-as-a-package + + cfg := &guerrilla.AppConfig{ + AllowedHosts: mod.allowedHosts, + // LogLevel controls the lowest level we log. + // "info", "debug", "error", "panic". Default "info" + LogLevel: "info", + } + + tc := guerrilla.ServerTLSConfig{ + StartTLSOn: mod.startTLSOn, + AlwaysOn: mod.tlsAlwaysOn, + PrivateKeyFile: mod.privateKeyFile, + PublicKeyFile: mod.publicKeyFile, + } + sc := guerrilla.ServerConfig{ + IsEnabled: true, + Hostname: mod.hostname, + ListenInterface: mod.address, + MaxSize: mod.maxSize, + Timeout: mod.timeout, + MaxClients: mod.maxClients, + TLS: tc, + } + cfg.Servers = append(cfg.Servers, sc) + + bcfg := backends.BackendConfig{ + "save_process": "HeadersParser|Header|Hasher|Beehive", + "log_received_mails": true, + } + cfg.BackendConfig = bcfg + + d := guerrilla.Daemon{Config: cfg} + d.AddProcessor("Beehive", mod.mailProcessor()) + + err := d.Start() + if err != nil { + mod.LogFatal("Error starting SMTP-Server", err) + } + + select { + case <-mod.SigChan: + d.Shutdown() + return + } +} + +// ReloadOptions parses the config options and initializes the Bee. +func (mod *EmailServerBee) ReloadOptions(options bees.BeeOptions) { + mod.SetOptions(options) + + options.Bind("address", &mod.address) + options.Bind("allowedHosts", &mod.allowedHosts) + options.Bind("startTLSOn", &mod.startTLSOn) + options.Bind("tlsAlwaysOn", &mod.tlsAlwaysOn) + options.Bind("privateKeyFile", &mod.privateKeyFile) + options.Bind("publicKeyFile", &mod.publicKeyFile) + options.Bind("hostname", &mod.hostname) + options.Bind("maxSize", &mod.maxSize) + options.Bind("timeout", &mod.timeout) + options.Bind("maxClient", &mod.maxClients) +} diff --git a/bees/emailserverbee/emailserverbeefactory.go b/bees/emailserverbee/emailserverbeefactory.go new file mode 100644 index 00000000..bcb4dc26 --- /dev/null +++ b/bees/emailserverbee/emailserverbeefactory.go @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2014-2017 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * Matthias Krauser + */ + +package emailserverbee + +import ( + "os" + + "github.com/muesli/beehive/bees" +) + +// EmailServerBeeFactory is a factory for EmailServerBees. +type EmailServerBeeFactory struct { + bees.BeeFactory +} + +// New returns a new Bee instance configured with the supplied options. +func (factory *EmailServerBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { + bee := EmailServerBee{ + Bee: bees.NewBee(name, factory.ID(), description, options), + } + bee.ReloadOptions(options) + + return &bee +} + +// ID returns the ID of this Bee. +func (factory *EmailServerBeeFactory) ID() string { + return "emailserverbee" +} + +// Name returns the name of this Bee. +func (factory *EmailServerBeeFactory) Name() string { + return "Email Server" +} + +// Description returns the description of this Bee. +func (factory *EmailServerBeeFactory) Description() string { + return "Receives incoming Emails via SMTP(S) and reacts to them" +} + +// Image returns the filename of an image for this Bee. +func (factory *EmailServerBeeFactory) Image() string { + return factory.ID() + ".png" +} + +// LogoColor returns the preferred logo background color (used by the admin interface). +func (factory *EmailServerBeeFactory) LogoColor() string { + return "#00bbff" +} + +// Options returns the options available to configure this Bee. +func (factory *EmailServerBeeFactory) Options() []bees.BeeOptionDescriptor { + hostname, _ := os.Hostname() + + opts := []bees.BeeOptionDescriptor{ + { + Name: "address", + Description: "Which addr to listen on, eg: 0.0.0.0:25", + Type: "address", + Mandatory: true, + }, + { + Name: "allowedHosts", + Description: "AllowedHosts lists which hosts to accept email for.", + Type: "[]string", + Default: hostname, + Mandatory: false, + }, + { + Name: "hostname", + Description: "Hostname will be used in the server's reply to HELO/EHLO. If TLS enabled make sure that the Hostname matches the cert.", + Default: hostname, + Type: "string", + Mandatory: false, + }, + { + Name: "maxSize", + Description: "MaxSize is the maximum size of an email that will be accepted for delivery.", + Default: 1024 * 1024 * 10, + Type: "int64", + Mandatory: false, + }, + { + Name: "timeout", + Description: "Timeout specifies the connection timeout in seconds. Defaults to 30", + Default: 30, + Type: "int", + Mandatory: false, + }, + { + Name: "maxClients", + Description: "MaxClients controls how many maxiumum clients we can handle at once.", + Default: 10, + Type: "int", + Mandatory: false, + }, + { + Name: "startTLSOn", + Description: "StartTLSOn should we offer STARTTLS command. Cert must be valid.", + Default: false, + Type: "bool", + Mandatory: false, + }, + { + Name: "tlsAlwaysOn", + Description: "TLSAlwaysOn run this server as a pure TLS server, i.e. SMTPS", + Default: false, + Type: "bool", + Mandatory: false, + }, + { + Name: "privateKeyFile", + Description: "PrivateKeyFile path to cert private key in PEM format", + Default: "", + Type: "string", + Mandatory: false, + }, + { + Name: "publicKeyFile", + Description: "PublicKeyFile path to cert (public key) chain in PEM format.", + Default: "", + Type: "string", + Mandatory: false, + }, + } + return opts +} + +// Events describes the available events provided by this Bee. +func (factory *EmailServerBeeFactory) Events() []bees.EventDescriptor { + events := []bees.EventDescriptor{ + { + Namespace: factory.Name(), + Name: "received", + Description: "An Email was received", + Options: []bees.PlaceholderDescriptor{ + { + Name: "sender", + Description: "The Email sender", + Type: "string", + }, + { + Name: "remote_ip", + Description: "The IP from the remote-server", + Type: "string", + }, + { + Name: "recipients", + Description: "The recipients", + Type: "[]string", + }, + { + Name: "subject", + Description: "The Email subject", + Type: "string", + }, + { + Name: "tls", + Description: "Indicates, if the mail was transmitted using tls", + Type: "bool", + }, + { + Name: "headers", + Description: "The Email headers", + Type: "[]string", + }, + { + Name: "body", + Description: "The raw Email body", + Type: "string", + }, + }, + }, + } + return events +} + +func init() { + f := EmailServerBeeFactory{} + bees.RegisterFactory(&f) +} diff --git a/bees/events.go b/bees/events.go index c42e5595..bf303474 100644 --- a/bees/events.go +++ b/bees/events.go @@ -23,6 +23,7 @@ package bees import log "github.com/sirupsen/logrus" import "runtime/debug" +import "fmt" // An Event describes an event including its parameters. type Event struct { @@ -51,7 +52,8 @@ func handleEvents() { log.Println() log.Println("Event received:", event.Bee, "/", event.Name, "-", GetEventDescriptor(&event).Description) for _, v := range event.Options { - log.Println("\tOptions:", v) + vv := truncateString(fmt.Sprintln(v), 1000) + log.Println("\tOptions:", vv) } go func() { @@ -65,3 +67,14 @@ func handleEvents() { }() } } + +func truncateString(str string, num int) string { + bnoden := str + if len(str) > num { + if num > 3 { + num -= 3 + } + bnoden = str[0:num] + "... (" + fmt.Sprint(len(str)-num) + " more characters)" + } + return bnoden +} diff --git a/go.mod b/go.mod index ea862ed8..605617bc 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/PuerkitoBio/goquery v1.5.0 github.com/akashshinde/go_cricket v0.0.0-20170322162016-01a06b2c3f22 github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83 // indirect + github.com/asaskevich/EventBus v0.0.0-20180315140547-d46933a94f05 // indirect github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 // indirect github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1 @@ -19,6 +20,7 @@ require ( github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect github.com/emicklei/go-restful v2.9.3+incompatible github.com/fatih/set v0.2.1 // indirect + github.com/flashmob/go-guerrilla v0.0.0-20190502151606-07043ae76e81 github.com/fluffle/goirc v1.0.1 github.com/fsnotify/fsnotify v1.4.7 github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 // indirect diff --git a/go.sum b/go.sum index 845165bf..fcef4a80 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRy github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83 h1:ukTLOeMC0aVxbJWVg6hOsVJ0VPIo8w++PbNsze/pqF8= github.com/araddon/dateparse v0.0.0-20190426192744-0d74ffceef83/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= +github.com/asaskevich/EventBus v0.0.0-20180315140547-d46933a94f05 h1:Shem5lRG4gJyrrg9YMIl7dOQazyWCq0Daz4LjompZ28= +github.com/asaskevich/EventBus v0.0.0-20180315140547-d46933a94f05/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII= github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 h1:ekDALXAVvY/Ub1UtNta3inKQwZ/jMB/zpOtD8rAYh78= github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330/go.mod h1:nH+k0SvAt3HeiYyOlJpLLv1HG1p7KWP7qU9QPp2/pCo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= @@ -39,6 +41,8 @@ github.com/emicklei/go-restful v2.9.3+incompatible h1:2OwhVdhtzYUp5P5wuGsVDPagKS github.com/emicklei/go-restful v2.9.3+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA= github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= +github.com/flashmob/go-guerrilla v0.0.0-20190502151606-07043ae76e81 h1:45gIhMM+MtaoDrhBYFCSjYiQDNr9r6NNyGqzwPfKGco= +github.com/flashmob/go-guerrilla v0.0.0-20190502151606-07043ae76e81/go.mod h1:ZT9TRggRsSY4ZVndoyx8TRUxi3tM/nOYtKWKDX94H0I= github.com/fluffle/goirc v1.0.1 h1:YHBfWIXSFgABz8dbijvOIKucFejnbHdk78+r2z/6B/Q= github.com/fluffle/goirc v1.0.1/go.mod h1:bm91JNJ5r070PbWm8uG9UDcy9GJxvB6fmVuHDttWwR4= github.com/fluffle/golog v1.0.2/go.mod h1:TKZoUh/MNb9worAhWP158Ol0TXc5EfhMJK/qB/7j+Ko= diff --git a/hives.go b/hives.go index 6d290bcc..782ea303 100644 --- a/hives.go +++ b/hives.go @@ -29,6 +29,7 @@ import ( _ "github.com/muesli/beehive/bees/devrantbee" _ "github.com/muesli/beehive/bees/efabee" _ "github.com/muesli/beehive/bees/emailbee" + _ "github.com/muesli/beehive/bees/emailserverbee" _ "github.com/muesli/beehive/bees/execbee" _ "github.com/muesli/beehive/bees/facebookbee" _ "github.com/muesli/beehive/bees/fsnotifybee" From 618423881bf8d2734a97e84bb387cbf31b6170c7 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sun, 5 May 2019 10:54:08 +0200 Subject: [PATCH 19/30] Bumped smolder dependency to @master --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 605617bc..ecee8020 100644 --- a/go.mod +++ b/go.mod @@ -61,7 +61,7 @@ require ( github.com/muesli/go-pkg-xmlx v0.0.0-20151201012946-76f54ee73233 // indirect github.com/muesli/go.hue v0.0.0-20140802040715-8aefcc693caf github.com/muesli/goefa v0.0.0-20180507204150-08d8ee2555d2 - github.com/muesli/smolder v0.0.0-20181113094957-e6752d792454 + github.com/muesli/smolder v0.0.0-20190505085143-9c21fc7135ee github.com/nlopes/slack v0.5.0 github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7 diff --git a/go.sum b/go.sum index fcef4a80..2fc78766 100644 --- a/go.sum +++ b/go.sum @@ -141,6 +141,8 @@ github.com/muesli/goefa v0.0.0-20180507204150-08d8ee2555d2 h1:A0yDQZg4PVcBvzH9IY github.com/muesli/goefa v0.0.0-20180507204150-08d8ee2555d2/go.mod h1:cbhVWIL28EF8sTH71/qsU+TeEEmYC33MES0J7Ul0TFI= github.com/muesli/smolder v0.0.0-20181113094957-e6752d792454 h1:M4sPHl3GXRrWLL4gQHzjf0pIiy3LyqCHqNfbGWNA7OI= github.com/muesli/smolder v0.0.0-20181113094957-e6752d792454/go.mod h1:vBtOJlVGxLheofBQdKVQGaG40aJQUwr6Lh4PVliqebY= +github.com/muesli/smolder v0.0.0-20190505085143-9c21fc7135ee h1:owp+45s+e2xN1fFUHIld1X+2ZtHSUjXKkgEr7iwq7u8= +github.com/muesli/smolder v0.0.0-20190505085143-9c21fc7135ee/go.mod h1:vBtOJlVGxLheofBQdKVQGaG40aJQUwr6Lh4PVliqebY= github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0= github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= From 9032deae3a66d84b72e3f197341955c5ca227abb Mon Sep 17 00:00:00 2001 From: Sergio Rubio Date: Mon, 6 May 2019 17:14:16 +0000 Subject: [PATCH 20/30] Add timestamp to telegram events (#153) --- bees/telegrambee/telegrambee.go | 6 ++++++ bees/telegrambee/telegrambeefactory.go | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/bees/telegrambee/telegrambee.go b/bees/telegrambee/telegrambee.go index 8da2adfd..0b0de9f0 100644 --- a/bees/telegrambee/telegrambee.go +++ b/bees/telegrambee/telegrambee.go @@ -28,6 +28,7 @@ import ( "os" "strconv" "strings" + "time" telegram "github.com/go-telegram-bot-api/telegram-bot-api" @@ -116,6 +117,11 @@ func (mod *TelegramBee) Run(eventChan chan bees.Event) { Type: "string", Value: strconv.Itoa(update.Message.From.ID), }, + { + Name: "timestamp", + Type: "timestamp", + Value: time.Now(), + }, }, } eventChan <- ev diff --git a/bees/telegrambee/telegrambeefactory.go b/bees/telegrambee/telegrambeefactory.go index 2ba13478..b7ee0f6a 100644 --- a/bees/telegrambee/telegrambeefactory.go +++ b/bees/telegrambee/telegrambeefactory.go @@ -99,6 +99,11 @@ func (factory *TelegramBeeFactory) Events() []bees.EventDescriptor { Description: "User ID sending the message", Type: "string", }, + { + Name: "timestamp", + Description: "Timestamp", + Type: "timestamp", + }, }, }, } From abc4184d8af0493975789dc3d52a5e997442e437 Mon Sep 17 00:00:00 2001 From: Matthias Krauser Date: Mon, 6 May 2019 23:14:23 +0200 Subject: [PATCH 21/30] Added missing event name --- bees/emailserverbee/emailserverbee.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bees/emailserverbee/emailserverbee.go b/bees/emailserverbee/emailserverbee.go index 94fddd72..f3391ff7 100644 --- a/bees/emailserverbee/emailserverbee.go +++ b/bees/emailserverbee/emailserverbee.go @@ -72,7 +72,8 @@ func (mod *EmailServerBee) mailProcessor() func() backends.Decorator { // create events and send it to cin ev := bees.Event{ - Bee: mod.Name(), + Bee: mod.Name(), + Name: "received", Options: []bees.Placeholder{ { Name: "sender", From f0a1a852daa72a297ce389d331c1fc8886d8e769 Mon Sep 17 00:00:00 2001 From: Matthias Krauser Date: Tue, 7 May 2019 14:30:45 +0200 Subject: [PATCH 22/30] Add JSON-Function for Templates (#242) --- templatehelper/templatehelper.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/templatehelper/templatehelper.go b/templatehelper/templatehelper.go index e4eb1b2c..0142d677 100644 --- a/templatehelper/templatehelper.go +++ b/templatehelper/templatehelper.go @@ -22,6 +22,8 @@ package templatehelper import ( + "encoding/json" + htmlTemplate "html/template" "regexp" "strings" "text/template" @@ -30,6 +32,10 @@ import ( // FuncMap contains all the common string helpers var ( FuncMap = template.FuncMap{ + "JSON": func(values ...interface{}) htmlTemplate.JS { + json, _ := json.Marshal(values) + return htmlTemplate.JS(json) + }, "Left": func(values ...interface{}) string { return values[0].(string)[:values[1].(int)] }, From 9137dbb2b5410752dd77fd7a7280e42ebd2f76ae Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 7 May 2019 22:07:42 +0200 Subject: [PATCH 23/30] Added Docker example with CANONICAL_URL env var --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 066c3868..29c05474 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,10 @@ the `-bind` and `-canonicalurl` parameters. For example: beehive -bind "192.168.0.1:8181" -canonicalurl "http://192.168.0.1:8181" +or + + docker run --name beehive -d -e CANONICAL_URL="http://192.168.0.1:8181" -p 8181:8181 fribbledom/beehive + ## Development Need help? Want to hack on your own Hives? Join us on IRC (irc://freenode.net/#beehive) or [Gitter](https://gitter.im/the_beehive/Lobby). From 7715804daf4f3b02b9be0cfe2dc2ceab4ac8bb0e Mon Sep 17 00:00:00 2001 From: CalmBit Date: Wed, 8 May 2019 18:03:46 -0400 Subject: [PATCH 24/30] Discord Bee (#239) --- assets/bees/discordbee.png | Bin 0 -> 5330 bytes bees/discordbee/discordbee.go | 153 ++++++++++++++++++++++++++ bees/discordbee/discordbeefactory.go | 158 +++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 3 + hives.go | 1 + 6 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 assets/bees/discordbee.png create mode 100644 bees/discordbee/discordbee.go create mode 100644 bees/discordbee/discordbeefactory.go diff --git a/assets/bees/discordbee.png b/assets/bees/discordbee.png new file mode 100644 index 0000000000000000000000000000000000000000..5d3bbb9afc72d15920ff4ec47ffe17037d6cc843 GIT binary patch literal 5330 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 literal 0 HcmV?d00001 diff --git a/bees/discordbee/discordbee.go b/bees/discordbee/discordbee.go new file mode 100644 index 00000000..75ed3bfe --- /dev/null +++ b/bees/discordbee/discordbee.go @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2019 CalmBit + * 2014-2019 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * CalmBit + * Christian Muehlhaeuser + */ + +// Package discordbee is a bee for sending and receiving messages with Discord +// servers. +package discordbee + +import ( + "github.com/bwmarrin/discordgo" + "github.com/muesli/beehive/bees" +) + +// DiscordBee is a bee for sending and receiving messages with Discord +// servers. +type DiscordBee struct { + bees.Bee + + apiToken string + triggerPhrase string + eventChan chan bees.Event + discord *discordgo.Session +} + +// Run executes the Bee's event loop. +func (mod *DiscordBee) Run(eventChan chan bees.Event) { + mod.eventChan = eventChan + + mod.LogDebugf("Starting discord bee with apiToken %s", mod.apiToken) + d, err := discordgo.New("Bot " + mod.apiToken) + if err != nil { + mod.LogFatal("Unable to start discordbee! Error: ", err) + } + mod.discord = d + mod.LogDebugf("Done!") + + mod.discord.AddHandler(mod.isReady) + mod.discord.AddHandler(mod.onSend) + + err = mod.discord.Open() + + if err != nil { + mod.LogFatal("Error opening websocket: ", err) + } + + defer mod.discord.Close() + + select { + case <-mod.SigChan: + return + } +} + +func (mod *DiscordBee) isReady(s *discordgo.Session, event *discordgo.Ready) { + // Default status - once the persistance layer exists: + // TODO: Persist status, use it here. + mod.LogDebugf("isReady called") + s.UpdateStatus(0, "with bees") +} + +func (mod *DiscordBee) onSend(s *discordgo.Session, event *discordgo.MessageCreate) { + if event.Author.ID == s.State.User.ID { + return + } + + c, e := s.Channel(event.ChannelID) + if e != nil { + mod.LogErrorf("Unable to find channel with id %s", event.ChannelID) + return + } + ev := bees.Event{ + Bee: mod.Name(), + Name: "message", + Options: []bees.Placeholder{ + { + Name: "contents", + Type: "string", + Value: event.Content, + }, + { + Name: "username", + Type: "string", + Value: event.Author.String(), + }, + { + Name: "channel_id", + Type: "string", + Value: event.ChannelID, + }, + { + Name: "channel_name", + Type: "string", + Value: c.Name, + }, + }, + } + mod.eventChan <- ev + +} + +// Action triggers the action passed to it. +func (mod *DiscordBee) Action(action bees.Action) []bees.Placeholder { + outs := []bees.Placeholder{} + switch action.Name { + case "send": + var contents string + var channelID string + action.Options.Bind("contents", &contents) + action.Options.Bind("channel_id", &channelID) + + _, err := mod.discord.ChannelMessageSend(channelID, contents) + if err != nil { + mod.LogErrorf("Unable to send message: %v", err) + } + case "set_status": + var status string + action.Options.Bind("status", &status) + + err := mod.discord.UpdateStatus(0, status) + if err != nil { + mod.LogErrorf("Unable to update status: %v", err) + } + default: + panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) + } + return outs +} + +// ReloadOptions parses the config options and initializes the Bee. +func (mod *DiscordBee) ReloadOptions(options bees.BeeOptions) { + mod.SetOptions(options) + + options.Bind("api_token", &mod.apiToken) + options.Bind("trigger_phrase", &mod.triggerPhrase) +} diff --git a/bees/discordbee/discordbeefactory.go b/bees/discordbee/discordbeefactory.go new file mode 100644 index 00000000..c3f2da30 --- /dev/null +++ b/bees/discordbee/discordbeefactory.go @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2019 CalmBit + * 2014-2019 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * CalmBit + * Christian Muehlhaeuser + */ + +package discordbee + +import ( + "github.com/muesli/beehive/bees" +) + +// DiscordBeeFactory is a factory for DiscordBees. +type DiscordBeeFactory struct { + bees.BeeFactory +} + +// New returns a new Bee instance configured with the supplied options. +func (factory *DiscordBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { + bee := DiscordBee{ + Bee: bees.NewBee(name, factory.ID(), description, options), + } + bee.ReloadOptions(options) + + return &bee +} + +// ID returns the ID of this Bee. +func (factory *DiscordBeeFactory) ID() string { + return "discordbee" +} + +// Name returns the name of this Bee. +func (factory *DiscordBeeFactory) Name() string { + return "Discord" +} + +// Description returns the description of this Bee. +func (factory *DiscordBeeFactory) Description() string { + return "Connects to Discord as a bot!" +} + +// Image returns the filename of an image for this Bee. +func (factory *DiscordBeeFactory) Image() string { + return factory.ID() + ".png" +} + +// LogoColor returns the preferred logo background color (used by the admin interface). +func (factory *DiscordBeeFactory) LogoColor() string { + return "#7289DA" +} + +// Options returns the options available to configure this Bee. +func (factory *DiscordBeeFactory) Options() []bees.BeeOptionDescriptor { + opts := []bees.BeeOptionDescriptor{ + { + Name: "api_token", + Description: "The Discord API token for your bot", + Type: "string", + Mandatory: true, + }, + } + return opts +} + +// Events describes the available events provided by this Bee. +func (factory *DiscordBeeFactory) Events() []bees.EventDescriptor { + events := []bees.EventDescriptor{ + { + Namespace: factory.Name(), + Name: "message", + Description: "is triggered when a message has been received", + Options: []bees.PlaceholderDescriptor{ + { + Name: "contents", + Description: "Contents of the message", + Type: "string", + }, + { + Name: "username", + Description: "Name of the user who sent the message", + Type: "string", + }, + { + Name: "channel_id", + Description: "ID of the channel the message was sent in", + Type: "string", + }, + { + Name: "channel_name", + Description: "Name of the channel the message was sent in", + Type: "string", + }, + }, + }, + } + return events +} + +// Actions describes the available actions provided by this Bee. +func (factory *DiscordBeeFactory) Actions() []bees.ActionDescriptor { + actions := []bees.ActionDescriptor{ + { + Namespace: factory.Name(), + Name: "send", + Description: "Sends a general message to the specified channel", + Options: []bees.PlaceholderDescriptor{ + { + Name: "contents", + Description: "Contents of the message", + Type: "string", + Mandatory: true, + }, + { + Name: "channel_id", + Description: "ID of the channel to post in", + Type: "string", + Mandatory: true, + }, + }, + }, + { + Namespace: factory.Name(), + Name: "set_status", + Description: "Sets the status of the discord bot", + Options: []bees.PlaceholderDescriptor{ + { + Name: "status", + Description: "Playing {status}", + Type: "string", + Mandatory: true, + }, + }, + }, + } + return actions +} + +func init() { + f := DiscordBeeFactory{} + bees.RegisterFactory(&f) +} diff --git a/go.mod b/go.mod index ecee8020..692a0da4 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/asaskevich/EventBus v0.0.0-20180315140547-d46933a94f05 // indirect github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 // indirect github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d + github.com/bwmarrin/discordgo v0.19.0 github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1 github.com/deckarep/gosx-notifier v0.0.0-20180201035817-e127226297fb github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect @@ -34,7 +35,6 @@ require ( github.com/google/go-github v17.0.0+incompatible github.com/google/go-querystring v1.0.0 // indirect github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect - github.com/gorilla/websocket v1.4.0 // indirect github.com/guelfey/go.dbus v0.0.0-20131113121618-f6a3a2366cc3 github.com/huandu/facebook v2.3.1+incompatible github.com/jacobsa/go-serial v0.0.0-20180131005756-15cf729a72d4 diff --git a/go.sum b/go.sum index 2fc78766..292a50b0 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLM github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d h1:28xWzPQ9bdGxKAAwQpZipZZ9Xz8kQcgMPF9cZnvMeuI= github.com/briandowns/openweathermap v0.0.0-20180804155945-5f41b7c9d92d/go.mod h1:8g1Bgq9PbPpXIA3sdlWmWf2JpiWGJee/O4Q+ddYO6+k= +github.com/bwmarrin/discordgo v0.19.0 h1:kMED/DB0NR1QhRcalb85w0Cu3Ep2OrGAqZH1R5awQiY= +github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1 h1:hXakhQtPnXH839q1pBl/GqfTSchqE+R5Fqn98Iu7UQM= github.com/carlosdp/twiliogo v0.0.0-20161027183705-b26045ebb9d1/go.mod h1:pAxCBpjl/0JxYZlWGP/Dyi8f/LQSCQD2WAsG/iNzqQ8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= @@ -197,6 +199,7 @@ github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQ github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= diff --git a/hives.go b/hives.go index 782ea303..a120b575 100644 --- a/hives.go +++ b/hives.go @@ -27,6 +27,7 @@ import ( _ "github.com/muesli/beehive/bees/cricketbee" _ "github.com/muesli/beehive/bees/cronbee" _ "github.com/muesli/beehive/bees/devrantbee" + _ "github.com/muesli/beehive/bees/discordbee" _ "github.com/muesli/beehive/bees/efabee" _ "github.com/muesli/beehive/bees/emailbee" _ "github.com/muesli/beehive/bees/emailserverbee" From d28e8b251c1048009dc63aab1a63da23e299602b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 9 May 2019 07:55:43 +0200 Subject: [PATCH 25/30] Disable notification & serial hives on non-Linux unices --- hives.go | 1 - hives_linux.go | 28 ++++++++++++++++++++++++++++ hives_osx.go | 1 + hives_unix.go | 1 - 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 hives_linux.go diff --git a/hives.go b/hives.go index a120b575..f3bdd05e 100644 --- a/hives.go +++ b/hives.go @@ -52,7 +52,6 @@ import ( _ "github.com/muesli/beehive/bees/pushoverbee" _ "github.com/muesli/beehive/bees/rssbee" _ "github.com/muesli/beehive/bees/s3bee" - _ "github.com/muesli/beehive/bees/serialbee" _ "github.com/muesli/beehive/bees/simplepushbee" _ "github.com/muesli/beehive/bees/slackbee" _ "github.com/muesli/beehive/bees/socketbee" diff --git a/hives_linux.go b/hives_linux.go new file mode 100644 index 00000000..230a6dde --- /dev/null +++ b/hives_linux.go @@ -0,0 +1,28 @@ +// +build linux + +/* + * Copyright (C) 2014-2017 Christian Muehlhaeuser + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * Authors: + * Christian Muehlhaeuser + */ + +package main + +import ( + _ "github.com/muesli/beehive/bees/notificationbee" + _ "github.com/muesli/beehive/bees/serialbee" +) diff --git a/hives_osx.go b/hives_osx.go index ad829fe8..91100cde 100644 --- a/hives_osx.go +++ b/hives_osx.go @@ -24,4 +24,5 @@ package main import ( _ "github.com/muesli/beehive/bees/notificationbee" + _ "github.com/muesli/beehive/bees/serialbee" ) diff --git a/hives_unix.go b/hives_unix.go index 4b1422ac..ea37f828 100644 --- a/hives_unix.go +++ b/hives_unix.go @@ -23,5 +23,4 @@ package main import ( - _ "github.com/muesli/beehive/bees/notificationbee" ) From 7b75d900020327a9a7e416edaffa80c7fda72298 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Mon, 13 May 2019 08:41:13 +0200 Subject: [PATCH 26/30] Fixed typos in a few bees --- bees/githubbee/githubbeefactory.go | 2 +- bees/gitterbee/gitterbeefactory.go | 2 +- bees/openweathermapbee/openweathermapbeefactory.go | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bees/githubbee/githubbeefactory.go b/bees/githubbee/githubbeefactory.go index 34229d56..26781d9a 100644 --- a/bees/githubbee/githubbeefactory.go +++ b/bees/githubbee/githubbeefactory.go @@ -61,7 +61,7 @@ func (factory *GitHubBeeFactory) Image() string { return factory.ID() + ".png" } -// LogoColor returns ther preferred logo background color (used by the admin interface). +// LogoColor returns the preferred logo background color (used by the admin interface). func (factory *GitHubBeeFactory) LogoColor() string { return "#6098d0" } diff --git a/bees/gitterbee/gitterbeefactory.go b/bees/gitterbee/gitterbeefactory.go index 9be35ca1..7d55f254 100644 --- a/bees/gitterbee/gitterbeefactory.go +++ b/bees/gitterbee/gitterbeefactory.go @@ -61,7 +61,7 @@ func (factory *GitterBeeFactory) Image() string { return factory.ID() + ".png" } -// LogoColor returns ther preferred logo background color (used by the admin interface). +// LogoColor returns the preferred logo background color (used by the admin interface). func (factory *GitterBeeFactory) LogoColor() string { return "#994499" } diff --git a/bees/openweathermapbee/openweathermapbeefactory.go b/bees/openweathermapbee/openweathermapbeefactory.go index 0dc35247..3da9cd24 100644 --- a/bees/openweathermapbee/openweathermapbeefactory.go +++ b/bees/openweathermapbee/openweathermapbeefactory.go @@ -70,21 +70,21 @@ func (factory *OpenweathermapBeeFactory) Options() []bees.BeeOptionDescriptor { opts := []bees.BeeOptionDescriptor{ { Name: "unit", - Description: "Your prefered unit", + Description: "Your preferred unit", Type: "string", Default: "c", // celcius -> The right one Mandatory: true, }, { Name: "language", - Description: "Your prefered language", + Description: "Your preferred language", Type: "string", Default: "en", // english Mandatory: true, }, { Name: "key", - Description: "Your openweathermap api key", + Description: "Your OpenWeatherMap api key", Type: "string", Mandatory: true, }, From 439811667129ea26ed21e37800f590c036ccaea2 Mon Sep 17 00:00:00 2001 From: Mark Jung Date: Wed, 15 May 2019 11:44:35 -0500 Subject: [PATCH 27/30] fixed comments added myself as author, replaced hardcoded address, changed error handling, changed event name --- bees/youtubebee/youtube.go | 82 ++++++++++++++++--------------- bees/youtubebee/youtubefactory.go | 2 +- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/bees/youtubebee/youtube.go b/bees/youtubebee/youtube.go index cac96b54..5d9718cd 100644 --- a/bees/youtubebee/youtube.go +++ b/bees/youtubebee/youtube.go @@ -18,6 +18,7 @@ * Authors: * Daniel 'grindhold' Brendle * Christian Muehlhaeuser + * Mark Jung */ // Package youtubebee is a Bee for tunneling Youtube push notifications. @@ -48,6 +49,39 @@ type YoutubeBee struct { eventChan chan bees.Event } +type Feed struct { + XMLName xml.Name `xml:"feed"` + Text string `xml:",chardata"` + Yt string `xml:"yt,attr"` + Xmlns string `xml:"xmlns,attr"` + Link []struct { + Text string `xml:",chardata"` + Rel string `xml:"rel,attr"` + Href string `xml:"href,attr"` + } `xml:"link"` + Title string `xml:"title"` + Updated string `xml:"updated"` + Entry struct { + Text string `xml:",chardata"` + ID string `xml:"id"` + VideoId string `xml:"videoId"` + ChannelId string `xml:"channelId"` + Title string `xml:"title"` + Link struct { + Text string `xml:",chardata"` + Rel string `xml:"rel,attr"` + Href string `xml:"href,attr"` + } `xml:"link"` + Author struct { + Text string `xml:",chardata"` + Name string `xml:"name"` + URI string `xml:"uri"` + } `xml:"author"` + Published string `xml:"published"` + Updated string `xml:"updated"` + } `xml:"entry"` +} + // Run executes the Bee's event loop. func (mod *YoutubeBee) Run(eventChan chan bees.Event) { mod.eventChan = eventChan @@ -55,10 +89,9 @@ func (mod *YoutubeBee) Run(eventChan chan bees.Event) { channelURLTokens := strings.Split(mod.url, "/") channelID := channelURLTokens[len(channelURLTokens)-1] topic := "https://www.youtube.com/xml/feeds/videos.xml?channel_id=" + channelID - hardcodedAddress := "0.0.0.0:5050" // should be mod.addr - srv := &http.Server{Addr: hardcodedAddress, Handler: mod} - l, err := net.Listen("tcp", hardcodedAddress) + srv := &http.Server{Addr: mod.addr, Handler: mod} + l, err := net.Listen("tcp", mod.addr) if err != nil { mod.LogErrorf("Can't listen on %s", mod.addr) return @@ -82,10 +115,10 @@ func (mod *YoutubeBee) Run(eventChan chan bees.Event) { r.Header.Add("Content-Type", "application/x-www-form-urlencoded") r.Header.Add("Content-Length", strconv.Itoa(len(data.Encode()))) - resp, _ := client.Do(r) - for resp.Status != "202 Accepted" { - // redo until success - resp, _ = client.Do(r) + _, err = client.Do(r) + if err != nil { + mod.LogErrorf("Can't subscribe to youtube channel") + return } }() @@ -101,39 +134,8 @@ func (mod *YoutubeBee) ServeHTTP(w http.ResponseWriter, req *http.Request) { ev := bees.Event{ Bee: mod.Name(), } - ev.Name = "push" - type Feed struct { - XMLName xml.Name `xml:"feed"` - Text string `xml:",chardata"` - Yt string `xml:"yt,attr"` - Xmlns string `xml:"xmlns,attr"` - Link []struct { - Text string `xml:",chardata"` - Rel string `xml:"rel,attr"` - Href string `xml:"href,attr"` - } `xml:"link"` - Title string `xml:"title"` - Updated string `xml:"updated"` - Entry struct { - Text string `xml:",chardata"` - ID string `xml:"id"` - VideoId string `xml:"videoId"` - ChannelId string `xml:"channelId"` - Title string `xml:"title"` - Link struct { - Text string `xml:",chardata"` - Rel string `xml:"rel,attr"` - Href string `xml:"href,attr"` - } `xml:"link"` - Author struct { - Text string `xml:",chardata"` - Name string `xml:"name"` - URI string `xml:"uri"` - } `xml:"author"` - Published string `xml:"published"` - Updated string `xml:"updated"` - } `xml:"entry"` - } + ev.Name = "notification" + var feed Feed body, err := ioutil.ReadAll(req.Body) if err != nil { diff --git a/bees/youtubebee/youtubefactory.go b/bees/youtubebee/youtubefactory.go index e0d81892..4e1d931d 100644 --- a/bees/youtubebee/youtubefactory.go +++ b/bees/youtubebee/youtubefactory.go @@ -88,7 +88,7 @@ func (factory *YoutubeBeeFactory) Events() []bees.EventDescriptor { events := []bees.EventDescriptor{ { Namespace: factory.Name(), - Name: "push", + Name: "notification", Description: "A push notification was sent by the Youtube channel", Options: []bees.PlaceholderDescriptor{ { From def2f4272da335a028dd00a1f4ca494809503ecd Mon Sep 17 00:00:00 2001 From: Mark Jung Date: Wed, 15 May 2019 11:48:46 -0500 Subject: [PATCH 28/30] forgot to fix indentation. oops. --- bees/youtubebee/youtube.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bees/youtubebee/youtube.go b/bees/youtubebee/youtube.go index 5d9718cd..91490dd2 100644 --- a/bees/youtubebee/youtube.go +++ b/bees/youtubebee/youtube.go @@ -13,7 +13,7 @@ * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * along with this program. If not, see . * * Authors: * Daniel 'grindhold' Brendle From e1a471f59d311f7106f210222dbd2b246ebf476e Mon Sep 17 00:00:00 2001 From: Mark-Jung Date: Sun, 26 May 2019 13:46:21 -0500 Subject: [PATCH 29/30] debugging --- bees/youtubebee/youtube.go | 13 +++++++++---- bees/youtubebee/youtubefactory.go | 22 ++++++++++++++++++++-- hives.go | 2 +- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/bees/youtubebee/youtube.go b/bees/youtubebee/youtube.go index 91490dd2..cae8074b 100644 --- a/bees/youtubebee/youtube.go +++ b/bees/youtubebee/youtube.go @@ -90,8 +90,10 @@ func (mod *YoutubeBee) Run(eventChan chan bees.Event) { channelID := channelURLTokens[len(channelURLTokens)-1] topic := "https://www.youtube.com/xml/feeds/videos.xml?channel_id=" + channelID - srv := &http.Server{Addr: mod.addr, Handler: mod} - l, err := net.Listen("tcp", mod.addr) + local := "http://localhost:5050/" + + srv := &http.Server{Addr: local, Handler: mod} // SWAP BEFORE COMMIT + l, err := net.Listen("tcp", local) // SWAP BEFORE COMMIT if err != nil { mod.LogErrorf("Can't listen on %s", mod.addr) return @@ -134,8 +136,6 @@ func (mod *YoutubeBee) ServeHTTP(w http.ResponseWriter, req *http.Request) { ev := bees.Event{ Bee: mod.Name(), } - ev.Name = "notification" - var feed Feed body, err := ioutil.ReadAll(req.Body) if err != nil { @@ -143,6 +143,11 @@ func (mod *YoutubeBee) ServeHTTP(w http.ResponseWriter, req *http.Request) { http.Error(w, "can't read body", http.StatusBadRequest) } xml.Unmarshal([]byte(body), &feed) + if feed.Entry.Updated == feed.Entry.Published { + ev.Name = "new_video" + } else { + ev.Name = "change_video" + } ev.Options.SetValue("channelUrl", "string", feed.Entry.Author.URI) ev.Options.SetValue("vidUrl", "string", feed.Entry.Link.Href) diff --git a/bees/youtubebee/youtubefactory.go b/bees/youtubebee/youtubefactory.go index 4e1d931d..709eca74 100644 --- a/bees/youtubebee/youtubefactory.go +++ b/bees/youtubebee/youtubefactory.go @@ -16,6 +16,7 @@ * * Authors: * Christian Muehlhaeuser + * Mark Jung */ package youtubebee @@ -88,8 +89,25 @@ func (factory *YoutubeBeeFactory) Events() []bees.EventDescriptor { events := []bees.EventDescriptor{ { Namespace: factory.Name(), - Name: "notification", - Description: "A push notification was sent by the Youtube channel", + Name: "new_video", + Description: "The channel posted a new video", + Options: []bees.PlaceholderDescriptor{ + { + Name: "channelUrl", + Description: "The url of the channel push notification was sent from", + Type: "url", + }, + { + Name: "vidUrl", + Description: "The url of the video relevant to the push notification", + Type: "url", + }, + }, + }, + { + Namespace: factory.Name(), + Name: "change_video", + Description: "The channel updated a video", Options: []bees.PlaceholderDescriptor{ { Name: "channelUrl", diff --git a/hives.go b/hives.go index f3bdd05e..7a43a06a 100644 --- a/hives.go +++ b/hives.go @@ -64,5 +64,5 @@ import ( _ "github.com/muesli/beehive/bees/twiliobee" _ "github.com/muesli/beehive/bees/twitterbee" _ "github.com/muesli/beehive/bees/webbee" - _ "github.com/muesli/beehive/bees/youtubebee" + //_ "github.com/muesli/beehive/bees/youtubebee" ) From a5a10186043264be3e0e7ba22671398e4740faa5 Mon Sep 17 00:00:00 2001 From: Mark-Jung Date: Mon, 27 May 2019 21:12:36 -0500 Subject: [PATCH 30/30] specified incoming events to two Parsed the monolithic event into two: new_video and change_video --- bees/youtubebee/youtube.go | 18 ++++++++++-------- hives.go | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/bees/youtubebee/youtube.go b/bees/youtubebee/youtube.go index cae8074b..7ca38a76 100644 --- a/bees/youtubebee/youtube.go +++ b/bees/youtubebee/youtube.go @@ -25,6 +25,7 @@ package youtubebee import ( + "time" "encoding/xml" "fmt" "io/ioutil" @@ -90,10 +91,8 @@ func (mod *YoutubeBee) Run(eventChan chan bees.Event) { channelID := channelURLTokens[len(channelURLTokens)-1] topic := "https://www.youtube.com/xml/feeds/videos.xml?channel_id=" + channelID - local := "http://localhost:5050/" - - srv := &http.Server{Addr: local, Handler: mod} // SWAP BEFORE COMMIT - l, err := net.Listen("tcp", local) // SWAP BEFORE COMMIT + srv := &http.Server{Addr: mod.addr, Handler: mod} + l, err := net.Listen("tcp", mod.addr) if err != nil { mod.LogErrorf("Can't listen on %s", mod.addr) return @@ -111,7 +110,7 @@ func (mod *YoutubeBee) Run(eventChan chan bees.Event) { data := url.Values{} data.Set("hub.mode", "subscribe") data.Set("hub.topic", topic) - data.Set("hub.callback", mod.addr) + data.Set("hub.callback", "mod.addr") client := &http.Client{} r, _ := http.NewRequest("POST", subscriptionLink, strings.NewReader(data.Encode())) // URL-encoded payload r.Header.Add("Content-Type", "application/x-www-form-urlencoded") @@ -121,8 +120,7 @@ func (mod *YoutubeBee) Run(eventChan chan bees.Event) { if err != nil { mod.LogErrorf("Can't subscribe to youtube channel") return - } - + } }() select { @@ -143,7 +141,11 @@ func (mod *YoutubeBee) ServeHTTP(w http.ResponseWriter, req *http.Request) { http.Error(w, "can't read body", http.StatusBadRequest) } xml.Unmarshal([]byte(body), &feed) - if feed.Entry.Updated == feed.Entry.Published { + updatedTime, _ := time.Parse(time.RFC3339, feed.Entry.Updated) + publishedTime, _ := time.Parse(time.RFC3339, feed.Entry.Published) + diff := updatedTime.Sub(publishedTime) + // give the channel a minute window - for new videos, update and publish times aren't exact. + if diff.Minutes() <= 5 { ev.Name = "new_video" } else { ev.Name = "change_video" diff --git a/hives.go b/hives.go index 8a96ae49..1bfc23d2 100644 --- a/hives.go +++ b/hives.go @@ -65,5 +65,5 @@ import ( _ "github.com/muesli/beehive/bees/twiliobee" _ "github.com/muesli/beehive/bees/twitterbee" _ "github.com/muesli/beehive/bees/webbee" - //_ "github.com/muesli/beehive/bees/youtubebee" + _ "github.com/muesli/beehive/bees/youtubebee" )