diff options
-rw-r--r-- | .golangci.yaml | 2 | ||||
-rw-r--r-- | .travis.yml | 4 | ||||
-rw-r--r-- | README.md | 50 | ||||
-rw-r--r-- | bridge/slack/handlers.go | 3 | ||||
-rw-r--r-- | bridge/slack/helpers.go | 7 | ||||
-rw-r--r-- | bridge/slack/slack.go | 6 | ||||
-rw-r--r-- | bridge/zulip/zulip.go | 25 | ||||
-rw-r--r-- | gateway/gateway.go | 6 | ||||
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | go.sum | 4 | ||||
-rw-r--r-- | vendor/github.com/matterbridge/gozulipbot/queue.go | 57 | ||||
-rw-r--r-- | vendor/modules.txt | 2 |
12 files changed, 138 insertions, 30 deletions
diff --git a/.golangci.yaml b/.golangci.yaml index acdc612e..64c7f4c2 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -132,6 +132,7 @@ linters-settings: # ifElseChain regexpMust singleCaseSwitch sloppyLen switchTrue typeSwitchVar underef # unlambda unslice rangeValCopy defaultCaseOrder]; # all checks list: https://github.com/go-critic/checkers + # disabled for now - hugeParam enabled-checks: - appendAssign - assignOp @@ -147,7 +148,6 @@ linters-settings: - dupSubExpr - elseif - emptyFallthrough - - hugeParam - ifElseChain - importShadow - indexAlloc diff --git a/.travis.yml b/.travis.yml index 4dd02ee5..9830d88c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ git: env: global: - GOOS=linux GOARCH=amd64 - - GOLANGCI_VERSION="v1.12.3" + - GOLANGCI_VERSION="v1.14.0" matrix: # It's ok if our code fails on unstable development versions of Go. @@ -54,4 +54,4 @@ deploy: file: ci/deploy.json user: 42wim key: - secure: "CeXXe6JOmt7HYR81MdWLua0ltQHhDdkIeRGBFbgd7hkb1wi8eF9DgpAcQrTso8NIlHNZmSAP46uhFgsRvkuezzX0ygalZ7DCJyAyn3sAMEh+UQSHV1WGThRehTtidqRGjetzsIGSwdrJOWil+XTfbO1Z8DGzfakhSuAZka8CM4BAoe3YeP9rYK8h+84x0GHfczvsLtXZ3mWLvQuwe4pK6+ItBCUg0ae7O7ZUpWHy0xQQkkWztY/6RAzXfaG7DuGjIw+20fhx3WOXRNpHCtZ6Bc3qERCpk0s1HhlQWlrN9wDaFTBWYwlvSnNgvxxMbNXJ6RrRJ0l0bA7FUswYwyroxhzrGLdzWDg8dHaQkypocngdalfhpsnoO9j3ApJhomUFJ3UoEq5nOGRUrKn8MPi+dP0zE4kNQ3e4VNa1ufNrvfpWolMg3xh8OXuhQdD5wIM5zFAbRJLqWSCVAjPq4DDPecmvXBOlIial7oa312lN5qnBnUjvAcxszZ+FUyDHT1Grxzna4tMwxY9obPzZUzm7359AOCCwIQFVB8GLqD2nwIstcXS0zGRz+fhviPipHuBa02q5bGUZwmkvrSNab0s8Jo7pCrel2Rz3nWPKaiCfq2WjbW1CLheSMkOQrjsdUd1hhbqNWFPUjJPInTc77NAKCfm5runv5uyowRLh4NNd0sI="
\ No newline at end of file + secure: "CeXXe6JOmt7HYR81MdWLua0ltQHhDdkIeRGBFbgd7hkb1wi8eF9DgpAcQrTso8NIlHNZmSAP46uhFgsRvkuezzX0ygalZ7DCJyAyn3sAMEh+UQSHV1WGThRehTtidqRGjetzsIGSwdrJOWil+XTfbO1Z8DGzfakhSuAZka8CM4BAoe3YeP9rYK8h+84x0GHfczvsLtXZ3mWLvQuwe4pK6+ItBCUg0ae7O7ZUpWHy0xQQkkWztY/6RAzXfaG7DuGjIw+20fhx3WOXRNpHCtZ6Bc3qERCpk0s1HhlQWlrN9wDaFTBWYwlvSnNgvxxMbNXJ6RrRJ0l0bA7FUswYwyroxhzrGLdzWDg8dHaQkypocngdalfhpsnoO9j3ApJhomUFJ3UoEq5nOGRUrKn8MPi+dP0zE4kNQ3e4VNa1ufNrvfpWolMg3xh8OXuhQdD5wIM5zFAbRJLqWSCVAjPq4DDPecmvXBOlIial7oa312lN5qnBnUjvAcxszZ+FUyDHT1Grxzna4tMwxY9obPzZUzm7359AOCCwIQFVB8GLqD2nwIstcXS0zGRz+fhviPipHuBa02q5bGUZwmkvrSNab0s8Jo7pCrel2Rz3nWPKaiCfq2WjbW1CLheSMkOQrjsdUd1hhbqNWFPUjJPInTc77NAKCfm5runv5uyowRLh4NNd0sI=" @@ -15,6 +15,7 @@ [Matrix][mb-matrix] | [Slack][mb-slack] | [Mattermost][mb-mattermost] | + [Rocket.Chat][mb-rocketchat] | [XMPP][mb-xmpp] | [Twitch][mb-twitch] | [Zulip][mb-zulip] | @@ -34,8 +35,10 @@ ### Table of Contents * [Features](https://github.com/42wim/matterbridge/wiki/Features) + * [Natively supported](#natively-supported) + * [3rd party via matterbridge api](#3rd-party-via-matterbridge-api) * [API](#API) - * [Requirements](#requirements) + * [Chat with us](#chat-with-us) * [Screenshots](https://github.com/42wim/matterbridge/wiki/) * [Installing](#installing) * [Binaries](#binaries) @@ -61,18 +64,8 @@ * [Private groups](https://github.com/42wim/matterbridge/wiki/Features#private-groups) * [API](https://github.com/42wim/matterbridge/wiki/Features#api) -### API -The API is very basic at the moment. -More info and examples on the [wiki](https://github.com/42wim/matterbridge/wiki/Api). +### Natively supported -Used by at least 3 projects. Feel free to make a PR to add your project to this list. - -* [MatterLink](https://github.com/elytra/MatterLink) (Matterbridge link for Minecraft Server chat) -* [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot) -* [Mattereddit](https://github.com/bonehurtingjuice/mattereddit) (Reddit chat support) - -## Requirements -Accounts to one of the supported bridges * [Mattermost](https://github.com/mattermost/mattermost-server/) 4.x, 5.x * [IRC](http://www.mirc.com/servers.html) * [XMPP](https://xmpp.org) @@ -88,6 +81,37 @@ Accounts to one of the supported bridges * [Ssh-chat](https://github.com/shazow/ssh-chat) * [Zulip](https://zulipchat.com) +### 3rd party via matterbridge api +* [Minecraft](https://github.com/elytra/MatterLink) +* [Reddit](https://github.com/bonehurtingjuice/mattereddit) +* [Facebook messenger](https://github.com/VictorNine/fbridge) + +### API +The API is very basic at the moment. +More info and examples on the [wiki](https://github.com/42wim/matterbridge/wiki/Api). + +Used by the projects below. Feel free to make a PR to add your project to this list. + +* [MatterLink](https://github.com/elytra/MatterLink) (Matterbridge link for Minecraft Server chat) +* [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot) +* [Mattereddit](https://github.com/bonehurtingjuice/mattereddit) (Reddit chat support) +* [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support) + +## Chat with us + +Questions or want to test on your favorite platform? Join below: + +* [Gitter][mb-gitter] +* [IRC][mb-irc] +* [Discord][mb-discord] +* [Matrix][mb-matrix] +* [Slack][mb-slack] +* [Mattermost][mb-mattermost] +* [Rocket.Chat][mb-rocketchat] +* [XMPP][mb-xmpp] +* [Twitch][mb-twitch] +* [Zulip][mb-zulip] + ## Screenshots See https://github.com/42wim/matterbridge/wiki @@ -222,6 +246,7 @@ Want to tip ? * [matterlink](https://github.com/elytra/MatterLink) * [mattermost-plugin](https://github.com/matterbridge/mattermost-plugin) - Run matterbridge as a plugin in mattermost * [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot) +* [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support) ## Articles * [matterbridge on kubernetes](https://medium.freecodecamp.org/using-kubernetes-to-deploy-a-chat-gateway-or-when-technology-works-like-its-supposed-to-a169a8cd69a3) @@ -260,6 +285,7 @@ Matterbridge wouldn't exist without these libraries: [mb-matrix]: https://riot.im/app/#/room/#matterbridge:matrix.org [mb-slack]: https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA [mb-mattermost]: https://framateam.org/signup_user_complete/?id=tfqm33ggop8x3qgu4boeieta6e + [mb-rocketchat]: https://open.rocket.chat/channel/matterbridge [mb-xmpp]: https://inverse.chat/ [mb-twitch]: https://www.twitch.tv/matterbridge [mb-zulip]: https://matterbridge.zulipchat.com/register/ diff --git a/bridge/slack/handlers.go b/bridge/slack/handlers.go index e013b830..5cfcc42b 100644 --- a/bridge/slack/handlers.go +++ b/bridge/slack/handlers.go @@ -192,6 +192,9 @@ func (b *Bslack) handleMessageEvent(ev *slack.MessageEvent) (*config.Message, er // This is probably a webhook we couldn't resolve. return nil, fmt.Errorf("message handling resulted in an empty bot message (probably an incoming webhook we couldn't resolve): %#v", ev) } + if ev.SubMessage != nil { + return nil, fmt.Errorf("message handling resulted in an empty message: %#v with submessage %#v", ev, ev.SubMessage) + } return nil, fmt.Errorf("message handling resulted in an empty message: %#v", ev) } return rmsg, nil diff --git a/bridge/slack/helpers.go b/bridge/slack/helpers.go index 9959d4fa..4d191c0d 100644 --- a/bridge/slack/helpers.go +++ b/bridge/slack/helpers.go @@ -254,6 +254,13 @@ func (b *Bslack) populateReceivedMessage(ev *slack.MessageEvent) (*config.Messag } } + // For edits, only submessage has thread ts. + // Ensures edits to threaded messages maintain their prefix hint on the + // unthreaded end. + if ev.SubMessage != nil { + rmsg.ParentID = ev.SubMessage.ThreadTimestamp + } + if err = b.populateMessageWithUserInfo(ev, rmsg); err != nil { return nil, err } diff --git a/bridge/slack/slack.go b/bridge/slack/slack.go index 001b1268..1685c4fc 100644 --- a/bridge/slack/slack.go +++ b/bridge/slack/slack.go @@ -293,6 +293,12 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) { return "", err } + // Handle prefix hint for unthreaded messages. + if msg.ParentID == "msg-parent-not-found" { + msg.ParentID = "" + msg.Text = fmt.Sprintf("[thread]: %s", msg.Text) + } + // Handle message deletions. if handled, err = b.deleteMessage(&msg, channelInfo); handled { return msg.ID, err diff --git a/bridge/zulip/zulip.go b/bridge/zulip/zulip.go index 88832d36..3c6c7ec6 100644 --- a/bridge/zulip/zulip.go +++ b/bridge/zulip/zulip.go @@ -100,7 +100,30 @@ func (b *Bzulip) getChannel(id int) string { func (b *Bzulip) handleQueue() error { for { - messages, _ := b.q.GetEvents() + messages, err := b.q.GetEvents() + switch err { + case gzb.BackoffError: + time.Sleep(time.Second * 5) + case gzb.NoJSONError: + b.Log.Error("Response wasn't JSON, server down or restarting? sleeping 10 seconds") + time.Sleep(time.Second * 10) + case gzb.BadEventQueueError: + b.Log.Info("got a bad event queue id error, reconnecting") + b.bot.Queues = nil + b.q, err = b.bot.RegisterAll() + if err != nil { + b.Log.Errorf("reconnecting failed: %s. Sleeping 10 seconds", err) + time.Sleep(time.Second * 10) + continue + } + case gzb.HeartbeatError: + b.Log.Debug("heartbeat received.") + default: + b.Log.Debugf("receiving error: %#v", err) + } + if err != nil { + continue + } for _, m := range messages { b.Log.Debugf("== Receiving %#v", m) // ignore our own messages diff --git a/gateway/gateway.go b/gateway/gateway.go index 6fe19963..72d0831b 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -398,6 +398,12 @@ func (gw *Gateway) SendMessage(origmsg config.Message, dest *bridge.Bridge, chan msg.ParentID = canonicalParentMsgID } + // if the parentID is still empty and we have a parentID set in the original message + // this means that we didn't find it in the cache so set it "msg-parent-not-found" + if msg.ParentID == "" && origmsg.ParentID != "" { + msg.ParentID = "msg-parent-not-found" + } + // if we are using mattermost plugin account, send messages to MattermostPlugin channel // that can be picked up by the mattermost matterbridge plugin if dest.Account == "mattermost.plugin" { @@ -28,7 +28,7 @@ require ( github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea - github.com/matterbridge/gozulipbot v0.0.0-20180507190239-b6bb12d33544 + github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 github.com/mattermost/mattermost-server v5.5.0+incompatible github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect @@ -76,8 +76,8 @@ github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 h1:KzDEcy8eDb github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q= github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea h1:kaADGqpK4gGO2BpzEyJrBxq2Jc57Rsar4i2EUxcACUc= github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea/go.mod h1:+jWeaaUtXQbBRdKYWfjW6JDDYiI2XXE+3NnTjW5kg8g= -github.com/matterbridge/gozulipbot v0.0.0-20180507190239-b6bb12d33544 h1:A8lLG3DAu75B5jITHs9z4JBmU6oCq1WiUNnDAmqKCZc= -github.com/matterbridge/gozulipbot v0.0.0-20180507190239-b6bb12d33544/go.mod h1:yAjnZ34DuDyPHMPHHjOsTk/FefW4JJjoMMCGt/8uuQA= +github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 h1:fLhwXtWGtfTgZVxHG1lcKjv+re7dRwyyuYFNu69xdho= +github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18/go.mod h1:yAjnZ34DuDyPHMPHHjOsTk/FefW4JJjoMMCGt/8uuQA= github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 h1:R/MgM/eUyRBQx2FiH6JVmXck8PaAuKfe2M1tWIzW7nE= github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61/go.mod h1:iXGEotOvwI1R1SjLxRc+BF5rUORTMtE0iMZBT2lxqAU= github.com/mattermost/mattermost-server v5.5.0+incompatible h1:0wcLGgYtd+YImtLDPf2AOfpBHxbU4suATx+6XKw1XbU= diff --git a/vendor/github.com/matterbridge/gozulipbot/queue.go b/vendor/github.com/matterbridge/gozulipbot/queue.go index 9a37a8e7..d6e910ee 100644 --- a/vendor/github.com/matterbridge/gozulipbot/queue.go +++ b/vendor/github.com/matterbridge/gozulipbot/queue.go @@ -1,6 +1,7 @@ package gozulipbot import ( + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -13,10 +14,12 @@ import ( ) var ( - HeartbeatError = fmt.Errorf("EventMessage is a heartbeat") - UnauthorizedError = fmt.Errorf("Request is unauthorized") - BackoffError = fmt.Errorf("Too many requests") - UnknownError = fmt.Errorf("Error was unknown") + HeartbeatError = fmt.Errorf("EventMessage is a heartbeat") + UnauthorizedError = fmt.Errorf("Request is unauthorized") + BackoffError = fmt.Errorf("Too many requests") + BadEventQueueError = fmt.Errorf("BAD_EVENT_QUEUE_ID error") + UnknownError = fmt.Errorf("Error was unknown") + NoJSONError = fmt.Errorf("No JSON in body found") ) type Queue struct { @@ -26,6 +29,13 @@ type Queue struct { Bot *Bot `json:"-"` } +type QueueError struct { + Code string `json:"code"` + Msg string `json:"msg"` + ID string `json:"queue_id"` + Result string `json:"result"` +} + func (q *Queue) EventsChan() (chan EventMessage, func()) { end := false endFunc := func() { @@ -131,18 +141,25 @@ func (q *Queue) GetEvents() ([]EventMessage, error) { } defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + switch { case resp.StatusCode == 429: return nil, BackoffError case resp.StatusCode == 403: return nil, UnauthorizedError case resp.StatusCode >= 400: - return nil, UnknownError - } - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err + if bytes.HasPrefix(body, []byte("<")) { + return nil, NoJSONError + } + qErr, err := q.ParseError(body) + if err != nil || qErr == nil { + return nil, UnknownError + } + return nil, BadEventQueueError } msgs, err := q.ParseEventMessages(body) @@ -170,6 +187,26 @@ func (q *Queue) RawGetEvents() (*http.Response, error) { return q.Bot.Client.Do(req) } +func (q *Queue) ParseError(rawEventResponse []byte) (*QueueError, error) { + rawResponse := map[string]json.RawMessage{} + err := json.Unmarshal(rawEventResponse, &rawResponse) + if err != nil { + return nil, err + } + + if _, ok := rawResponse["code"]; ok { + var qErr QueueError + err = json.Unmarshal(rawEventResponse, &qErr) + if err != nil { + return nil, err + } + if qErr.Code == "BAD_EVENT_QUEUE_ID" { + return &qErr, nil + } + } + return nil, nil +} + func (q *Queue) ParseEventMessages(rawEventResponse []byte) ([]EventMessage, error) { rawResponse := map[string]json.RawMessage{} err := json.Unmarshal(rawEventResponse, &rawResponse) diff --git a/vendor/modules.txt b/vendor/modules.txt index a2e4a3da..8c8160b6 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -78,7 +78,7 @@ github.com/matterbridge/Rocket.Chat.Go.SDK/rest github.com/matterbridge/go-xmpp # github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea github.com/matterbridge/gomatrix -# github.com/matterbridge/gozulipbot v0.0.0-20180507190239-b6bb12d33544 +# github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 github.com/matterbridge/gozulipbot # github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 github.com/matterbridge/logrus-prefixed-formatter |