diff options
Diffstat (limited to 'vendor/github.com/matterbridge/gozulipbot/bot.go')
-rw-r--r-- | vendor/github.com/matterbridge/gozulipbot/bot.go | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/vendor/github.com/matterbridge/gozulipbot/bot.go b/vendor/github.com/matterbridge/gozulipbot/bot.go new file mode 100644 index 00000000..24bc8768 --- /dev/null +++ b/vendor/github.com/matterbridge/gozulipbot/bot.go @@ -0,0 +1,256 @@ +package gozulipbot + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strings" + "time" +) + +type Bot struct { + APIKey string + APIURL string + Email string + Queues []*Queue + Streams []string + Client Doer + Backoff time.Duration + Retries int64 +} + +type Doer interface { + Do(*http.Request) (*http.Response, error) +} + +// Init adds an http client to an existing bot struct. +func (b *Bot) Init() *Bot { + b.Client = &http.Client{} + return b +} + +// GetStreamList gets the raw http response when requesting all public streams. +func (b *Bot) GetStreamList() (*http.Response, error) { + req, err := b.constructRequest("GET", "streams", "") + if err != nil { + return nil, err + } + + return b.Client.Do(req) +} + +type StreamJSON struct { + Msg string `json:"msg"` + Streams []struct { + StreamID int `json:"stream_id"` + InviteOnly bool `json:"invite_only"` + Description string `json:"description"` + Name string `json:"name"` + } `json:"streams"` + Result string `json:"result"` +} + +// GetStreams returns a list of all public streams +func (b *Bot) GetStreams() ([]string, error) { + resp, err := b.GetStreamList() + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var sj StreamJSON + err = json.Unmarshal(body, &sj) + if err != nil { + return nil, err + } + + var streams []string + for _, s := range sj.Streams { + streams = append(streams, s.Name) + } + + return streams, nil +} + +// GetStreams returns a list of all public streams +func (b *Bot) GetRawStreams() (StreamJSON, error) { + var sj StreamJSON + resp, err := b.GetStreamList() + if err != nil { + return sj, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return sj, err + } + + err = json.Unmarshal(body, &sj) + if err != nil { + return sj, err + } + return sj, nil +} + +// Subscribe will set the bot to receive messages from the given streams. +// If no streams are given, it will subscribe the bot to the streams in the bot struct. +func (b *Bot) Subscribe(streams []string) (*http.Response, error) { + if streams == nil { + streams = b.Streams + } + + var toSubStreams []map[string]string + for _, name := range streams { + toSubStreams = append(toSubStreams, map[string]string{"name": name}) + } + + bodyBts, err := json.Marshal(toSubStreams) + if err != nil { + return nil, err + } + + body := "subscriptions=" + string(bodyBts) + + req, err := b.constructRequest("POST", "users/me/subscriptions", body) + if err != nil { + return nil, err + } + + return b.Client.Do(req) +} + +// Unsubscribe will remove the bot from the given streams. +// If no streams are given, nothing will happen and the function will error. +func (b *Bot) Unsubscribe(streams []string) (*http.Response, error) { + if len(streams) == 0 { + return nil, fmt.Errorf("No streams were provided") + } + + body := `delete=["` + strings.Join(streams, `","`) + `"]` + + req, err := b.constructRequest("PATCH", "users/me/subscriptions", body) + if err != nil { + return nil, err + } + + return b.Client.Do(req) +} + +func (b *Bot) ListSubscriptions() (*http.Response, error) { + req, err := b.constructRequest("GET", "users/me/subscriptions", "") + if err != nil { + return nil, err + } + + return b.Client.Do(req) +} + +type EventType string + +const ( + Messages EventType = "messages" + Subscriptions EventType = "subscriptions" + RealmUser EventType = "realm_user" + Pointer EventType = "pointer" +) + +type Narrow string + +const ( + NarrowPrivate Narrow = `[["is", "private"]]` + NarrowAt Narrow = `[["is", "mentioned"]]` +) + +// RegisterEvents adds a queue to the bot. It includes the EventTypes and +// Narrow given. If neither is given, it will default to all Messages. +func (b *Bot) RegisterEvents(ets []EventType, n Narrow) (*Queue, error) { + resp, err := b.RawRegisterEvents(ets, n) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + q := &Queue{Bot: b} + err = json.Unmarshal(body, q) + if err != nil { + return nil, err + } + + if q.LastEventID < q.MaxMessageID { + q.LastEventID = q.MaxMessageID + } + + b.Queues = append(b.Queues, q) + + return q, nil +} + +func (b *Bot) RegisterAll() (*Queue, error) { + return b.RegisterEvents(nil, "") +} + +func (b *Bot) RegisterAt() (*Queue, error) { + return b.RegisterEvents(nil, NarrowAt) +} + +func (b *Bot) RegisterPrivate() (*Queue, error) { + return b.RegisterEvents(nil, NarrowPrivate) +} + +func (b *Bot) RegisterSubscriptions() (*Queue, error) { + events := []EventType{Subscriptions} + return b.RegisterEvents(events, "") +} + +// RawRegisterEvents tells Zulip to include message events in the bots events queue. +// Passing nil as the slice of EventType will default to receiving Messages +func (b *Bot) RawRegisterEvents(ets []EventType, n Narrow) (*http.Response, error) { + // default to Messages if no EventTypes given + query := `event_types=["message"]` + + if len(ets) != 0 { + query = `event_types=["` + for i, s := range ets { + query += fmt.Sprintf("%s", s) + if i != len(ets)-1 { + query += `", "` + } + } + query += `"]` + } + + if n != "" { + query += fmt.Sprintf("&narrow=%s", n) + } + query += fmt.Sprintf("&all_public_streams=true") + req, err := b.constructRequest("POST", "register", query) + if err != nil { + return nil, err + } + + return b.Client.Do(req) +} + +// constructRequest makes a zulip request and ensures the proper headers are set. +func (b *Bot) constructRequest(method, endpoint, body string) (*http.Request, error) { + url := b.APIURL + endpoint + req, err := http.NewRequest(method, url, strings.NewReader(body)) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.SetBasicAuth(b.Email, b.APIKey) + + return req, nil +} |