Compare commits

...

83 Commits

Author SHA1 Message Date
Wim
6c442e239d Release v1.17.4 (#1112) 2020-04-21 23:53:51 +02:00
Wim
eaf92fca4d Add an ID cache (discord). Fixes #1106 (#1111)
When a webhook "edits" a message, it does this by deleting the message
and creating a new one with the new content.

On creation of this new message, we'll get another ID then already is
know by the gateway in its id cache. So we add it in our own cache and
replace it whenever we want to edit/delete it again.
2020-04-21 23:35:46 +02:00
Wim
06b7bad714 Lowercase account names. Fixes #1108 (#1110) 2020-04-21 20:42:11 +02:00
Wim
19eec2ed03 Update Rhymen/go-whatsapp. Fixes #1107 (#1109) 2020-04-21 19:55:47 +02:00
Wim
d99c54343a Remove panics and retry polling on failure (msteams). Fixes #1104 (#1105) 2020-04-21 19:29:24 +02:00
Wim
308a110000 Bump version 2020-04-19 17:23:17 +02:00
Wim
4f406b2ce6 Release v1.17.3 (#1103) 2020-04-19 17:13:58 +02:00
Wim
e564c555d7 Clip too long messages on 3000 length (slack). Fixes #1081 (#1102) 2020-04-19 17:00:11 +02:00
Wim
f7ec9af9e8 Add extra space before colon in attachments (irc). Fixes #1089 (#1101) 2020-04-19 16:45:53 +02:00
Wim
4d93a774ce Ignore non-critical errors (whatsapp). Fixes #1094 (#1100) 2020-04-19 13:45:35 +02:00
Wim
2595dd30bf Update matterbridge/go-xmpp. Fixes #1097 (#1099) 2020-04-19 01:06:44 +02:00
Wim
9190365289 Add JoinDelay option (irc). Fixes #1084 (#1098) 2020-04-19 00:46:35 +02:00
Wim
57794b3b9f Prevent image/message looping (slack). Fixes #1088 (#1096)
Also check for our matterbridge ID in Blocks set in SubMessages.
2020-04-18 22:30:49 +02:00
ldruschk
3c36f651be Fix the behavior of ShowTopicChange and SyncTopic (#1086)
Currently, the "topic_change" events are ignored if both, 
ShowTopicChange and SyncTopic are set, and forwarded otherwise. 

This pull requests changes the behavior such that the events are 
only forwarded if one of those two config options is set to true 
and ignored otherwise.
2020-04-18 22:05:27 +02:00
ldruschk
8e6ddadba2 Relay Joins/Topic changes in RocketChat bridge (#1085)
This pull request properly sets the events EventJoinLeave and EventTopicChange for messages from the RocketChat bridge and drops messages which are neither one of those events nor plain messages.
2020-04-18 22:00:35 +02:00
Wim
8a87a71927 Update matterbridge/go-xmpp to add PEP-0030 support (#1095) 2020-04-18 20:58:55 +02:00
Qais Patankar
0047e6f523 Sort README bridge and library links (#1093) 2020-04-18 18:12:16 +02:00
Alexander
7183095a28 Implement User Avatar spoofing of XMPP users (#1090)
* Implement User Avatar spoofing of XMPP users
2020-04-16 22:16:25 +02:00
Wim
13c90893c7 Update matterbridge/Rocket.Chat.Go.SDK (#1087) 2020-04-16 21:48:53 +02:00
Wim
976fbcd07f Bump version 2020-04-09 23:03:45 +02:00
Wim
d97b077e85 Release v1.17.2 (#1080) 2020-04-09 22:54:51 +02:00
Wim
8950575bfb Update Rhymen/go-whatsapp vendor and whatsapp version (#1078) 2020-04-09 22:30:08 +02:00
Jerry Heiselman
11fc4c286f Clarify terminology used in mapping group chat IDs to channels in config (#1079)
* Clarify embedded docs for channel specification

Should help with #1072
2020-04-08 23:52:38 +02:00
Wim
8d08e348a9 Reset start timestamp on reconnect (whatsapp). Fixes #1059 (#1064) 2020-03-31 23:26:53 +02:00
Wim
a18807f19e Update matterbridge/go-xmpp to add xmpp avatar support (#1070) 2020-03-29 17:35:40 +02:00
Wim
29f658fd3c Use DebugWriter after upstream changes (xmpp) 2020-03-29 15:03:24 +02:00
Wim
a30bb8fed0 Sync matterbridge/go-xmpp with upstream 2020-03-29 15:03:24 +02:00
Wim
092ca1cd67 Update vendor slack-go/slack (#1068) 2020-03-28 23:50:47 +01:00
Wim
0df2539641 Use upstream yaegashi/msgraph.go/msauth (msteams) (#1067) 2020-03-28 23:44:49 +01:00
Wim
0f2d8a599c Update vendor d5/tengo (#1066) 2020-03-28 23:41:35 +01:00
Wim
54b3143a1d Bump version 2020-03-28 00:29:41 +01:00
Wim
148f7d2a91 Release v1.17.1 (#1063) 2020-03-28 00:18:29 +01:00
Wim
1aa662f763 Update client version whatsapp. Fixes #1061 (#1062)
See https://github.com/Rhymen/go-whatsapp/issues/305
2020-03-28 00:18:03 +01:00
Alex Wigen
0b86b88de7 Remove build dependencies from final docker image (multistage build) (#1057)
This multistage build takes the resulting image size down from 346MB to
90MB.
2020-03-22 22:55:29 +01:00
Qais Patankar
98033b1ba7 Don't transmit typing events from ourselves (slack/discord) (#1056) 2020-03-22 18:39:11 +01:00
Qais Patankar
2b7eab629d Add support for build tags (#1054)
By default all bridges are available.

You can turn off certain bridges by providing
e.g. "nodiscord" as a build tag.

    go build -tags nomsteams,noapi
2020-03-22 18:34:14 +01:00
Wim
0e4973e15c Exclude gateway/bridgemap from linting (#1055) 2020-03-22 14:35:48 +01:00
Qais Patankar
af0acf0dae Strip extra info from emotes (discord) (#1052) 2020-03-22 14:16:31 +01:00
Qais Patankar
76e5fe5a87 Update vendor yaegashi/msgraph.go to v0.1.2 (2) 2020-03-22 00:02:48 +01:00
Qais Patankar
802c80f40c Update vendor yaegashi/msgraph.go to v0.1.2 (1) 2020-03-22 00:02:48 +01:00
Wim
a51c5bd905 Add more msteams docs (#1051) 2020-03-21 23:30:22 +01:00
Wim
8c68556f52 Bump version 2020-03-21 22:51:22 +01:00
Wim
cca1ea2404 Release v1.17.0 (#1050) 2020-03-21 21:33:16 +01:00
Wim
281016a501 Fix duplicate separator on empty description/url (discord). Fixes #1008 (#1035)
Make this work for all possible cases.
Add tests
2020-03-21 21:27:17 +01:00
Qais Patankar
d4acdf2f89 Use blocks not attachments (slack) (#1048)
This removes the extra space below messages, as shown in
https://user-images.githubusercontent.com/923242/77235190-a3359980-6bab-11ea-8b7b-697d730ae5c1.png
2020-03-21 21:03:12 +01:00
Qais Patankar
0951e75c85 Fix #1039: messages sent to Slack being synced back (#1046)
This is a regression from https://github.com/42wim/matterbridge/pull/581#issuecomment-562937576

Behaves the same as 95190f11bf
2020-03-21 20:12:30 +01:00
Jakub
6b017b226a Support JSON and YAML config formats (#1045)
Signed-off-by: Jakub Sokołowski <jakub@status.im>
2020-03-18 23:20:29 +01:00
Qais Patankar
9e3bd7398c Fix #1027: warning when handling inbound webhooks (discord) (#1044) 2020-03-18 23:12:48 +01:00
Qais Patankar
79f764c7a8 Refactor webhook permission checks 2020-03-18 23:10:47 +01:00
Qais Patankar
b5dc4353fb Fix #1040: spotty webhook permission verification 2020-03-18 23:10:47 +01:00
Qais Patankar
2fbac73c29 Ignore ConnectingEvent (slack) (#1041) 2020-03-18 23:03:20 +01:00
burner1024
6616d105d1 Add markdownv2 mode for telegram documentation, see #1032 (#1037) 2020-03-18 22:43:11 +01:00
Wim
6b4b19194e Update vendor shazow/ssh-chat (#1029) 2020-03-08 23:55:09 +01:00
Wim
9785edd263 Remove replace directives and use own fork to make go get work again (#1028)
See https://github.com/golang/go/issues/30354
go get doesn't honor the go.mod replace options.
2020-03-08 17:08:18 +01:00
Qais Patankar
2a0bc11b68 Make some discord matterbridge.toml.sample lines less verbose 2020-03-08 14:30:54 +01:00
Qais Patankar
dd0325a88d Remove trailing newlines from matterbridge.toml.sample 2020-03-08 14:30:54 +01:00
Qais Patankar
20783c0978 Refactor matterbridge.toml.sample discord section 2020-03-08 14:30:54 +01:00
Wim
3f06a40bd5 Support code snippets from msteams 2020-03-01 22:19:33 +01:00
Wim
68f43985ad Add scopes again 2020-03-01 22:19:33 +01:00
Wim
915ca8f817 Make linter happy and cleanup (msteams) 2020-03-01 22:19:33 +01:00
Wim
a65a81610b Support threading from other bridges to msteams 2020-03-01 22:19:33 +01:00
Wim
8eb6ed5639 Support receiving attachments from msteams 2020-03-01 22:19:33 +01:00
Wim
795a8705c3 Add initial Microsoft Teams support
Documentation on https://github.com/42wim/matterbridge/wiki/MS-Teams-setup
2020-03-01 22:19:33 +01:00
Wim
3af0dc3b3a Vendor libraries needed for msteams support 2020-03-01 22:19:33 +01:00
Wim
9cf9b958a3 Do not lint gomnd (#1021) 2020-03-01 22:05:50 +01:00
Wim
3ac2ba8d5a Update to go1.14 and golangci-lint 1.23.7 (#1020) 2020-03-01 21:50:21 +01:00
Wim
d893421c7b Update vendor keybase/go-keybase-chat-bot (#1019) 2020-03-01 21:09:23 +01:00
Wim
250b3bb579 Use upstream slack-go/slack again (#1018) 2020-03-01 20:59:19 +01:00
Alexander Pushkov
e9edbfc051 Make Keybase link point to the team directly (#1013) 2020-02-19 21:02:44 +01:00
Wim
e343db6f72 Make avatars download work with mediaserverdownload (telegram). Fixes #920 (#1012) 2020-02-15 18:31:40 +01:00
Qais Patankar
4d57d66f85 Fix typo in feature_request.md (#1009) 2020-02-10 22:35:11 +01:00
Wim
54ed6320c2 Add support for avatars from matrix. #984 (#1007) 2020-02-10 00:06:54 +01:00
Wim
23083f3ae0 Rebase gomatrix vendor with upstream (#1006) 2020-02-09 23:49:17 +01:00
Wim
1985873494 Implement basic reconnect (whatsapp). Fixes #987 (#1003) 2020-02-09 22:11:46 +01:00
Qais Patankar
8ae5917659 Be less lossy when throttling IRC messages (#1004)
Note that msg.Text and chucking it through a chan is OK: https://play.golang.org/p/MTfT3YSsgPX
2020-02-09 22:10:18 +01:00
Qais Patankar
c91bfd08d8 Add ability to procure avatars from the destination bridge (#1000)
* remote_avatar: add UseLocalAvatar

* remote_avatar: make sure msg.Protocol is always set correctly

* remote_avatars: support msg.Account

* remote_avatar: add to matterbridge.toml.sample

* remote_avatar: clarify something
2020-02-09 22:07:26 +01:00
Qais Patankar
49110a5872 Assign automatically labels when creating issues (#1005)
* Update Bug_report.md

* Add 'label: enhancement' to feature_request.md
2020-02-09 22:03:53 +01:00
Wim
c01c8edeb8 Fix go-keybase-chat-bot api changes 2020-02-08 18:33:05 +01:00
Wim
ff8cf067b8 Update kekeybase/go-keybase-chat-bot vendor 2020-02-08 18:33:05 +01:00
Qais Patankar
1420f68050 Check only bridged channels for PermManageWebhooks (discord) (#1001)
* Check only bridged channels for PermManageWebhooks

* add note
2020-02-08 15:13:23 +01:00
Martijn Braam
c0be3e585a Enable intra-word emphasis supression in markdown (#999)
This fixes plain links sent to Matrix being broken if they contain
underscores. Fixes issue #997
2020-02-04 13:22:05 +01:00
Wim
3049ef9151 Bump version 2020-02-02 22:40:44 +01:00
Wim
4be00bbe6b Release v1.16.5 2020-02-02 22:36:07 +01:00
1704 changed files with 268066 additions and 2012 deletions

View File

@@ -1,6 +1,7 @@
---
name: Bug report
about: Create a report to help us improve. (Check the FAQ on the wiki first)
labels: bug
---

View File

@@ -1,6 +1,7 @@
---
name: Feature request
about: Suggest an idea for this project
labels: enhancement
---

View File

@@ -23,7 +23,7 @@ run:
# default value is empty list, but next dirs are always skipped independently
# from this option's value:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs:
skip-dirs: gateway/bridgemap$
# which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is
@@ -175,6 +175,7 @@ linters:
- maligned
- prealloc
- wsl
- gomnd
# rules to deal with reported isues

View File

@@ -20,22 +20,22 @@ jobs:
- stage: lint
# Run linting in one Go environment only.
script: ./ci/lint.sh
go: 1.13.x
go: 1.14.x
env:
- GO111MODULE=on
- GOLANGCI_VERSION="v1.21.0"
- GOLANGCI_VERSION="v1.23.7"
- stage: test
# Run tests in a combination of Go environments.
script: ./ci/test.sh
go: 1.12.x
go: 1.13.x
env:
- GO111MODULE=off
- GOFLAGS=-mod=vendor
- script: ./ci/test.sh
go: 1.12.x
go: 1.13.x
env:
- GO111MODULE=on
- script: ./ci/test.sh
go: 1.13.x
go: 1.14.x
env:
- GO111MODULE=on
- REPORT_COVERAGE=1

View File

@@ -1,11 +1,13 @@
FROM alpine:edge
ENTRYPOINT ["/bin/matterbridge"]
FROM alpine:edge AS builder
COPY . /go/src/github.com/42wim/matterbridge
RUN apk update && apk add go git gcc musl-dev ca-certificates mailcap \
RUN apk update && apk add go git gcc musl-dev \
&& cd /go/src/github.com/42wim/matterbridge \
&& export GOPATH=/go \
&& go get \
&& go build -x -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge \
&& rm -rf /go \
&& apk del --purge git go gcc musl-dev
&& go build -x -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
FROM alpine:edge
RUN apk --no-cache add ca-certificates mailcap
COPY --from=builder /bin/matterbridge /bin/matterbridge
ENTRYPOINT ["/bin/matterbridge"]

127
README.md
View File

@@ -9,19 +9,20 @@ Letting people be where they want to be.<br />
<sup>
[Discord][mb-discord] |
[Gitter][mb-gitter] |
[IRC][mb-irc] |
[Discord][mb-discord] |
[Keybase][mb-keybase] |
[Matrix][mb-matrix] |
[Slack][mb-slack] |
[Mattermost][mb-mattermost] |
[MSTeams][mb-msteams] |
[Rocket.Chat][mb-rocketchat] |
[XMPP][mb-xmpp] |
[Slack][mb-slack] |
[Telegram][mb-telegram] |
[Twitch][mb-twitch] |
[WhatsApp][mb-whatsapp] |
[XMPP][mb-xmpp] |
[Zulip][mb-zulip] |
[Telegram][mb-telegram] |
[Keybase][mb-keybase] |
And more...
</sup>
@@ -44,28 +45,34 @@ And more...
</a>
</p>
### Table of Contents
# 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)
- [Chat with us](#chat-with-us)
- [Screenshots](https://github.com/42wim/matterbridge/wiki/)
- [Installing/upgrading](#installing--upgrading)
- [Binaries](#binaries)
- [Building](#building)
- [Configuration](#configuration)
- [Howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config)
- [Settings](#settings)
- [Examples](#examples)
- [Running](#running)
- [Docker](#docker)
- [Changelog](#changelog)
- [FAQ](#faq)
- [Related projects](#related-projects)
- [Articles](#articles)
- [Thanks](#thanks)
- [matterbridge](#matterbridge)
- [Table of Contents](#table-of-contents)
- [Features](#features)
- [Natively supported](#natively-supported)
- [3rd party via matterbridge api](#3rd-party-via-matterbridge-api)
- [API](#api)
- [Chat with us](#chat-with-us)
- [Screenshots](#screenshots)
- [Installing / upgrading](#installing--upgrading)
- [Binaries](#binaries)
- [Packages](#packages)
- [Building](#building)
- [Configuration](#configuration)
- [Basic configuration](#basic-configuration)
- [Settings](#settings)
- [Advanced configuration](#advanced-configuration)
- [Examples](#examples)
- [Bridge mattermost (off-topic) - irc (#testing)](#bridge-mattermost-off-topic---irc-testing)
- [Bridge slack (#general) - discord (general)](#bridge-slack-general---discord-general)
- [Running](#running)
- [Docker](#docker)
- [Changelog](#changelog)
- [FAQ](#faq)
- [Related projects](#related-projects)
- [Articles](#articles)
- [Thanks](#thanks)
## Features
@@ -80,28 +87,29 @@ And more...
### Natively supported
- [Mattermost](https://github.com/mattermost/mattermost-server/) 4.x, 5.x
- [IRC](http://www.mirc.com/servers.html)
- [XMPP](https://xmpp.org)
- [Gitter](https://gitter.im)
- [Slack](https://slack.com)
- [Discord](https://discordapp.com)
- [Telegram](https://telegram.org)
- [Rocket.chat](https://rocket.chat)
- [Matrix](https://matrix.org)
- [Steam](https://store.steampowered.com/)
- [Twitch](https://twitch.tv)
- [Ssh-chat](https://github.com/shazow/ssh-chat)
- [WhatsApp](https://www.whatsapp.com/)
- [Zulip](https://zulipchat.com)
- [Gitter](https://gitter.im)
- [IRC](http://www.mirc.com/servers.html)
- [Keybase](https://keybase.io)
- [Matrix](https://matrix.org)
- [Mattermost](https://github.com/mattermost/mattermost-server/) 4.x, 5.x
- [Microsoft Teams](https://teams.microsoft.com)
- [Rocket.chat](https://rocket.chat)
- [Slack](https://slack.com)
- [Ssh-chat](https://github.com/shazow/ssh-chat)
- [Steam](https://store.steampowered.com/)
- [Telegram](https://telegram.org)
- [Twitch](https://twitch.tv)
- [WhatsApp](https://www.whatsapp.com/)
- [XMPP](https://xmpp.org)
- [Zulip](https://zulipchat.com)
### 3rd party via matterbridge api
- [Discourse](https://github.com/DeclanHoare/matterbabble)
- [Facebook messenger](https://github.com/VictorNine/fbridge)
- [Minecraft](https://github.com/elytra/MatterLink)
- [Reddit](https://github.com/bonehurtingjuice/mattereddit)
- [Facebook messenger](https://github.com/VictorNine/fbridge)
- [Discourse](https://github.com/DeclanHoare/matterbabble)
- [Counter-Strike, half-life and more](https://forums.alliedmods.net/showthread.php?t=319430)
### API
@@ -122,17 +130,18 @@ Used by the projects below. Feel free to make a PR to add your project to this l
Questions or want to test on your favorite platform? Join below:
- [Discord][mb-discord]
- [Gitter][mb-gitter]
- [IRC][mb-irc]
- [Discord][mb-discord]
- [Keybase][mb-keybase]
- [Matrix][mb-matrix]
- [Slack][mb-slack]
- [Mattermost][mb-mattermost]
- [Rocket.Chat][mb-rocketchat]
- [XMPP][mb-xmpp] (matterbridge@conference.jabber.de)
- [Twitch][mb-twitch]
- [Zulip][mb-zulip]
- [Slack][mb-slack]
- [Telegram][mb-telegram]
- [Twitch][mb-twitch]
- [XMPP][mb-xmpp] (matterbridge@conference.jabber.de)
- [Zulip][mb-zulip]
## Screenshots
@@ -142,7 +151,7 @@ See https://github.com/42wim/matterbridge/wiki
### Binaries
- Latest stable release [v1.16.4](https://github.com/42wim/matterbridge/releases/latest)
- Latest stable release [v1.17.4](https://github.com/42wim/matterbridge/releases/latest)
- Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)
To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest) and follow the instructions on the [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
@@ -315,30 +324,32 @@ Matterbridge wouldn't exist without these libraries:
- gops - https://github.com/google/gops
- gozulipbot - https://github.com/ifo/gozulipbot
- irc - https://github.com/lrstanley/girc
- mattermost - https://github.com/mattermost/mattermost-server
- keybase - https://github.com/keybase/go-keybase-chat-bot
- matrix - https://github.com/matrix-org/gomatrix
- sshchat - https://github.com/shazow/ssh-chat
- mattermost - https://github.com/mattermost/mattermost-server
- msgraph.go - https://github.com/yaegashi/msgraph.go
- slack - https://github.com/nlopes/slack
- sshchat - https://github.com/shazow/ssh-chat
- steam - https://github.com/Philipp15b/go-steam
- telegram - https://github.com/go-telegram-bot-api/telegram-bot-api
- xmpp - https://github.com/mattn/go-xmpp
- whatsapp - https://github.com/Rhymen/go-whatsapp/
- zulip - https://github.com/ifo/gozulipbot
- tengo - https://github.com/d5/tengo
- keybase - https://github.com/keybase/go-keybase-chat-bot
- whatsapp - https://github.com/Rhymen/go-whatsapp/
- xmpp - https://github.com/mattn/go-xmpp
- zulip - https://github.com/ifo/gozulipbot
<!-- Links -->
[mb-discord]: https://discord.gg/AkKPtrQ
[mb-gitter]: https://gitter.im/42wim/matterbridge
[mb-irc]: https://webchat.freenode.net/?channels=matterbridgechat
[mb-discord]: https://discord.gg/AkKPtrQ
[mb-keybase]: https://keybase.io/team/matterbridge
[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-msteams]: https://teams.microsoft.com/join/hj92x75gd3y7
[mb-rocketchat]: https://open.rocket.chat/channel/matterbridge
[mb-xmpp]: https://inverse.chat/
[mb-slack]: https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA
[mb-telegram]: https://t.me/Matterbridge
[mb-twitch]: https://www.twitch.tv/matterbridge
[mb-whatsapp]: https://www.whatsapp.com/
[mb-keybase]: https://keybase.io
[mb-xmpp]: https://inverse.chat/
[mb-zulip]: https://matterbridge.zulipchat.com/register/
[mb-telegram]: https://t.me/Matterbridge

View File

@@ -4,6 +4,7 @@ import (
"log"
"strings"
"sync"
"time"
"github.com/42wim/matterbridge/bridge/config"
"github.com/sirupsen/logrus"
@@ -74,6 +75,7 @@ func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map
for ID, channel := range channels {
if !exists[ID] {
b.Log.Infof("%s: joining %s (ID: %s)", b.Account, channel.Name, ID)
time.Sleep(time.Duration(b.GetInt("JoinDelay")) * time.Millisecond)
err := b.JoinChannel(channel)
if err != nil {
return err

View File

@@ -3,6 +3,7 @@ package config
import (
"bytes"
"io/ioutil"
"path/filepath"
"strings"
"sync"
"time"
@@ -76,6 +77,7 @@ type Protocol struct {
BindAddress string // mattermost, slack // DEPRECATED
Buffer int // api
Charset string // irc
ClientID string // msteams
ColorNicks bool // only irc for now
Debug bool // general
DebugLevel int // only for irc now
@@ -87,6 +89,7 @@ type Protocol struct {
IgnoreNicks string // all protocols
IgnoreMessages string // all protocols
Jid string // xmpp
JoinDelay string // all protocols
Label string // all protocols
Login string // mattermost, matrix
MediaDownloadBlackList []string
@@ -124,6 +127,7 @@ type Protocol struct {
RemoteNickFormat string // all protocols
RunCommands []string // IRC
Server string // IRC,mattermost,XMPP,discord
SessionFile string // msteams,whatsapp
ShowJoinPart bool // all protocols
ShowTopicChange bool // slack
ShowUserTyping bool // slack
@@ -134,10 +138,13 @@ type Protocol struct {
SyncTopic bool // slack
TengoModifyMessage string // general
Team string // mattermost, keybase
TeamID string // msteams
TenantID string // msteams
Token string // gitter, slack, discord, api
Topic string // zulip
URL string // mattermost, slack // DEPRECATED
UseAPI bool // mattermost, slack
UseLocalAvatar []string // discord
UseSASL bool // IRC
UseTLS bool // IRC
UseDiscriminator bool // discord
@@ -235,7 +242,8 @@ func NewConfig(rootLogger *logrus.Logger, cfgfile string) Config {
logger.Fatalf("Failed to read configuration file: %#v", err)
}
mycfg := newConfigFromString(logger, input)
cfgtype := detectConfigType(cfgfile)
mycfg := newConfigFromString(logger, input, cfgtype)
if mycfg.cv.General.MediaDownloadSize == 0 {
mycfg.cv.General.MediaDownloadSize = 1000000
}
@@ -246,14 +254,26 @@ func NewConfig(rootLogger *logrus.Logger, cfgfile string) Config {
return mycfg
}
// detectConfigType detects JSON and YAML formats, defaults to TOML.
func detectConfigType(cfgfile string) string {
fileExt := filepath.Ext(cfgfile)
switch fileExt {
case ".json":
return "json"
case ".yaml", ".yml":
return "yaml"
}
return "toml"
}
// NewConfigFromString instantiates a new configuration based on the specified string.
func NewConfigFromString(rootLogger *logrus.Logger, input []byte) Config {
logger := rootLogger.WithFields(logrus.Fields{"prefix": "config"})
return newConfigFromString(logger, input)
return newConfigFromString(logger, input, "toml")
}
func newConfigFromString(logger *logrus.Entry, input []byte) *config {
viper.SetConfigType("toml")
func newConfigFromString(logger *logrus.Entry, input []byte, cfgtype string) *config {
viper.SetConfigType(cfgtype)
viper.SetEnvPrefix("matterbridge")
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
viper.AutomaticEnv()

View File

@@ -10,7 +10,7 @@ import (
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/bwmarrin/discordgo"
"github.com/matterbridge/discordgo"
)
const MessageLength = 1950
@@ -21,6 +21,7 @@ type Bdiscord struct {
c *discordgo.Session
nick string
userID string
guildID string
webhookID string
webhookToken string
@@ -33,6 +34,8 @@ type Bdiscord struct {
membersMutex sync.RWMutex
userMemberMap map[string]*discordgo.Member
nickMemberMap map[string]*discordgo.Member
webhookCache map[string]string
webhookMutex sync.RWMutex
}
func New(cfg *bridge.Config) bridge.Bridger {
@@ -40,6 +43,7 @@ func New(cfg *bridge.Config) bridge.Bridger {
b.userMemberMap = make(map[string]*discordgo.Member)
b.nickMemberMap = make(map[string]*discordgo.Member)
b.channelInfoMap = make(map[string]*config.ChannelInfo)
b.webhookCache = make(map[string]string)
if b.GetString("WebhookURL") != "" {
b.Log.Debug("Configuring Discord Incoming Webhook")
b.webhookID, b.webhookToken = b.splitURL(b.GetString("WebhookURL"))
@@ -92,6 +96,7 @@ func (b *Bdiscord) Connect() error {
}
serverName := strings.Replace(b.GetString("Server"), "ID:", "", -1)
b.nick = userinfo.Username
b.userID = userinfo.ID
b.channelsMutex.Lock()
for _, guild := range guilds {
if guild.Name == serverName || guild.ID == serverName {
@@ -114,30 +119,37 @@ func (b *Bdiscord) Connect() error {
b.Log.Infof("Server=\"%s\" # Server ID", guild.ID)
}
}
if err != nil {
return err
}
b.channelsMutex.RLock()
if b.GetString("WebhookURL") == "" {
for _, channel := range b.channels {
b.Log.Debugf("found channel %#v", channel)
}
} else {
b.canEditWebhooks = true
for _, channel := range b.channels {
b.Log.Debugf("found channel %#v; verifying PermissionManageWebhooks", channel)
perms, permsErr := b.c.State.UserChannelPermissions(userinfo.ID, channel.ID)
manageWebhooks := discordgo.PermissionManageWebhooks
if permsErr != nil || perms&manageWebhooks != manageWebhooks {
b.Log.Warnf("Can't manage webhooks in channel \"%s\"", channel.Name)
b.canEditWebhooks = false
manageWebhooks := discordgo.PermissionManageWebhooks
var channelsDenied []string
for _, info := range b.Channels {
id := b.getChannelID(info.Name) // note(qaisjp): this readlocks channelsMutex
b.Log.Debugf("Verifying PermissionManageWebhooks for %s with ID %s", info.ID, id)
perms, permsErr := b.c.UserChannelPermissions(userinfo.ID, id)
if permsErr != nil {
b.Log.Warnf("Failed to check PermissionManageWebhooks in channel \"%s\": %s", info.Name, permsErr.Error())
} else if perms&manageWebhooks == manageWebhooks {
continue
}
channelsDenied = append(channelsDenied, fmt.Sprintf("%#v", info.Name))
}
b.canEditWebhooks = len(channelsDenied) == 0
if b.canEditWebhooks {
b.Log.Info("Can manage webhooks; will edit channel for global webhook on send")
} else {
b.Log.Warn("Can't manage webhooks; won't edit channel for global webhook on send")
b.Log.Warn("Can't manage webhooks in channels: ", strings.Join(channelsDenied, ", "))
}
}
b.channelsMutex.RUnlock()
@@ -179,6 +191,8 @@ func (b *Bdiscord) JoinChannel(channel config.ChannelInfo) error {
func (b *Bdiscord) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg)
origMsgID := msg.ID
channelID := b.getChannelID(msg.Channel)
if channelID == "" {
return "", fmt.Errorf("Could not find channelID for %v", msg.Channel)
@@ -221,6 +235,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
// If we are editing a message, delete the old message
if msg.ID != "" {
msg.ID = b.getCacheID(msg.ID)
b.Log.Debugf("Deleting edited webhook message")
err := b.c.ChannelMessageDelete(channelID, msg.ID)
if err != nil {
@@ -264,6 +279,8 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
if msg == nil {
return "", nil
}
b.updateCacheID(origMsgID, msg.ID)
return msg.ID, nil
}
@@ -274,6 +291,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
if msg.ID == "" {
return "", nil
}
msg.ID = b.getCacheID(msg.ID)
err := b.c.ChannelMessageDelete(channelID, msg.ID)
return "", err
}
@@ -380,6 +398,19 @@ func (b *Bdiscord) webhookSend(msg *config.Message, webhookID, token string) (*d
err error
)
// If avatar is unset, check if UseLocalAvatar contains the message's
// account or protocol, and if so, try to find a local avatar
if msg.Avatar == "" {
for _, val := range b.GetStringSlice("UseLocalAvatar") {
if msg.Protocol == val || msg.Account == val {
if avatar := b.findAvatar(msg); avatar != "" {
msg.Avatar = avatar
}
break
}
}
}
// WebhookParams can have either `Content` or `File`.
// We can't send empty messages.
@@ -429,3 +460,11 @@ func (b *Bdiscord) webhookSend(msg *config.Message, webhookID, token string) (*d
}
return res, err
}
func (b *Bdiscord) findAvatar(m *config.Message) string {
member, err := b.getGuildMemberByNick(m.Username)
if err != nil {
return ""
}
return member.User.AvatarURL("")
}

View File

@@ -2,7 +2,7 @@ package bdiscord
import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/bwmarrin/discordgo"
"github.com/matterbridge/discordgo"
)
func (b *Bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) { //nolint:unparam
@@ -36,6 +36,11 @@ func (b *Bdiscord) messageTyping(s *discordgo.Session, m *discordgo.TypingStart)
return
}
// Ignore our own typing messages
if m.UserID == b.userID {
return
}
rmsg := config.Message{Account: b.Account, Event: config.EventUserTyping}
rmsg.Channel = b.getChannelName(m.ChannelID)
b.Remote <- rmsg
@@ -90,12 +95,12 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
// set channel name
rmsg.Channel = b.getChannelName(m.ChannelID)
// set username
if !b.GetBool("UseUserName") {
fromWebhook := m.WebhookID != ""
if !fromWebhook && !b.GetBool("UseUserName") {
rmsg.Username = b.getNick(m.Author, m.GuildID)
} else {
rmsg.Username = m.Author.Username
if b.GetBool("UseDiscriminator") {
if !fromWebhook && b.GetBool("UseDiscriminator") {
rmsg.Username += "#" + m.Author.Discriminator
}
}
@@ -103,7 +108,7 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
// if we have embedded content add it to text
if b.GetBool("ShowEmbeds") && m.Message.Embeds != nil {
for _, embed := range m.Message.Embeds {
rmsg.Text = rmsg.Text + "embed: " + embed.Title + " - " + embed.Description + " - " + embed.URL + "\n"
rmsg.Text += handleEmbed(embed)
}
}
@@ -119,6 +124,9 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
rmsg.Event = config.EventUserAction
}
// Replace emotes
rmsg.Text = replaceEmotes(rmsg.Text)
b.Log.Debugf("<= Sending message from %s on %s to gateway", m.Author.Username, b.Account)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
@@ -192,3 +200,33 @@ func (b *Bdiscord) memberRemove(s *discordgo.Session, m *discordgo.GuildMemberRe
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}
func handleEmbed(embed *discordgo.MessageEmbed) string {
var t []string
var result string
t = append(t, embed.Title)
t = append(t, embed.Description)
t = append(t, embed.URL)
i := 0
for _, e := range t {
if e == "" {
continue
}
i++
if i == 1 {
result += "embed: " + e
continue
}
result += " - " + e
}
if result != "" {
result += "\n"
}
return result
}

View File

@@ -0,0 +1,58 @@
package bdiscord
import (
"testing"
"github.com/matterbridge/discordgo"
"github.com/stretchr/testify/assert"
)
func TestHandleEmbed(t *testing.T) {
testcases := map[string]struct {
embed *discordgo.MessageEmbed
result string
}{
"allempty": {
embed: &discordgo.MessageEmbed{},
result: "",
},
"one": {
embed: &discordgo.MessageEmbed{
Title: "blah",
},
result: "embed: blah\n",
},
"two": {
embed: &discordgo.MessageEmbed{
Title: "blah",
Description: "blah2",
},
result: "embed: blah - blah2\n",
},
"three": {
embed: &discordgo.MessageEmbed{
Title: "blah",
Description: "blah2",
URL: "blah3",
},
result: "embed: blah - blah2 - blah3\n",
},
"twob": {
embed: &discordgo.MessageEmbed{
Description: "blah2",
URL: "blah3",
},
result: "embed: blah2 - blah3\n",
},
"oneb": {
embed: &discordgo.MessageEmbed{
URL: "blah3",
},
result: "embed: blah3\n",
},
}
for name, tc := range testcases {
assert.Equalf(t, tc.result, handleEmbed(tc.embed), "Testcases %s", name)
}
}

View File

@@ -6,7 +6,7 @@ import (
"strings"
"unicode"
"github.com/bwmarrin/discordgo"
"github.com/matterbridge/discordgo"
)
func (b *Bdiscord) getNick(user *discordgo.User, guildID string) string {
@@ -137,6 +137,7 @@ var (
// See https://discordapp.com/developers/docs/reference#message-formatting.
channelMentionRE = regexp.MustCompile("<#[0-9]+>")
userMentionRE = regexp.MustCompile("@[^@\n]{1,32}")
emoteRE = regexp.MustCompile(`<a?(:\w+:)\d+>`)
)
func (b *Bdiscord) replaceChannelMentions(text string) string {
@@ -182,6 +183,10 @@ func (b *Bdiscord) replaceUserMentions(text string) string {
return userMentionRE.ReplaceAllStringFunc(text, replaceUserMentionFunc)
}
func replaceEmotes(text string) string {
return emoteRE.ReplaceAllString(text, "$1")
}
func (b *Bdiscord) replaceAction(text string) (string, bool) {
if strings.HasPrefix(text, "_") && strings.HasSuffix(text, "_") {
return text[1 : len(text)-1], true
@@ -203,6 +208,40 @@ func (b *Bdiscord) splitURL(url string) (string, string) {
return webhookURLSplit[webhookIdxID], webhookURLSplit[webhookIdxToken]
}
// getcacheID tries to find a corresponding msgID in the webhook cache.
// if not found returns the original request.
func (b *Bdiscord) getCacheID(msgID string) string {
b.webhookMutex.RLock()
defer b.webhookMutex.RUnlock()
for k, v := range b.webhookCache {
if msgID == k {
return v
}
}
return msgID
}
// updateCacheID updates the cache so that the newID takes the place of
// the original ID. This is used for edit/deletes in combination with webhooks
// as editing a message via webhook means deleting the message and creating a
// new message (with a new ID). This ID needs to be set instead of the original ID
func (b *Bdiscord) updateCacheID(origID, newID string) {
b.webhookMutex.Lock()
match := false
for k, v := range b.webhookCache {
if v == origID {
delete(b.webhookCache, k)
b.webhookCache[origID] = newID
match = true
continue
}
}
if !match && origID != "" {
b.webhookCache[origID] = newID
}
b.webhookMutex.Unlock()
}
func enumerateUsernames(s string) []string {
onlySpace := true
for _, r := range s {

View File

@@ -180,7 +180,7 @@ func ClipMessage(text string, length int) string {
// ParseMarkdown takes in an input string as markdown and parses it to html
func ParseMarkdown(input string) string {
extensions := parser.HardLineBreak
extensions := parser.HardLineBreak | parser.NoIntraEmphasis
markdownParser := parser.NewWithExtensions(extensions)
renderer := html.NewRenderer(html.RendererOptions{
Flags: 0,

View File

@@ -54,12 +54,12 @@ func (b *Birc) handleFiles(msg *config.Message) bool {
for _, f := range msg.Extra["file"] {
fi := f.(config.FileInfo)
if fi.Comment != "" {
msg.Text += fi.Comment + ": "
msg.Text += fi.Comment + " : "
}
if fi.URL != "" {
msg.Text = fi.URL
if fi.Comment != "" {
msg.Text = fi.Comment + ": " + fi.URL
msg.Text = fi.Comment + " : " + fi.URL
}
}
b.Local <- config.Message{Text: msg.Text, Username: msg.Username, Channel: msg.Channel, Event: msg.Event}

View File

@@ -167,12 +167,8 @@ func (b *Birc) Send(msg config.Message) (string, error) {
return "", nil
}
b.Local <- config.Message{
Text: msgLines[i],
Username: msg.Username,
Channel: msg.Channel,
Event: msg.Event,
}
msg.Text = msgLines[i]
b.Local <- msg
}
return "", nil
}

View File

@@ -4,7 +4,7 @@ import (
"strconv"
"github.com/42wim/matterbridge/bridge/config"
"github.com/keybase/go-keybase-chat-bot/kbchat"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
)
func (b *Bkeybase) handleKeybase() {
@@ -20,7 +20,7 @@ func (b *Bkeybase) handleKeybase() {
b.Log.Errorf("failed to read message: %s", err.Error())
}
if msg.Message.Content.Type != "text" {
if msg.Message.Content.TypeName != "text" {
continue
}
@@ -34,7 +34,7 @@ func (b *Bkeybase) handleKeybase() {
}()
}
func (b *Bkeybase) handleMessage(msg kbchat.Message) {
func (b *Bkeybase) handleMessage(msg chat1.MsgSummary) {
b.Log.Debugf("== Receiving event: %#v", msg)
if msg.Channel.TopicName != b.channel || msg.Channel.Name != b.team {
return
@@ -45,10 +45,10 @@ func (b *Bkeybase) handleMessage(msg kbchat.Message) {
// TODO download avatar
// Create our message
rmsg := config.Message{Username: msg.Sender.Username, Text: msg.Content.Text.Body, UserID: msg.Sender.Uid, Channel: msg.Channel.TopicName, ID: strconv.Itoa(msg.MsgID), Account: b.Account}
rmsg := config.Message{Username: msg.Sender.Username, Text: msg.Content.Text.Body, UserID: string(msg.Sender.Uid), Channel: msg.Channel.TopicName, ID: strconv.Itoa(int(msg.Id)), Account: b.Account}
// Text must be a string
if msg.Content.Type != "text" {
if msg.Content.TypeName != "text" {
b.Log.Errorf("message is not text")
return
}

View File

@@ -90,16 +90,17 @@ func (b *Bkeybase) Send(msg config.Message) (string, error) {
return "", err
}
_, _ = b.kbc.SendAttachmentByTeam(b.team, fpath, fcaption, &b.channel)
_, _ = b.kbc.SendAttachmentByTeam(b.team, &b.channel, fpath, fcaption)
}
return "", nil
}
// Send regular message
resp, err := b.kbc.SendMessageByTeamName(b.team, msg.Username+msg.Text, &b.channel)
text := msg.Username + msg.Text
resp, err := b.kbc.SendMessageByTeamName(b.team, &b.channel, text)
if err != nil {
return "", err
}
return strconv.Itoa(resp.Result.MsgID), err
return strconv.Itoa(int(*resp.Result.MessageID)), err
}

View File

@@ -172,10 +172,15 @@ func (b *Bmatrix) handleEvent(ev *matrix.Event) {
return
}
// TODO download avatar
// Create our message
rmsg := config.Message{Username: ev.Sender[1:], Channel: channel, Account: b.Account, UserID: ev.Sender, ID: ev.ID}
rmsg := config.Message{
Username: ev.Sender[1:],
Channel: channel,
Account: b.Account,
UserID: ev.Sender,
ID: ev.ID,
Avatar: b.getAvatarURL(ev.Sender),
}
// Text must be a string
if rmsg.Text, ok = ev.Content["body"].(string); !ok {
@@ -358,3 +363,15 @@ func (b *Bmatrix) containsAttachment(content map[string]interface{}) bool {
}
return true
}
// getAvatarURL returns the avatar URL of the specified sender
func (b *Bmatrix) getAvatarURL(sender string) string {
mxcURL, err := b.mc.GetSenderAvatarURL(sender)
if err != nil {
b.Log.Errorf("getAvatarURL failed: %s", err)
return ""
}
url := strings.ReplaceAll(mxcURL, "mxc://", b.GetString("Server")+"/_matrix/media/r0/thumbnail/")
url += "?width=37&height=37&method=crop"
return url
}

101
bridge/msteams/handler.go Normal file
View File

@@ -0,0 +1,101 @@
package bmsteams
import (
"encoding/json"
"fmt"
"io/ioutil"
"strings"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
msgraph "github.com/yaegashi/msgraph.go/beta"
)
func (b *Bmsteams) findFile(weburl string) (string, error) {
itemRB, err := b.gc.GetDriveItemByURL(b.ctx, weburl)
if err != nil {
return "", err
}
itemRB.Workbook().Worksheets()
b.gc.Workbooks()
item, err := itemRB.Request().Get(b.ctx)
if err != nil {
return "", err
}
if url, ok := item.GetAdditionalData("@microsoft.graph.downloadUrl"); ok {
return url.(string), nil
}
return "", nil
}
// handleDownloadFile handles file download
func (b *Bmsteams) handleDownloadFile(rmsg *config.Message, filename, weburl string) error {
realURL, err := b.findFile(weburl)
if err != nil {
return err
}
// Actually download the file.
data, err := helper.DownloadFile(realURL)
if err != nil {
return fmt.Errorf("download %s failed %#v", weburl, err)
}
// If a comment is attached to the file(s) it is in the 'Text' field of the teams messge event
// and should be added as comment to only one of the files. We reset the 'Text' field to ensure
// that the comment is not duplicated.
comment := rmsg.Text
rmsg.Text = ""
helper.HandleDownloadData(b.Log, rmsg, filename, comment, weburl, data, b.General)
return nil
}
func (b *Bmsteams) handleAttachments(rmsg *config.Message, msg msgraph.ChatMessage) {
for _, a := range msg.Attachments {
//remove the attachment tags from the text
rmsg.Text = attachRE.ReplaceAllString(rmsg.Text, "")
//handle a code snippet (code block)
if *a.ContentType == "application/vnd.microsoft.card.codesnippet" {
b.handleCodeSnippet(rmsg, a)
continue
}
//handle the download
err := b.handleDownloadFile(rmsg, *a.Name, *a.ContentURL)
if err != nil {
b.Log.Errorf("download of %s failed: %s", *a.Name, err)
}
}
}
type AttachContent struct {
Language string `json:"language"`
CodeSnippetURL string `json:"codeSnippetUrl"`
}
func (b *Bmsteams) handleCodeSnippet(rmsg *config.Message, attach msgraph.ChatMessageAttachment) {
var content AttachContent
err := json.Unmarshal([]byte(*attach.Content), &content)
if err != nil {
b.Log.Errorf("unmarshal codesnippet failed: %s", err)
return
}
s := strings.Split(content.CodeSnippetURL, "/")
if len(s) != 13 {
b.Log.Errorf("codesnippetUrl has unexpected size: %s", content.CodeSnippetURL)
return
}
resp, err := b.gc.Teams().Request().Client().Get(content.CodeSnippetURL)
if err != nil {
b.Log.Errorf("retrieving snippet content failed:%s", err)
return
}
defer resp.Body.Close()
res, err := ioutil.ReadAll(resp.Body)
if err != nil {
b.Log.Errorf("reading snippet data failed: %s", err)
return
}
rmsg.Text = rmsg.Text + "\n```" + content.Language + "\n" + string(res) + "\n```\n"
}

212
bridge/msteams/msteams.go Normal file
View File

@@ -0,0 +1,212 @@
package bmsteams
import (
"context"
"fmt"
"os"
"regexp"
"strings"
"time"
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/mattn/godown"
msgraph "github.com/yaegashi/msgraph.go/beta"
"github.com/yaegashi/msgraph.go/msauth"
"golang.org/x/oauth2"
)
var defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"}
var attachRE = regexp.MustCompile(`<attachment id=.*?attachment>`)
type Bmsteams struct {
gc *msgraph.GraphServiceRequestBuilder
ctx context.Context
botID string
*bridge.Config
}
func New(cfg *bridge.Config) bridge.Bridger {
return &Bmsteams{Config: cfg}
}
func (b *Bmsteams) Connect() error {
tokenCachePath := b.GetString("sessionFile")
if tokenCachePath == "" {
tokenCachePath = "msteams_session.json"
}
ctx := context.Background()
m := msauth.NewManager()
m.LoadFile(tokenCachePath) //nolint:errcheck
ts, err := m.DeviceAuthorizationGrant(ctx, b.GetString("TenantID"), b.GetString("ClientID"), defaultScopes, nil)
if err != nil {
return err
}
err = m.SaveFile(tokenCachePath)
if err != nil {
b.Log.Errorf("Couldn't save sessionfile in %s: %s", tokenCachePath, err)
}
// make file readable only for matterbridge user
err = os.Chmod(tokenCachePath, 0600)
if err != nil {
b.Log.Errorf("Couldn't change permissions for %s: %s", tokenCachePath, err)
}
httpClient := oauth2.NewClient(ctx, ts)
graphClient := msgraph.NewClient(httpClient)
b.gc = graphClient
b.ctx = ctx
err = b.setBotID()
if err != nil {
return err
}
b.Log.Info("Connection succeeded")
return nil
}
func (b *Bmsteams) Disconnect() error {
return nil
}
func (b *Bmsteams) JoinChannel(channel config.ChannelInfo) error {
go func(name string) {
for {
err := b.poll(name)
if err != nil {
b.Log.Errorf("polling failed for %s: %s. retrying in 5 seconds", name, err)
}
time.Sleep(time.Second * 5)
}
}(channel.Name)
return nil
}
func (b *Bmsteams) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg)
if msg.ParentID != "" && msg.ParentID != "msg-parent-not-found" {
return b.sendReply(msg)
}
if msg.ParentID == "msg-parent-not-found" {
msg.ParentID = ""
msg.Text = fmt.Sprintf("[thread]: %s", msg.Text)
}
ct := b.gc.Teams().ID(b.GetString("TeamID")).Channels().ID(msg.Channel).Messages().Request()
text := msg.Username + msg.Text
content := &msgraph.ItemBody{Content: &text}
rmsg := &msgraph.ChatMessage{Body: content}
res, err := ct.Add(b.ctx, rmsg)
if err != nil {
return "", err
}
return *res.ID, nil
}
func (b *Bmsteams) sendReply(msg config.Message) (string, error) {
ct := b.gc.Teams().ID(b.GetString("TeamID")).Channels().ID(msg.Channel).Messages().ID(msg.ParentID).Replies().Request()
// Handle prefix hint for unthreaded messages.
text := msg.Username + msg.Text
content := &msgraph.ItemBody{Content: &text}
rmsg := &msgraph.ChatMessage{Body: content}
res, err := ct.Add(b.ctx, rmsg)
if err != nil {
return "", err
}
return *res.ID, nil
}
func (b *Bmsteams) getMessages(channel string) ([]msgraph.ChatMessage, error) {
ct := b.gc.Teams().ID(b.GetString("TeamID")).Channels().ID(channel).Messages().Request()
rct, err := ct.Get(b.ctx)
if err != nil {
return nil, err
}
b.Log.Debugf("got %#v messages", len(rct))
return rct, nil
}
//nolint:gocognit
func (b *Bmsteams) poll(channelName string) error {
msgmap := make(map[string]time.Time)
b.Log.Debug("getting initial messages")
res, err := b.getMessages(channelName)
if err != nil {
return err
}
for _, msg := range res {
msgmap[*msg.ID] = *msg.CreatedDateTime
if msg.LastModifiedDateTime != nil {
msgmap[*msg.ID] = *msg.LastModifiedDateTime
}
}
time.Sleep(time.Second * 5)
b.Log.Debug("polling for messages")
for {
res, err := b.getMessages(channelName)
if err != nil {
return err
}
for i := len(res) - 1; i >= 0; i-- {
msg := res[i]
if mtime, ok := msgmap[*msg.ID]; ok {
if mtime == *msg.CreatedDateTime && msg.LastModifiedDateTime == nil {
continue
}
if msg.LastModifiedDateTime != nil && mtime == *msg.LastModifiedDateTime {
continue
}
}
if *msg.From.User.ID == b.botID {
b.Log.Debug("skipping own message")
msgmap[*msg.ID] = *msg.CreatedDateTime
continue
}
msgmap[*msg.ID] = *msg.CreatedDateTime
if msg.LastModifiedDateTime != nil {
msgmap[*msg.ID] = *msg.LastModifiedDateTime
}
b.Log.Debugf("<= Sending message from %s on %s to gateway", *msg.From.User.DisplayName, b.Account)
text := b.convertToMD(*msg.Body.Content)
rmsg := config.Message{
Username: *msg.From.User.DisplayName,
Text: text,
Channel: channelName,
Account: b.Account,
Avatar: "",
UserID: *msg.From.User.ID,
ID: *msg.ID,
Extra: make(map[string][]interface{}),
}
b.handleAttachments(&rmsg, msg)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}
time.Sleep(time.Second * 5)
}
}
func (b *Bmsteams) setBotID() error {
req := b.gc.Me().Request()
r, err := req.Get(b.ctx)
if err != nil {
return err
}
b.botID = *r.ID
return nil
}
func (b *Bmsteams) convertToMD(text string) string {
if !strings.Contains(text, "<div>") {
return text
}
var sb strings.Builder
err := godown.Convert(&sb, strings.NewReader(text), nil)
if err != nil {
b.Log.Errorf("Couldn't convert message to markdown %s", text)
return text
}
return sb.String()
}

View File

@@ -2,6 +2,7 @@ package brocketchat
import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/matterbridge/Rocket.Chat.Go.SDK/models"
)
func (b *Brocketchat) handleRocket() {
@@ -38,6 +39,23 @@ func (b *Brocketchat) handleRocketHook(messages chan *config.Message) {
}
}
func (b *Brocketchat) handleStatusEvent(ev models.Message, rmsg *config.Message) bool {
switch ev.Type {
case "":
// this is a normal message, no processing needed
// return true so the message is not dropped
return true
case sUserJoined, sUserLeft:
rmsg.Event = config.EventJoinLeave
return true
case sRoomChangedTopic:
rmsg.Event = config.EventTopicChange
return true
}
b.Log.Debugf("Dropping message with unknown type: %s", ev.Type)
return false
}
func (b *Brocketchat) handleRocketClient(messages chan *config.Message) {
for message := range b.messageChan {
// skip messages with same ID, apparently messages get duplicated for an unknown reason
@@ -59,7 +77,12 @@ func (b *Brocketchat) handleRocketClient(messages chan *config.Message) {
UserID: message.User.ID,
ID: message.ID,
}
messages <- rmsg
// handleStatusEvent returns false if the message should be dropped
// in that case it is probably some modification to the channel we do not want to relay
if b.handleStatusEvent(m, rmsg) {
messages <- rmsg
}
}
}

View File

@@ -29,6 +29,12 @@ type Brocketchat struct {
sync.RWMutex
}
const (
sUserJoined = "uj"
sUserLeft = "ul"
sRoomChangedTopic = "room_changed_topic"
)
func New(cfg *bridge.Config) bridge.Bridger {
newCache, err := lru.New(100)
if err != nil {

View File

@@ -1,15 +1,19 @@
package bslack
import (
"errors"
"fmt"
"html"
"time"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/nlopes/slack"
"github.com/slack-go/slack"
)
// ErrEventIgnored is for events that should be ignored
var ErrEventIgnored = errors.New("this event message should ignored")
func (b *Bslack) handleSlack() {
messages := make(chan *config.Message)
if b.GetString(incomingWebhookConfig) != "" {
@@ -53,7 +57,9 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) {
continue
}
rmsg, err := b.handleTypingEvent(ev)
if err != nil {
if err == ErrEventIgnored {
continue
} else if err != nil {
b.Log.Errorf("%#v", err)
continue
}
@@ -87,7 +93,7 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) {
b.Log.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj)
case *slack.MemberJoinedChannelEvent:
b.users.populateUser(ev.User)
case *slack.HelloEvent, *slack.LatencyReport:
case *slack.HelloEvent, *slack.LatencyReport, *slack.ConnectingEvent:
continue
default:
b.Log.Debugf("Unhandled incoming event: %T", ev)
@@ -124,11 +130,11 @@ func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool {
}
}
// Skip any messages that we made ourselves or from 'slackbot' (see #527).
if ev.Username == sSlackBotUser ||
(b.rtm != nil && ev.Username == b.si.User.Name) ||
(len(ev.Attachments) > 0 && ev.Attachments[0].CallbackID == "matterbridge_"+b.uuid) {
return true
// Check for our callback ID
hasOurCallbackID := false
if len(ev.Blocks.BlockSet) == 1 {
block, ok := ev.Blocks.BlockSet[0].(*slack.SectionBlock)
hasOurCallbackID = ok && block.BlockID == "matterbridge_"+b.uuid
}
if ev.SubMessage != nil {
@@ -143,6 +149,16 @@ func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool {
if ev.SubType == "message_replied" && ev.Hidden {
return true
}
if len(ev.SubMessage.Blocks.BlockSet) == 1 {
block, ok := ev.SubMessage.Blocks.BlockSet[0].(*slack.SectionBlock)
hasOurCallbackID = ok && block.BlockID == "matterbridge_"+b.uuid
}
}
// Skip any messages that we made ourselves or from 'slackbot' (see #527).
if ev.Username == sSlackBotUser ||
(b.rtm != nil && ev.Username == b.si.User.Name) || hasOurCallbackID {
return true
}
if len(ev.Files) > 0 {
@@ -270,6 +286,9 @@ func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message)
}
func (b *Bslack) handleTypingEvent(ev *slack.UserTypingEvent) (*config.Message, error) {
if ev.User == b.si.User.ID {
return nil, ErrEventIgnored
}
channelInfo, err := b.channels.getChannelByID(ev.Channel)
if err != nil {
return nil, err

View File

@@ -7,8 +7,8 @@ import (
"time"
"github.com/42wim/matterbridge/bridge/config"
"github.com/nlopes/slack"
"github.com/sirupsen/logrus"
"github.com/slack-go/slack"
)
// populateReceivedMessage shapes the initial Matterbridge message that we will forward to the

View File

@@ -5,7 +5,7 @@ import (
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/matterhook"
"github.com/nlopes/slack"
"github.com/slack-go/slack"
)
type BLegacy struct {

View File

@@ -13,8 +13,8 @@ import (
"github.com/42wim/matterbridge/bridge/helper"
"github.com/42wim/matterbridge/matterhook"
lru "github.com/hashicorp/golang-lru"
"github.com/nlopes/slack"
"github.com/rs/xid"
"github.com/slack-go/slack"
)
type Bslack struct {
@@ -64,6 +64,7 @@ const (
editSuffixConfig = "EditSuffix"
iconURLConfig = "iconurl"
noSendJoinConfig = "nosendjoinpart"
messageLength = 3000
)
func New(cfg *bridge.Config) bridge.Bridger {
@@ -194,6 +195,7 @@ func (b *Bslack) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg)
}
msg.Text = helper.ClipMessage(msg.Text, messageLength)
msg.Text = b.replaceCodeFence(msg.Text)
// Make a action /me of the message
@@ -408,7 +410,6 @@ func (b *Bslack) editMessage(msg *config.Message, channelInfo *slack.Channel) (b
}
messageOptions := b.prepareMessageOptions(msg)
for {
messageOptions = append(messageOptions, slack.MsgOptionText(msg.Text, false))
_, _, _, err := b.rtm.UpdateMessage(channelInfo.ID, msg.ID, messageOptions...)
if err == nil {
return true, nil
@@ -427,11 +428,6 @@ func (b *Bslack) postMessage(msg *config.Message, channelInfo *slack.Channel) (s
return "", nil
}
messageOptions := b.prepareMessageOptions(msg)
messageOptions = append(
messageOptions,
slack.MsgOptionText(msg.Text, false),
slack.MsgOptionEnableLinkUnfurl(),
)
for {
_, id, err := b.rtm.PostMessage(channelInfo.ID, messageOptions...)
if err == nil {
@@ -497,8 +493,6 @@ func (b *Bslack) prepareMessageOptions(msg *config.Message) []slack.MsgOption {
}
var attachments []slack.Attachment
// add a callback ID so we can see we created it
attachments = append(attachments, slack.Attachment{CallbackID: "matterbridge_" + b.uuid})
// add file attachments
attachments = append(attachments, b.createAttach(msg.Extra)...)
// add slack attachments (from another slack bridge)
@@ -509,6 +503,19 @@ func (b *Bslack) prepareMessageOptions(msg *config.Message) []slack.MsgOption {
}
var opts []slack.MsgOption
opts = append(opts,
// provide regular text field (fallback used in Slack notifications, etc.)
slack.MsgOptionText(msg.Text, false),
// add a callback ID so we can see we created it
slack.MsgOptionBlocks(slack.NewSectionBlock(
slack.NewTextBlockObject(slack.MarkdownType, msg.Text, false, false),
nil, nil,
slack.SectionBlockOptionBlockID("matterbridge_"+b.uuid),
)),
slack.MsgOptionEnableLinkUnfurl(),
)
opts = append(opts, slack.MsgOptionAttachments(attachments...))
opts = append(opts, slack.MsgOptionPostMessageParameters(params))
return opts

View File

@@ -8,8 +8,8 @@ import (
"time"
"github.com/42wim/matterbridge/bridge/config"
"github.com/nlopes/slack"
"github.com/sirupsen/logrus"
"github.com/slack-go/slack"
)
const minimumRefreshInterval = 10 * time.Second

View File

@@ -95,7 +95,7 @@ func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Messa
}
}
// only download avatars if we have a place to upload them (configured mediaserver)
if b.General.MediaServerUpload != "" {
if b.General.MediaServerUpload != "" || (b.General.MediaServerDownload != "" && b.General.MediaDownloadPath != "") {
b.handleDownloadAvatar(message.From.ID, rmsg.Channel)
}
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/Rhymen/go-whatsapp"
"github.com/jpillora/backoff"
)
/*
@@ -22,10 +23,43 @@ Check:
// HandleError received from WhatsApp
func (b *Bwhatsapp) HandleError(err error) {
// ignore received invalid data errors. https://github.com/42wim/matterbridge/issues/843
if strings.Contains(err.Error(), "error processing data: received invalid data") {
// ignore tag 174 errors. https://github.com/42wim/matterbridge/issues/1094
if strings.Contains(err.Error(), "error processing data: received invalid data") || strings.Contains(err.Error(), "invalid string with tag 174") {
return
}
b.Log.Errorf("%v", err) // TODO implement proper handling? at least respond to different error types
switch err.(type) {
case *whatsapp.ErrConnectionClosed, *whatsapp.ErrConnectionFailed:
b.reconnect(err)
default:
switch err {
case whatsapp.ErrConnectionTimeout:
b.reconnect(err)
default:
b.Log.Errorf("%v", err)
}
}
}
func (b *Bwhatsapp) reconnect(err error) {
bf := &backoff.Backoff{
Min: time.Second,
Max: 5 * time.Minute,
Jitter: true,
}
for {
d := bf.Duration()
b.Log.Errorf("Connection failed, underlying error: %v", err)
b.Log.Infof("Waiting %s...", d)
time.Sleep(d)
b.Log.Info("Reconnecting...")
err := b.conn.Restore()
if err == nil {
bf.Reset()
b.startedAt = uint64(time.Now().Unix())
return
}
}
}
// HandleTextMessage sent from WhatsApp, relay it to the brige

View File

@@ -67,6 +67,7 @@ func (b *Bwhatsapp) Connect() error {
// https://github.com/Rhymen/go-whatsapp#creating-a-connection
b.Log.Debugln("Connecting to WhatsApp..")
conn, err := whatsapp.NewConn(20 * time.Second)
conn.SetClientVersion(0, 4, 2080)
if err != nil {
return errors.New("failed to connect to WhatsApp: " + err.Error())
}

34
bridge/xmpp/handler.go Normal file
View File

@@ -0,0 +1,34 @@
package bxmpp
import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/matterbridge/go-xmpp"
)
// handleDownloadAvatar downloads the avatar of userid from channel
// sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful.
// logs an error message if it fails
func (b *Bxmpp) handleDownloadAvatar(avatar xmpp.AvatarData) {
rmsg := config.Message{
Username: "system",
Text: "avatar",
Channel: b.parseChannel(avatar.From),
Account: b.Account,
UserID: avatar.From,
Event: config.EventAvatarDownload,
Extra: make(map[string][]interface{}),
}
if _, ok := b.avatarMap[avatar.From]; !ok {
b.Log.Debugf("Avatar.From: %s", avatar.From)
err := helper.HandleDownloadSize(b.Log, &rmsg, avatar.From+".png", int64(len(avatar.Data)), b.General)
if err != nil {
b.Log.Error(err)
return
}
helper.HandleDownloadData(b.Log, &rmsg, avatar.From+".png", rmsg.Text, "", &avatar.Data, b.General)
b.Log.Debugf("Avatar download complete")
b.Remote <- rmsg
}
}

30
bridge/xmpp/helpers.go Normal file
View File

@@ -0,0 +1,30 @@
package bxmpp
import (
"regexp"
"github.com/42wim/matterbridge/bridge/config"
)
var pathRegex = regexp.MustCompile("[^a-zA-Z0-9]+")
// GetAvatar constructs a URL for a given user-avatar if it is available in the cache.
func getAvatar(av map[string]string, userid string, general *config.Protocol) string {
if hash, ok := av[userid]; ok {
// NOTE: This does not happen in bridge/helper/helper.go but messes up XMPP
id := pathRegex.ReplaceAllString(userid, "_")
return general.MediaServerDownload + "/" + hash + "/" + id + ".png"
}
return ""
}
func (b *Bxmpp) cacheAvatar(msg *config.Message) string {
fi := msg.Extra["file"][0].(config.FileInfo)
/* if we have a sha we have successfully uploaded the file to the media server,
so we can now cache the sha */
if fi.SHA != "" {
b.Log.Debugf("Added %s to %s in avatarMap", fi.SHA, msg.UserID)
b.avatarMap[msg.UserID] = fi.SHA
}
return ""
}

View File

@@ -23,12 +23,15 @@ type Bxmpp struct {
xmppMap map[string]string
connected bool
sync.RWMutex
avatarMap map[string]string
}
func New(cfg *bridge.Config) bridge.Bridger {
return &Bxmpp{
Config: cfg,
xmppMap: make(map[string]string),
Config: cfg,
xmppMap: make(map[string]string),
avatarMap: make(map[string]string),
}
}
@@ -69,6 +72,10 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) {
}
b.Log.Debugf("=> Receiving %#v", msg)
if msg.Event == config.EventAvatarDownload {
return b.cacheAvatar(&msg), nil
}
// Upload a file (in XMPP case send the upload URL because XMPP has no native upload support).
if msg.Extra != nil {
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
@@ -114,6 +121,9 @@ func (b *Bxmpp) createXMPP() error {
ServerName: strings.Split(b.GetString("Jid"), "@")[1],
InsecureSkipVerify: b.GetBool("SkipTLSVerify"), // nolint: gosec
}
xmpp.DebugWriter = b.Log.Writer()
options := xmpp.Options{
Host: b.GetString("Server"),
User: b.GetString("Jid"),
@@ -122,7 +132,6 @@ func (b *Bxmpp) createXMPP() error {
StartTLS: true,
TLSConfig: tc,
Debug: b.GetBool("debug"),
Logger: b.Log.Writer(),
Session: true,
Status: "",
StatusMessage: "",
@@ -228,6 +237,12 @@ func (b *Bxmpp) handleXMPP() error {
event = config.EventTopicChange
}
avatar := getAvatar(b.avatarMap, v.Remote, b.General)
if avatar == "" {
b.Log.Debugf("Requesting avatar data")
b.xc.AvatarRequestData(v.Remote)
}
msgID := v.ID
if v.ReplaceID != "" {
msgID = v.ReplaceID
@@ -237,6 +252,7 @@ func (b *Bxmpp) handleXMPP() error {
Text: v.Text,
Channel: b.parseChannel(v.Remote),
Account: b.Account,
Avatar: avatar,
UserID: v.Remote,
ID: msgID,
Event: event,
@@ -253,6 +269,8 @@ func (b *Bxmpp) handleXMPP() error {
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}
case xmpp.AvatarData:
b.handleDownloadAvatar(v)
case xmpp.Presence:
// Do nothing.
}

View File

@@ -1,3 +1,103 @@
# v1.17.4
## Bugfix
- general: Lowercase account names. Fixes #1108 (#1110)
- msteams: Remove panics and retry polling on failure (msteams). Fixes #1104 (#1105
- whatsapp: Update Rhymen/go-whatsapp. Fixes #1107 (#1109) (make whatsapp working again)
- discord: Add an ID cache (discord). Fixes #1106 (#1111) (fix delete/edits with webhooks)
# v1.17.3
## Enhancements
- xmpp: Implement User Avatar spoofing of XMPP users #1090
- rocketchat: Relay Joins/Topic changes in RocketChat bridge (#1085)
- irc: Add JoinDelay option (irc). Fixes #1084 (#1098)
- slack: Clip too long messages on 3000 length (slack). Fixes #1081 (#1102)
## Bugfix
- general: Fix the behavior of ShowTopicChange and SyncTopic (#1086)
- slack: Prevent image/message looping (slack). Fixes #1088 (#1096)
- whatsapp: Ignore non-critical errors (whatsapp). Fixes #1094 (#1100)
- irc: Add extra space before colon in attachments (irc). Fixes #1089 (#1101)
This release couldn't exist without the following contributors:
@42wim, @ldruschk, @qaisjp, @Polynomdivision
# v1.17.2
## Enhancements
- slack: Update vendor slack-go/slack (#1068)
- general: Update vendor d5/tengo (#1066)
- general: Clarify terminology used in mapping group chat IDs to channels in config (#1079)
## Bugfix
- whatsapp: Update Rhymen/go-whatsapp vendor and whatsapp version (#1078). Fixes Media upload #1074
- whatsapp: Reset start timestamp on reconnect (whatsapp). Fixes #1059 (#1064)
This release couldn't exist without the following contributors:
@42wim, @jheiselman
# v1.17.1
## Enhancements
- docker: Remove build dependencies from final image (multistage build) #1057
## Bugfix
- general: Don't transmit typing events from ourselves #1056
- general: Add support for build tags #1054
- discord: Strip extra info from emotes (discord) #1052
- msteams: fix macos build: Update vendor yaegashi/msgraph.go to v0.1.2 #1036
- whatsapp: Update client version whatsapp. Fixes #1061 #1062
This release couldn't exist without the following contributors:
@awigen, @qaisjp, @42wim
# v1.17.0
## New features
- msteams: new protocol added. Add initial Microsoft Teams support #967
See https://github.com/42wim/matterbridge/wiki/MS-Teams-setup for a complete walkthrough
- discord: Add ability to procure avatars from the destination bridge #1000
- matrix: Add support for avatars from matrix. #1007
- general: support JSON and YAML config formats #1045
## Enhancements
- discord: Check only bridged channels for PermManageWebhooks #1001
- irc: Be less lossy when throttling IRC messages #1004
- keybase: updated library #1002, #1019
- matrix: Rebase gomatrix vendor with upstream #1006
- slack: Use upstream slack-go/slack again #1018
- slack: Ignore ConnectingEvent #1041
- slack: use blocks not attachments #1048
- sshchat: Update vendor shazow/ssh-chat #1029
- telegram: added markdownv2 mode for telegram #1037
- whatsapp: Implement basic reconnect (whatsapp). Fixes #987 #1003
## Bugfix
- discord: Fix webhook permission checks sometimes failing #1043
- discord: Fix #1027: warning when handling inbound webhooks #1044
- discord: Fix duplicate separator on empty description/url (discord) #1035
- matrix: Fix issue with underscores in links #999
- slack: Fix #1039: messages sent to Slack being synced back #1046
- telegram: Make avatars download work with mediaserverdownload (telegram). Fixes #920
This release couldn't exist without the following contributors:
@qaisjp, @jakubgs, @burner1024, @notpushkin, @MartijnBraam, @42wim
# v1.16.5
- Fix version bump
# v1.16.4
## New features

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -u -e -x -o pipefail
go version | grep go1.13 || exit
go version | grep go1.14 || exit
VERSION=$(git describe --tags)
mkdir ci/binaries

11
gateway/bridgemap/api.go Normal file
View File

@@ -0,0 +1,11 @@
// +build !noapi
package bridgemap
import (
"github.com/42wim/matterbridge/bridge/api"
)
func init() {
FullMap["api"] = api.New
}

View File

@@ -0,0 +1,12 @@
// +build !nodiscord
package bridgemap
import (
bdiscord "github.com/42wim/matterbridge/bridge/discord"
)
func init() {
FullMap["discord"] = bdiscord.New
UserTypingSupport["discord"] = struct{}{}
}

View File

@@ -0,0 +1,11 @@
// +build !nogitter
package bridgemap
import (
bgitter "github.com/42wim/matterbridge/bridge/gitter"
)
func init() {
FullMap["gitter"] = bgitter.New
}

11
gateway/bridgemap/birc.go Normal file
View File

@@ -0,0 +1,11 @@
// +build !noirc
package bridgemap
import (
birc "github.com/42wim/matterbridge/bridge/irc"
)
func init() {
FullMap["irc"] = birc.New
}

View File

@@ -0,0 +1,11 @@
// +build !nokeybase
package bridgemap
import (
bkeybase "github.com/42wim/matterbridge/bridge/keybase"
)
func init() {
FullMap["keybase"] = bkeybase.New
}

View File

@@ -0,0 +1,11 @@
// +build !nomatrix
package bridgemap
import (
bmatrix "github.com/42wim/matterbridge/bridge/matrix"
)
func init() {
FullMap["matrix"] = bmatrix.New
}

View File

@@ -0,0 +1,11 @@
// +build !nomattermost
package bridgemap
import (
bmattermost "github.com/42wim/matterbridge/bridge/mattermost"
)
func init() {
FullMap["mattermost"] = bmattermost.New
}

View File

@@ -0,0 +1,11 @@
// +build !nomsteams
package bridgemap
import (
bmsteams "github.com/42wim/matterbridge/bridge/msteams"
)
func init() {
FullMap["msteams"] = bmsteams.New
}

View File

@@ -2,45 +2,9 @@ package bridgemap
import (
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/api"
bdiscord "github.com/42wim/matterbridge/bridge/discord"
bgitter "github.com/42wim/matterbridge/bridge/gitter"
birc "github.com/42wim/matterbridge/bridge/irc"
bkeybase "github.com/42wim/matterbridge/bridge/keybase"
bmatrix "github.com/42wim/matterbridge/bridge/matrix"
bmattermost "github.com/42wim/matterbridge/bridge/mattermost"
brocketchat "github.com/42wim/matterbridge/bridge/rocketchat"
bslack "github.com/42wim/matterbridge/bridge/slack"
bsshchat "github.com/42wim/matterbridge/bridge/sshchat"
bsteam "github.com/42wim/matterbridge/bridge/steam"
btelegram "github.com/42wim/matterbridge/bridge/telegram"
bwhatsapp "github.com/42wim/matterbridge/bridge/whatsapp"
bxmpp "github.com/42wim/matterbridge/bridge/xmpp"
bzulip "github.com/42wim/matterbridge/bridge/zulip"
)
var (
FullMap = map[string]bridge.Factory{
"api": api.New,
"discord": bdiscord.New,
"gitter": bgitter.New,
"irc": birc.New,
"mattermost": bmattermost.New,
"matrix": bmatrix.New,
"rocketchat": brocketchat.New,
"slack-legacy": bslack.NewLegacy,
"slack": bslack.New,
"sshchat": bsshchat.New,
"steam": bsteam.New,
"telegram": btelegram.New,
"whatsapp": bwhatsapp.New,
"xmpp": bxmpp.New,
"zulip": bzulip.New,
"keybase": bkeybase.New,
}
UserTypingSupport = map[string]struct{}{
"slack": {},
"discord": {},
}
FullMap = map[string]bridge.Factory{}
UserTypingSupport = map[string]struct{}{}
)

View File

@@ -0,0 +1,11 @@
// +build !norocketchat
package bridgemap
import (
brocketchat "github.com/42wim/matterbridge/bridge/rocketchat"
)
func init() {
FullMap["rocketchat"] = brocketchat.New
}

View File

@@ -0,0 +1,13 @@
// +build !noslack
package bridgemap
import (
bslack "github.com/42wim/matterbridge/bridge/slack"
)
func init() {
FullMap["slack-legacy"] = bslack.NewLegacy
FullMap["slack"] = bslack.New
UserTypingSupport["slack"] = struct{}{}
}

View File

@@ -0,0 +1,11 @@
// +build !nosshchat
package bridgemap
import (
bsshchat "github.com/42wim/matterbridge/bridge/sshchat"
)
func init() {
FullMap["sshchat"] = bsshchat.New
}

View File

@@ -0,0 +1,11 @@
// +build !nosteam
package bridgemap
import (
bsteam "github.com/42wim/matterbridge/bridge/steam"
)
func init() {
FullMap["steam"] = bsteam.New
}

View File

@@ -0,0 +1,11 @@
// +build !notelegram
package bridgemap
import (
btelegram "github.com/42wim/matterbridge/bridge/telegram"
)
func init() {
FullMap["telegram"] = btelegram.New
}

View File

@@ -0,0 +1,11 @@
// +build !nowhatsapp
package bridgemap
import (
bwhatsapp "github.com/42wim/matterbridge/bridge/whatsapp"
)
func init() {
FullMap["whatsapp"] = bwhatsapp.New
}

View File

@@ -0,0 +1,11 @@
// +build !noxmpp
package bridgemap
import (
bxmpp "github.com/42wim/matterbridge/bridge/xmpp"
)
func init() {
FullMap["xmpp"] = bxmpp.New
}

View File

@@ -0,0 +1,11 @@
// +build !nozulip
package bridgemap
import (
bzulip "github.com/42wim/matterbridge/bridge/zulip"
)
func init() {
FullMap["zulip"] = bzulip.New
}

View File

@@ -108,7 +108,7 @@ func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
func (gw *Gateway) checkConfig(cfg *config.Bridge) {
match := false
for _, key := range gw.Router.Config.Viper().AllKeys() {
if strings.HasPrefix(key, cfg.Account) {
if strings.HasPrefix(key, strings.ToLower(cfg.Account)) {
match = true
break
}
@@ -306,8 +306,6 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
}
func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) string {
br := gw.Bridges[msg.Account]
msg.Protocol = br.Protocol
if dest.GetBool("StripNick") {
re := regexp.MustCompile("[^a-zA-Z0-9]+")
msg.Username = re.ReplaceAllString(msg.Username, "")
@@ -315,6 +313,7 @@ func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) stri
nick := dest.GetString("RemoteNickFormat")
// loop to replace nicks
br := gw.Bridges[msg.Account]
for _, outer := range br.GetStringSlice2D("ReplaceNicks") {
search := outer[0]
replace := outer[1]

View File

@@ -169,7 +169,7 @@ func (gw *Gateway) ignoreEvent(event string, dest *bridge.Bridge) bool {
switch event {
case config.EventAvatarDownload:
// Avatar downloads are only relevant for telegram and mattermost for now
if dest.Protocol != "mattermost" && dest.Protocol != "telegram" {
if dest.Protocol != "mattermost" && dest.Protocol != "telegram" && dest.Protocol != "xmpp" {
return true
}
case config.EventJoinLeave:
@@ -179,7 +179,7 @@ func (gw *Gateway) ignoreEvent(event string, dest *bridge.Bridge) bool {
}
case config.EventTopicChange:
// only relay topic change when used in some way on other side
if dest.GetBool("ShowTopicChange") && dest.GetBool("SyncTopic") {
if !dest.GetBool("ShowTopicChange") && !dest.GetBool("SyncTopic") {
return true
}
}

View File

@@ -132,6 +132,9 @@ func (r *Router) handleReceive() {
r.handleEventFailure(&msg)
r.handleEventRejoinChannels(&msg)
// Set message protocol based on the account it came from
msg.Protocol = r.getBridge(msg.Account).Protocol
filesHandled := false
for _, gw := range r.Gateways {
// record all the message ID's of the different bridges

26
go.mod
View File

@@ -5,9 +5,8 @@ require (
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
github.com/Jeffail/gabs v1.1.1 // indirect
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0
github.com/Rhymen/go-whatsapp v0.1.0
github.com/bwmarrin/discordgo v0.20.2
github.com/d5/tengo/v2 v2.0.2
github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334
github.com/d5/tengo/v2 v2.1.2
github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec
github.com/fsnotify/fsnotify v1.4.7
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible
@@ -19,22 +18,24 @@ require (
github.com/hashicorp/golang-lru v0.5.3
github.com/hpcloud/tail v1.0.0 // indirect
github.com/jpillora/backoff v1.0.0
github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2
github.com/keybase/go-keybase-chat-bot v0.0.0-20200226211841-4e48f3eaef3e
github.com/labstack/echo/v4 v4.1.13
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048
github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91
github.com/matterbridge/gomatrix v0.0.0-20191026211822-6fc7accd00ca
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050
github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6
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/mattn/go-runewidth v0.0.7 // indirect
github.com/mattn/godown v0.0.0-20180312012330-2e9e17e0ea51
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 // indirect
github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9
github.com/nicksnyder/go-i18n v1.4.0 // indirect
github.com/nlopes/slack v0.6.0
github.com/onsi/ginkgo v1.6.0 // indirect
github.com/onsi/gomega v1.4.1 // indirect
github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
@@ -42,21 +43,22 @@ require (
github.com/rs/xid v1.2.1
github.com/russross/blackfriday v1.5.2
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
github.com/shazow/ssh-chat v1.8.2
github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98
github.com/sirupsen/logrus v1.4.2
github.com/slack-go/slack v0.6.3
github.com/spf13/viper v1.6.1
github.com/stretchr/testify v1.4.0
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
github.com/yaegashi/msgraph.go v0.1.2
github.com/zfjagann/golang-ring v0.0.0-20190106091943-a88bb6aef447
golang.org/x/image v0.0.0-20191214001246-9130b4cfad52
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
)
replace github.com/nlopes/slack v0.6.0 => github.com/matterbridge/slack v0.1.1-0.20191208194820-95190f11bfb6
replace github.com/bwmarrin/discordgo v0.20.2 => github.com/matterbridge/discordgo v0.18.1-0.20200109173909-ed873362fa43
//replace github.com/bwmarrin/discordgo v0.20.2 => github.com/matterbridge/discordgo v0.18.1-0.20200109173909-ed873362fa43
go 1.13

79
go.sum
View File

@@ -1,4 +1,5 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 h1:IZtuWGfzQnKnCSu+vl8WGLhpVQ5Uvy3rlSwqXSg+sQg=
github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557/go.mod h1:jL0YSXMs/txjtGJ4PWrmETOk6KUHMDPMshgQZlTeB3Y=
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f h1:2dk3eOnYllh+wUOuDhOoC2vUVoJF/5z478ryJ+wzEII=
@@ -11,13 +12,12 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0 h1:TO7d4rocnNFng6ZQrPe7U6WqHtK5eHEMrgrnnM/72IQ=
github.com/Philipp15b/go-steam v1.0.1-0.20190816133340-b04c5a83c1c0/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg=
github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
github.com/Rhymen/go-whatsapp v0.1.0 h1:XTXhFIQ/fx9jKObUnUX2Q+nh58EyeHNhX7DniE8xeuA=
github.com/Rhymen/go-whatsapp v0.1.0/go.mod h1:xJSy+okeRjKkQEH/lEYrnekXB3PG33fqL0I6ncAkV50=
github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334 h1:kb1zvD+xd+XbPUdQ0lMxnRaQ76N5C9vMAClLi8Dyw1Y=
github.com/Rhymen/go-whatsapp v0.1.1-0.20200421062035-31e8111ac334/go.mod h1:o7jjkvKnigfu432dMbQ/w4PH0Yp5u4Y6ysCNjUlcYCk=
github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME=
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM=
github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e h1:IHXQQIpxASe3m0Jtcd3XongL+lxHNd5nUmvHxJARUmg=
github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -33,8 +33,8 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/d5/tengo/v2 v2.0.2 h1:3APkPZPc1FExaJoWrN5YzvDqc6GNkQH6ehmCRDmN83I=
github.com/d5/tengo/v2 v2.0.2/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8=
github.com/d5/tengo/v2 v2.1.2 h1:JR5O6qJW2GW9lpv/MfEqK16a/Wpp2y8I0JZZ5fqNOL0=
github.com/d5/tengo/v2 v2.1.2/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8=
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=
@@ -49,18 +49,18 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible h1:i64CCJcSqkRIkm5OSdZQjZq84/gJsk2zNwHWIRYWlKE=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -70,6 +70,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/gops v0.3.6 h1:6akvbMlpZrEYOuoebn2kR+ZJekbZqJ28fJXTs84+8to=
github.com/google/gops v0.3.6/go.mod h1:RZ1rH95wsAGX4vMWKmqBOIWynmWisBf4QFdgT/k/xOI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 h1:4EZlYQIiyecYJlUbVkFXCXHz1QPhVXcHnQKAzBTPfQo=
github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/xNRBCxrn4h/CEB67h0kW1B0t4ooP2yrjUA=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
@@ -77,7 +78,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
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/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -100,8 +100,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2 h1:zacJswvfPqUSGdcBXJzKvLN/dB1UjDGDvDesMBBzoA4=
github.com/keybase/go-keybase-chat-bot v0.0.0-20190816161829-561f10822eb2/go.mod h1:vNc28YFzigVJod0j5EbuTtRIe7swx8vodh2yA4jZ2s8=
github.com/keybase/go-keybase-chat-bot v0.0.0-20200226211841-4e48f3eaef3e h1:KbPTfR/PYuau1IzKoE4lnd8yby5I2pBj+VR6fSVbYU8=
github.com/keybase/go-keybase-chat-bot v0.0.0-20200226211841-4e48f3eaef3e/go.mod h1:vNc28YFzigVJod0j5EbuTtRIe7swx8vodh2yA4jZ2s8=
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999 h1:2d+FLQbz4xRTi36DO1qYNUwfORax9XcQ0jhbO81Vago=
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@@ -124,38 +124,35 @@ github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7 h1:BS9tqL0OCiOGuy/C
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7/go.mod h1:liX5MxHPrwgHaKowoLkYGwbXfYABh1jbZ6FpElbGF1I=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d h1:F+Sr+C0ojSlYQ37BLylQtSFmyQULe3jbAygcyXQ9mVs=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
github.com/matterbridge/discordgo v0.18.1-0.20200109173909-ed873362fa43 h1:xTcLiEPMp9jVh/lHEPpLc87RZ4sRWRZe0rM578/waOk=
github.com/matterbridge/discordgo v0.18.1-0.20200109173909-ed873362fa43/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048 h1:B9HaistmV+MD8/33BXmZe1zPIn+RImAFVXNNSOrwU2E=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3 h1:VP/DNRn2HtrVRN6+X3h4FDcQI2OOKT+88WUi21ZD1Kw=
github.com/matterbridge/discordgo v0.18.1-0.20200308151012-aa40f01cbcc3/go.mod h1:5a1bHtG/38ofcx9cgwM5eTW/Pl4SpbQksNDnTRcGA2Y=
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible h1:oaOqwbg5HxHRxvAbd84ks0Okwoc1ISyUZ87EiVJFhGI=
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible/go.mod h1:igE6rUAn3jai2wCdsjFHfhUoekjrFthoEjFObKKwSb4=
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 h1:KzDEcy8eDbTx881giW8a6llsAck3e2bJvMyKvh1IK+k=
github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q=
github.com/matterbridge/gomatrix v0.0.0-20191026211822-6fc7accd00ca h1:3ypqEpFpt6vg5Sv2xxA8/v4WiSOnWMXW7DqxTxpM4XI=
github.com/matterbridge/gomatrix v0.0.0-20191026211822-6fc7accd00ca/go.mod h1:+jWeaaUtXQbBRdKYWfjW6JDDYiI2XXE+3NnTjW5kg8g=
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050 h1:kWkP1lXpkvtoNL08jkP3XQH/zvDOEXJpdCJd/DlIvMw=
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q=
github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6 h1:Kl65VJv38HjYFnnwH+MP6Z8hcJT5UHuSpHVU5vW1HH0=
github.com/matterbridge/gomatrix v0.0.0-20200209224845-c2104d7936a6/go.mod h1:+jWeaaUtXQbBRdKYWfjW6JDDYiI2XXE+3NnTjW5kg8g=
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/matterbridge/slack v0.1.1-0.20191208194820-95190f11bfb6 h1:UvXXR9tHYqJUXZVEtiK2qkEWBXfFneicate5kOshVFk=
github.com/matterbridge/slack v0.1.1-0.20191208194820-95190f11bfb6/go.mod h1:2uCJim0Ct2z1Uj+XQq47KCLLC1b/9UTYaZOvDtbZfK4=
github.com/mattermost/mattermost-server v5.5.0+incompatible h1:0wcLGgYtd+YImtLDPf2AOfpBHxbU4suATx+6XKw1XbU=
github.com/mattermost/mattermost-server v5.5.0+incompatible/go.mod h1:5L6MjAec+XXQwMIt791Ganu45GKsSiM+I0tLR9wUj8Y=
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-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/godown v0.0.0-20180312012330-2e9e17e0ea51 h1:MpI7hy3MiCnrggmZI/s8LaPbLVOOWpzDbjA4F+XaXaM=
github.com/mattn/godown v0.0.0-20180312012330-2e9e17e0ea51/go.mod h1:s3KUdOIXJ+jaGM++XHiXA6gikdleaWVATCcQGD4h734=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
@@ -170,6 +167,8 @@ github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 h1:mp6tU1r0xLostUGL
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9/go.mod h1:A5SRAcpTemjGgIuBq6Kic2yHcoeUFWUinOAlMP/i9xo=
github.com/nicksnyder/go-i18n v1.4.0 h1:AgLl+Yq7kg5OYlzCgu9cKTZOyI4tD/NgukKqLqC8E+I=
github.com/nicksnyder/go-i18n v1.4.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
github.com/nlopes/slack v0.6.0 h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -195,6 +194,10 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rickb777/date v1.12.4 h1:+6IzcCCS/1t17DrmnEvrznyq7nM8vPwir6/UhlyohKw=
github.com/rickb777/date v1.12.4/go.mod h1:xP0eo/I5qmUt97yRGClHZfyLZ3ikMw6v6SU5MOGZTE0=
github.com/rickb777/plural v1.2.0 h1:5tvEc7UBCZ7l8h/2UeybSkt/uu1DQsZFOFdNevmUhlE=
github.com/rickb777/plural v1.2.0/go.mod h1:UdpyWFCGbo3mvK3f/PfZOAOrkjzJlYN/sD46XNWJ+Es=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@@ -204,17 +207,17 @@ github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxT
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 h1:Lx3BlDGFElJt4u/zKc9A3BuGYbQAGlEFyPuUA3jeMD0=
github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1/go.mod h1:vt2jWY/3Qw1bIzle5thrJWucsLuuX9iUNnp20CqCciI=
github.com/shazow/ssh-chat v1.8.2 h1:MMso9eWfCnPBelRsusYxKcRBUwHIPEQkR9WrO89II38=
github.com/shazow/ssh-chat v1.8.2/go.mod h1:cXTZK/D1zujEwB0y8DIT1GX8rIKjyLDYeWd+jitPX84=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 h1:80VN+vGkqM773Br/uNNTSheo3KatTgV8IpjIKjvVLng=
github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98 h1:sN07ff+PSRsUNhpSod4uGKAQ+Nc0FXsBPG9FmYMNg4w=
github.com/shazow/ssh-chat v1.8.3-0.20200308224626-80ddf1f43a98/go.mod h1:xkTgfD+WP+KR4HuG76oal25BBEeu5kJyi2EOsgiu/4Q=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE=
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
github.com/slack-go/slack v0.6.3 h1:qU037g8gQ71EuH6S9zYKnvYrEUj0fLFH4HFekFqBoRU=
github.com/slack-go/slack v0.6.3/go.mod h1:HE4RwNe7YpOg/F0vqo5PwXH3Hki31TplTvKRW9dGGaw=
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 v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
@@ -232,7 +235,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk=
github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
@@ -245,16 +247,16 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6 h1:YdYsPAZ2pC6Tow/nPZOPQ96O3hm/ToAkGsPLzedXERk=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yaegashi/msgraph.go v0.1.2 h1:83uVRQaj8YBsVqOUGj0WRwzxdgGF69jRpg5IQYaTvoY=
github.com/yaegashi/msgraph.go v0.1.2/go.mod h1:Lp39e9oo596G5FcmMKI0cXR3mg/QikSdabgZdbMqbAM=
github.com/zfjagann/golang-ring v0.0.0-20190106091943-a88bb6aef447 h1:CHgPZh8bFkZmislPrr/0gd7MciDAX+JJB70A2/5Lvmo=
github.com/zfjagann/golang-ring v0.0.0-20190106091943-a88bb6aef447/go.mod h1:0MsIttMJIF/8Y7x0XjonJP7K99t3sR6bjj4m5S4JmqU=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -268,7 +270,6 @@ golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90te
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/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-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc=
@@ -277,20 +278,22 @@ golang.org/x/image v0.0.0-20191214001246-9130b4cfad52 h1:2fktqPPvDiVEEVT/vSTeoUP
golang.org/x/image v0.0.0-20191214001246-9130b4cfad52/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20171017063910-8dbc5d05d6ed/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -302,12 +305,10 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 h1:JA8d3MPx/IToSyXZG/RhwYEtfrKO1Fxrqe8KrkiLXKM=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/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=
@@ -318,6 +319,8 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -337,10 +340,8 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
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=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/goversion v1.0.0 h1:/IhXBiai89TyuerPquiZZ39IQkTfAUbZB2awsyYZ/2c=
rsc.io/goversion v1.0.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=

View File

@@ -15,7 +15,7 @@ import (
)
var (
version = "1.16.4-dev"
version = "1.17.4"
githash string
flagConfig = flag.String("conf", "matterbridge.toml", "config file")

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@ import (
"time"
"github.com/gorilla/schema"
"github.com/nlopes/slack"
"github.com/slack-go/slack"
)
// OMessage for mattermost incoming webhook. (send to mattermost)

File diff suppressed because it is too large Load Diff

View File

@@ -56,6 +56,8 @@ message Location {
}
message Point {
optional int32 xDeprecated = 1;
optional int32 yDeprecated = 2;
optional double x = 3;
optional double y = 4;
}
@@ -93,6 +95,7 @@ message ContextInfo {
optional AdReplyInfo quotedAd = 23;
optional MessageKey placeholderKey = 24;
optional uint32 expiration = 25;
optional int64 ephemeralSettingTimestamp = 26;
}
message SenderKeyDistributionMessage {
@@ -136,6 +139,11 @@ message LocationMessage {
optional string name = 3;
optional string address = 4;
optional string url = 5;
optional bool isLive = 6;
optional uint32 accuracyInMeters = 7;
optional float speedInMps = 8;
optional uint32 degreesClockwiseFromMagneticNorth = 9;
optional string comment = 11;
optional bytes jpegThumbnail = 16;
optional ContextInfo contextInfo = 17;
}
@@ -238,9 +246,29 @@ message ProtocolMessage {
enum PROTOCOL_MESSAGE_TYPE {
REVOKE = 0;
EPHEMERAL_SETTING = 3;
EPHEMERAL_SYNC_RESPONSE = 4;
HISTORY_SYNC_NOTIFICATION = 5;
}
optional PROTOCOL_MESSAGE_TYPE type = 2;
optional uint32 ephemeralExpiration = 4;
optional int64 ephemeralSettingTimestamp = 5;
optional HistorySyncNotification historySyncNotification = 6;
}
message HistorySyncNotification {
optional bytes fileSha256 = 1;
optional uint64 fileLength = 2;
optional bytes mediaKey = 3;
optional bytes fileEncSha256 = 4;
optional string directPath = 5;
enum HISTORY_SYNC_NOTIFICATION_HISTORYSYNCTYPE {
INITIAL_BOOTSTRAP = 0;
INITIAL_STATUS_V3 = 1;
FULL = 2;
RECENT = 3;
}
optional HISTORY_SYNC_NOTIFICATION_HISTORYSYNCTYPE syncType = 6;
optional uint32 chunkOrder = 7;
}
message ContactsArrayMessage {
@@ -355,6 +383,8 @@ message StickerMessage {
optional int64 mediaKeyTimestamp = 10;
optional uint32 firstFrameLength = 11;
optional bytes firstFrameSidecar = 12;
optional bool isAnimated = 13;
optional bytes pngThumbnail = 16;
optional ContextInfo contextInfo = 17;
}
@@ -401,6 +431,12 @@ message TemplateButtonReplyMessage {
optional uint32 selectedIndex = 4;
}
message CatalogSnapshot {
optional ImageMessage catalogImage = 1;
optional string title = 2;
optional string description = 3;
}
message ProductSnapshot {
optional ImageMessage productImage = 1;
optional string productId = 2;
@@ -417,6 +453,7 @@ message ProductSnapshot {
message ProductMessage {
optional ProductSnapshot product = 1;
optional string businessOwnerJid = 2;
optional CatalogSnapshot catalog = 4;
optional ContextInfo contextInfo = 17;
}
@@ -513,6 +550,8 @@ message WebFeatures {
optional WEB_FEATURES_FLAG templateMessage = 30;
optional WEB_FEATURES_FLAG templateMessageInteractivity = 31;
optional WEB_FEATURES_FLAG ephemeralMessages = 32;
optional WEB_FEATURES_FLAG e2ENotificationSync = 33;
optional WEB_FEATURES_FLAG recentStickersV2 = 34;
}
message TabletNotificationsInfo {
@@ -537,6 +576,11 @@ message WebNotificationsInfo {
}
message PaymentInfo {
enum PAYMENT_INFO_CURRENCY {
UNKNOWN_CURRENCY = 0;
INR = 1;
}
optional PAYMENT_INFO_CURRENCY currencyDeprecated = 1;
optional uint64 amount1000 = 2;
optional string receiverJid = 3;
enum PAYMENT_INFO_STATUS {
@@ -559,6 +603,37 @@ message PaymentInfo {
optional uint64 expiryTimestamp = 7;
optional bool futureproofed = 8;
optional string currency = 9;
enum PAYMENT_INFO_TXNSTATUS {
UNKNOWN = 0;
PENDING_SETUP = 1;
PENDING_RECEIVER_SETUP = 2;
INIT = 3;
SUCCESS = 4;
COMPLETED = 5;
FAILED = 6;
FAILED_RISK = 7;
FAILED_PROCESSING = 8;
FAILED_RECEIVER_PROCESSING = 9;
FAILED_DA = 10;
FAILED_DA_FINAL = 11;
REFUNDED_TXN = 12;
REFUND_FAILED = 13;
REFUND_FAILED_PROCESSING = 14;
REFUND_FAILED_DA = 15;
EXPIRED_TXN = 16;
AUTH_CANCELED = 17;
AUTH_CANCEL_FAILED_PROCESSING = 18;
AUTH_CANCEL_FAILED = 19;
COLLECT_INIT = 20;
COLLECT_SUCCESS = 21;
COLLECT_FAILED = 22;
COLLECT_FAILED_RISK = 23;
COLLECT_REJECTED = 24;
COLLECT_EXPIRED = 25;
COLLECT_CANCELED = 26;
COLLECT_CANCELLING = 27;
}
optional PAYMENT_INFO_TXNSTATUS txnStatus = 10;
}
message WebMessageInfo {
@@ -668,4 +743,5 @@ message WebMessageInfo {
optional PaymentInfo quotedPaymentInfo = 31;
optional uint64 ephemeralStartTimestamp = 32;
optional uint32 ephemeralDuration = 33;
}
}

View File

@@ -90,6 +90,7 @@ type Conn struct {
longClientName string
shortClientName string
clientVersion string
loginSessionLock sync.RWMutex
Proxy func(*http.Request) (*url.URL, error)
@@ -121,6 +122,7 @@ func NewConn(timeout time.Duration) (*Conn, error) {
longClientName: "github.com/rhymen/go-whatsapp",
shortClientName: "go-whatsapp",
clientVersion: "0.1.0",
}
return wac, wac.connect()
}
@@ -135,6 +137,7 @@ func NewConnWithProxy(timeout time.Duration, proxy func(*http.Request) (*url.URL
longClientName: "github.com/rhymen/go-whatsapp",
shortClientName: "go-whatsapp",
clientVersion: "0.1.0",
Proxy: proxy,
}
return wac, wac.connect()

View File

@@ -6,7 +6,7 @@ require (
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d // indirect
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d // indirect
github.com/golang/protobuf v1.3.0
github.com/gorilla/websocket v1.4.0
github.com/gorilla/websocket v1.4.1
github.com/pkg/errors v0.8.1
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
)

View File

@@ -12,8 +12,9 @@ github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
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/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
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 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=

View File

@@ -10,10 +10,8 @@ import (
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"strings"
"net/url"
"time"
"github.com/Rhymen/go-whatsapp/crypto/cbc"
@@ -95,7 +93,50 @@ func downloadMedia(url string) (file []byte, mac []byte, err error) {
return data[:n-10], data[n-10 : n], nil
}
func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (url string, mediaKey []byte, fileEncSha256 []byte, fileSha256 []byte, fileLength uint64, err error) {
type MediaConn struct {
Status int `json:"status"`
MediaConn struct {
Auth string `json:"auth"`
TTL int `json:"ttl"`
Hosts []struct {
Hostname string `json:"hostname"`
IPs []string `json:"ips"`
} `json:"hosts"`
} `json:"media_conn"`
}
func (wac *Conn) queryMediaConn() (hostname, auth string, ttl int, err error) {
queryReq := []interface{}{"query", "mediaConn"}
ch, err := wac.writeJson(queryReq)
if err != nil {
return "", "", 0, err
}
var resp MediaConn
select {
case r := <-ch:
if err = json.Unmarshal([]byte(r), &resp); err != nil {
return "", "", 0, fmt.Errorf("error decoding query media conn response: %v", err)
}
case <-time.After(wac.msgTimeout):
return "", "", 0, fmt.Errorf("query media conn timed out")
}
if resp.Status != 200 {
return "", "", 0, fmt.Errorf("query media conn responded with %d", resp.Status)
}
return resp.MediaConn.Hosts[0].Hostname, resp.MediaConn.Auth, resp.MediaConn.TTL, nil
}
var mediaTypeMap = map[MediaType]string{
MediaImage: "/mms/image",
MediaVideo: "/mms/video",
MediaDocument: "/mms/document",
MediaAudio: "/mms/audio",
}
func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (downloadURL string, mediaKey []byte, fileEncSha256 []byte, fileSha256 []byte, fileLength uint64, err error) {
data, err := ioutil.ReadAll(reader)
if err != nil {
return "", nil, nil, nil, 0, err
@@ -128,67 +169,30 @@ func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (url string, mediaK
sha.Write(append(enc, mac...))
fileEncSha256 = sha.Sum(nil)
var filetype string
switch appInfo {
case MediaImage:
filetype = "image"
case MediaAudio:
filetype = "audio"
case MediaDocument:
filetype = "document"
case MediaVideo:
filetype = "video"
hostname, auth, _, err := wac.queryMediaConn()
token := base64.URLEncoding.EncodeToString(fileEncSha256)
q := url.Values{
"auth": []string{auth},
"token": []string{token},
}
path := mediaTypeMap[appInfo]
uploadURL := url.URL{
Scheme: "https",
Host: hostname,
Path: fmt.Sprintf("%s/%s", path, token),
RawQuery: q.Encode(),
}
uploadReq := []interface{}{"action", "encr_upload", filetype, base64.StdEncoding.EncodeToString(fileEncSha256)}
ch, err := wac.writeJson(uploadReq)
body := bytes.NewReader(append(enc, mac...))
req, err := http.NewRequest("POST", uploadURL.String(), body)
if err != nil {
return "", nil, nil, nil, 0, err
}
var resp map[string]interface{}
select {
case r := <-ch:
if err = json.Unmarshal([]byte(r), &resp); err != nil {
return "", nil, nil, nil, 0, fmt.Errorf("error decoding upload response: %v", err)
}
case <-time.After(wac.msgTimeout):
return "", nil, nil, nil, 0, fmt.Errorf("restore session init timed out")
}
if int(resp["status"].(float64)) != 200 {
return "", nil, nil, nil, 0, fmt.Errorf("upload responsed with %d", resp["status"])
}
var b bytes.Buffer
w := multipart.NewWriter(&b)
hashWriter, err := w.CreateFormField("hash")
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
}
io.Copy(hashWriter, strings.NewReader(base64.StdEncoding.EncodeToString(fileEncSha256)))
fileWriter, err := w.CreateFormFile("file", "blob")
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
}
io.Copy(fileWriter, bytes.NewReader(append(enc, mac...)))
err = w.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
}
req, err := http.NewRequest("POST", resp["url"].(string), &b)
if err != nil {
return "", nil, nil, nil, 0, err
}
req.Header.Set("Content-Type", w.FormDataContentType())
req.Header.Set("Origin", "https://web.whatsapp.com")
req.Header.Set("Referer", "https://web.whatsapp.com/")
req.URL.Query().Set("f", "j")
client := &http.Client{}
// Submit the request
res, err := client.Do(req)

View File

@@ -15,7 +15,10 @@ import (
)
func (wac *Conn) readPump() {
defer wac.wg.Done()
defer func() {
wac.wg.Done()
_, _ = wac.Disconnect()
}()
var readErr error
var msgType int
@@ -31,7 +34,6 @@ func (wac *Conn) readPump() {
case <-readerFound:
if readErr != nil {
wac.handle(&ErrConnectionFailed{Err: readErr})
_, _ = wac.Disconnect()
return
}
msg, err := ioutil.ReadAll(reader)

View File

@@ -18,7 +18,7 @@ import (
)
//represents the WhatsAppWeb client version
var waVersion = []int{0, 3, 3324}
var waVersion = []int{0, 4, 2080}
/*
Session contains session individual information. To be able to resume the connection without scanning the qr code
@@ -107,10 +107,10 @@ func CheckCurrentServerVersion() ([]int, error) {
}
b64ClientId := base64.StdEncoding.EncodeToString(clientId)
login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, b64ClientId, true}
login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName, wac.clientVersion}, b64ClientId, true}
loginChan, err := wac.writeJson(login)
if err != nil {
return nil, fmt.Errorf("error writing login", err)
return nil, fmt.Errorf("error writing login: %s", err.Error())
}
// Retrieve an answer from the websocket
@@ -123,7 +123,7 @@ func CheckCurrentServerVersion() ([]int, error) {
var resp map[string]interface{}
if err = json.Unmarshal([]byte(r), &resp); err != nil {
return nil, fmt.Errorf("error decoding login", err)
return nil, fmt.Errorf("error decoding login: %s", err.Error())
}
// Take the curr property as X.Y.Z and split it into as int slice
@@ -141,17 +141,17 @@ func CheckCurrentServerVersion() ([]int, error) {
SetClientName sets the long and short client names that are sent to WhatsApp when logging in and displayed in the
WhatsApp Web device list. As the values are only sent when logging in, changing them after logging in is not possible.
*/
func (wac *Conn) SetClientName(long, short string) error {
func (wac *Conn) SetClientName(long, short, version string) error {
if wac.session != nil && (wac.session.EncKey != nil || wac.session.MacKey != nil) {
return fmt.Errorf("cannot change client name after logging in")
}
wac.longClientName, wac.shortClientName = long, short
wac.longClientName, wac.shortClientName, wac.clientVersion = long, short, version
return nil
}
/*
SetClientVersion sets WhatsApp client version
Default value is 0.3.3324
Default value is 0.4.2080
*/
func (wac *Conn) SetClientVersion(major int, minor int, patch int) {
waVersion = []int{major, minor, patch}
@@ -213,7 +213,7 @@ func (wac *Conn) Login(qrChan chan<- string) (Session, error) {
}
session.ClientId = base64.StdEncoding.EncodeToString(clientId)
login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, session.ClientId, true}
login := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName, wac.clientVersion}, session.ClientId, true}
loginChan, err := wac.writeJson(login)
if err != nil {
return session, fmt.Errorf("error writing login: %v\n", err)
@@ -369,7 +369,7 @@ func (wac *Conn) Restore() error {
wac.listener.Unlock()
//admin init
init := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName}, wac.session.ClientId, true}
init := []interface{}{"admin", "init", waVersion, []string{wac.longClientName, wac.shortClientName, wac.clientVersion}, wac.session.ClientId, true}
initChan, err := wac.writeJson(init)
if err != nil {
return fmt.Errorf("error writing admin init: %v\n", err)

View File

@@ -11,9 +11,10 @@ builds:
- darwin
- linux
- windows
archive:
files:
- none*
archives:
-
files:
- none*
checksum:
name_template: 'checksums.txt'
changelog:

View File

@@ -7,7 +7,6 @@
[![GoDoc](https://godoc.org/github.com/d5/tengo?status.svg)](https://godoc.org/github.com/d5/tengo)
[![Go Report Card](https://goreportcard.com/badge/github.com/d5/tengo)](https://goreportcard.com/report/github.com/d5/tengo)
[![CircleCI](https://circleci.com/gh/d5/tengo.svg?style=svg)](https://circleci.com/gh/d5/tengo)
[![Sourcegraph](https://sourcegraph.com/github.com/d5/tengo/-/badge.svg)](https://sourcegraph.com/github.com/d5/tengo?badge)
**Tengo is a small, dynamic, fast, secure script language for Go.**
@@ -75,6 +74,10 @@ _* See [here](https://github.com/d5/tengobench) for commands/codes used_
## Quick Start
```
go get github.com/d5/tengo/v2
```
A simple Go example code that compiles/runs Tengo script code with some input/output values:
```golang

View File

@@ -13,6 +13,14 @@ var builtinFuncs = []*BuiltinFunction{
Name: "append",
Value: builtinAppend,
},
{
Name: "delete",
Value: builtinDelete,
},
{
Name: "splice",
Value: builtinSplice,
},
{
Name: "string",
Value: builtinString,
@@ -500,3 +508,104 @@ func builtinAppend(args ...Object) (Object, error) {
}
}
}
// builtinDelete deletes Map keys
// usage: delete(map, "key")
// key must be a string
func builtinDelete(args ...Object) (Object, error) {
argsLen := len(args)
if argsLen != 2 {
return nil, ErrWrongNumArguments
}
switch arg := args[0].(type) {
case *Map:
if key, ok := args[1].(*String); ok {
delete(arg.Value, key.Value)
return UndefinedValue, nil
}
return nil, ErrInvalidArgumentType{
Name: "second",
Expected: "string",
Found: args[1].TypeName(),
}
default:
return nil, ErrInvalidArgumentType{
Name: "first",
Expected: "map",
Found: arg.TypeName(),
}
}
}
// builtinSplice deletes and changes given Array, returns deleted items.
// usage:
// deleted_items := splice(array[,start[,delete_count[,item1[,item2[,...]]]])
func builtinSplice(args ...Object) (Object, error) {
argsLen := len(args)
if argsLen == 0 {
return nil, ErrWrongNumArguments
}
array, ok := args[0].(*Array)
if !ok {
return nil, ErrInvalidArgumentType{
Name: "first",
Expected: "array",
Found: args[0].TypeName(),
}
}
arrayLen := len(array.Value)
var startIdx int
if argsLen > 1 {
arg1, ok := args[1].(*Int)
if !ok {
return nil, ErrInvalidArgumentType{
Name: "second",
Expected: "int",
Found: args[1].TypeName(),
}
}
startIdx = int(arg1.Value)
if startIdx < 0 || startIdx > arrayLen {
return nil, ErrIndexOutOfBounds
}
}
delCount := len(array.Value)
if argsLen > 2 {
arg2, ok := args[2].(*Int)
if !ok {
return nil, ErrInvalidArgumentType{
Name: "third",
Expected: "int",
Found: args[2].TypeName(),
}
}
delCount = int(arg2.Value)
if delCount < 0 {
return nil, ErrIndexOutOfBounds
}
}
// if count of to be deleted items is bigger than expected, truncate it
if startIdx+delCount > arrayLen {
delCount = arrayLen - startIdx
}
// delete items
endIdx := startIdx + delCount
deleted := append([]Object{}, array.Value[startIdx:endIdx]...)
head := array.Value[:startIdx]
var items []Object
if argsLen > 3 {
items = make([]Object, 0, argsLen-3)
for i := 3; i < argsLen; i++ {
items = append(items, args[i])
}
}
items = append(items, array.Value[endIdx:]...)
array.Value = append(head, items...)
// return deleted items
return &Array{Value: deleted}, nil
}

View File

@@ -80,14 +80,14 @@ func (v *VM) Run() (err error) {
if err != nil {
filePos := v.fileSet.Position(
v.curFrame.fn.SourcePos(v.ip - 1))
err = fmt.Errorf("Runtime Error: %s\n\tat %s",
err.Error(), filePos)
err = fmt.Errorf("Runtime Error: %w\n\tat %s",
err, filePos)
for v.framesIndex > 1 {
v.framesIndex--
v.curFrame = &v.frames[v.framesIndex-1]
filePos = v.fileSet.Position(
v.curFrame.fn.SourcePos(v.curFrame.ip - 1))
err = fmt.Errorf("%s\n\tat %s", err.Error(), filePos)
err = fmt.Errorf("%w\n\tat %s", err, filePos)
}
return err
}

View File

@@ -0,0 +1,651 @@
package kbchat
import (
"encoding/json"
"errors"
"fmt"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/keybase1"
)
type Thread struct {
Result chat1.Thread `json:"result"`
Error *Error `json:"error,omitempty"`
}
type Inbox struct {
Result Result `json:"result"`
Error *Error `json:"error,omitempty"`
}
type sendMessageBody struct {
Body string
}
type sendMessageOptions struct {
Channel chat1.ChatChannel `json:"channel,omitempty"`
ConversationID chat1.ConvIDStr `json:"conversation_id,omitempty"`
Message sendMessageBody `json:",omitempty"`
Filename string `json:"filename,omitempty"`
Title string `json:"title,omitempty"`
MsgID chat1.MessageID `json:"message_id,omitempty"`
ConfirmLumenSend bool `json:"confirm_lumen_send"`
ReplyTo *chat1.MessageID `json:"reply_to,omitempty"`
}
type sendMessageParams struct {
Options sendMessageOptions
}
type sendMessageArg struct {
Method string
Params sendMessageParams
}
func newSendArg(options sendMessageOptions) sendMessageArg {
return sendMessageArg{
Method: "send",
Params: sendMessageParams{
Options: options,
},
}
}
// GetConversations reads all conversations from the current user's inbox.
func (a *API) GetConversations(unreadOnly bool) ([]chat1.ConvSummary, error) {
apiInput := fmt.Sprintf(`{"method":"list", "params": { "options": { "unread_only": %v}}}`, unreadOnly)
output, err := a.doFetch(apiInput)
if err != nil {
return nil, err
}
var inbox Inbox
if err := json.Unmarshal(output, &inbox); err != nil {
return nil, err
} else if inbox.Error != nil {
return nil, errors.New(inbox.Error.Message)
}
return inbox.Result.Convs, nil
}
func (a *API) GetConversation(convID chat1.ConvIDStr) (res chat1.ConvSummary, err error) {
apiInput := fmt.Sprintf(`{"method":"list", "params": { "options": { "conversation_id": "%s"}}}`, convID)
output, err := a.doFetch(apiInput)
if err != nil {
return res, err
}
var inbox Inbox
if err := json.Unmarshal(output, &inbox); err != nil {
return res, err
} else if inbox.Error != nil {
return res, errors.New(inbox.Error.Message)
} else if len(inbox.Result.Convs) == 0 {
return res, errors.New("conversation not found")
}
return inbox.Result.Convs[0], nil
}
// GetTextMessages fetches all text messages from a given channel. Optionally can filter
// ont unread status.
func (a *API) GetTextMessages(channel chat1.ChatChannel, unreadOnly bool) ([]chat1.MsgSummary, error) {
channelBytes, err := json.Marshal(channel)
if err != nil {
return nil, err
}
apiInput := fmt.Sprintf(`{"method": "read", "params": {"options": {"channel": %s}}}`, string(channelBytes))
output, err := a.doFetch(apiInput)
if err != nil {
return nil, err
}
var thread Thread
if err := json.Unmarshal(output, &thread); err != nil {
return nil, fmt.Errorf("unable to decode thread: %v", err)
} else if thread.Error != nil {
return nil, errors.New(thread.Error.Message)
}
var res []chat1.MsgSummary
for _, msg := range thread.Result.Messages {
if msg.Msg.Content.TypeName == "text" {
res = append(res, *msg.Msg)
}
}
return res, nil
}
func (a *API) SendMessage(channel chat1.ChatChannel, body string, args ...interface{}) (SendResponse, error) {
arg := newSendArg(sendMessageOptions{
Channel: channel,
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
})
return a.doSend(arg)
}
func (a *API) Broadcast(body string, args ...interface{}) (SendResponse, error) {
return a.SendMessage(chat1.ChatChannel{
Name: a.GetUsername(),
Public: true,
}, fmt.Sprintf(body, args...))
}
func (a *API) SendMessageByConvID(convID chat1.ConvIDStr, body string, args ...interface{}) (SendResponse, error) {
arg := newSendArg(sendMessageOptions{
ConversationID: convID,
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
})
return a.doSend(arg)
}
// SendMessageByTlfName sends a message on the given TLF name
func (a *API) SendMessageByTlfName(tlfName string, body string, args ...interface{}) (SendResponse, error) {
arg := newSendArg(sendMessageOptions{
Channel: chat1.ChatChannel{
Name: tlfName,
},
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
})
return a.doSend(arg)
}
func (a *API) SendMessageByTeamName(teamName string, inChannel *string, body string, args ...interface{}) (SendResponse, error) {
channel := "general"
if inChannel != nil {
channel = *inChannel
}
arg := newSendArg(sendMessageOptions{
Channel: chat1.ChatChannel{
MembersType: "team",
Name: teamName,
TopicName: channel,
},
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
})
return a.doSend(arg)
}
func (a *API) SendReply(channel chat1.ChatChannel, replyTo *chat1.MessageID, body string, args ...interface{}) (SendResponse, error) {
arg := newSendArg(sendMessageOptions{
Channel: channel,
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
ReplyTo: replyTo,
})
return a.doSend(arg)
}
func (a *API) SendReplyByConvID(convID chat1.ConvIDStr, replyTo *chat1.MessageID, body string, args ...interface{}) (SendResponse, error) {
arg := newSendArg(sendMessageOptions{
ConversationID: convID,
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
ReplyTo: replyTo,
})
return a.doSend(arg)
}
func (a *API) SendReplyByTlfName(tlfName string, replyTo *chat1.MessageID, body string, args ...interface{}) (SendResponse, error) {
arg := newSendArg(sendMessageOptions{
Channel: chat1.ChatChannel{
Name: tlfName,
},
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
ReplyTo: replyTo,
})
return a.doSend(arg)
}
func (a *API) SendAttachmentByTeam(teamName string, inChannel *string, filename string, title string) (SendResponse, error) {
channel := "general"
if inChannel != nil {
channel = *inChannel
}
arg := sendMessageArg{
Method: "attach",
Params: sendMessageParams{
Options: sendMessageOptions{
Channel: chat1.ChatChannel{
MembersType: "team",
Name: teamName,
TopicName: channel,
},
Filename: filename,
Title: title,
},
},
}
return a.doSend(arg)
}
func (a *API) SendAttachmentByConvID(convID chat1.ConvIDStr, filename string, title string) (SendResponse, error) {
arg := sendMessageArg{
Method: "attach",
Params: sendMessageParams{
Options: sendMessageOptions{
ConversationID: convID,
Filename: filename,
Title: title,
},
},
}
return a.doSend(arg)
}
////////////////////////////////////////////////////////
// React to chat ///////////////////////////////////////
////////////////////////////////////////////////////////
type reactionOptions struct {
ConversationID chat1.ConvIDStr `json:"conversation_id"`
Message sendMessageBody
MsgID chat1.MessageID `json:"message_id"`
Channel chat1.ChatChannel `json:"channel"`
}
type reactionParams struct {
Options reactionOptions
}
type reactionArg struct {
Method string
Params reactionParams
}
func newReactionArg(options reactionOptions) reactionArg {
return reactionArg{
Method: "reaction",
Params: reactionParams{Options: options},
}
}
func (a *API) ReactByChannel(channel chat1.ChatChannel, msgID chat1.MessageID, reaction string) (SendResponse, error) {
arg := newReactionArg(reactionOptions{
Message: sendMessageBody{Body: reaction},
MsgID: msgID,
Channel: channel,
})
return a.doSend(arg)
}
func (a *API) ReactByConvID(convID chat1.ConvIDStr, msgID chat1.MessageID, reaction string) (SendResponse, error) {
arg := newReactionArg(reactionOptions{
Message: sendMessageBody{Body: reaction},
MsgID: msgID,
ConversationID: convID,
})
return a.doSend(arg)
}
func (a *API) EditByConvID(convID chat1.ConvIDStr, msgID chat1.MessageID, text string) (SendResponse, error) {
arg := reactionArg{
Method: "edit",
Params: reactionParams{Options: reactionOptions{
Message: sendMessageBody{Body: text},
MsgID: msgID,
ConversationID: convID,
}},
}
return a.doSend(arg)
}
////////////////////////////////////////////////////////
// Manage channels /////////////////////////////////////
////////////////////////////////////////////////////////
type ChannelsList struct {
Result Result `json:"result"`
Error *Error `json:"error,omitempty"`
}
type JoinChannel struct {
Error *Error `json:"error,omitempty"`
Result chat1.EmptyRes `json:"result"`
}
type LeaveChannel struct {
Error *Error `json:"error,omitempty"`
Result chat1.EmptyRes `json:"result"`
}
func (a *API) ListChannels(teamName string) ([]string, error) {
apiInput := fmt.Sprintf(`{"method": "listconvsonname", "params": {"options": {"topic_type": "CHAT", "members_type": "team", "name": "%s"}}}`, teamName)
output, err := a.doFetch(apiInput)
if err != nil {
return nil, err
}
var channelsList ChannelsList
if err := json.Unmarshal(output, &channelsList); err != nil {
return nil, err
} else if channelsList.Error != nil {
return nil, errors.New(channelsList.Error.Message)
}
var channels []string
for _, conv := range channelsList.Result.Convs {
channels = append(channels, conv.Channel.TopicName)
}
return channels, nil
}
func (a *API) JoinChannel(teamName string, channelName string) (chat1.EmptyRes, error) {
empty := chat1.EmptyRes{}
apiInput := fmt.Sprintf(`{"method": "join", "params": {"options": {"channel": {"name": "%s", "members_type": "team", "topic_name": "%s"}}}}`, teamName, channelName)
output, err := a.doFetch(apiInput)
if err != nil {
return empty, err
}
joinChannel := JoinChannel{}
err = json.Unmarshal(output, &joinChannel)
if err != nil {
return empty, fmt.Errorf("failed to parse output from keybase team api: %v", err)
} else if joinChannel.Error != nil {
return empty, errors.New(joinChannel.Error.Message)
}
return joinChannel.Result, nil
}
func (a *API) LeaveChannel(teamName string, channelName string) (chat1.EmptyRes, error) {
empty := chat1.EmptyRes{}
apiInput := fmt.Sprintf(`{"method": "leave", "params": {"options": {"channel": {"name": "%s", "members_type": "team", "topic_name": "%s"}}}}`, teamName, channelName)
output, err := a.doFetch(apiInput)
if err != nil {
return empty, err
}
leaveChannel := LeaveChannel{}
err = json.Unmarshal(output, &leaveChannel)
if err != nil {
return empty, fmt.Errorf("failed to parse output from keybase team api: %v", err)
} else if leaveChannel.Error != nil {
return empty, errors.New(leaveChannel.Error.Message)
}
return leaveChannel.Result, nil
}
////////////////////////////////////////////////////////
// Send lumens in chat /////////////////////////////////
////////////////////////////////////////////////////////
func (a *API) InChatSend(channel chat1.ChatChannel, body string, args ...interface{}) (SendResponse, error) {
arg := newSendArg(sendMessageOptions{
Channel: channel,
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
ConfirmLumenSend: true,
})
return a.doSend(arg)
}
func (a *API) InChatSendByConvID(convID chat1.ConvIDStr, body string, args ...interface{}) (SendResponse, error) {
arg := newSendArg(sendMessageOptions{
ConversationID: convID,
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
ConfirmLumenSend: true,
})
return a.doSend(arg)
}
func (a *API) InChatSendByTlfName(tlfName string, body string, args ...interface{}) (SendResponse, error) {
arg := newSendArg(sendMessageOptions{
Channel: chat1.ChatChannel{
Name: tlfName,
},
Message: sendMessageBody{
Body: fmt.Sprintf(body, args...),
},
ConfirmLumenSend: true,
})
return a.doSend(arg)
}
////////////////////////////////////////////////////////
// Misc commands ///////////////////////////////////////
////////////////////////////////////////////////////////
type Advertisement struct {
Alias string `json:"alias,omitempty"`
Advertisements []chat1.AdvertiseCommandAPIParam
}
type ListCommandsResponse struct {
Result struct {
Commands []chat1.UserBotCommandOutput `json:"commands"`
} `json:"result"`
Error *Error `json:"error,omitempty"`
}
type advertiseCmdsParams struct {
Options Advertisement
}
type advertiseCmdsMsgArg struct {
Method string
Params advertiseCmdsParams
}
func newAdvertiseCmdsMsgArg(ad Advertisement) advertiseCmdsMsgArg {
return advertiseCmdsMsgArg{
Method: "advertisecommands",
Params: advertiseCmdsParams{
Options: ad,
},
}
}
func (a *API) AdvertiseCommands(ad Advertisement) (SendResponse, error) {
return a.doSend(newAdvertiseCmdsMsgArg(ad))
}
func (a *API) ClearCommands() error {
arg := struct {
Method string
}{
Method: "clearcommands",
}
_, err := a.doSend(arg)
return err
}
type listCmdsOptions struct {
Channel chat1.ChatChannel `json:"channel,omitempty"`
ConversationID chat1.ConvIDStr `json:"conversation_id,omitempty"`
}
type listCmdsParams struct {
Options listCmdsOptions
}
type listCmdsArg struct {
Method string
Params listCmdsParams
}
func newListCmdsArg(options listCmdsOptions) listCmdsArg {
return listCmdsArg{
Method: "listcommands",
Params: listCmdsParams{
Options: options,
},
}
}
func (a *API) ListCommands(channel chat1.ChatChannel) ([]chat1.UserBotCommandOutput, error) {
arg := newListCmdsArg(listCmdsOptions{
Channel: channel,
})
return a.listCommands(arg)
}
func (a *API) ListCommandsByConvID(convID chat1.ConvIDStr) ([]chat1.UserBotCommandOutput, error) {
arg := newListCmdsArg(listCmdsOptions{
ConversationID: convID,
})
return a.listCommands(arg)
}
func (a *API) listCommands(arg listCmdsArg) ([]chat1.UserBotCommandOutput, error) {
bArg, err := json.Marshal(arg)
if err != nil {
return nil, err
}
output, err := a.doFetch(string(bArg))
if err != nil {
return nil, err
}
var res ListCommandsResponse
if err := json.Unmarshal(output, &res); err != nil {
return nil, err
} else if res.Error != nil {
return nil, errors.New(res.Error.Message)
}
return res.Result.Commands, nil
}
type listMembersOptions struct {
Channel chat1.ChatChannel `json:"channel,omitempty"`
ConversationID chat1.ConvIDStr `json:"conversation_id,omitempty"`
}
type listMembersParams struct {
Options listMembersOptions
}
type listMembersArg struct {
Method string
Params listMembersParams
}
func newListMembersArg(options listMembersOptions) listMembersArg {
return listMembersArg{
Method: "listmembers",
Params: listMembersParams{
Options: options,
},
}
}
func (a *API) ListMembers(channel chat1.ChatChannel) (keybase1.TeamMembersDetails, error) {
arg := newListMembersArg(listMembersOptions{
Channel: channel,
})
return a.listMembers(arg)
}
func (a *API) ListMembersByConvID(conversationID chat1.ConvIDStr) (keybase1.TeamMembersDetails, error) {
arg := newListMembersArg(listMembersOptions{
ConversationID: conversationID,
})
return a.listMembers(arg)
}
func (a *API) listMembers(arg listMembersArg) (res keybase1.TeamMembersDetails, err error) {
bArg, err := json.Marshal(arg)
if err != nil {
return res, err
}
output, err := a.doFetch(string(bArg))
if err != nil {
return res, err
}
members := ListTeamMembers{}
err = json.Unmarshal(output, &members)
if err != nil {
return res, UnmarshalError{err}
}
if members.Error.Message != "" {
return res, members.Error
}
return members.Result.Members, nil
}
type GetMessagesResult struct {
Result struct {
Messages []chat1.Message `json:"messages"`
} `json:"result"`
Error *Error `json:"error,omitempty"`
}
type getMessagesOptions struct {
Channel chat1.ChatChannel `json:"channel,omitempty"`
ConversationID chat1.ConvIDStr `json:"conversation_id,omitempty"`
MessageIDs []chat1.MessageID `json:"message_ids,omitempty"`
}
type getMessagesParams struct {
Options getMessagesOptions
}
type getMessagesArg struct {
Method string
Params getMessagesParams
}
func newGetMessagesArg(options getMessagesOptions) getMessagesArg {
return getMessagesArg{
Method: "get",
Params: getMessagesParams{
Options: options,
},
}
}
func (a *API) GetMessages(channel chat1.ChatChannel, msgIDs []chat1.MessageID) ([]chat1.Message, error) {
arg := newGetMessagesArg(getMessagesOptions{
Channel: channel,
MessageIDs: msgIDs,
})
return a.getMessages(arg)
}
func (a *API) GetMessagesByConvID(conversationID chat1.ConvIDStr, msgIDs []chat1.MessageID) ([]chat1.Message, error) {
arg := newGetMessagesArg(getMessagesOptions{
ConversationID: conversationID,
MessageIDs: msgIDs,
})
return a.getMessages(arg)
}
func (a *API) getMessages(arg getMessagesArg) ([]chat1.Message, error) {
bArg, err := json.Marshal(arg)
if err != nil {
return nil, err
}
output, err := a.doFetch(string(bArg))
if err != nil {
return nil, err
}
var res GetMessagesResult
err = json.Unmarshal(output, &res)
if err != nil {
return nil, UnmarshalError{err}
}
if res.Error != nil {
return nil, res.Error
}
return res.Result.Messages, nil
}

View File

@@ -0,0 +1,36 @@
package kbchat
import "fmt"
type ErrorCode int
const (
RevisionErrorCode ErrorCode = 2760
DeleteNonExistentErrorCode ErrorCode = 2762
)
// Error is for unmarshaling CLI json responses
type Error struct {
Code ErrorCode `json:"code"`
Message string `json:"message"`
}
func (e Error) Error() string {
return fmt.Sprintf("received error response from keybase api: %s", e.Message)
}
type APIError struct {
err error
}
func (e APIError) Error() string {
return fmt.Sprintf("failed to call keybase api: %v", e.err)
}
type UnmarshalError struct {
err error
}
func (e UnmarshalError) Error() string {
return fmt.Sprintf("failed to parse output from keybase api: %v", e.err)
}

View File

@@ -6,47 +6,63 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"strings"
"sync"
"time"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/keybase1"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/stellar1"
)
// API is the main object used for communicating with the Keybase JSON API
type API struct {
sync.Mutex
apiInput io.Writer
apiOutput *bufio.Reader
apiCmd *exec.Cmd
username string
runOpts RunOptions
apiInput io.Writer
apiOutput *bufio.Reader
apiCmd *exec.Cmd
username string
runOpts RunOptions
subscriptions []*NewSubscription
}
func getUsername(runOpts RunOptions) (username string, err error) {
p := runOpts.Command("status")
p := runOpts.Command("whoami", "-json")
output, err := p.StdoutPipe()
if err != nil {
return "", err
}
p.ExtraFiles = []*os.File{output.(*os.File)}
if err = p.Start(); err != nil {
return "", err
}
doneCh := make(chan error)
go func() {
scanner := bufio.NewScanner(output)
if !scanner.Scan() {
doneCh <- errors.New("unable to find Keybase username")
defer func() { close(doneCh) }()
statusJSON, err := ioutil.ReadAll(output)
if err != nil {
doneCh <- fmt.Errorf("error reading whoami output: %v", err)
return
}
toks := strings.Fields(scanner.Text())
if len(toks) != 2 {
doneCh <- errors.New("invalid Keybase username output")
var status keybase1.CurrentStatus
if err := json.Unmarshal(statusJSON, &status); err != nil {
doneCh <- fmt.Errorf("invalid whoami JSON %q: %v", statusJSON, err)
return
}
username = toks[1]
doneCh <- nil
if status.LoggedIn && status.User != nil {
username = status.User.Username
doneCh <- nil
} else {
doneCh <- fmt.Errorf("unable to authenticate to keybase service: logged in: %v user: %+v", status.LoggedIn, status.User)
}
// Cleanup the command
if err := p.Wait(); err != nil {
log.Printf("unable to wait for cmd: %v", err)
}
}()
select {
@@ -71,6 +87,10 @@ type RunOptions struct {
HomeDir string
Oneshot *OneshotOptions
StartService bool
// Have the bot send/receive typing notifications
EnableTyping bool
// Disable bot lite mode
DisableBotLiteMode bool
}
func (r RunOptions) Location() string {
@@ -100,6 +120,10 @@ func Start(runOpts RunOptions) (*API, error) {
return api, nil
}
func (a *API) Command(args ...string) *exec.Cmd {
return a.runOpts.Command(args...)
}
func (a *API) auth() (string, error) {
username, err := getUsername(a.runOpts)
if err == nil {
@@ -132,17 +156,28 @@ func (a *API) startPipes() (err error) {
a.Lock()
defer a.Unlock()
if a.apiCmd != nil {
a.apiCmd.Process.Kill()
if err := a.apiCmd.Process.Kill(); err != nil {
return err
}
}
a.apiCmd = nil
if a.runOpts.StartService {
a.runOpts.Command("service").Start()
args := []string{fmt.Sprintf("-enable-bot-lite-mode=%v", a.runOpts.DisableBotLiteMode), "service"}
if err := a.runOpts.Command(args...).Start(); err != nil {
return err
}
}
if a.username, err = a.auth(); err != nil {
return err
}
cmd := a.runOpts.Command("chat", "notification-settings", fmt.Sprintf("-disable-typing=%v", !a.runOpts.EnableTyping))
if err = cmd.Run(); err != nil {
return err
}
a.apiCmd = a.runOpts.Command("chat", "api")
if a.apiInput, err = a.apiCmd.StdinPipe(); err != nil {
return err
@@ -151,6 +186,7 @@ func (a *API) startPipes() (err error) {
if err != nil {
return err
}
a.apiCmd.ExtraFiles = []*os.File{output.(*os.File)}
if err := a.apiCmd.Start(); err != nil {
return err
}
@@ -168,73 +204,11 @@ func (a *API) getAPIPipesLocked() (io.Writer, *bufio.Reader, error) {
return a.apiInput, a.apiOutput, nil
}
// GetConversations reads all conversations from the current user's inbox.
func (a *API) GetConversations(unreadOnly bool) ([]Conversation, error) {
apiInput := fmt.Sprintf(`{"method":"list", "params": { "options": { "unread_only": %v}}}`, unreadOnly)
output, err := a.doFetch(apiInput)
if err != nil {
return nil, err
}
var inbox Inbox
if err := json.Unmarshal(output, &inbox); err != nil {
return nil, err
}
return inbox.Result.Convs, nil
func (a *API) GetUsername() string {
return a.username
}
// GetTextMessages fetches all text messages from a given channel. Optionally can filter
// ont unread status.
func (a *API) GetTextMessages(channel Channel, unreadOnly bool) ([]Message, error) {
channelBytes, err := json.Marshal(channel)
if err != nil {
return nil, err
}
apiInput := fmt.Sprintf(`{"method": "read", "params": {"options": {"channel": %s}}}`, string(channelBytes))
output, err := a.doFetch(apiInput)
if err != nil {
return nil, err
}
var thread Thread
if err := json.Unmarshal(output, &thread); err != nil {
return nil, fmt.Errorf("unable to decode thread: %s", err.Error())
}
var res []Message
for _, msg := range thread.Result.Messages {
if msg.Msg.Content.Type == "text" {
res = append(res, msg.Msg)
}
}
return res, nil
}
type sendMessageBody struct {
Body string
}
type sendMessageOptions struct {
Channel Channel `json:"channel,omitempty"`
ConversationID string `json:"conversation_id,omitempty"`
Message sendMessageBody `json:",omitempty"`
Filename string `json:"filename,omitempty"`
Title string `json:"title,omitempty"`
MsgID int `json:"message_id,omitempty"`
}
type sendMessageParams struct {
Options sendMessageOptions
}
type sendMessageArg struct {
Method string
Params sendMessageParams
}
func (a *API) doSend(arg interface{}) (response SendResponse, err error) {
func (a *API) doSend(arg interface{}) (resp SendResponse, err error) {
a.Lock()
defer a.Unlock()
@@ -253,10 +227,12 @@ func (a *API) doSend(arg interface{}) (response SendResponse, err error) {
if err != nil {
return SendResponse{}, err
}
if err := json.Unmarshal(responseRaw, &response); err != nil {
return SendResponse{}, fmt.Errorf("failed to decode API response: %s", err)
if err := json.Unmarshal(responseRaw, &resp); err != nil {
return resp, fmt.Errorf("failed to decode API response: %s", err)
} else if resp.Error != nil {
return resp, errors.New(resp.Error.Message)
}
return response, nil
return resp, nil
}
func (a *API) doFetch(apiInput string) ([]byte, error) {
@@ -278,237 +254,131 @@ func (a *API) doFetch(apiInput string) ([]byte, error) {
return byteOutput, nil
}
func (a *API) SendMessage(channel Channel, body string) (SendResponse, error) {
arg := sendMessageArg{
Method: "send",
Params: sendMessageParams{
Options: sendMessageOptions{
Channel: channel,
Message: sendMessageBody{
Body: body,
},
},
},
}
return a.doSend(arg)
}
func (a *API) SendMessageByConvID(convID string, body string) (SendResponse, error) {
arg := sendMessageArg{
Method: "send",
Params: sendMessageParams{
Options: sendMessageOptions{
ConversationID: convID,
Message: sendMessageBody{
Body: body,
},
},
},
}
return a.doSend(arg)
}
// SendMessageByTlfName sends a message on the given TLF name
func (a *API) SendMessageByTlfName(tlfName string, body string) (SendResponse, error) {
arg := sendMessageArg{
Method: "send",
Params: sendMessageParams{
Options: sendMessageOptions{
Channel: Channel{
Name: tlfName,
},
Message: sendMessageBody{
Body: body,
},
},
},
}
return a.doSend(arg)
}
func (a *API) SendMessageByTeamName(teamName string, body string, inChannel *string) (SendResponse, error) {
channel := "general"
if inChannel != nil {
channel = *inChannel
}
arg := sendMessageArg{
Method: "send",
Params: sendMessageParams{
Options: sendMessageOptions{
Channel: Channel{
MembersType: "team",
Name: teamName,
TopicName: channel,
},
Message: sendMessageBody{
Body: body,
},
},
},
}
return a.doSend(arg)
}
func (a *API) SendAttachmentByTeam(teamName string, filename string, title string, inChannel *string) (SendResponse, error) {
channel := "general"
if inChannel != nil {
channel = *inChannel
}
arg := sendMessageArg{
Method: "attach",
Params: sendMessageParams{
Options: sendMessageOptions{
Channel: Channel{
MembersType: "team",
Name: teamName,
TopicName: channel,
},
Filename: filename,
Title: title,
},
},
}
return a.doSend(arg)
}
type reactionOptions struct {
ConversationID string `json:"conversation_id"`
Message sendMessageBody
MsgID int `json:"message_id"`
Channel Channel `json:"channel"`
}
type reactionParams struct {
Options reactionOptions
}
type reactionArg struct {
Method string
Params reactionParams
}
func newReactionArg(options reactionOptions) reactionArg {
return reactionArg{
Method: "reaction",
Params: reactionParams{Options: options},
}
}
func (a *API) ReactByChannel(channel Channel, msgID int, reaction string) (SendResponse, error) {
arg := newReactionArg(reactionOptions{
Message: sendMessageBody{Body: reaction},
MsgID: msgID,
Channel: channel,
})
return a.doSend(arg)
}
func (a *API) ReactByConvID(convID string, msgID int, reaction string) (SendResponse, error) {
arg := newReactionArg(reactionOptions{
Message: sendMessageBody{Body: reaction},
MsgID: msgID,
ConversationID: convID,
})
return a.doSend(arg)
}
type advertiseParams struct {
Options Advertisement
}
type advertiseMsgArg struct {
Method string
Params advertiseParams
}
func newAdvertiseMsgArg(ad Advertisement) advertiseMsgArg {
return advertiseMsgArg{
Method: "advertisecommands",
Params: advertiseParams{
Options: ad,
},
}
}
func (a *API) AdvertiseCommands(ad Advertisement) (SendResponse, error) {
return a.doSend(newAdvertiseMsgArg(ad))
}
func (a *API) Username() string {
return a.username
}
// SubscriptionMessage contains a message and conversation object
type SubscriptionMessage struct {
Message Message
Conversation Conversation
Message chat1.MsgSummary
Conversation chat1.ConvSummary
}
type SubscriptionConversation struct {
Conversation chat1.ConvSummary
}
type SubscriptionWalletEvent struct {
Payment Payment
Payment stellar1.PaymentDetailsLocal
}
// NewSubscription has methods to control the background message fetcher loop
type NewSubscription struct {
sync.Mutex
newMsgsCh <-chan SubscriptionMessage
newConvsCh <-chan SubscriptionConversation
newWalletCh <-chan SubscriptionWalletEvent
errorCh <-chan error
running bool
shutdownCh chan struct{}
}
// Read blocks until a new message arrives
func (m NewSubscription) Read() (SubscriptionMessage, error) {
func (m *NewSubscription) Read() (SubscriptionMessage, error) {
select {
case msg := <-m.newMsgsCh:
return msg, nil
case err := <-m.errorCh:
return SubscriptionMessage{}, err
case <-m.shutdownCh:
return SubscriptionMessage{}, errors.New("Subscription shutdown")
}
}
func (m *NewSubscription) ReadNewConvs() (SubscriptionConversation, error) {
select {
case conv := <-m.newConvsCh:
return conv, nil
case err := <-m.errorCh:
return SubscriptionConversation{}, err
case <-m.shutdownCh:
return SubscriptionConversation{}, errors.New("Subscription shutdown")
}
}
// Read blocks until a new message arrives
func (m NewSubscription) ReadWallet() (SubscriptionWalletEvent, error) {
func (m *NewSubscription) ReadWallet() (SubscriptionWalletEvent, error) {
select {
case msg := <-m.newWalletCh:
return msg, nil
case err := <-m.errorCh:
return SubscriptionWalletEvent{}, err
case <-m.shutdownCh:
return SubscriptionWalletEvent{}, errors.New("Subscription shutdown")
}
}
// Shutdown terminates the background process
func (m NewSubscription) Shutdown() {
m.shutdownCh <- struct{}{}
func (m *NewSubscription) Shutdown() {
m.Lock()
defer m.Unlock()
if m.running {
close(m.shutdownCh)
m.running = false
}
}
type ListenOptions struct {
Wallet bool
Convs bool
}
type PaymentHolder struct {
Payment stellar1.PaymentDetailsLocal `json:"notification"`
}
type TypeHolder struct {
Type string `json:"type"`
}
// ListenForNewTextMessages proxies to Listen without wallet events
func (a *API) ListenForNewTextMessages() (NewSubscription, error) {
func (a *API) ListenForNewTextMessages() (*NewSubscription, error) {
opts := ListenOptions{Wallet: false}
return a.Listen(opts)
}
func (a *API) registerSubscription(sub *NewSubscription) {
a.Lock()
defer a.Unlock()
a.subscriptions = append(a.subscriptions, sub)
}
// Listen fires of a background loop and puts chat messages and wallet
// events into channels
func (a *API) Listen(opts ListenOptions) (NewSubscription, error) {
newMsgCh := make(chan SubscriptionMessage, 100)
func (a *API) Listen(opts ListenOptions) (*NewSubscription, error) {
newMsgsCh := make(chan SubscriptionMessage, 100)
newConvsCh := make(chan SubscriptionConversation, 100)
newWalletCh := make(chan SubscriptionWalletEvent, 100)
errorCh := make(chan error, 100)
shutdownCh := make(chan struct{})
done := make(chan struct{})
sub := NewSubscription{
newMsgsCh: newMsgCh,
sub := &NewSubscription{
newMsgsCh: newMsgsCh,
newConvsCh: newConvsCh,
newWalletCh: newWalletCh,
shutdownCh: shutdownCh,
errorCh: errorCh,
running: true,
}
a.registerSubscription(sub)
pause := 2 * time.Second
readScanner := func(boutput *bufio.Scanner) {
defer func() { done <- struct{}{} }()
for {
select {
case <-shutdownCh:
log.Printf("readScanner: received shutdown")
return
default:
}
boutput.Scan()
t := boutput.Text()
var typeHolder TypeHolder
@@ -518,41 +388,72 @@ func (a *API) Listen(opts ListenOptions) (NewSubscription, error) {
}
switch typeHolder.Type {
case "chat":
var holder MessageHolder
if err := json.Unmarshal([]byte(t), &holder); err != nil {
var notification chat1.MsgNotification
if err := json.Unmarshal([]byte(t), &notification); err != nil {
errorCh <- err
break
}
subscriptionMessage := SubscriptionMessage{
Message: holder.Msg,
Conversation: Conversation{
ID: holder.Msg.ConversationID,
Channel: holder.Msg.Channel,
},
if notification.Error != nil {
log.Printf("error message received: %s", *notification.Error)
} else if notification.Msg != nil {
subscriptionMessage := SubscriptionMessage{
Message: *notification.Msg,
Conversation: chat1.ConvSummary{
Id: notification.Msg.ConvID,
Channel: notification.Msg.Channel,
},
}
newMsgsCh <- subscriptionMessage
}
case "chat_conv":
var notification chat1.ConvNotification
if err := json.Unmarshal([]byte(t), &notification); err != nil {
errorCh <- err
break
}
if notification.Error != nil {
log.Printf("error message received: %s", *notification.Error)
} else if notification.Conv != nil {
subscriptionConv := SubscriptionConversation{
Conversation: *notification.Conv,
}
newConvsCh <- subscriptionConv
}
newMsgCh <- subscriptionMessage
case "wallet":
var holder PaymentHolder
if err := json.Unmarshal([]byte(t), &holder); err != nil {
errorCh <- err
break
}
subscriptionPayment := SubscriptionWalletEvent{
Payment: holder.Payment,
}
subscriptionPayment := SubscriptionWalletEvent(holder)
newWalletCh <- subscriptionPayment
default:
continue
}
}
done <- struct{}{}
}
attempts := 0
maxAttempts := 1800
go func() {
defer func() {
close(newMsgsCh)
close(newConvsCh)
close(newWalletCh)
close(errorCh)
}()
for {
select {
case <-shutdownCh:
log.Printf("Listen: received shutdown")
return
default:
}
if attempts >= maxAttempts {
if err := a.LogSend("Listen: failed to auth, giving up"); err != nil {
log.Printf("Listen: logsend failed to send: %v", err)
}
panic("Listen: failed to auth, giving up")
}
attempts++
@@ -565,6 +466,9 @@ func (a *API) Listen(opts ListenOptions) (NewSubscription, error) {
if opts.Wallet {
cmdElements = append(cmdElements, "--wallet")
}
if opts.Convs {
cmdElements = append(cmdElements, "--convs")
}
p := a.runOpts.Command(cmdElements...)
output, err := p.StdoutPipe()
if err != nil {
@@ -572,8 +476,16 @@ func (a *API) Listen(opts ListenOptions) (NewSubscription, error) {
time.Sleep(pause)
continue
}
stderr, err := p.StderrPipe()
if err != nil {
log.Printf("Listen: failed to listen to stderr: %s", err)
time.Sleep(pause)
continue
}
p.ExtraFiles = []*os.File{stderr.(*os.File), output.(*os.File)}
boutput := bufio.NewScanner(output)
if err := p.Start(); err != nil {
log.Printf("Listen: failed to make listen scanner: %s", err)
time.Sleep(pause)
continue
@@ -581,78 +493,19 @@ func (a *API) Listen(opts ListenOptions) (NewSubscription, error) {
attempts = 0
go readScanner(boutput)
<-done
p.Wait()
if err := p.Wait(); err != nil {
stderrBytes, rerr := ioutil.ReadAll(stderr)
if rerr != nil {
stderrBytes = []byte("failed to get stderr")
}
log.Printf("Listen: failed to Wait for command: %s (```%s```)", err, stderrBytes)
}
time.Sleep(pause)
}
}()
return sub, nil
}
func (a *API) GetUsername() string {
return a.username
}
func (a *API) ListChannels(teamName string) ([]string, error) {
apiInput := fmt.Sprintf(`{"method": "listconvsonname", "params": {"options": {"topic_type": "CHAT", "members_type": "team", "name": "%s"}}}`, teamName)
output, err := a.doFetch(apiInput)
if err != nil {
return nil, err
}
var channelsList ChannelsList
if err := json.Unmarshal(output, &channelsList); err != nil {
return nil, err
}
var channels []string
for _, conv := range channelsList.Result.Convs {
channels = append(channels, conv.Channel.TopicName)
}
return channels, nil
}
func (a *API) JoinChannel(teamName string, channelName string) (JoinChannelResult, error) {
empty := JoinChannelResult{}
apiInput := fmt.Sprintf(`{"method": "join", "params": {"options": {"channel": {"name": "%s", "members_type": "team", "topic_name": "%s"}}}}`, teamName, channelName)
output, err := a.doFetch(apiInput)
if err != nil {
return empty, err
}
joinChannel := JoinChannel{}
err = json.Unmarshal(output, &joinChannel)
if err != nil {
return empty, fmt.Errorf("failed to parse output from keybase team api: %v", err)
}
if joinChannel.Error.Message != "" {
return empty, fmt.Errorf("received error from keybase team api: %s", joinChannel.Error.Message)
}
return joinChannel.Result, nil
}
func (a *API) LeaveChannel(teamName string, channelName string) (LeaveChannelResult, error) {
empty := LeaveChannelResult{}
apiInput := fmt.Sprintf(`{"method": "leave", "params": {"options": {"channel": {"name": "%s", "members_type": "team", "topic_name": "%s"}}}}`, teamName, channelName)
output, err := a.doFetch(apiInput)
if err != nil {
return empty, err
}
leaveChannel := LeaveChannel{}
err = json.Unmarshal(output, &leaveChannel)
if err != nil {
return empty, fmt.Errorf("failed to parse output from keybase team api: %v", err)
}
if leaveChannel.Error.Message != "" {
return empty, fmt.Errorf("received error from keybase team api: %s", leaveChannel.Error.Message)
}
return leaveChannel.Result, nil
}
func (a *API) LogSend(feedback string) error {
feedback = "go-keybase-chat-bot log send\n" +
"username: " + a.GetUsername() + "\n" +
@@ -675,6 +528,17 @@ func (a *API) LogSend(feedback string) error {
}
func (a *API) Shutdown() error {
a.Lock()
defer a.Unlock()
for _, sub := range a.subscriptions {
sub.Shutdown()
}
if a.apiCmd != nil {
if err := a.apiCmd.Wait(); err != nil {
return err
}
}
if a.runOpts.Oneshot != nil {
err := a.runOpts.Command("logout", "--force").Run()
if err != nil {

View File

@@ -0,0 +1,228 @@
package kbchat
import (
"encoding/json"
"strings"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/keybase1"
)
type kvstoreMethod string
type kvstoreOptions struct {
Team *string `json:"team"`
Namespace *string `json:"namespace,omitempty"`
EntryKey *string `json:"entryKey,omitempty"`
EntryValue *string `json:"entryValue,omitempty"`
Revision *int `json:"revision,omitempty"`
}
type kvstoreParams struct {
Options kvstoreOptions `json:"options"`
}
type kvstoreAPIReq struct {
Method kvstoreMethod `json:"method"`
Params kvstoreParams `json:"params"`
}
type GetEntryRes struct {
Result keybase1.KVGetResult `json:"result"`
Error Error `json:"error,omitempty"`
}
type PutEntryRes struct {
Result keybase1.KVPutResult `json:"result"`
Error Error `json:"error,omitempty"`
}
type DeleteEntryRes struct {
Result keybase1.KVDeleteEntryResult `json:"result"`
Error Error `json:"error,omitempty"`
}
type ListNamespacesRes struct {
Result keybase1.KVListNamespaceResult `json:"result"`
Error Error `json:"error,omitempty"`
}
type ListEntryKeysRes struct {
Result keybase1.KVListEntryResult `json:"result"`
Error Error `json:"error,omitempty"`
}
type KVStoreAPI interface {
PutEntry(teamName *string, namespace string, entryKey string, entryValue string) (keybase1.KVPutResult, error)
PutEntryWithRevision(teamName *string, namespace string, entryKey string, entryValue string, revision int) (keybase1.KVPutResult, error)
DeleteEntry(teamName *string, namespace string, entryKey string) (keybase1.KVDeleteEntryResult, error)
DeleteEntryWithRevision(teamName *string, namespace string, entryKey string, revision int) (keybase1.KVDeleteEntryResult, error)
GetEntry(teamName *string, namespace string, entryKey string) (keybase1.KVGetResult, error)
ListNamespaces(teamName *string) (keybase1.KVListNamespaceResult, error)
ListEntryKeys(teamName *string, namespace string) (keybase1.KVListEntryResult, error)
}
func (a *API) PutEntry(teamName *string, namespace string, entryKey string, entryValue string) (result keybase1.KVPutResult, err error) {
return a.PutEntryWithRevision(teamName, namespace, entryKey, entryValue, 0)
}
func (a *API) PutEntryWithRevision(teamName *string, namespace string, entryKey string, entryValue string, revision int) (result keybase1.KVPutResult, err error) {
opts := kvstoreOptions{
Team: teamName,
Namespace: &namespace,
EntryKey: &entryKey,
EntryValue: &entryValue,
}
if revision != 0 {
opts.Revision = &revision
}
args := kvstoreAPIReq{Method: "put", Params: kvstoreParams{Options: opts}}
apiInput, err := json.Marshal(args)
if err != nil {
return result, err
}
cmd := a.runOpts.Command("kvstore", "api")
cmd.Stdin = strings.NewReader(string(apiInput))
bytes, err := cmd.Output()
if err != nil {
return result, APIError{err}
}
entry := PutEntryRes{}
err = json.Unmarshal(bytes, &entry)
if err != nil {
return result, UnmarshalError{err}
}
if entry.Error.Message != "" {
return result, entry.Error
}
return entry.Result, nil
}
func (a *API) DeleteEntry(teamName *string, namespace string, entryKey string) (result keybase1.KVDeleteEntryResult, err error) {
return a.DeleteEntryWithRevision(teamName, namespace, entryKey, 0)
}
func (a *API) DeleteEntryWithRevision(teamName *string, namespace string, entryKey string, revision int) (result keybase1.KVDeleteEntryResult, err error) {
opts := kvstoreOptions{
Team: teamName,
Namespace: &namespace,
EntryKey: &entryKey,
}
if revision != 0 {
opts.Revision = &revision
}
args := kvstoreAPIReq{Method: "del", Params: kvstoreParams{Options: opts}}
apiInput, err := json.Marshal(args)
if err != nil {
return result, err
}
cmd := a.runOpts.Command("kvstore", "api")
cmd.Stdin = strings.NewReader(string(apiInput))
bytes, err := cmd.Output()
if err != nil {
return result, APIError{err}
}
entry := DeleteEntryRes{}
err = json.Unmarshal(bytes, &entry)
if err != nil {
return result, UnmarshalError{err}
}
if entry.Error.Message != "" {
return result, entry.Error
}
return entry.Result, nil
}
func (a *API) GetEntry(teamName *string, namespace string, entryKey string) (result keybase1.KVGetResult, err error) {
opts := kvstoreOptions{
Team: teamName,
Namespace: &namespace,
EntryKey: &entryKey,
}
args := kvstoreAPIReq{Method: "get", Params: kvstoreParams{Options: opts}}
apiInput, err := json.Marshal(args)
if err != nil {
return result, err
}
cmd := a.runOpts.Command("kvstore", "api")
cmd.Stdin = strings.NewReader(string(apiInput))
bytes, err := cmd.Output()
if err != nil {
return result, APIError{err}
}
entry := GetEntryRes{}
err = json.Unmarshal(bytes, &entry)
if err != nil {
return result, UnmarshalError{err}
}
if entry.Error.Message != "" {
return result, entry.Error
}
return entry.Result, nil
}
func (a *API) ListNamespaces(teamName *string) (result keybase1.KVListNamespaceResult, err error) {
opts := kvstoreOptions{
Team: teamName,
}
args := kvstoreAPIReq{Method: "list", Params: kvstoreParams{Options: opts}}
apiInput, err := json.Marshal(args)
if err != nil {
return result, err
}
cmd := a.runOpts.Command("kvstore", "api")
cmd.Stdin = strings.NewReader(string(apiInput))
bytes, err := cmd.Output()
if err != nil {
return result, APIError{err}
}
var namespaces ListNamespacesRes
err = json.Unmarshal(bytes, &namespaces)
if err != nil {
return result, UnmarshalError{err}
}
if namespaces.Error.Message != "" {
return result, namespaces.Error
}
return namespaces.Result, nil
}
func (a *API) ListEntryKeys(teamName *string, namespace string) (result keybase1.KVListEntryResult, err error) {
opts := kvstoreOptions{
Team: teamName,
Namespace: &namespace,
}
args := kvstoreAPIReq{Method: "list", Params: kvstoreParams{Options: opts}}
apiInput, err := json.Marshal(args)
if err != nil {
return result, err
}
cmd := a.runOpts.Command("kvstore", "api")
cmd.Stdin = strings.NewReader(string(apiInput))
bytes, err := cmd.Output()
if err != nil {
return result, APIError{err}
}
entryKeys := ListEntryKeysRes{}
err = json.Unmarshal(bytes, &entryKeys)
if err != nil {
return result, UnmarshalError{err}
}
if entryKeys.Error.Message != "" {
return result, entryKeys.Error
}
return entryKeys.Result, nil
}

View File

@@ -1,25 +1,18 @@
package kbchat
import (
"bytes"
"encoding/json"
"fmt"
"log"
"strings"
"github.com/keybase/go-keybase-chat-bot/kbchat/types/keybase1"
)
type ListTeamMembers struct {
Result ListTeamMembersResult `json:"result"`
Error Error `json:"error"`
}
type ListTeamMembersResult struct {
Members ListTeamMembersResultMembers `json:"members"`
}
type ListTeamMembersResultMembers struct {
Owners []ListMembersOutputMembersCategory `json:"owners"`
Admins []ListMembersOutputMembersCategory `json:"admins"`
Writers []ListMembersOutputMembersCategory `json:"writers"`
Readers []ListMembersOutputMembersCategory `json:"readers"`
Result keybase1.TeamDetails `json:"result"`
Error Error `json:"error"`
}
type ListMembersOutputMembersCategory struct {
@@ -28,62 +21,56 @@ type ListMembersOutputMembersCategory struct {
}
type ListUserMemberships struct {
Result ListUserMembershipsResult `json:"result"`
Error Error `json:"error"`
Result keybase1.AnnotatedTeamList `json:"result"`
Error Error `json:"error"`
}
type ListUserMembershipsResult struct {
Teams []ListUserMembershipsResultTeam `json:"teams"`
}
type ListUserMembershipsResultTeam struct {
TeamName string `json:"fq_name"`
IsImplicitTeam bool `json:"is_implicit_team"`
IsOpenTeam bool `json:"is_open_team"`
Role int `json:"role"`
MemberCount int `json:"member_count"`
}
func (a *API) ListMembersOfTeam(teamName string) (ListTeamMembersResultMembers, error) {
empty := ListTeamMembersResultMembers{}
func (a *API) ListMembersOfTeam(teamName string) (res keybase1.TeamMembersDetails, err error) {
apiInput := fmt.Sprintf(`{"method": "list-team-memberships", "params": {"options": {"team": "%s"}}}`, teamName)
cmd := a.runOpts.Command("team", "api")
cmd.Stdin = strings.NewReader(apiInput)
bytes, err := cmd.CombinedOutput()
var stderr bytes.Buffer
cmd.Stderr = &stderr
output, err := cmd.Output()
if err != nil {
return empty, fmt.Errorf("failed to call keybase team api: %v", err)
return res, APIError{err}
}
if stderr.Len() != 0 {
log.Printf("ListMembersOfTeam error: %s", stderr.String())
}
members := ListTeamMembers{}
err = json.Unmarshal(bytes, &members)
err = json.Unmarshal(output, &members)
if err != nil {
return empty, fmt.Errorf("failed to parse output from keybase team api: %v", err)
return res, UnmarshalError{err}
}
if members.Error.Message != "" {
return empty, fmt.Errorf("received error from keybase team api: %s", members.Error.Message)
return res, members.Error
}
return members.Result.Members, nil
}
func (a *API) ListUserMemberships(username string) ([]ListUserMembershipsResultTeam, error) {
empty := []ListUserMembershipsResultTeam{}
func (a *API) ListUserMemberships(username string) ([]keybase1.AnnotatedMemberInfo, error) {
apiInput := fmt.Sprintf(`{"method": "list-user-memberships", "params": {"options": {"username": "%s"}}}`, username)
cmd := a.runOpts.Command("team", "api")
cmd.Stdin = strings.NewReader(apiInput)
bytes, err := cmd.CombinedOutput()
var stderr bytes.Buffer
cmd.Stderr = &stderr
output, err := cmd.Output()
if err != nil {
return empty, fmt.Errorf("failed to call keybase team api: %v", err)
return nil, APIError{err}
}
if stderr.Len() != 0 {
log.Printf("ListUserMemberships error: %s", stderr.String())
}
members := ListUserMemberships{}
err = json.Unmarshal(bytes, &members)
err = json.Unmarshal(output, &members)
if err != nil {
return empty, fmt.Errorf("failed to parse output from keybase team api: %v", err)
return nil, UnmarshalError{err}
}
if members.Error.Message != "" {
return empty, fmt.Errorf("received error from keybase team api: %s", members.Error.Message)
return nil, members.Error
}
return members.Result.Teams, nil
}

View File

@@ -1,16 +1,17 @@
# Rename this file to `test_config.yaml`
config:
bots:
alice:
username: "alice"
paperkey: "foo bar car..."
bob:
username: "bob"
paperkey: "one two three four..."
teams:
acme:
# A real team that you add your alice1 and bob1 into
name: "acme"
# The channel to use
topicname: "mysupercoolchannel"
keybase: "/path/to/keybase"
bots:
# Alice should have an active Stellar account with a little bit of XLM in it
alice:
username: "alice"
paperkey: "foo bar car..."
bob:
username: "bob"
paperkey: "one two three four..."
teams:
acme:
# A real team that you add your alice and bob into
name: "acme"
# The channel to use
topicname: "mysupercoolchannel"

View File

@@ -41,9 +41,7 @@ func copyFile(t *testing.T, source, dest string) {
// Creates the working directory and copies over the keybase binary in PATH.
// We do this to avoid any version mismatch issues.
func prepWorkingDir(t *testing.T, workingDir string) string {
kbLocation := whichKeybase(t)
func prepWorkingDir(t *testing.T, workingDir string, kbLocation string) string {
err := os.Mkdir(workingDir, 0777)
require.NoError(t, err)
kbDestination := path.Join(workingDir, "keybase")

View File

@@ -1,159 +1,14 @@
package kbchat
type Sender struct {
Uid string `json:"uid"`
Username string `json:"username"`
DeviceID string `json:"device_id"`
DeviceName string `json:"device_name"`
}
type Channel struct {
Name string `json:"name"`
Public bool `json:"public"`
TopicType string `json:"topic_type"`
TopicName string `json:"topic_name"`
MembersType string `json:"members_type"`
}
type Conversation struct {
ID string `json:"id"`
Unread bool `json:"unread"`
Channel Channel `json:"channel"`
}
type PaymentHolder struct {
Payment Payment `json:"notification"`
}
type Payment struct {
TxID string `json:"txID"`
StatusDescription string `json:"statusDescription"`
FromAccountID string `json:"fromAccountID"`
FromUsername string `json:"fromUsername"`
ToAccountID string `json:"toAccountID"`
ToUsername string `json:"toUsername"`
AmountDescription string `json:"amountDescription"`
WorthAtSendTime string `json:"worthAtSendTime"`
ExternalTxURL string `json:"externalTxURL"`
}
import (
"github.com/keybase/go-keybase-chat-bot/kbchat/types/chat1"
)
type Result struct {
Convs []Conversation `json:"conversations"`
}
type Inbox struct {
Result Result `json:"result"`
}
type ChannelsList struct {
Result Result `json:"result"`
}
type MsgPaymentDetails struct {
ResultType int `json:"resultTyp"` // 0 good. 1 error
PaymentID string `json:"sent"`
}
type MsgPayment struct {
Username string `json:"username"`
PaymentText string `json:"paymentText"`
Details MsgPaymentDetails `json:"result"`
}
type Text struct {
Body string `json:"body"`
Payments []MsgPayment `json:"payments"`
ReplyTo int `json:"replyTo"`
}
type Content struct {
Type string `json:"type"`
Text Text `json:"text"`
}
type Message struct {
Content Content `json:"content"`
Sender Sender `json:"sender"`
Channel Channel `json:"channel"`
ConversationID string `json:"conversation_id"`
MsgID int `json:"id"`
}
type SendResult struct {
MsgID int `json:"id"`
Convs []chat1.ConvSummary `json:"conversations"`
}
type SendResponse struct {
Result SendResult `json:"result"`
}
type TypeHolder struct {
Type string `json:"type"`
}
type MessageHolder struct {
Msg Message `json:"msg"`
Source string `json:"source"`
}
type ThreadResult struct {
Messages []MessageHolder `json:"messages"`
}
type Thread struct {
Result ThreadResult `json:"result"`
}
type CommandExtendedDescription struct {
Title string `json:"title"`
DesktopBody string `json:"desktop_body"`
MobileBody string `json:"mobile_body"`
}
type Command struct {
Name string `json:"name"`
Description string `json:"description"`
Usage string `json:"usage"`
ExtendedDescription *CommandExtendedDescription `json:"extended_description,omitempty"`
}
type CommandsAdvertisement struct {
Typ string `json:"type"`
Commands []Command
TeamName string `json:"team_name,omitempty"`
}
type Advertisement struct {
Alias string `json:"alias,omitempty"`
Advertisements []CommandsAdvertisement
}
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
}
type JoinChannel struct {
Error Error `json:"error"`
Result JoinChannelResult `json:"result"`
}
type JoinChannelResult struct {
RateLimit []RateLimit `json:"ratelimits"`
}
type LeaveChannel struct {
Error Error `json:"error"`
Result LeaveChannelResult `json:"result"`
}
type LeaveChannelResult struct {
RateLimit []RateLimit `json:"ratelimits"`
}
type RateLimit struct {
Tank string `json:"tank"`
Capacity int `json:"capacity"`
Reset int `json:"reset"`
Gas int `json:"gas"`
Result chat1.SendRes `json:"result"`
Error *Error `json:"error,omitempty"`
}

View File

@@ -0,0 +1,933 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/chat1/api.avdl
package chat1
import (
gregor1 "github.com/keybase/go-keybase-chat-bot/kbchat/types/gregor1"
keybase1 "github.com/keybase/go-keybase-chat-bot/kbchat/types/keybase1"
)
type ConvIDStr string
func (o ConvIDStr) DeepCopy() ConvIDStr {
return o
}
type TLFIDStr string
func (o TLFIDStr) DeepCopy() TLFIDStr {
return o
}
type FlipGameIDStr string
func (o FlipGameIDStr) DeepCopy() FlipGameIDStr {
return o
}
type RateLimitRes struct {
Tank string `codec:"tank" json:"tank"`
Capacity int `codec:"capacity" json:"capacity"`
Reset int `codec:"reset" json:"reset"`
Gas int `codec:"gas" json:"gas"`
}
func (o RateLimitRes) DeepCopy() RateLimitRes {
return RateLimitRes{
Tank: o.Tank,
Capacity: o.Capacity,
Reset: o.Reset,
Gas: o.Gas,
}
}
// A Keybase chat channel. This can be a channel in a team, or just an informal channel between two users.
// name: the name of the team or comma-separated list of participants
type ChatChannel struct {
Name string `codec:"name" json:"name"`
Public bool `codec:"public,omitempty" json:"public,omitempty"`
MembersType string `codec:"membersType,omitempty" json:"members_type,omitempty"`
TopicType string `codec:"topicType,omitempty" json:"topic_type,omitempty"`
TopicName string `codec:"topicName,omitempty" json:"topic_name,omitempty"`
}
func (o ChatChannel) DeepCopy() ChatChannel {
return ChatChannel{
Name: o.Name,
Public: o.Public,
MembersType: o.MembersType,
TopicType: o.TopicType,
TopicName: o.TopicName,
}
}
// A chat message. The content goes in the `body` property!
type ChatMessage struct {
Body string `codec:"body" json:"body"`
}
func (o ChatMessage) DeepCopy() ChatMessage {
return ChatMessage{
Body: o.Body,
}
}
type MsgSender struct {
Uid keybase1.UID `codec:"uid" json:"uid"`
Username string `codec:"username,omitempty" json:"username,omitempty"`
DeviceID keybase1.DeviceID `codec:"deviceID" json:"device_id"`
DeviceName string `codec:"deviceName,omitempty" json:"device_name,omitempty"`
}
func (o MsgSender) DeepCopy() MsgSender {
return MsgSender{
Uid: o.Uid.DeepCopy(),
Username: o.Username,
DeviceID: o.DeviceID.DeepCopy(),
DeviceName: o.DeviceName,
}
}
type MsgBotInfo struct {
BotUID keybase1.UID `codec:"botUID" json:"bot_uid"`
BotUsername string `codec:"botUsername,omitempty" json:"bot_username,omitempty"`
}
func (o MsgBotInfo) DeepCopy() MsgBotInfo {
return MsgBotInfo{
BotUID: o.BotUID.DeepCopy(),
BotUsername: o.BotUsername,
}
}
type MsgFlipContent struct {
Text string `codec:"text" json:"text"`
GameID FlipGameIDStr `codec:"gameID" json:"game_id"`
FlipConvID ConvIDStr `codec:"flipConvID" json:"flip_conv_id"`
UserMentions []KnownUserMention `codec:"userMentions" json:"user_mentions"`
TeamMentions []KnownTeamMention `codec:"teamMentions" json:"team_mentions"`
}
func (o MsgFlipContent) DeepCopy() MsgFlipContent {
return MsgFlipContent{
Text: o.Text,
GameID: o.GameID.DeepCopy(),
FlipConvID: o.FlipConvID.DeepCopy(),
UserMentions: (func(x []KnownUserMention) []KnownUserMention {
if x == nil {
return nil
}
ret := make([]KnownUserMention, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.UserMentions),
TeamMentions: (func(x []KnownTeamMention) []KnownTeamMention {
if x == nil {
return nil
}
ret := make([]KnownTeamMention, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.TeamMentions),
}
}
type MsgContent struct {
TypeName string `codec:"typeName" json:"type"`
Text *MessageText `codec:"text,omitempty" json:"text,omitempty"`
Attachment *MessageAttachment `codec:"attachment,omitempty" json:"attachment,omitempty"`
Edit *MessageEdit `codec:"edit,omitempty" json:"edit,omitempty"`
Reaction *MessageReaction `codec:"reaction,omitempty" json:"reaction,omitempty"`
Delete *MessageDelete `codec:"delete,omitempty" json:"delete,omitempty"`
Metadata *MessageConversationMetadata `codec:"metadata,omitempty" json:"metadata,omitempty"`
Headline *MessageHeadline `codec:"headline,omitempty" json:"headline,omitempty"`
AttachmentUploaded *MessageAttachmentUploaded `codec:"attachmentUploaded,omitempty" json:"attachment_uploaded,omitempty"`
System *MessageSystem `codec:"system,omitempty" json:"system,omitempty"`
SendPayment *MessageSendPayment `codec:"sendPayment,omitempty" json:"send_payment,omitempty"`
RequestPayment *MessageRequestPayment `codec:"requestPayment,omitempty" json:"request_payment,omitempty"`
Unfurl *MessageUnfurl `codec:"unfurl,omitempty" json:"unfurl,omitempty"`
Flip *MsgFlipContent `codec:"flip,omitempty" json:"flip,omitempty"`
}
func (o MsgContent) DeepCopy() MsgContent {
return MsgContent{
TypeName: o.TypeName,
Text: (func(x *MessageText) *MessageText {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Text),
Attachment: (func(x *MessageAttachment) *MessageAttachment {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Attachment),
Edit: (func(x *MessageEdit) *MessageEdit {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Edit),
Reaction: (func(x *MessageReaction) *MessageReaction {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Reaction),
Delete: (func(x *MessageDelete) *MessageDelete {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Delete),
Metadata: (func(x *MessageConversationMetadata) *MessageConversationMetadata {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Metadata),
Headline: (func(x *MessageHeadline) *MessageHeadline {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Headline),
AttachmentUploaded: (func(x *MessageAttachmentUploaded) *MessageAttachmentUploaded {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.AttachmentUploaded),
System: (func(x *MessageSystem) *MessageSystem {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.System),
SendPayment: (func(x *MessageSendPayment) *MessageSendPayment {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.SendPayment),
RequestPayment: (func(x *MessageRequestPayment) *MessageRequestPayment {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.RequestPayment),
Unfurl: (func(x *MessageUnfurl) *MessageUnfurl {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Unfurl),
Flip: (func(x *MsgFlipContent) *MsgFlipContent {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Flip),
}
}
type MsgSummary struct {
Id MessageID `codec:"id" json:"id"`
ConvID ConvIDStr `codec:"convID" json:"conversation_id"`
Channel ChatChannel `codec:"channel" json:"channel"`
Sender MsgSender `codec:"sender" json:"sender"`
SentAt int64 `codec:"sentAt" json:"sent_at"`
SentAtMs int64 `codec:"sentAtMs" json:"sent_at_ms"`
Content MsgContent `codec:"content" json:"content"`
Prev []MessagePreviousPointer `codec:"prev" json:"prev"`
Unread bool `codec:"unread" json:"unread"`
RevokedDevice bool `codec:"revokedDevice,omitempty" json:"revoked_device,omitempty"`
Offline bool `codec:"offline,omitempty" json:"offline,omitempty"`
KbfsEncrypted bool `codec:"kbfsEncrypted,omitempty" json:"kbfs_encrypted,omitempty"`
IsEphemeral bool `codec:"isEphemeral,omitempty" json:"is_ephemeral,omitempty"`
IsEphemeralExpired bool `codec:"isEphemeralExpired,omitempty" json:"is_ephemeral_expired,omitempty"`
ETime gregor1.Time `codec:"eTime,omitempty" json:"e_time,omitempty"`
Reactions *ReactionMap `codec:"reactions,omitempty" json:"reactions,omitempty"`
HasPairwiseMacs bool `codec:"hasPairwiseMacs,omitempty" json:"has_pairwise_macs,omitempty"`
AtMentionUsernames []string `codec:"atMentionUsernames,omitempty" json:"at_mention_usernames,omitempty"`
ChannelMention string `codec:"channelMention,omitempty" json:"channel_mention,omitempty"`
ChannelNameMentions []UIChannelNameMention `codec:"channelNameMentions,omitempty" json:"channel_name_mentions,omitempty"`
BotInfo *MsgBotInfo `codec:"botInfo,omitempty" json:"bot_info,omitempty"`
}
func (o MsgSummary) DeepCopy() MsgSummary {
return MsgSummary{
Id: o.Id.DeepCopy(),
ConvID: o.ConvID.DeepCopy(),
Channel: o.Channel.DeepCopy(),
Sender: o.Sender.DeepCopy(),
SentAt: o.SentAt,
SentAtMs: o.SentAtMs,
Content: o.Content.DeepCopy(),
Prev: (func(x []MessagePreviousPointer) []MessagePreviousPointer {
if x == nil {
return nil
}
ret := make([]MessagePreviousPointer, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Prev),
Unread: o.Unread,
RevokedDevice: o.RevokedDevice,
Offline: o.Offline,
KbfsEncrypted: o.KbfsEncrypted,
IsEphemeral: o.IsEphemeral,
IsEphemeralExpired: o.IsEphemeralExpired,
ETime: o.ETime.DeepCopy(),
Reactions: (func(x *ReactionMap) *ReactionMap {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Reactions),
HasPairwiseMacs: o.HasPairwiseMacs,
AtMentionUsernames: (func(x []string) []string {
if x == nil {
return nil
}
ret := make([]string, len(x))
for i, v := range x {
vCopy := v
ret[i] = vCopy
}
return ret
})(o.AtMentionUsernames),
ChannelMention: o.ChannelMention,
ChannelNameMentions: (func(x []UIChannelNameMention) []UIChannelNameMention {
if x == nil {
return nil
}
ret := make([]UIChannelNameMention, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.ChannelNameMentions),
BotInfo: (func(x *MsgBotInfo) *MsgBotInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.BotInfo),
}
}
type Message struct {
Msg *MsgSummary `codec:"msg,omitempty" json:"msg,omitempty"`
Error *string `codec:"error,omitempty" json:"error,omitempty"`
}
func (o Message) DeepCopy() Message {
return Message{
Msg: (func(x *MsgSummary) *MsgSummary {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Msg),
Error: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.Error),
}
}
type Thread struct {
Messages []Message `codec:"messages" json:"messages"`
Pagination *Pagination `codec:"pagination,omitempty" json:"pagination,omitempty"`
Offline bool `codec:"offline,omitempty" json:"offline,omitempty"`
IdentifyFailures []keybase1.TLFIdentifyFailure `codec:"identifyFailures,omitempty" json:"identify_failures,omitempty"`
RateLimits []RateLimitRes `codec:"rateLimits,omitempty" json:"ratelimits,omitempty"`
}
func (o Thread) DeepCopy() Thread {
return Thread{
Messages: (func(x []Message) []Message {
if x == nil {
return nil
}
ret := make([]Message, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Messages),
Pagination: (func(x *Pagination) *Pagination {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Pagination),
Offline: o.Offline,
IdentifyFailures: (func(x []keybase1.TLFIdentifyFailure) []keybase1.TLFIdentifyFailure {
if x == nil {
return nil
}
ret := make([]keybase1.TLFIdentifyFailure, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.IdentifyFailures),
RateLimits: (func(x []RateLimitRes) []RateLimitRes {
if x == nil {
return nil
}
ret := make([]RateLimitRes, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RateLimits),
}
}
// A chat conversation. This is essentially a chat channel plus some additional metadata.
type ConvSummary struct {
Id ConvIDStr `codec:"id" json:"id"`
Channel ChatChannel `codec:"channel" json:"channel"`
IsDefaultConv bool `codec:"isDefaultConv" json:"is_default_conv"`
Unread bool `codec:"unread" json:"unread"`
ActiveAt int64 `codec:"activeAt" json:"active_at"`
ActiveAtMs int64 `codec:"activeAtMs" json:"active_at_ms"`
MemberStatus string `codec:"memberStatus" json:"member_status"`
ResetUsers []string `codec:"resetUsers,omitempty" json:"reset_users,omitempty"`
FinalizeInfo *ConversationFinalizeInfo `codec:"finalizeInfo,omitempty" json:"finalize_info,omitempty"`
Supersedes []string `codec:"supersedes,omitempty" json:"supersedes,omitempty"`
SupersededBy []string `codec:"supersededBy,omitempty" json:"superseded_by,omitempty"`
Error string `codec:"error,omitempty" json:"error,omitempty"`
CreatorInfo *ConversationCreatorInfoLocal `codec:"creatorInfo,omitempty" json:"creator_info,omitempty"`
}
func (o ConvSummary) DeepCopy() ConvSummary {
return ConvSummary{
Id: o.Id.DeepCopy(),
Channel: o.Channel.DeepCopy(),
IsDefaultConv: o.IsDefaultConv,
Unread: o.Unread,
ActiveAt: o.ActiveAt,
ActiveAtMs: o.ActiveAtMs,
MemberStatus: o.MemberStatus,
ResetUsers: (func(x []string) []string {
if x == nil {
return nil
}
ret := make([]string, len(x))
for i, v := range x {
vCopy := v
ret[i] = vCopy
}
return ret
})(o.ResetUsers),
FinalizeInfo: (func(x *ConversationFinalizeInfo) *ConversationFinalizeInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.FinalizeInfo),
Supersedes: (func(x []string) []string {
if x == nil {
return nil
}
ret := make([]string, len(x))
for i, v := range x {
vCopy := v
ret[i] = vCopy
}
return ret
})(o.Supersedes),
SupersededBy: (func(x []string) []string {
if x == nil {
return nil
}
ret := make([]string, len(x))
for i, v := range x {
vCopy := v
ret[i] = vCopy
}
return ret
})(o.SupersededBy),
Error: o.Error,
CreatorInfo: (func(x *ConversationCreatorInfoLocal) *ConversationCreatorInfoLocal {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.CreatorInfo),
}
}
type ChatList struct {
Conversations []ConvSummary `codec:"conversations" json:"conversations"`
Offline bool `codec:"offline" json:"offline"`
IdentifyFailures []keybase1.TLFIdentifyFailure `codec:"identifyFailures,omitempty" json:"identify_failures,omitempty"`
RateLimits []RateLimitRes `codec:"rateLimits,omitempty" json:"ratelimits,omitempty"`
}
func (o ChatList) DeepCopy() ChatList {
return ChatList{
Conversations: (func(x []ConvSummary) []ConvSummary {
if x == nil {
return nil
}
ret := make([]ConvSummary, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Conversations),
Offline: o.Offline,
IdentifyFailures: (func(x []keybase1.TLFIdentifyFailure) []keybase1.TLFIdentifyFailure {
if x == nil {
return nil
}
ret := make([]keybase1.TLFIdentifyFailure, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.IdentifyFailures),
RateLimits: (func(x []RateLimitRes) []RateLimitRes {
if x == nil {
return nil
}
ret := make([]RateLimitRes, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RateLimits),
}
}
type SendRes struct {
Message string `codec:"message" json:"message"`
MessageID *MessageID `codec:"messageID,omitempty" json:"id,omitempty"`
OutboxID *OutboxID `codec:"outboxID,omitempty" json:"outbox_id,omitempty"`
IdentifyFailures []keybase1.TLFIdentifyFailure `codec:"identifyFailures,omitempty" json:"identify_failures,omitempty"`
RateLimits []RateLimitRes `codec:"rateLimits,omitempty" json:"ratelimits,omitempty"`
}
func (o SendRes) DeepCopy() SendRes {
return SendRes{
Message: o.Message,
MessageID: (func(x *MessageID) *MessageID {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.MessageID),
OutboxID: (func(x *OutboxID) *OutboxID {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.OutboxID),
IdentifyFailures: (func(x []keybase1.TLFIdentifyFailure) []keybase1.TLFIdentifyFailure {
if x == nil {
return nil
}
ret := make([]keybase1.TLFIdentifyFailure, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.IdentifyFailures),
RateLimits: (func(x []RateLimitRes) []RateLimitRes {
if x == nil {
return nil
}
ret := make([]RateLimitRes, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RateLimits),
}
}
type SearchInboxResOutput struct {
Results *ChatSearchInboxResults `codec:"results,omitempty" json:"results,omitempty"`
IdentifyFailures []keybase1.TLFIdentifyFailure `codec:"identifyFailures,omitempty" json:"identify_failures,omitempty"`
RateLimits []RateLimitRes `codec:"rateLimits,omitempty" json:"ratelimits,omitempty"`
}
func (o SearchInboxResOutput) DeepCopy() SearchInboxResOutput {
return SearchInboxResOutput{
Results: (func(x *ChatSearchInboxResults) *ChatSearchInboxResults {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Results),
IdentifyFailures: (func(x []keybase1.TLFIdentifyFailure) []keybase1.TLFIdentifyFailure {
if x == nil {
return nil
}
ret := make([]keybase1.TLFIdentifyFailure, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.IdentifyFailures),
RateLimits: (func(x []RateLimitRes) []RateLimitRes {
if x == nil {
return nil
}
ret := make([]RateLimitRes, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RateLimits),
}
}
type RegexpRes struct {
Hits []ChatSearchHit `codec:"hits" json:"hits"`
IdentifyFailures []keybase1.TLFIdentifyFailure `codec:"identifyFailures,omitempty" json:"identify_failures,omitempty"`
RateLimits []RateLimitRes `codec:"rateLimits,omitempty" json:"ratelimits,omitempty"`
}
func (o RegexpRes) DeepCopy() RegexpRes {
return RegexpRes{
Hits: (func(x []ChatSearchHit) []ChatSearchHit {
if x == nil {
return nil
}
ret := make([]ChatSearchHit, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Hits),
IdentifyFailures: (func(x []keybase1.TLFIdentifyFailure) []keybase1.TLFIdentifyFailure {
if x == nil {
return nil
}
ret := make([]keybase1.TLFIdentifyFailure, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.IdentifyFailures),
RateLimits: (func(x []RateLimitRes) []RateLimitRes {
if x == nil {
return nil
}
ret := make([]RateLimitRes, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RateLimits),
}
}
type NewConvRes struct {
Id ConvIDStr `codec:"id" json:"id"`
IdentifyFailures []keybase1.TLFIdentifyFailure `codec:"identifyFailures,omitempty" json:"identify_failures,omitempty"`
RateLimits []RateLimitRes `codec:"rateLimits,omitempty" json:"ratelimits,omitempty"`
}
func (o NewConvRes) DeepCopy() NewConvRes {
return NewConvRes{
Id: o.Id.DeepCopy(),
IdentifyFailures: (func(x []keybase1.TLFIdentifyFailure) []keybase1.TLFIdentifyFailure {
if x == nil {
return nil
}
ret := make([]keybase1.TLFIdentifyFailure, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.IdentifyFailures),
RateLimits: (func(x []RateLimitRes) []RateLimitRes {
if x == nil {
return nil
}
ret := make([]RateLimitRes, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RateLimits),
}
}
type ListCommandsRes struct {
Commands []UserBotCommandOutput `codec:"commands" json:"commands"`
RateLimits []RateLimitRes `codec:"rateLimits,omitempty" json:"ratelimits,omitempty"`
}
func (o ListCommandsRes) DeepCopy() ListCommandsRes {
return ListCommandsRes{
Commands: (func(x []UserBotCommandOutput) []UserBotCommandOutput {
if x == nil {
return nil
}
ret := make([]UserBotCommandOutput, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Commands),
RateLimits: (func(x []RateLimitRes) []RateLimitRes {
if x == nil {
return nil
}
ret := make([]RateLimitRes, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RateLimits),
}
}
type EmptyRes struct {
RateLimits []RateLimitRes `codec:"rateLimits,omitempty" json:"ratelimits,omitempty"`
}
func (o EmptyRes) DeepCopy() EmptyRes {
return EmptyRes{
RateLimits: (func(x []RateLimitRes) []RateLimitRes {
if x == nil {
return nil
}
ret := make([]RateLimitRes, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RateLimits),
}
}
type MsgNotification struct {
Type string `codec:"type" json:"type"`
Source string `codec:"source" json:"source"`
Msg *MsgSummary `codec:"msg,omitempty" json:"msg,omitempty"`
Error *string `codec:"error,omitempty" json:"error,omitempty"`
Pagination *UIPagination `codec:"pagination,omitempty" json:"pagination,omitempty"`
}
func (o MsgNotification) DeepCopy() MsgNotification {
return MsgNotification{
Type: o.Type,
Source: o.Source,
Msg: (func(x *MsgSummary) *MsgSummary {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Msg),
Error: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.Error),
Pagination: (func(x *UIPagination) *UIPagination {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Pagination),
}
}
type ConvNotification struct {
Type string `codec:"type" json:"type"`
Conv *ConvSummary `codec:"conv,omitempty" json:"conv,omitempty"`
Error *string `codec:"error,omitempty" json:"error,omitempty"`
}
func (o ConvNotification) DeepCopy() ConvNotification {
return ConvNotification{
Type: o.Type,
Conv: (func(x *ConvSummary) *ConvSummary {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Conv),
Error: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.Error),
}
}
type AdvertiseCommandAPIParam struct {
Typ string `codec:"typ" json:"type"`
Commands []UserBotCommandInput `codec:"commands" json:"commands"`
TeamName string `codec:"teamName,omitempty" json:"team_name,omitempty"`
}
func (o AdvertiseCommandAPIParam) DeepCopy() AdvertiseCommandAPIParam {
return AdvertiseCommandAPIParam{
Typ: o.Typ,
Commands: (func(x []UserBotCommandInput) []UserBotCommandInput {
if x == nil {
return nil
}
ret := make([]UserBotCommandInput, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Commands),
TeamName: o.TeamName,
}
}
type ResetConvMemberAPI struct {
ConversationID ConvIDStr `codec:"conversationID" json:"conversationID"`
Username string `codec:"username" json:"username"`
}
func (o ResetConvMemberAPI) DeepCopy() ResetConvMemberAPI {
return ResetConvMemberAPI{
ConversationID: o.ConversationID.DeepCopy(),
Username: o.Username,
}
}
type GetResetConvMembersRes struct {
Members []ResetConvMemberAPI `codec:"members" json:"members"`
RateLimits []RateLimitRes `codec:"rateLimits" json:"rateLimits"`
}
func (o GetResetConvMembersRes) DeepCopy() GetResetConvMembersRes {
return GetResetConvMembersRes{
Members: (func(x []ResetConvMemberAPI) []ResetConvMemberAPI {
if x == nil {
return nil
}
ret := make([]ResetConvMemberAPI, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Members),
RateLimits: (func(x []RateLimitRes) []RateLimitRes {
if x == nil {
return nil
}
ret := make([]RateLimitRes, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RateLimits),
}
}
type DeviceInfo struct {
DeviceID keybase1.DeviceID `codec:"deviceID" json:"id"`
DeviceDescription string `codec:"deviceDescription" json:"description"`
DeviceType string `codec:"deviceType" json:"type"`
DeviceCtime int64 `codec:"deviceCtime" json:"ctime"`
}
func (o DeviceInfo) DeepCopy() DeviceInfo {
return DeviceInfo{
DeviceID: o.DeviceID.DeepCopy(),
DeviceDescription: o.DeviceDescription,
DeviceType: o.DeviceType,
DeviceCtime: o.DeviceCtime,
}
}
type GetDeviceInfoRes struct {
Devices []DeviceInfo `codec:"devices" json:"devices"`
}
func (o GetDeviceInfoRes) DeepCopy() GetDeviceInfoRes {
return GetDeviceInfoRes{
Devices: (func(x []DeviceInfo) []DeviceInfo {
if x == nil {
return nil
}
ret := make([]DeviceInfo, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Devices),
}
}

View File

@@ -0,0 +1,4 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/chat1/blocking.avdl
package chat1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,199 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/chat1/commands.avdl
package chat1
import (
"errors"
"fmt"
)
type ConversationCommand struct {
Description string `codec:"description" json:"description"`
Name string `codec:"name" json:"name"`
Usage string `codec:"usage" json:"usage"`
HasHelpText bool `codec:"hasHelpText" json:"hasHelpText"`
Username *string `codec:"username,omitempty" json:"username,omitempty"`
}
func (o ConversationCommand) DeepCopy() ConversationCommand {
return ConversationCommand{
Description: o.Description,
Name: o.Name,
Usage: o.Usage,
HasHelpText: o.HasHelpText,
Username: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.Username),
}
}
type ConversationCommandGroupsTyp int
const (
ConversationCommandGroupsTyp_BUILTIN ConversationCommandGroupsTyp = 0
ConversationCommandGroupsTyp_CUSTOM ConversationCommandGroupsTyp = 1
ConversationCommandGroupsTyp_NONE ConversationCommandGroupsTyp = 2
)
func (o ConversationCommandGroupsTyp) DeepCopy() ConversationCommandGroupsTyp { return o }
var ConversationCommandGroupsTypMap = map[string]ConversationCommandGroupsTyp{
"BUILTIN": 0,
"CUSTOM": 1,
"NONE": 2,
}
var ConversationCommandGroupsTypRevMap = map[ConversationCommandGroupsTyp]string{
0: "BUILTIN",
1: "CUSTOM",
2: "NONE",
}
func (e ConversationCommandGroupsTyp) String() string {
if v, ok := ConversationCommandGroupsTypRevMap[e]; ok {
return v
}
return fmt.Sprintf("%v", int(e))
}
type ConversationBuiltinCommandTyp int
const (
ConversationBuiltinCommandTyp_NONE ConversationBuiltinCommandTyp = 0
ConversationBuiltinCommandTyp_ADHOC ConversationBuiltinCommandTyp = 1
ConversationBuiltinCommandTyp_SMALLTEAM ConversationBuiltinCommandTyp = 2
ConversationBuiltinCommandTyp_BIGTEAM ConversationBuiltinCommandTyp = 3
ConversationBuiltinCommandTyp_BIGTEAMGENERAL ConversationBuiltinCommandTyp = 4
)
func (o ConversationBuiltinCommandTyp) DeepCopy() ConversationBuiltinCommandTyp { return o }
var ConversationBuiltinCommandTypMap = map[string]ConversationBuiltinCommandTyp{
"NONE": 0,
"ADHOC": 1,
"SMALLTEAM": 2,
"BIGTEAM": 3,
"BIGTEAMGENERAL": 4,
}
var ConversationBuiltinCommandTypRevMap = map[ConversationBuiltinCommandTyp]string{
0: "NONE",
1: "ADHOC",
2: "SMALLTEAM",
3: "BIGTEAM",
4: "BIGTEAMGENERAL",
}
func (e ConversationBuiltinCommandTyp) String() string {
if v, ok := ConversationBuiltinCommandTypRevMap[e]; ok {
return v
}
return fmt.Sprintf("%v", int(e))
}
type ConversationCommandGroupsCustom struct {
Commands []ConversationCommand `codec:"commands" json:"commands"`
}
func (o ConversationCommandGroupsCustom) DeepCopy() ConversationCommandGroupsCustom {
return ConversationCommandGroupsCustom{
Commands: (func(x []ConversationCommand) []ConversationCommand {
if x == nil {
return nil
}
ret := make([]ConversationCommand, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Commands),
}
}
type ConversationCommandGroups struct {
Typ__ ConversationCommandGroupsTyp `codec:"typ" json:"typ"`
Builtin__ *ConversationBuiltinCommandTyp `codec:"builtin,omitempty" json:"builtin,omitempty"`
Custom__ *ConversationCommandGroupsCustom `codec:"custom,omitempty" json:"custom,omitempty"`
}
func (o *ConversationCommandGroups) Typ() (ret ConversationCommandGroupsTyp, err error) {
switch o.Typ__ {
case ConversationCommandGroupsTyp_BUILTIN:
if o.Builtin__ == nil {
err = errors.New("unexpected nil value for Builtin__")
return ret, err
}
case ConversationCommandGroupsTyp_CUSTOM:
if o.Custom__ == nil {
err = errors.New("unexpected nil value for Custom__")
return ret, err
}
}
return o.Typ__, nil
}
func (o ConversationCommandGroups) Builtin() (res ConversationBuiltinCommandTyp) {
if o.Typ__ != ConversationCommandGroupsTyp_BUILTIN {
panic("wrong case accessed")
}
if o.Builtin__ == nil {
return
}
return *o.Builtin__
}
func (o ConversationCommandGroups) Custom() (res ConversationCommandGroupsCustom) {
if o.Typ__ != ConversationCommandGroupsTyp_CUSTOM {
panic("wrong case accessed")
}
if o.Custom__ == nil {
return
}
return *o.Custom__
}
func NewConversationCommandGroupsWithBuiltin(v ConversationBuiltinCommandTyp) ConversationCommandGroups {
return ConversationCommandGroups{
Typ__: ConversationCommandGroupsTyp_BUILTIN,
Builtin__: &v,
}
}
func NewConversationCommandGroupsWithCustom(v ConversationCommandGroupsCustom) ConversationCommandGroups {
return ConversationCommandGroups{
Typ__: ConversationCommandGroupsTyp_CUSTOM,
Custom__: &v,
}
}
func NewConversationCommandGroupsWithNone() ConversationCommandGroups {
return ConversationCommandGroups{
Typ__: ConversationCommandGroupsTyp_NONE,
}
}
func (o ConversationCommandGroups) DeepCopy() ConversationCommandGroups {
return ConversationCommandGroups{
Typ__: o.Typ__.DeepCopy(),
Builtin__: (func(x *ConversationBuiltinCommandTyp) *ConversationBuiltinCommandTyp {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Builtin__),
Custom__: (func(x *ConversationCommandGroupsCustom) *ConversationCommandGroupsCustom {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Custom__),
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,548 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/chat1/gregor.avdl
package chat1
import (
gregor1 "github.com/keybase/go-keybase-chat-bot/kbchat/types/gregor1"
keybase1 "github.com/keybase/go-keybase-chat-bot/kbchat/types/keybase1"
)
type GenericPayload struct {
Action string `codec:"Action" json:"Action"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
ConvID ConversationID `codec:"convID" json:"convID"`
TopicType TopicType `codec:"topicType" json:"topicType"`
UnreadUpdate *UnreadUpdate `codec:"unreadUpdate,omitempty" json:"unreadUpdate,omitempty"`
}
func (o GenericPayload) DeepCopy() GenericPayload {
return GenericPayload{
Action: o.Action,
InboxVers: o.InboxVers.DeepCopy(),
ConvID: o.ConvID.DeepCopy(),
TopicType: o.TopicType.DeepCopy(),
UnreadUpdate: (func(x *UnreadUpdate) *UnreadUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.UnreadUpdate),
}
}
type NewConversationPayload struct {
Action string `codec:"Action" json:"Action"`
ConvID ConversationID `codec:"convID" json:"convID"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
TopicType TopicType `codec:"topicType" json:"topicType"`
UnreadUpdate *UnreadUpdate `codec:"unreadUpdate,omitempty" json:"unreadUpdate,omitempty"`
}
func (o NewConversationPayload) DeepCopy() NewConversationPayload {
return NewConversationPayload{
Action: o.Action,
ConvID: o.ConvID.DeepCopy(),
InboxVers: o.InboxVers.DeepCopy(),
TopicType: o.TopicType.DeepCopy(),
UnreadUpdate: (func(x *UnreadUpdate) *UnreadUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.UnreadUpdate),
}
}
type NewMessagePayload struct {
Action string `codec:"Action" json:"Action"`
ConvID ConversationID `codec:"convID" json:"convID"`
Message MessageBoxed `codec:"message" json:"message"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
TopicType TopicType `codec:"topicType" json:"topicType"`
UnreadUpdate *UnreadUpdate `codec:"unreadUpdate,omitempty" json:"unreadUpdate,omitempty"`
UntrustedTeamRole keybase1.TeamRole `codec:"untrustedTeamRole" json:"untrustedTeamRole"`
MaxMsgs []MessageSummary `codec:"maxMsgs" json:"maxMsgs"`
}
func (o NewMessagePayload) DeepCopy() NewMessagePayload {
return NewMessagePayload{
Action: o.Action,
ConvID: o.ConvID.DeepCopy(),
Message: o.Message.DeepCopy(),
InboxVers: o.InboxVers.DeepCopy(),
TopicType: o.TopicType.DeepCopy(),
UnreadUpdate: (func(x *UnreadUpdate) *UnreadUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.UnreadUpdate),
UntrustedTeamRole: o.UntrustedTeamRole.DeepCopy(),
MaxMsgs: (func(x []MessageSummary) []MessageSummary {
if x == nil {
return nil
}
ret := make([]MessageSummary, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.MaxMsgs),
}
}
type ReadMessagePayload struct {
Action string `codec:"Action" json:"Action"`
ConvID ConversationID `codec:"convID" json:"convID"`
MsgID MessageID `codec:"msgID" json:"msgID"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
TopicType TopicType `codec:"topicType" json:"topicType"`
UnreadUpdate *UnreadUpdate `codec:"unreadUpdate,omitempty" json:"unreadUpdate,omitempty"`
}
func (o ReadMessagePayload) DeepCopy() ReadMessagePayload {
return ReadMessagePayload{
Action: o.Action,
ConvID: o.ConvID.DeepCopy(),
MsgID: o.MsgID.DeepCopy(),
InboxVers: o.InboxVers.DeepCopy(),
TopicType: o.TopicType.DeepCopy(),
UnreadUpdate: (func(x *UnreadUpdate) *UnreadUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.UnreadUpdate),
}
}
type SetStatusPayload struct {
Action string `codec:"Action" json:"Action"`
ConvID ConversationID `codec:"convID" json:"convID"`
Status ConversationStatus `codec:"status" json:"status"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
TopicType TopicType `codec:"topicType" json:"topicType"`
UnreadUpdate *UnreadUpdate `codec:"unreadUpdate,omitempty" json:"unreadUpdate,omitempty"`
}
func (o SetStatusPayload) DeepCopy() SetStatusPayload {
return SetStatusPayload{
Action: o.Action,
ConvID: o.ConvID.DeepCopy(),
Status: o.Status.DeepCopy(),
InboxVers: o.InboxVers.DeepCopy(),
TopicType: o.TopicType.DeepCopy(),
UnreadUpdate: (func(x *UnreadUpdate) *UnreadUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.UnreadUpdate),
}
}
type TeamTypePayload struct {
Action string `codec:"Action" json:"Action"`
ConvID ConversationID `codec:"convID" json:"convID"`
TeamType TeamType `codec:"teamType" json:"teamType"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
TopicType TopicType `codec:"topicType" json:"topicType"`
UnreadUpdate *UnreadUpdate `codec:"unreadUpdate,omitempty" json:"unreadUpdate,omitempty"`
}
func (o TeamTypePayload) DeepCopy() TeamTypePayload {
return TeamTypePayload{
Action: o.Action,
ConvID: o.ConvID.DeepCopy(),
TeamType: o.TeamType.DeepCopy(),
InboxVers: o.InboxVers.DeepCopy(),
TopicType: o.TopicType.DeepCopy(),
UnreadUpdate: (func(x *UnreadUpdate) *UnreadUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.UnreadUpdate),
}
}
type SetAppNotificationSettingsPayload struct {
Action string `codec:"Action" json:"Action"`
ConvID ConversationID `codec:"convID" json:"convID"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
Settings ConversationNotificationInfo `codec:"settings" json:"settings"`
TopicType TopicType `codec:"topicType" json:"topicType"`
UnreadUpdate *UnreadUpdate `codec:"unreadUpdate,omitempty" json:"unreadUpdate,omitempty"`
}
func (o SetAppNotificationSettingsPayload) DeepCopy() SetAppNotificationSettingsPayload {
return SetAppNotificationSettingsPayload{
Action: o.Action,
ConvID: o.ConvID.DeepCopy(),
InboxVers: o.InboxVers.DeepCopy(),
Settings: o.Settings.DeepCopy(),
TopicType: o.TopicType.DeepCopy(),
UnreadUpdate: (func(x *UnreadUpdate) *UnreadUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.UnreadUpdate),
}
}
type ExpungePayload struct {
Action string `codec:"Action" json:"Action"`
ConvID ConversationID `codec:"convID" json:"convID"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
Expunge Expunge `codec:"expunge" json:"expunge"`
MaxMsgs []MessageSummary `codec:"maxMsgs" json:"maxMsgs"`
TopicType TopicType `codec:"topicType" json:"topicType"`
UnreadUpdate *UnreadUpdate `codec:"unreadUpdate,omitempty" json:"unreadUpdate,omitempty"`
}
func (o ExpungePayload) DeepCopy() ExpungePayload {
return ExpungePayload{
Action: o.Action,
ConvID: o.ConvID.DeepCopy(),
InboxVers: o.InboxVers.DeepCopy(),
Expunge: o.Expunge.DeepCopy(),
MaxMsgs: (func(x []MessageSummary) []MessageSummary {
if x == nil {
return nil
}
ret := make([]MessageSummary, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.MaxMsgs),
TopicType: o.TopicType.DeepCopy(),
UnreadUpdate: (func(x *UnreadUpdate) *UnreadUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.UnreadUpdate),
}
}
type UnreadUpdate struct {
ConvID ConversationID `codec:"convID" json:"convID"`
UnreadMessages int `codec:"unreadMessages" json:"unreadMessages"`
UnreadNotifyingMessages map[keybase1.DeviceType]int `codec:"unreadNotifyingMessages" json:"unreadNotifyingMessages"`
CompatUnreadMessages int `codec:"UnreadMessages" json:"UnreadMessages"`
Diff bool `codec:"diff" json:"diff"`
}
func (o UnreadUpdate) DeepCopy() UnreadUpdate {
return UnreadUpdate{
ConvID: o.ConvID.DeepCopy(),
UnreadMessages: o.UnreadMessages,
UnreadNotifyingMessages: (func(x map[keybase1.DeviceType]int) map[keybase1.DeviceType]int {
if x == nil {
return nil
}
ret := make(map[keybase1.DeviceType]int, len(x))
for k, v := range x {
kCopy := k.DeepCopy()
vCopy := v
ret[kCopy] = vCopy
}
return ret
})(o.UnreadNotifyingMessages),
CompatUnreadMessages: o.CompatUnreadMessages,
Diff: o.Diff,
}
}
type TLFFinalizeUpdate struct {
FinalizeInfo ConversationFinalizeInfo `codec:"finalizeInfo" json:"finalizeInfo"`
ConvIDs []ConversationID `codec:"convIDs" json:"convIDs"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
}
func (o TLFFinalizeUpdate) DeepCopy() TLFFinalizeUpdate {
return TLFFinalizeUpdate{
FinalizeInfo: o.FinalizeInfo.DeepCopy(),
ConvIDs: (func(x []ConversationID) []ConversationID {
if x == nil {
return nil
}
ret := make([]ConversationID, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.ConvIDs),
InboxVers: o.InboxVers.DeepCopy(),
}
}
type TLFResolveUpdate struct {
ConvID ConversationID `codec:"convID" json:"convID"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
}
func (o TLFResolveUpdate) DeepCopy() TLFResolveUpdate {
return TLFResolveUpdate{
ConvID: o.ConvID.DeepCopy(),
InboxVers: o.InboxVers.DeepCopy(),
}
}
type RemoteUserTypingUpdate struct {
Uid gregor1.UID `codec:"uid" json:"uid"`
DeviceID gregor1.DeviceID `codec:"deviceID" json:"deviceID"`
ConvID ConversationID `codec:"convID" json:"convID"`
Typing bool `codec:"typing" json:"typing"`
TeamType TeamType `codec:"t" json:"teamType"`
}
func (o RemoteUserTypingUpdate) DeepCopy() RemoteUserTypingUpdate {
return RemoteUserTypingUpdate{
Uid: o.Uid.DeepCopy(),
DeviceID: o.DeviceID.DeepCopy(),
ConvID: o.ConvID.DeepCopy(),
Typing: o.Typing,
TeamType: o.TeamType.DeepCopy(),
}
}
type TeamMemberRoleUpdate struct {
TlfID TLFID `codec:"tlfID" json:"tlfID"`
Role keybase1.TeamRole `codec:"role" json:"role"`
}
func (o TeamMemberRoleUpdate) DeepCopy() TeamMemberRoleUpdate {
return TeamMemberRoleUpdate{
TlfID: o.TlfID.DeepCopy(),
Role: o.Role.DeepCopy(),
}
}
type UpdateConversationMembership struct {
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
TeamMemberRoleUpdate *TeamMemberRoleUpdate `codec:"teamMemberRoleUpdate,omitempty" json:"teamMemberRoleUpdate,omitempty"`
Joined []ConversationMember `codec:"joined" json:"joined"`
Removed []ConversationMember `codec:"removed" json:"removed"`
Reset []ConversationMember `codec:"reset" json:"reset"`
Previewed []ConversationID `codec:"previewed" json:"previewed"`
UnreadUpdate *UnreadUpdate `codec:"unreadUpdate,omitempty" json:"unreadUpdate,omitempty"`
UnreadUpdates []UnreadUpdate `codec:"unreadUpdates" json:"unreadUpdates"`
}
func (o UpdateConversationMembership) DeepCopy() UpdateConversationMembership {
return UpdateConversationMembership{
InboxVers: o.InboxVers.DeepCopy(),
TeamMemberRoleUpdate: (func(x *TeamMemberRoleUpdate) *TeamMemberRoleUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.TeamMemberRoleUpdate),
Joined: (func(x []ConversationMember) []ConversationMember {
if x == nil {
return nil
}
ret := make([]ConversationMember, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Joined),
Removed: (func(x []ConversationMember) []ConversationMember {
if x == nil {
return nil
}
ret := make([]ConversationMember, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Removed),
Reset: (func(x []ConversationMember) []ConversationMember {
if x == nil {
return nil
}
ret := make([]ConversationMember, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Reset),
Previewed: (func(x []ConversationID) []ConversationID {
if x == nil {
return nil
}
ret := make([]ConversationID, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Previewed),
UnreadUpdate: (func(x *UnreadUpdate) *UnreadUpdate {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.UnreadUpdate),
UnreadUpdates: (func(x []UnreadUpdate) []UnreadUpdate {
if x == nil {
return nil
}
ret := make([]UnreadUpdate, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.UnreadUpdates),
}
}
type ConversationUpdate struct {
ConvID ConversationID `codec:"convID" json:"convID"`
Existence ConversationExistence `codec:"existence" json:"existence"`
}
func (o ConversationUpdate) DeepCopy() ConversationUpdate {
return ConversationUpdate{
ConvID: o.ConvID.DeepCopy(),
Existence: o.Existence.DeepCopy(),
}
}
type UpdateConversations struct {
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
ConvUpdates []ConversationUpdate `codec:"convUpdates" json:"convUpdates"`
}
func (o UpdateConversations) DeepCopy() UpdateConversations {
return UpdateConversations{
InboxVers: o.InboxVers.DeepCopy(),
ConvUpdates: (func(x []ConversationUpdate) []ConversationUpdate {
if x == nil {
return nil
}
ret := make([]ConversationUpdate, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.ConvUpdates),
}
}
type TeamChannelUpdate struct {
TeamID TLFID `codec:"teamID" json:"teamID"`
}
func (o TeamChannelUpdate) DeepCopy() TeamChannelUpdate {
return TeamChannelUpdate{
TeamID: o.TeamID.DeepCopy(),
}
}
type SetConvRetentionUpdate struct {
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
ConvID ConversationID `codec:"convID" json:"convID"`
Policy RetentionPolicy `codec:"policy" json:"policy"`
}
func (o SetConvRetentionUpdate) DeepCopy() SetConvRetentionUpdate {
return SetConvRetentionUpdate{
InboxVers: o.InboxVers.DeepCopy(),
ConvID: o.ConvID.DeepCopy(),
Policy: o.Policy.DeepCopy(),
}
}
type SetTeamRetentionUpdate struct {
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
TeamID keybase1.TeamID `codec:"teamID" json:"teamID"`
Policy RetentionPolicy `codec:"policy" json:"policy"`
}
func (o SetTeamRetentionUpdate) DeepCopy() SetTeamRetentionUpdate {
return SetTeamRetentionUpdate{
InboxVers: o.InboxVers.DeepCopy(),
TeamID: o.TeamID.DeepCopy(),
Policy: o.Policy.DeepCopy(),
}
}
type SetConvSettingsUpdate struct {
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
ConvID ConversationID `codec:"convID" json:"convID"`
ConvSettings *ConversationSettings `codec:"convSettings,omitempty" json:"convSettings,omitempty"`
}
func (o SetConvSettingsUpdate) DeepCopy() SetConvSettingsUpdate {
return SetConvSettingsUpdate{
InboxVers: o.InboxVers.DeepCopy(),
ConvID: o.ConvID.DeepCopy(),
ConvSettings: (func(x *ConversationSettings) *ConversationSettings {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.ConvSettings),
}
}
type KBFSImpteamUpgradeUpdate struct {
ConvID ConversationID `codec:"convID" json:"convID"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
TopicType TopicType `codec:"topicType" json:"topicType"`
}
func (o KBFSImpteamUpgradeUpdate) DeepCopy() KBFSImpteamUpgradeUpdate {
return KBFSImpteamUpgradeUpdate{
ConvID: o.ConvID.DeepCopy(),
InboxVers: o.InboxVers.DeepCopy(),
TopicType: o.TopicType.DeepCopy(),
}
}
type SubteamRenameUpdate struct {
ConvIDs []ConversationID `codec:"convIDs" json:"convIDs"`
InboxVers InboxVers `codec:"inboxVers" json:"inboxVers"`
}
func (o SubteamRenameUpdate) DeepCopy() SubteamRenameUpdate {
return SubteamRenameUpdate{
ConvIDs: (func(x []ConversationID) []ConversationID {
if x == nil {
return nil
}
ret := make([]ConversationID, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.ConvIDs),
InboxVers: o.InboxVers.DeepCopy(),
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,938 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/chat1/notify.avdl
package chat1
import (
"errors"
"fmt"
keybase1 "github.com/keybase/go-keybase-chat-bot/kbchat/types/keybase1"
)
type ChatActivitySource int
const (
ChatActivitySource_LOCAL ChatActivitySource = 0
ChatActivitySource_REMOTE ChatActivitySource = 1
)
func (o ChatActivitySource) DeepCopy() ChatActivitySource { return o }
var ChatActivitySourceMap = map[string]ChatActivitySource{
"LOCAL": 0,
"REMOTE": 1,
}
var ChatActivitySourceRevMap = map[ChatActivitySource]string{
0: "LOCAL",
1: "REMOTE",
}
func (e ChatActivitySource) String() string {
if v, ok := ChatActivitySourceRevMap[e]; ok {
return v
}
return fmt.Sprintf("%v", int(e))
}
type ChatActivityType int
const (
ChatActivityType_RESERVED ChatActivityType = 0
ChatActivityType_INCOMING_MESSAGE ChatActivityType = 1
ChatActivityType_READ_MESSAGE ChatActivityType = 2
ChatActivityType_NEW_CONVERSATION ChatActivityType = 3
ChatActivityType_SET_STATUS ChatActivityType = 4
ChatActivityType_FAILED_MESSAGE ChatActivityType = 5
ChatActivityType_MEMBERS_UPDATE ChatActivityType = 6
ChatActivityType_SET_APP_NOTIFICATION_SETTINGS ChatActivityType = 7
ChatActivityType_TEAMTYPE ChatActivityType = 8
ChatActivityType_EXPUNGE ChatActivityType = 9
ChatActivityType_EPHEMERAL_PURGE ChatActivityType = 10
ChatActivityType_REACTION_UPDATE ChatActivityType = 11
ChatActivityType_MESSAGES_UPDATED ChatActivityType = 12
)
func (o ChatActivityType) DeepCopy() ChatActivityType { return o }
var ChatActivityTypeMap = map[string]ChatActivityType{
"RESERVED": 0,
"INCOMING_MESSAGE": 1,
"READ_MESSAGE": 2,
"NEW_CONVERSATION": 3,
"SET_STATUS": 4,
"FAILED_MESSAGE": 5,
"MEMBERS_UPDATE": 6,
"SET_APP_NOTIFICATION_SETTINGS": 7,
"TEAMTYPE": 8,
"EXPUNGE": 9,
"EPHEMERAL_PURGE": 10,
"REACTION_UPDATE": 11,
"MESSAGES_UPDATED": 12,
}
var ChatActivityTypeRevMap = map[ChatActivityType]string{
0: "RESERVED",
1: "INCOMING_MESSAGE",
2: "READ_MESSAGE",
3: "NEW_CONVERSATION",
4: "SET_STATUS",
5: "FAILED_MESSAGE",
6: "MEMBERS_UPDATE",
7: "SET_APP_NOTIFICATION_SETTINGS",
8: "TEAMTYPE",
9: "EXPUNGE",
10: "EPHEMERAL_PURGE",
11: "REACTION_UPDATE",
12: "MESSAGES_UPDATED",
}
func (e ChatActivityType) String() string {
if v, ok := ChatActivityTypeRevMap[e]; ok {
return v
}
return fmt.Sprintf("%v", int(e))
}
type IncomingMessage struct {
Message UIMessage `codec:"message" json:"message"`
ModifiedMessage *UIMessage `codec:"modifiedMessage,omitempty" json:"modifiedMessage,omitempty"`
ConvID ConversationID `codec:"convID" json:"convID"`
DisplayDesktopNotification bool `codec:"displayDesktopNotification" json:"displayDesktopNotification"`
DesktopNotificationSnippet string `codec:"desktopNotificationSnippet" json:"desktopNotificationSnippet"`
Conv *InboxUIItem `codec:"conv,omitempty" json:"conv,omitempty"`
Pagination *UIPagination `codec:"pagination,omitempty" json:"pagination,omitempty"`
}
func (o IncomingMessage) DeepCopy() IncomingMessage {
return IncomingMessage{
Message: o.Message.DeepCopy(),
ModifiedMessage: (func(x *UIMessage) *UIMessage {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.ModifiedMessage),
ConvID: o.ConvID.DeepCopy(),
DisplayDesktopNotification: o.DisplayDesktopNotification,
DesktopNotificationSnippet: o.DesktopNotificationSnippet,
Conv: (func(x *InboxUIItem) *InboxUIItem {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Conv),
Pagination: (func(x *UIPagination) *UIPagination {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Pagination),
}
}
type ReadMessageInfo struct {
ConvID ConversationID `codec:"convID" json:"convID"`
MsgID MessageID `codec:"msgID" json:"msgID"`
Conv *InboxUIItem `codec:"conv,omitempty" json:"conv,omitempty"`
}
func (o ReadMessageInfo) DeepCopy() ReadMessageInfo {
return ReadMessageInfo{
ConvID: o.ConvID.DeepCopy(),
MsgID: o.MsgID.DeepCopy(),
Conv: (func(x *InboxUIItem) *InboxUIItem {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Conv),
}
}
type NewConversationInfo struct {
ConvID ConversationID `codec:"convID" json:"convID"`
Conv *InboxUIItem `codec:"conv,omitempty" json:"conv,omitempty"`
}
func (o NewConversationInfo) DeepCopy() NewConversationInfo {
return NewConversationInfo{
ConvID: o.ConvID.DeepCopy(),
Conv: (func(x *InboxUIItem) *InboxUIItem {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Conv),
}
}
type SetStatusInfo struct {
ConvID ConversationID `codec:"convID" json:"convID"`
Status ConversationStatus `codec:"status" json:"status"`
Conv *InboxUIItem `codec:"conv,omitempty" json:"conv,omitempty"`
}
func (o SetStatusInfo) DeepCopy() SetStatusInfo {
return SetStatusInfo{
ConvID: o.ConvID.DeepCopy(),
Status: o.Status.DeepCopy(),
Conv: (func(x *InboxUIItem) *InboxUIItem {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Conv),
}
}
type SetAppNotificationSettingsInfo struct {
ConvID ConversationID `codec:"convID" json:"convID"`
Settings ConversationNotificationInfo `codec:"settings" json:"settings"`
}
func (o SetAppNotificationSettingsInfo) DeepCopy() SetAppNotificationSettingsInfo {
return SetAppNotificationSettingsInfo{
ConvID: o.ConvID.DeepCopy(),
Settings: o.Settings.DeepCopy(),
}
}
type FailedMessageInfo struct {
OutboxRecords []OutboxRecord `codec:"outboxRecords" json:"outboxRecords"`
IsEphemeralPurge bool `codec:"isEphemeralPurge" json:"isEphemeralPurge"`
Conv *InboxUIItem `codec:"conv,omitempty" json:"conv,omitempty"`
}
func (o FailedMessageInfo) DeepCopy() FailedMessageInfo {
return FailedMessageInfo{
OutboxRecords: (func(x []OutboxRecord) []OutboxRecord {
if x == nil {
return nil
}
ret := make([]OutboxRecord, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.OutboxRecords),
IsEphemeralPurge: o.IsEphemeralPurge,
Conv: (func(x *InboxUIItem) *InboxUIItem {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Conv),
}
}
type MemberInfo struct {
Member string `codec:"member" json:"member"`
Status ConversationMemberStatus `codec:"status" json:"status"`
}
func (o MemberInfo) DeepCopy() MemberInfo {
return MemberInfo{
Member: o.Member,
Status: o.Status.DeepCopy(),
}
}
type MembersUpdateInfo struct {
ConvID ConversationID `codec:"convID" json:"convID"`
Members []MemberInfo `codec:"members" json:"members"`
}
func (o MembersUpdateInfo) DeepCopy() MembersUpdateInfo {
return MembersUpdateInfo{
ConvID: o.ConvID.DeepCopy(),
Members: (func(x []MemberInfo) []MemberInfo {
if x == nil {
return nil
}
ret := make([]MemberInfo, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Members),
}
}
type TeamTypeInfo struct {
ConvID ConversationID `codec:"convID" json:"convID"`
TeamType TeamType `codec:"teamType" json:"teamType"`
Conv *InboxUIItem `codec:"conv,omitempty" json:"conv,omitempty"`
}
func (o TeamTypeInfo) DeepCopy() TeamTypeInfo {
return TeamTypeInfo{
ConvID: o.ConvID.DeepCopy(),
TeamType: o.TeamType.DeepCopy(),
Conv: (func(x *InboxUIItem) *InboxUIItem {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Conv),
}
}
type ExpungeInfo struct {
ConvID ConversationID `codec:"convID" json:"convID"`
Expunge Expunge `codec:"expunge" json:"expunge"`
}
func (o ExpungeInfo) DeepCopy() ExpungeInfo {
return ExpungeInfo{
ConvID: o.ConvID.DeepCopy(),
Expunge: o.Expunge.DeepCopy(),
}
}
type EphemeralPurgeNotifInfo struct {
ConvID ConversationID `codec:"convID" json:"convID"`
Msgs []UIMessage `codec:"msgs" json:"msgs"`
}
func (o EphemeralPurgeNotifInfo) DeepCopy() EphemeralPurgeNotifInfo {
return EphemeralPurgeNotifInfo{
ConvID: o.ConvID.DeepCopy(),
Msgs: (func(x []UIMessage) []UIMessage {
if x == nil {
return nil
}
ret := make([]UIMessage, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Msgs),
}
}
type ReactionUpdate struct {
Reactions ReactionMap `codec:"reactions" json:"reactions"`
TargetMsgID MessageID `codec:"targetMsgID" json:"targetMsgID"`
}
func (o ReactionUpdate) DeepCopy() ReactionUpdate {
return ReactionUpdate{
Reactions: o.Reactions.DeepCopy(),
TargetMsgID: o.TargetMsgID.DeepCopy(),
}
}
type ReactionUpdateNotif struct {
ConvID ConversationID `codec:"convID" json:"convID"`
UserReacjis keybase1.UserReacjis `codec:"userReacjis" json:"userReacjis"`
ReactionUpdates []ReactionUpdate `codec:"reactionUpdates" json:"reactionUpdates"`
}
func (o ReactionUpdateNotif) DeepCopy() ReactionUpdateNotif {
return ReactionUpdateNotif{
ConvID: o.ConvID.DeepCopy(),
UserReacjis: o.UserReacjis.DeepCopy(),
ReactionUpdates: (func(x []ReactionUpdate) []ReactionUpdate {
if x == nil {
return nil
}
ret := make([]ReactionUpdate, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.ReactionUpdates),
}
}
type MessagesUpdated struct {
ConvID ConversationID `codec:"convID" json:"convID"`
Updates []UIMessage `codec:"updates" json:"updates"`
}
func (o MessagesUpdated) DeepCopy() MessagesUpdated {
return MessagesUpdated{
ConvID: o.ConvID.DeepCopy(),
Updates: (func(x []UIMessage) []UIMessage {
if x == nil {
return nil
}
ret := make([]UIMessage, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Updates),
}
}
type ChatActivity struct {
ActivityType__ ChatActivityType `codec:"activityType" json:"activityType"`
IncomingMessage__ *IncomingMessage `codec:"incomingMessage,omitempty" json:"incomingMessage,omitempty"`
ReadMessage__ *ReadMessageInfo `codec:"readMessage,omitempty" json:"readMessage,omitempty"`
NewConversation__ *NewConversationInfo `codec:"newConversation,omitempty" json:"newConversation,omitempty"`
SetStatus__ *SetStatusInfo `codec:"setStatus,omitempty" json:"setStatus,omitempty"`
FailedMessage__ *FailedMessageInfo `codec:"failedMessage,omitempty" json:"failedMessage,omitempty"`
MembersUpdate__ *MembersUpdateInfo `codec:"membersUpdate,omitempty" json:"membersUpdate,omitempty"`
SetAppNotificationSettings__ *SetAppNotificationSettingsInfo `codec:"setAppNotificationSettings,omitempty" json:"setAppNotificationSettings,omitempty"`
Teamtype__ *TeamTypeInfo `codec:"teamtype,omitempty" json:"teamtype,omitempty"`
Expunge__ *ExpungeInfo `codec:"expunge,omitempty" json:"expunge,omitempty"`
EphemeralPurge__ *EphemeralPurgeNotifInfo `codec:"ephemeralPurge,omitempty" json:"ephemeralPurge,omitempty"`
ReactionUpdate__ *ReactionUpdateNotif `codec:"reactionUpdate,omitempty" json:"reactionUpdate,omitempty"`
MessagesUpdated__ *MessagesUpdated `codec:"messagesUpdated,omitempty" json:"messagesUpdated,omitempty"`
}
func (o *ChatActivity) ActivityType() (ret ChatActivityType, err error) {
switch o.ActivityType__ {
case ChatActivityType_INCOMING_MESSAGE:
if o.IncomingMessage__ == nil {
err = errors.New("unexpected nil value for IncomingMessage__")
return ret, err
}
case ChatActivityType_READ_MESSAGE:
if o.ReadMessage__ == nil {
err = errors.New("unexpected nil value for ReadMessage__")
return ret, err
}
case ChatActivityType_NEW_CONVERSATION:
if o.NewConversation__ == nil {
err = errors.New("unexpected nil value for NewConversation__")
return ret, err
}
case ChatActivityType_SET_STATUS:
if o.SetStatus__ == nil {
err = errors.New("unexpected nil value for SetStatus__")
return ret, err
}
case ChatActivityType_FAILED_MESSAGE:
if o.FailedMessage__ == nil {
err = errors.New("unexpected nil value for FailedMessage__")
return ret, err
}
case ChatActivityType_MEMBERS_UPDATE:
if o.MembersUpdate__ == nil {
err = errors.New("unexpected nil value for MembersUpdate__")
return ret, err
}
case ChatActivityType_SET_APP_NOTIFICATION_SETTINGS:
if o.SetAppNotificationSettings__ == nil {
err = errors.New("unexpected nil value for SetAppNotificationSettings__")
return ret, err
}
case ChatActivityType_TEAMTYPE:
if o.Teamtype__ == nil {
err = errors.New("unexpected nil value for Teamtype__")
return ret, err
}
case ChatActivityType_EXPUNGE:
if o.Expunge__ == nil {
err = errors.New("unexpected nil value for Expunge__")
return ret, err
}
case ChatActivityType_EPHEMERAL_PURGE:
if o.EphemeralPurge__ == nil {
err = errors.New("unexpected nil value for EphemeralPurge__")
return ret, err
}
case ChatActivityType_REACTION_UPDATE:
if o.ReactionUpdate__ == nil {
err = errors.New("unexpected nil value for ReactionUpdate__")
return ret, err
}
case ChatActivityType_MESSAGES_UPDATED:
if o.MessagesUpdated__ == nil {
err = errors.New("unexpected nil value for MessagesUpdated__")
return ret, err
}
}
return o.ActivityType__, nil
}
func (o ChatActivity) IncomingMessage() (res IncomingMessage) {
if o.ActivityType__ != ChatActivityType_INCOMING_MESSAGE {
panic("wrong case accessed")
}
if o.IncomingMessage__ == nil {
return
}
return *o.IncomingMessage__
}
func (o ChatActivity) ReadMessage() (res ReadMessageInfo) {
if o.ActivityType__ != ChatActivityType_READ_MESSAGE {
panic("wrong case accessed")
}
if o.ReadMessage__ == nil {
return
}
return *o.ReadMessage__
}
func (o ChatActivity) NewConversation() (res NewConversationInfo) {
if o.ActivityType__ != ChatActivityType_NEW_CONVERSATION {
panic("wrong case accessed")
}
if o.NewConversation__ == nil {
return
}
return *o.NewConversation__
}
func (o ChatActivity) SetStatus() (res SetStatusInfo) {
if o.ActivityType__ != ChatActivityType_SET_STATUS {
panic("wrong case accessed")
}
if o.SetStatus__ == nil {
return
}
return *o.SetStatus__
}
func (o ChatActivity) FailedMessage() (res FailedMessageInfo) {
if o.ActivityType__ != ChatActivityType_FAILED_MESSAGE {
panic("wrong case accessed")
}
if o.FailedMessage__ == nil {
return
}
return *o.FailedMessage__
}
func (o ChatActivity) MembersUpdate() (res MembersUpdateInfo) {
if o.ActivityType__ != ChatActivityType_MEMBERS_UPDATE {
panic("wrong case accessed")
}
if o.MembersUpdate__ == nil {
return
}
return *o.MembersUpdate__
}
func (o ChatActivity) SetAppNotificationSettings() (res SetAppNotificationSettingsInfo) {
if o.ActivityType__ != ChatActivityType_SET_APP_NOTIFICATION_SETTINGS {
panic("wrong case accessed")
}
if o.SetAppNotificationSettings__ == nil {
return
}
return *o.SetAppNotificationSettings__
}
func (o ChatActivity) Teamtype() (res TeamTypeInfo) {
if o.ActivityType__ != ChatActivityType_TEAMTYPE {
panic("wrong case accessed")
}
if o.Teamtype__ == nil {
return
}
return *o.Teamtype__
}
func (o ChatActivity) Expunge() (res ExpungeInfo) {
if o.ActivityType__ != ChatActivityType_EXPUNGE {
panic("wrong case accessed")
}
if o.Expunge__ == nil {
return
}
return *o.Expunge__
}
func (o ChatActivity) EphemeralPurge() (res EphemeralPurgeNotifInfo) {
if o.ActivityType__ != ChatActivityType_EPHEMERAL_PURGE {
panic("wrong case accessed")
}
if o.EphemeralPurge__ == nil {
return
}
return *o.EphemeralPurge__
}
func (o ChatActivity) ReactionUpdate() (res ReactionUpdateNotif) {
if o.ActivityType__ != ChatActivityType_REACTION_UPDATE {
panic("wrong case accessed")
}
if o.ReactionUpdate__ == nil {
return
}
return *o.ReactionUpdate__
}
func (o ChatActivity) MessagesUpdated() (res MessagesUpdated) {
if o.ActivityType__ != ChatActivityType_MESSAGES_UPDATED {
panic("wrong case accessed")
}
if o.MessagesUpdated__ == nil {
return
}
return *o.MessagesUpdated__
}
func NewChatActivityWithIncomingMessage(v IncomingMessage) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_INCOMING_MESSAGE,
IncomingMessage__: &v,
}
}
func NewChatActivityWithReadMessage(v ReadMessageInfo) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_READ_MESSAGE,
ReadMessage__: &v,
}
}
func NewChatActivityWithNewConversation(v NewConversationInfo) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_NEW_CONVERSATION,
NewConversation__: &v,
}
}
func NewChatActivityWithSetStatus(v SetStatusInfo) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_SET_STATUS,
SetStatus__: &v,
}
}
func NewChatActivityWithFailedMessage(v FailedMessageInfo) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_FAILED_MESSAGE,
FailedMessage__: &v,
}
}
func NewChatActivityWithMembersUpdate(v MembersUpdateInfo) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_MEMBERS_UPDATE,
MembersUpdate__: &v,
}
}
func NewChatActivityWithSetAppNotificationSettings(v SetAppNotificationSettingsInfo) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_SET_APP_NOTIFICATION_SETTINGS,
SetAppNotificationSettings__: &v,
}
}
func NewChatActivityWithTeamtype(v TeamTypeInfo) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_TEAMTYPE,
Teamtype__: &v,
}
}
func NewChatActivityWithExpunge(v ExpungeInfo) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_EXPUNGE,
Expunge__: &v,
}
}
func NewChatActivityWithEphemeralPurge(v EphemeralPurgeNotifInfo) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_EPHEMERAL_PURGE,
EphemeralPurge__: &v,
}
}
func NewChatActivityWithReactionUpdate(v ReactionUpdateNotif) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_REACTION_UPDATE,
ReactionUpdate__: &v,
}
}
func NewChatActivityWithMessagesUpdated(v MessagesUpdated) ChatActivity {
return ChatActivity{
ActivityType__: ChatActivityType_MESSAGES_UPDATED,
MessagesUpdated__: &v,
}
}
func (o ChatActivity) DeepCopy() ChatActivity {
return ChatActivity{
ActivityType__: o.ActivityType__.DeepCopy(),
IncomingMessage__: (func(x *IncomingMessage) *IncomingMessage {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.IncomingMessage__),
ReadMessage__: (func(x *ReadMessageInfo) *ReadMessageInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.ReadMessage__),
NewConversation__: (func(x *NewConversationInfo) *NewConversationInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.NewConversation__),
SetStatus__: (func(x *SetStatusInfo) *SetStatusInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.SetStatus__),
FailedMessage__: (func(x *FailedMessageInfo) *FailedMessageInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.FailedMessage__),
MembersUpdate__: (func(x *MembersUpdateInfo) *MembersUpdateInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.MembersUpdate__),
SetAppNotificationSettings__: (func(x *SetAppNotificationSettingsInfo) *SetAppNotificationSettingsInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.SetAppNotificationSettings__),
Teamtype__: (func(x *TeamTypeInfo) *TeamTypeInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Teamtype__),
Expunge__: (func(x *ExpungeInfo) *ExpungeInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Expunge__),
EphemeralPurge__: (func(x *EphemeralPurgeNotifInfo) *EphemeralPurgeNotifInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.EphemeralPurge__),
ReactionUpdate__: (func(x *ReactionUpdateNotif) *ReactionUpdateNotif {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.ReactionUpdate__),
MessagesUpdated__: (func(x *MessagesUpdated) *MessagesUpdated {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.MessagesUpdated__),
}
}
type TyperInfo struct {
Uid keybase1.UID `codec:"uid" json:"uid"`
Username string `codec:"username" json:"username"`
DeviceID keybase1.DeviceID `codec:"deviceID" json:"deviceID"`
DeviceName string `codec:"deviceName" json:"deviceName"`
DeviceType string `codec:"deviceType" json:"deviceType"`
}
func (o TyperInfo) DeepCopy() TyperInfo {
return TyperInfo{
Uid: o.Uid.DeepCopy(),
Username: o.Username,
DeviceID: o.DeviceID.DeepCopy(),
DeviceName: o.DeviceName,
DeviceType: o.DeviceType,
}
}
type ConvTypingUpdate struct {
ConvID ConversationID `codec:"convID" json:"convID"`
Typers []TyperInfo `codec:"typers" json:"typers"`
}
func (o ConvTypingUpdate) DeepCopy() ConvTypingUpdate {
return ConvTypingUpdate{
ConvID: o.ConvID.DeepCopy(),
Typers: (func(x []TyperInfo) []TyperInfo {
if x == nil {
return nil
}
ret := make([]TyperInfo, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Typers),
}
}
type StaleUpdateType int
const (
StaleUpdateType_CLEAR StaleUpdateType = 0
StaleUpdateType_NEWACTIVITY StaleUpdateType = 1
)
func (o StaleUpdateType) DeepCopy() StaleUpdateType { return o }
var StaleUpdateTypeMap = map[string]StaleUpdateType{
"CLEAR": 0,
"NEWACTIVITY": 1,
}
var StaleUpdateTypeRevMap = map[StaleUpdateType]string{
0: "CLEAR",
1: "NEWACTIVITY",
}
func (e StaleUpdateType) String() string {
if v, ok := StaleUpdateTypeRevMap[e]; ok {
return v
}
return fmt.Sprintf("%v", int(e))
}
type ConversationStaleUpdate struct {
ConvID ConversationID `codec:"convID" json:"convID"`
UpdateType StaleUpdateType `codec:"updateType" json:"updateType"`
}
func (o ConversationStaleUpdate) DeepCopy() ConversationStaleUpdate {
return ConversationStaleUpdate{
ConvID: o.ConvID.DeepCopy(),
UpdateType: o.UpdateType.DeepCopy(),
}
}
type ChatSyncIncrementalConv struct {
Conv UnverifiedInboxUIItem `codec:"conv" json:"conv"`
ShouldUnbox bool `codec:"shouldUnbox" json:"shouldUnbox"`
}
func (o ChatSyncIncrementalConv) DeepCopy() ChatSyncIncrementalConv {
return ChatSyncIncrementalConv{
Conv: o.Conv.DeepCopy(),
ShouldUnbox: o.ShouldUnbox,
}
}
type ChatSyncIncrementalInfo struct {
Items []ChatSyncIncrementalConv `codec:"items" json:"items"`
Removals []string `codec:"removals" json:"removals"`
}
func (o ChatSyncIncrementalInfo) DeepCopy() ChatSyncIncrementalInfo {
return ChatSyncIncrementalInfo{
Items: (func(x []ChatSyncIncrementalConv) []ChatSyncIncrementalConv {
if x == nil {
return nil
}
ret := make([]ChatSyncIncrementalConv, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Items),
Removals: (func(x []string) []string {
if x == nil {
return nil
}
ret := make([]string, len(x))
for i, v := range x {
vCopy := v
ret[i] = vCopy
}
return ret
})(o.Removals),
}
}
type ChatSyncResult struct {
SyncType__ SyncInboxResType `codec:"syncType" json:"syncType"`
Incremental__ *ChatSyncIncrementalInfo `codec:"incremental,omitempty" json:"incremental,omitempty"`
}
func (o *ChatSyncResult) SyncType() (ret SyncInboxResType, err error) {
switch o.SyncType__ {
case SyncInboxResType_INCREMENTAL:
if o.Incremental__ == nil {
err = errors.New("unexpected nil value for Incremental__")
return ret, err
}
}
return o.SyncType__, nil
}
func (o ChatSyncResult) Incremental() (res ChatSyncIncrementalInfo) {
if o.SyncType__ != SyncInboxResType_INCREMENTAL {
panic("wrong case accessed")
}
if o.Incremental__ == nil {
return
}
return *o.Incremental__
}
func NewChatSyncResultWithCurrent() ChatSyncResult {
return ChatSyncResult{
SyncType__: SyncInboxResType_CURRENT,
}
}
func NewChatSyncResultWithClear() ChatSyncResult {
return ChatSyncResult{
SyncType__: SyncInboxResType_CLEAR,
}
}
func NewChatSyncResultWithIncremental(v ChatSyncIncrementalInfo) ChatSyncResult {
return ChatSyncResult{
SyncType__: SyncInboxResType_INCREMENTAL,
Incremental__: &v,
}
}
func (o ChatSyncResult) DeepCopy() ChatSyncResult {
return ChatSyncResult{
SyncType__: o.SyncType__.DeepCopy(),
Incremental__: (func(x *ChatSyncIncrementalInfo) *ChatSyncIncrementalInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Incremental__),
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,850 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/chat1/unfurl.avdl
package chat1
import (
"errors"
"fmt"
gregor1 "github.com/keybase/go-keybase-chat-bot/kbchat/types/gregor1"
)
type UnfurlType int
const (
UnfurlType_GENERIC UnfurlType = 0
UnfurlType_YOUTUBE UnfurlType = 1
UnfurlType_GIPHY UnfurlType = 2
UnfurlType_MAPS UnfurlType = 3
)
func (o UnfurlType) DeepCopy() UnfurlType { return o }
var UnfurlTypeMap = map[string]UnfurlType{
"GENERIC": 0,
"YOUTUBE": 1,
"GIPHY": 2,
"MAPS": 3,
}
var UnfurlTypeRevMap = map[UnfurlType]string{
0: "GENERIC",
1: "YOUTUBE",
2: "GIPHY",
3: "MAPS",
}
func (e UnfurlType) String() string {
if v, ok := UnfurlTypeRevMap[e]; ok {
return v
}
return fmt.Sprintf("%v", int(e))
}
type UnfurlVideo struct {
Url string `codec:"url" json:"url"`
MimeType string `codec:"mimeType" json:"mimeType"`
Height int `codec:"height" json:"height"`
Width int `codec:"width" json:"width"`
}
func (o UnfurlVideo) DeepCopy() UnfurlVideo {
return UnfurlVideo{
Url: o.Url,
MimeType: o.MimeType,
Height: o.Height,
Width: o.Width,
}
}
type UnfurlGenericRaw struct {
Title string `codec:"title" json:"title"`
Url string `codec:"url" json:"url"`
SiteName string `codec:"siteName" json:"siteName"`
FaviconUrl *string `codec:"faviconUrl,omitempty" json:"faviconUrl,omitempty"`
ImageUrl *string `codec:"imageUrl,omitempty" json:"imageUrl,omitempty"`
Video *UnfurlVideo `codec:"video,omitempty" json:"video,omitempty"`
PublishTime *int `codec:"publishTime,omitempty" json:"publishTime,omitempty"`
Description *string `codec:"description,omitempty" json:"description,omitempty"`
}
func (o UnfurlGenericRaw) DeepCopy() UnfurlGenericRaw {
return UnfurlGenericRaw{
Title: o.Title,
Url: o.Url,
SiteName: o.SiteName,
FaviconUrl: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.FaviconUrl),
ImageUrl: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.ImageUrl),
Video: (func(x *UnfurlVideo) *UnfurlVideo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Video),
PublishTime: (func(x *int) *int {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.PublishTime),
Description: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.Description),
}
}
type UnfurlYoutubeRaw struct {
}
func (o UnfurlYoutubeRaw) DeepCopy() UnfurlYoutubeRaw {
return UnfurlYoutubeRaw{}
}
type UnfurlGiphyRaw struct {
ImageUrl *string `codec:"imageUrl,omitempty" json:"imageUrl,omitempty"`
Video *UnfurlVideo `codec:"video,omitempty" json:"video,omitempty"`
FaviconUrl *string `codec:"faviconUrl,omitempty" json:"faviconUrl,omitempty"`
}
func (o UnfurlGiphyRaw) DeepCopy() UnfurlGiphyRaw {
return UnfurlGiphyRaw{
ImageUrl: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.ImageUrl),
Video: (func(x *UnfurlVideo) *UnfurlVideo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Video),
FaviconUrl: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.FaviconUrl),
}
}
type UnfurlMapsRaw struct {
Title string `codec:"title" json:"title"`
Url string `codec:"url" json:"url"`
SiteName string `codec:"siteName" json:"siteName"`
ImageUrl string `codec:"imageUrl" json:"imageUrl"`
HistoryImageUrl *string `codec:"historyImageUrl,omitempty" json:"historyImageUrl,omitempty"`
Description string `codec:"description" json:"description"`
Coord Coordinate `codec:"coord" json:"coord"`
Time gregor1.Time `codec:"time" json:"time"`
LiveLocationEndTime *gregor1.Time `codec:"liveLocationEndTime,omitempty" json:"liveLocationEndTime,omitempty"`
LiveLocationDone bool `codec:"liveLocationDone" json:"liveLocationDone"`
}
func (o UnfurlMapsRaw) DeepCopy() UnfurlMapsRaw {
return UnfurlMapsRaw{
Title: o.Title,
Url: o.Url,
SiteName: o.SiteName,
ImageUrl: o.ImageUrl,
HistoryImageUrl: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.HistoryImageUrl),
Description: o.Description,
Coord: o.Coord.DeepCopy(),
Time: o.Time.DeepCopy(),
LiveLocationEndTime: (func(x *gregor1.Time) *gregor1.Time {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.LiveLocationEndTime),
LiveLocationDone: o.LiveLocationDone,
}
}
type UnfurlRaw struct {
UnfurlType__ UnfurlType `codec:"unfurlType" json:"unfurlType"`
Generic__ *UnfurlGenericRaw `codec:"generic,omitempty" json:"generic,omitempty"`
Youtube__ *UnfurlYoutubeRaw `codec:"youtube,omitempty" json:"youtube,omitempty"`
Giphy__ *UnfurlGiphyRaw `codec:"giphy,omitempty" json:"giphy,omitempty"`
Maps__ *UnfurlMapsRaw `codec:"maps,omitempty" json:"maps,omitempty"`
}
func (o *UnfurlRaw) UnfurlType() (ret UnfurlType, err error) {
switch o.UnfurlType__ {
case UnfurlType_GENERIC:
if o.Generic__ == nil {
err = errors.New("unexpected nil value for Generic__")
return ret, err
}
case UnfurlType_YOUTUBE:
if o.Youtube__ == nil {
err = errors.New("unexpected nil value for Youtube__")
return ret, err
}
case UnfurlType_GIPHY:
if o.Giphy__ == nil {
err = errors.New("unexpected nil value for Giphy__")
return ret, err
}
case UnfurlType_MAPS:
if o.Maps__ == nil {
err = errors.New("unexpected nil value for Maps__")
return ret, err
}
}
return o.UnfurlType__, nil
}
func (o UnfurlRaw) Generic() (res UnfurlGenericRaw) {
if o.UnfurlType__ != UnfurlType_GENERIC {
panic("wrong case accessed")
}
if o.Generic__ == nil {
return
}
return *o.Generic__
}
func (o UnfurlRaw) Youtube() (res UnfurlYoutubeRaw) {
if o.UnfurlType__ != UnfurlType_YOUTUBE {
panic("wrong case accessed")
}
if o.Youtube__ == nil {
return
}
return *o.Youtube__
}
func (o UnfurlRaw) Giphy() (res UnfurlGiphyRaw) {
if o.UnfurlType__ != UnfurlType_GIPHY {
panic("wrong case accessed")
}
if o.Giphy__ == nil {
return
}
return *o.Giphy__
}
func (o UnfurlRaw) Maps() (res UnfurlMapsRaw) {
if o.UnfurlType__ != UnfurlType_MAPS {
panic("wrong case accessed")
}
if o.Maps__ == nil {
return
}
return *o.Maps__
}
func NewUnfurlRawWithGeneric(v UnfurlGenericRaw) UnfurlRaw {
return UnfurlRaw{
UnfurlType__: UnfurlType_GENERIC,
Generic__: &v,
}
}
func NewUnfurlRawWithYoutube(v UnfurlYoutubeRaw) UnfurlRaw {
return UnfurlRaw{
UnfurlType__: UnfurlType_YOUTUBE,
Youtube__: &v,
}
}
func NewUnfurlRawWithGiphy(v UnfurlGiphyRaw) UnfurlRaw {
return UnfurlRaw{
UnfurlType__: UnfurlType_GIPHY,
Giphy__: &v,
}
}
func NewUnfurlRawWithMaps(v UnfurlMapsRaw) UnfurlRaw {
return UnfurlRaw{
UnfurlType__: UnfurlType_MAPS,
Maps__: &v,
}
}
func (o UnfurlRaw) DeepCopy() UnfurlRaw {
return UnfurlRaw{
UnfurlType__: o.UnfurlType__.DeepCopy(),
Generic__: (func(x *UnfurlGenericRaw) *UnfurlGenericRaw {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Generic__),
Youtube__: (func(x *UnfurlYoutubeRaw) *UnfurlYoutubeRaw {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Youtube__),
Giphy__: (func(x *UnfurlGiphyRaw) *UnfurlGiphyRaw {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Giphy__),
Maps__: (func(x *UnfurlMapsRaw) *UnfurlMapsRaw {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Maps__),
}
}
type UnfurlGenericMapInfo struct {
Coord Coordinate `codec:"coord" json:"coord"`
Time gregor1.Time `codec:"time" json:"time"`
LiveLocationEndTime *gregor1.Time `codec:"liveLocationEndTime,omitempty" json:"liveLocationEndTime,omitempty"`
IsLiveLocationDone bool `codec:"isLiveLocationDone" json:"isLiveLocationDone"`
}
func (o UnfurlGenericMapInfo) DeepCopy() UnfurlGenericMapInfo {
return UnfurlGenericMapInfo{
Coord: o.Coord.DeepCopy(),
Time: o.Time.DeepCopy(),
LiveLocationEndTime: (func(x *gregor1.Time) *gregor1.Time {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.LiveLocationEndTime),
IsLiveLocationDone: o.IsLiveLocationDone,
}
}
type UnfurlGeneric struct {
Title string `codec:"title" json:"title"`
Url string `codec:"url" json:"url"`
SiteName string `codec:"siteName" json:"siteName"`
Favicon *Asset `codec:"favicon,omitempty" json:"favicon,omitempty"`
Image *Asset `codec:"image,omitempty" json:"image,omitempty"`
PublishTime *int `codec:"publishTime,omitempty" json:"publishTime,omitempty"`
Description *string `codec:"description,omitempty" json:"description,omitempty"`
MapInfo *UnfurlGenericMapInfo `codec:"mapInfo,omitempty" json:"mapInfo,omitempty"`
}
func (o UnfurlGeneric) DeepCopy() UnfurlGeneric {
return UnfurlGeneric{
Title: o.Title,
Url: o.Url,
SiteName: o.SiteName,
Favicon: (func(x *Asset) *Asset {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Favicon),
Image: (func(x *Asset) *Asset {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Image),
PublishTime: (func(x *int) *int {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.PublishTime),
Description: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.Description),
MapInfo: (func(x *UnfurlGenericMapInfo) *UnfurlGenericMapInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.MapInfo),
}
}
type UnfurlYoutube struct {
}
func (o UnfurlYoutube) DeepCopy() UnfurlYoutube {
return UnfurlYoutube{}
}
type UnfurlGiphy struct {
Favicon *Asset `codec:"favicon,omitempty" json:"favicon,omitempty"`
Image *Asset `codec:"image,omitempty" json:"image,omitempty"`
Video *Asset `codec:"video,omitempty" json:"video,omitempty"`
}
func (o UnfurlGiphy) DeepCopy() UnfurlGiphy {
return UnfurlGiphy{
Favicon: (func(x *Asset) *Asset {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Favicon),
Image: (func(x *Asset) *Asset {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Image),
Video: (func(x *Asset) *Asset {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Video),
}
}
type Unfurl struct {
UnfurlType__ UnfurlType `codec:"unfurlType" json:"unfurlType"`
Generic__ *UnfurlGeneric `codec:"generic,omitempty" json:"generic,omitempty"`
Youtube__ *UnfurlYoutube `codec:"youtube,omitempty" json:"youtube,omitempty"`
Giphy__ *UnfurlGiphy `codec:"giphy,omitempty" json:"giphy,omitempty"`
}
func (o *Unfurl) UnfurlType() (ret UnfurlType, err error) {
switch o.UnfurlType__ {
case UnfurlType_GENERIC:
if o.Generic__ == nil {
err = errors.New("unexpected nil value for Generic__")
return ret, err
}
case UnfurlType_YOUTUBE:
if o.Youtube__ == nil {
err = errors.New("unexpected nil value for Youtube__")
return ret, err
}
case UnfurlType_GIPHY:
if o.Giphy__ == nil {
err = errors.New("unexpected nil value for Giphy__")
return ret, err
}
}
return o.UnfurlType__, nil
}
func (o Unfurl) Generic() (res UnfurlGeneric) {
if o.UnfurlType__ != UnfurlType_GENERIC {
panic("wrong case accessed")
}
if o.Generic__ == nil {
return
}
return *o.Generic__
}
func (o Unfurl) Youtube() (res UnfurlYoutube) {
if o.UnfurlType__ != UnfurlType_YOUTUBE {
panic("wrong case accessed")
}
if o.Youtube__ == nil {
return
}
return *o.Youtube__
}
func (o Unfurl) Giphy() (res UnfurlGiphy) {
if o.UnfurlType__ != UnfurlType_GIPHY {
panic("wrong case accessed")
}
if o.Giphy__ == nil {
return
}
return *o.Giphy__
}
func NewUnfurlWithGeneric(v UnfurlGeneric) Unfurl {
return Unfurl{
UnfurlType__: UnfurlType_GENERIC,
Generic__: &v,
}
}
func NewUnfurlWithYoutube(v UnfurlYoutube) Unfurl {
return Unfurl{
UnfurlType__: UnfurlType_YOUTUBE,
Youtube__: &v,
}
}
func NewUnfurlWithGiphy(v UnfurlGiphy) Unfurl {
return Unfurl{
UnfurlType__: UnfurlType_GIPHY,
Giphy__: &v,
}
}
func (o Unfurl) DeepCopy() Unfurl {
return Unfurl{
UnfurlType__: o.UnfurlType__.DeepCopy(),
Generic__: (func(x *UnfurlGeneric) *UnfurlGeneric {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Generic__),
Youtube__: (func(x *UnfurlYoutube) *UnfurlYoutube {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Youtube__),
Giphy__: (func(x *UnfurlGiphy) *UnfurlGiphy {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Giphy__),
}
}
type UnfurlResult struct {
Unfurl Unfurl `codec:"unfurl" json:"unfurl"`
Url string `codec:"url" json:"url"`
}
func (o UnfurlResult) DeepCopy() UnfurlResult {
return UnfurlResult{
Unfurl: o.Unfurl.DeepCopy(),
Url: o.Url,
}
}
type UnfurlImageDisplay struct {
Url string `codec:"url" json:"url"`
Height int `codec:"height" json:"height"`
Width int `codec:"width" json:"width"`
IsVideo bool `codec:"isVideo" json:"isVideo"`
}
func (o UnfurlImageDisplay) DeepCopy() UnfurlImageDisplay {
return UnfurlImageDisplay{
Url: o.Url,
Height: o.Height,
Width: o.Width,
IsVideo: o.IsVideo,
}
}
type UnfurlGenericDisplay struct {
Title string `codec:"title" json:"title"`
Url string `codec:"url" json:"url"`
SiteName string `codec:"siteName" json:"siteName"`
Favicon *UnfurlImageDisplay `codec:"favicon,omitempty" json:"favicon,omitempty"`
Media *UnfurlImageDisplay `codec:"media,omitempty" json:"media,omitempty"`
PublishTime *int `codec:"publishTime,omitempty" json:"publishTime,omitempty"`
Description *string `codec:"description,omitempty" json:"description,omitempty"`
MapInfo *UnfurlGenericMapInfo `codec:"mapInfo,omitempty" json:"mapInfo,omitempty"`
}
func (o UnfurlGenericDisplay) DeepCopy() UnfurlGenericDisplay {
return UnfurlGenericDisplay{
Title: o.Title,
Url: o.Url,
SiteName: o.SiteName,
Favicon: (func(x *UnfurlImageDisplay) *UnfurlImageDisplay {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Favicon),
Media: (func(x *UnfurlImageDisplay) *UnfurlImageDisplay {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Media),
PublishTime: (func(x *int) *int {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.PublishTime),
Description: (func(x *string) *string {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.Description),
MapInfo: (func(x *UnfurlGenericMapInfo) *UnfurlGenericMapInfo {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.MapInfo),
}
}
type UnfurlYoutubeDisplay struct {
}
func (o UnfurlYoutubeDisplay) DeepCopy() UnfurlYoutubeDisplay {
return UnfurlYoutubeDisplay{}
}
type UnfurlGiphyDisplay struct {
Favicon *UnfurlImageDisplay `codec:"favicon,omitempty" json:"favicon,omitempty"`
Image *UnfurlImageDisplay `codec:"image,omitempty" json:"image,omitempty"`
Video *UnfurlImageDisplay `codec:"video,omitempty" json:"video,omitempty"`
}
func (o UnfurlGiphyDisplay) DeepCopy() UnfurlGiphyDisplay {
return UnfurlGiphyDisplay{
Favicon: (func(x *UnfurlImageDisplay) *UnfurlImageDisplay {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Favicon),
Image: (func(x *UnfurlImageDisplay) *UnfurlImageDisplay {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Image),
Video: (func(x *UnfurlImageDisplay) *UnfurlImageDisplay {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Video),
}
}
type UnfurlDisplay struct {
UnfurlType__ UnfurlType `codec:"unfurlType" json:"unfurlType"`
Generic__ *UnfurlGenericDisplay `codec:"generic,omitempty" json:"generic,omitempty"`
Youtube__ *UnfurlYoutubeDisplay `codec:"youtube,omitempty" json:"youtube,omitempty"`
Giphy__ *UnfurlGiphyDisplay `codec:"giphy,omitempty" json:"giphy,omitempty"`
}
func (o *UnfurlDisplay) UnfurlType() (ret UnfurlType, err error) {
switch o.UnfurlType__ {
case UnfurlType_GENERIC:
if o.Generic__ == nil {
err = errors.New("unexpected nil value for Generic__")
return ret, err
}
case UnfurlType_YOUTUBE:
if o.Youtube__ == nil {
err = errors.New("unexpected nil value for Youtube__")
return ret, err
}
case UnfurlType_GIPHY:
if o.Giphy__ == nil {
err = errors.New("unexpected nil value for Giphy__")
return ret, err
}
}
return o.UnfurlType__, nil
}
func (o UnfurlDisplay) Generic() (res UnfurlGenericDisplay) {
if o.UnfurlType__ != UnfurlType_GENERIC {
panic("wrong case accessed")
}
if o.Generic__ == nil {
return
}
return *o.Generic__
}
func (o UnfurlDisplay) Youtube() (res UnfurlYoutubeDisplay) {
if o.UnfurlType__ != UnfurlType_YOUTUBE {
panic("wrong case accessed")
}
if o.Youtube__ == nil {
return
}
return *o.Youtube__
}
func (o UnfurlDisplay) Giphy() (res UnfurlGiphyDisplay) {
if o.UnfurlType__ != UnfurlType_GIPHY {
panic("wrong case accessed")
}
if o.Giphy__ == nil {
return
}
return *o.Giphy__
}
func NewUnfurlDisplayWithGeneric(v UnfurlGenericDisplay) UnfurlDisplay {
return UnfurlDisplay{
UnfurlType__: UnfurlType_GENERIC,
Generic__: &v,
}
}
func NewUnfurlDisplayWithYoutube(v UnfurlYoutubeDisplay) UnfurlDisplay {
return UnfurlDisplay{
UnfurlType__: UnfurlType_YOUTUBE,
Youtube__: &v,
}
}
func NewUnfurlDisplayWithGiphy(v UnfurlGiphyDisplay) UnfurlDisplay {
return UnfurlDisplay{
UnfurlType__: UnfurlType_GIPHY,
Giphy__: &v,
}
}
func (o UnfurlDisplay) DeepCopy() UnfurlDisplay {
return UnfurlDisplay{
UnfurlType__: o.UnfurlType__.DeepCopy(),
Generic__: (func(x *UnfurlGenericDisplay) *UnfurlGenericDisplay {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Generic__),
Youtube__: (func(x *UnfurlYoutubeDisplay) *UnfurlYoutubeDisplay {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Youtube__),
Giphy__: (func(x *UnfurlGiphyDisplay) *UnfurlGiphyDisplay {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Giphy__),
}
}
type UnfurlMode int
const (
UnfurlMode_ALWAYS UnfurlMode = 0
UnfurlMode_NEVER UnfurlMode = 1
UnfurlMode_WHITELISTED UnfurlMode = 2
)
func (o UnfurlMode) DeepCopy() UnfurlMode { return o }
var UnfurlModeMap = map[string]UnfurlMode{
"ALWAYS": 0,
"NEVER": 1,
"WHITELISTED": 2,
}
var UnfurlModeRevMap = map[UnfurlMode]string{
0: "ALWAYS",
1: "NEVER",
2: "WHITELISTED",
}
func (e UnfurlMode) String() string {
if v, ok := UnfurlModeRevMap[e]; ok {
return v
}
return fmt.Sprintf("%v", int(e))
}
type UnfurlSettings struct {
Mode UnfurlMode `codec:"mode" json:"mode"`
Whitelist map[string]bool `codec:"whitelist" json:"whitelist"`
}
func (o UnfurlSettings) DeepCopy() UnfurlSettings {
return UnfurlSettings{
Mode: o.Mode.DeepCopy(),
Whitelist: (func(x map[string]bool) map[string]bool {
if x == nil {
return nil
}
ret := make(map[string]bool, len(x))
for k, v := range x {
kCopy := k
vCopy := v
ret[kCopy] = vCopy
}
return ret
})(o.Whitelist),
}
}
type UnfurlSettingsDisplay struct {
Mode UnfurlMode `codec:"mode" json:"mode"`
Whitelist []string `codec:"whitelist" json:"whitelist"`
}
func (o UnfurlSettingsDisplay) DeepCopy() UnfurlSettingsDisplay {
return UnfurlSettingsDisplay{
Mode: o.Mode.DeepCopy(),
Whitelist: (func(x []string) []string {
if x == nil {
return nil
}
ret := make([]string, len(x))
for i, v := range x {
vCopy := v
ret[i] = vCopy
}
return ret
})(o.Whitelist),
}
}

View File

@@ -0,0 +1,20 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/gregor1/auth.avdl
package gregor1
type AuthResult struct {
Uid UID `codec:"uid" json:"uid"`
Username string `codec:"username" json:"username"`
Sid SessionID `codec:"sid" json:"sid"`
IsAdmin bool `codec:"isAdmin" json:"isAdmin"`
}
func (o AuthResult) DeepCopy() AuthResult {
return AuthResult{
Uid: o.Uid.DeepCopy(),
Username: o.Username,
Sid: o.Sid.DeepCopy(),
IsAdmin: o.IsAdmin,
}
}

View File

@@ -0,0 +1,4 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/gregor1/auth_internal.avdl
package gregor1

View File

@@ -0,0 +1,4 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/gregor1/auth_update.avdl
package gregor1

View File

@@ -0,0 +1,394 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/gregor1/common.avdl
package gregor1
type TimeOrOffset struct {
Time_ Time `codec:"time" json:"time"`
Offset_ DurationMsec `codec:"offset" json:"offset"`
}
func (o TimeOrOffset) DeepCopy() TimeOrOffset {
return TimeOrOffset{
Time_: o.Time_.DeepCopy(),
Offset_: o.Offset_.DeepCopy(),
}
}
type Metadata struct {
Uid_ UID `codec:"uid" json:"uid"`
MsgID_ MsgID `codec:"msgID" json:"msgID"`
Ctime_ Time `codec:"ctime" json:"ctime"`
DeviceID_ DeviceID `codec:"deviceID" json:"deviceID"`
InBandMsgType_ int `codec:"inBandMsgType" json:"inBandMsgType"`
}
func (o Metadata) DeepCopy() Metadata {
return Metadata{
Uid_: o.Uid_.DeepCopy(),
MsgID_: o.MsgID_.DeepCopy(),
Ctime_: o.Ctime_.DeepCopy(),
DeviceID_: o.DeviceID_.DeepCopy(),
InBandMsgType_: o.InBandMsgType_,
}
}
type InBandMessage struct {
StateUpdate_ *StateUpdateMessage `codec:"stateUpdate,omitempty" json:"stateUpdate,omitempty"`
StateSync_ *StateSyncMessage `codec:"stateSync,omitempty" json:"stateSync,omitempty"`
}
func (o InBandMessage) DeepCopy() InBandMessage {
return InBandMessage{
StateUpdate_: (func(x *StateUpdateMessage) *StateUpdateMessage {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.StateUpdate_),
StateSync_: (func(x *StateSyncMessage) *StateSyncMessage {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.StateSync_),
}
}
type State struct {
Items_ []ItemAndMetadata `codec:"items" json:"items"`
}
func (o State) DeepCopy() State {
return State{
Items_: (func(x []ItemAndMetadata) []ItemAndMetadata {
if x == nil {
return nil
}
ret := make([]ItemAndMetadata, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Items_),
}
}
type StateUpdateMessage struct {
Md_ Metadata `codec:"md" json:"md"`
Creation_ *Item `codec:"creation,omitempty" json:"creation,omitempty"`
Dismissal_ *Dismissal `codec:"dismissal,omitempty" json:"dismissal,omitempty"`
}
func (o StateUpdateMessage) DeepCopy() StateUpdateMessage {
return StateUpdateMessage{
Md_: o.Md_.DeepCopy(),
Creation_: (func(x *Item) *Item {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Creation_),
Dismissal_: (func(x *Dismissal) *Dismissal {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Dismissal_),
}
}
type StateSyncMessage struct {
Md_ Metadata `codec:"md" json:"md"`
}
func (o StateSyncMessage) DeepCopy() StateSyncMessage {
return StateSyncMessage{
Md_: o.Md_.DeepCopy(),
}
}
type MsgRange struct {
EndTime_ TimeOrOffset `codec:"endTime" json:"endTime"`
Category_ Category `codec:"category" json:"category"`
SkipMsgIDs_ []MsgID `codec:"skipMsgIDs" json:"skipMsgIDs"`
}
func (o MsgRange) DeepCopy() MsgRange {
return MsgRange{
EndTime_: o.EndTime_.DeepCopy(),
Category_: o.Category_.DeepCopy(),
SkipMsgIDs_: (func(x []MsgID) []MsgID {
if x == nil {
return nil
}
ret := make([]MsgID, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.SkipMsgIDs_),
}
}
type Dismissal struct {
MsgIDs_ []MsgID `codec:"msgIDs" json:"msgIDs"`
Ranges_ []MsgRange `codec:"ranges" json:"ranges"`
}
func (o Dismissal) DeepCopy() Dismissal {
return Dismissal{
MsgIDs_: (func(x []MsgID) []MsgID {
if x == nil {
return nil
}
ret := make([]MsgID, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.MsgIDs_),
Ranges_: (func(x []MsgRange) []MsgRange {
if x == nil {
return nil
}
ret := make([]MsgRange, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Ranges_),
}
}
type Item struct {
Category_ Category `codec:"category" json:"category"`
Dtime_ TimeOrOffset `codec:"dtime" json:"dtime"`
RemindTimes_ []TimeOrOffset `codec:"remindTimes" json:"remindTimes"`
Body_ Body `codec:"body" json:"body"`
}
func (o Item) DeepCopy() Item {
return Item{
Category_: o.Category_.DeepCopy(),
Dtime_: o.Dtime_.DeepCopy(),
RemindTimes_: (func(x []TimeOrOffset) []TimeOrOffset {
if x == nil {
return nil
}
ret := make([]TimeOrOffset, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.RemindTimes_),
Body_: o.Body_.DeepCopy(),
}
}
type ItemAndMetadata struct {
Md_ *Metadata `codec:"md,omitempty" json:"md,omitempty"`
Item_ *Item `codec:"item,omitempty" json:"item,omitempty"`
}
func (o ItemAndMetadata) DeepCopy() ItemAndMetadata {
return ItemAndMetadata{
Md_: (func(x *Metadata) *Metadata {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Md_),
Item_: (func(x *Item) *Item {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Item_),
}
}
type Reminder struct {
Item_ ItemAndMetadata `codec:"item" json:"item"`
Seqno_ int `codec:"seqno" json:"seqno"`
RemindTime_ Time `codec:"remindTime" json:"remindTime"`
}
func (o Reminder) DeepCopy() Reminder {
return Reminder{
Item_: o.Item_.DeepCopy(),
Seqno_: o.Seqno_,
RemindTime_: o.RemindTime_.DeepCopy(),
}
}
type ReminderID struct {
Uid_ UID `codec:"uid" json:"uid"`
MsgID_ MsgID `codec:"msgID" json:"msgID"`
Seqno_ int `codec:"seqno" json:"seqno"`
}
func (o ReminderID) DeepCopy() ReminderID {
return ReminderID{
Uid_: o.Uid_.DeepCopy(),
MsgID_: o.MsgID_.DeepCopy(),
Seqno_: o.Seqno_,
}
}
type OutOfBandMessage struct {
Uid_ UID `codec:"uid" json:"uid"`
System_ System `codec:"system" json:"system"`
Body_ Body `codec:"body" json:"body"`
}
func (o OutOfBandMessage) DeepCopy() OutOfBandMessage {
return OutOfBandMessage{
Uid_: o.Uid_.DeepCopy(),
System_: o.System_.DeepCopy(),
Body_: o.Body_.DeepCopy(),
}
}
type ReminderSet struct {
Reminders_ []Reminder `codec:"reminders" json:"reminders"`
MoreRemindersReady_ bool `codec:"moreRemindersReady" json:"moreRemindersReady"`
}
func (o ReminderSet) DeepCopy() ReminderSet {
return ReminderSet{
Reminders_: (func(x []Reminder) []Reminder {
if x == nil {
return nil
}
ret := make([]Reminder, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Reminders_),
MoreRemindersReady_: o.MoreRemindersReady_,
}
}
type Message struct {
Oobm_ *OutOfBandMessage `codec:"oobm,omitempty" json:"oobm,omitempty"`
Ibm_ *InBandMessage `codec:"ibm,omitempty" json:"ibm,omitempty"`
}
func (o Message) DeepCopy() Message {
return Message{
Oobm_: (func(x *OutOfBandMessage) *OutOfBandMessage {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Oobm_),
Ibm_: (func(x *InBandMessage) *InBandMessage {
if x == nil {
return nil
}
tmp := (*x).DeepCopy()
return &tmp
})(o.Ibm_),
}
}
type DurationMsec int64
func (o DurationMsec) DeepCopy() DurationMsec {
return o
}
type DurationSec int64
func (o DurationSec) DeepCopy() DurationSec {
return o
}
type Category string
func (o Category) DeepCopy() Category {
return o
}
type System string
func (o System) DeepCopy() System {
return o
}
type UID []byte
func (o UID) DeepCopy() UID {
return (func(x []byte) []byte {
if x == nil {
return nil
}
return append([]byte{}, x...)
})(o)
}
type MsgID []byte
func (o MsgID) DeepCopy() MsgID {
return (func(x []byte) []byte {
if x == nil {
return nil
}
return append([]byte{}, x...)
})(o)
}
type DeviceID []byte
func (o DeviceID) DeepCopy() DeviceID {
return (func(x []byte) []byte {
if x == nil {
return nil
}
return append([]byte{}, x...)
})(o)
}
type Body []byte
func (o Body) DeepCopy() Body {
return (func(x []byte) []byte {
if x == nil {
return nil
}
return append([]byte{}, x...)
})(o)
}
type Time int64
func (o Time) DeepCopy() Time {
return o
}
type SessionID string
func (o SessionID) DeepCopy() SessionID {
return o
}
type SessionToken string
func (o SessionToken) DeepCopy() SessionToken {
return o
}

View File

@@ -0,0 +1,72 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/gregor1/incoming.avdl
package gregor1
type SyncResult struct {
Msgs []InBandMessage `codec:"msgs" json:"msgs"`
Hash []byte `codec:"hash" json:"hash"`
}
func (o SyncResult) DeepCopy() SyncResult {
return SyncResult{
Msgs: (func(x []InBandMessage) []InBandMessage {
if x == nil {
return nil
}
ret := make([]InBandMessage, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Msgs),
Hash: (func(x []byte) []byte {
if x == nil {
return nil
}
return append([]byte{}, x...)
})(o.Hash),
}
}
// DescribeConnectedUsers will take a list of users, and return the list of users
// which are connected to any Gregor in the cluster, and what devices (and device type)
// those users are connected with.
type ConnectedDevice struct {
DeviceID DeviceID `codec:"deviceID" json:"deviceID"`
DeviceType string `codec:"deviceType" json:"deviceType"`
DevicePlatform string `codec:"devicePlatform" json:"devicePlatform"`
UserAgent string `codec:"userAgent" json:"userAgent"`
}
func (o ConnectedDevice) DeepCopy() ConnectedDevice {
return ConnectedDevice{
DeviceID: o.DeviceID.DeepCopy(),
DeviceType: o.DeviceType,
DevicePlatform: o.DevicePlatform,
UserAgent: o.UserAgent,
}
}
type ConnectedUser struct {
Uid UID `codec:"uid" json:"uid"`
Devices []ConnectedDevice `codec:"devices" json:"devices"`
}
func (o ConnectedUser) DeepCopy() ConnectedUser {
return ConnectedUser{
Uid: o.Uid.DeepCopy(),
Devices: (func(x []ConnectedDevice) []ConnectedDevice {
if x == nil {
return nil
}
ret := make([]ConnectedDevice, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Devices),
}
}

View File

@@ -0,0 +1,4 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/gregor1/outgoing.avdl
package gregor1

View File

@@ -0,0 +1,4 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/gregor1/remind.avdl
package gregor1

View File

@@ -0,0 +1,98 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/keybase1/account.avdl
package keybase1
type HasServerKeysRes struct {
HasServerKeys bool `codec:"hasServerKeys" json:"hasServerKeys"`
}
func (o HasServerKeysRes) DeepCopy() HasServerKeysRes {
return HasServerKeysRes{
HasServerKeys: o.HasServerKeys,
}
}
type LockdownHistory struct {
Status bool `codec:"status" json:"status"`
CreationTime Time `codec:"creationTime" json:"ctime"`
DeviceID DeviceID `codec:"deviceID" json:"device_id"`
DeviceName string `codec:"deviceName" json:"deviceName"`
}
func (o LockdownHistory) DeepCopy() LockdownHistory {
return LockdownHistory{
Status: o.Status,
CreationTime: o.CreationTime.DeepCopy(),
DeviceID: o.DeviceID.DeepCopy(),
DeviceName: o.DeviceName,
}
}
type GetLockdownResponse struct {
History []LockdownHistory `codec:"history" json:"history"`
Status bool `codec:"status" json:"status"`
}
func (o GetLockdownResponse) DeepCopy() GetLockdownResponse {
return GetLockdownResponse{
History: (func(x []LockdownHistory) []LockdownHistory {
if x == nil {
return nil
}
ret := make([]LockdownHistory, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.History),
Status: o.Status,
}
}
type TeamContactSettings struct {
TeamID TeamID `codec:"teamID" json:"team_id"`
Enabled bool `codec:"enabled" json:"enabled"`
}
func (o TeamContactSettings) DeepCopy() TeamContactSettings {
return TeamContactSettings{
TeamID: o.TeamID.DeepCopy(),
Enabled: o.Enabled,
}
}
type ContactSettings struct {
Version *int `codec:"version,omitempty" json:"version,omitempty"`
AllowFolloweeDegrees int `codec:"allowFolloweeDegrees" json:"allow_followee_degrees"`
AllowGoodTeams bool `codec:"allowGoodTeams" json:"allow_good_teams"`
Enabled bool `codec:"enabled" json:"enabled"`
Teams []TeamContactSettings `codec:"teams" json:"teams"`
}
func (o ContactSettings) DeepCopy() ContactSettings {
return ContactSettings{
Version: (func(x *int) *int {
if x == nil {
return nil
}
tmp := (*x)
return &tmp
})(o.Version),
AllowFolloweeDegrees: o.AllowFolloweeDegrees,
AllowGoodTeams: o.AllowGoodTeams,
Enabled: o.Enabled,
Teams: (func(x []TeamContactSettings) []TeamContactSettings {
if x == nil {
return nil
}
ret := make([]TeamContactSettings, len(x))
for i, v := range x {
vCopy := v.DeepCopy()
ret[i] = vCopy
}
return ret
})(o.Teams),
}
}

View File

@@ -0,0 +1,22 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/keybase1/airdrop.avdl
package keybase1
type AirdropDetails struct {
Uid UID `codec:"uid" json:"uid"`
Kid BinaryKID `codec:"kid" json:"kid"`
Vid VID `codec:"vid" json:"vid"`
Vers string `codec:"vers" json:"vers"`
Time Time `codec:"time" json:"time"`
}
func (o AirdropDetails) DeepCopy() AirdropDetails {
return AirdropDetails{
Uid: o.Uid.DeepCopy(),
Kid: o.Kid.DeepCopy(),
Vid: o.Vid.DeepCopy(),
Vers: o.Vers,
Time: o.Time.DeepCopy(),
}
}

View File

@@ -0,0 +1,20 @@
// Auto-generated to Go types using avdl-compiler v1.4.6 (https://github.com/keybase/node-avdl-compiler)
// Input file: ../client/protocol/avdl/keybase1/apiserver.avdl
package keybase1
type APIRes struct {
Status string `codec:"status" json:"status"`
Body string `codec:"body" json:"body"`
HttpStatus int `codec:"httpStatus" json:"httpStatus"`
AppStatus string `codec:"appStatus" json:"appStatus"`
}
func (o APIRes) DeepCopy() APIRes {
return APIRes{
Status: o.Status,
Body: o.Body,
HttpStatus: o.HttpStatus,
AppStatus: o.AppStatus,
}
}

Some files were not shown because too many files have changed in this diff Show More