Compare commits

...

49 Commits

Author SHA1 Message Date
Wim
051e6e76e9 Release v1.25.1 (#1832) 2022-05-09 23:28:02 +02:00
Wim
1e55dd47f2 Update dependencies (#1831) 2022-05-09 23:00:23 +02:00
Andy
700b95546b Improve Slack attachments formatting (slack) (#1807)
* Improve Slack attachments formatting (slack)

* Add TitleLink
* Add Footer

* Fix linter issues
2022-05-09 22:56:19 +02:00
Wim
2fa96ec0ed Add KeepQuotedReply option for matrix to fix regression (#1823)
Matrix quotes replies and as of matterbridge 1.24.0 we strip those as this causes
issues with bridges support threading and have PreserveThreading enabled.

Introduced via 9a8ce9b17e

But if you for example use mattermost or discord with webhooks you'll need to enable
this if you want something that looks like a reply from matrix.
See issues:
- https://github.com/42wim/matterbridge/issues/1819
- https://github.com/42wim/matterbridge/issues/1780
2022-05-06 23:32:25 +02:00
Wim
81e6f75aa4 Update dependencies (#1822) 2022-05-02 00:10:54 +02:00
Wim
888c8b9a84 Add space between filename and URL (mattermost). Fixes #1820 2022-05-01 23:28:51 +02:00
Wim
e775a8a22e Revert "Clear existing IRC event handlers before connecting new ones (#1795)"
This reverts commit f044b948e2.

Fixes #1815
2022-05-01 22:28:42 +02:00
Alexander
99fbd9cae6 Fix telegram message deletion request (#1818) 2022-05-01 22:00:50 +02:00
Wim
67adad3e08 Update dependencies (#1813) 2022-04-25 23:50:10 +02:00
Wim
2fca3c7563 Add CGO_ENABLED info also to whatsappmulti build 2022-04-24 16:52:25 +02:00
Wim
c3573f1a46 Add CGO_ENABLED info to README 2022-04-24 16:51:16 +02:00
Daniil Suvorov
ee932a9f8e Fix UploadMessagesPhoto for vk community chat (vk) (#1812) 2022-04-22 23:37:09 +02:00
ValdikSS
ce18c948e6 Do not apply any markup to URL entities (telegram) (#1808)
handleEntities code uses simple modification offset which does not
allow to detect whether the offset is placed before or after
the element in already modified string.
This works fine is most cases as Telegram server always sort the
elements by offset, in ascending order.
However, this is not the case when the modification, for example bold
text, is applied to the URL. In this case, the offset of URL and
bold entity is equal, which raises the issue.

This commit introduces additional hack for this case, stripping
any entities which intersect with URL.
2022-04-22 01:00:57 +02:00
Wim
7bc93c5506 Do not modify .webm files (telegram). Fixes #17** (#1802) 2022-04-17 13:35:11 +02:00
Wim
d7cad3b404 Update matterbridge/gomatrix. Fixes #1772 (#1803) 2022-04-12 00:59:30 +02:00
Wim
7740a362c9 Fix build command for latest stable 2022-04-12 00:39:06 +02:00
Wim
281ef53e7d Update dependencies (#1800) 2022-04-12 00:30:21 +02:00
Bryan Davis
f044b948e2 Clear existing IRC event handlers before connecting new ones (#1795)
Clear all existing IRC event handler registrations before registering
new handlers in case we are connecting via a BNC and are seeing
a reconnect.

Fixes #1564
2022-04-07 23:00:17 +02:00
Wim
32474a5f4d Bump version 2022-04-07 22:51:22 +02:00
Wim
26596acf80 Release v1.25.0 (#1793) 2022-04-04 00:44:43 +02:00
Wim
e63870a631 Add whatsapp deprecation warning (#1792) 2022-04-04 00:31:18 +02:00
Wim
ce782ff6fb Change discord non-native threading behaviour (discord) (#1791)
Sorta regression introduced by 9a8ce9b17e
which changes the way we get replies of matrix.

This causes issues like https://github.com/42wim/matterbridge/issues/1780
We "fix" this by mimicking the old behaviour when "PreserveThreading" is
disabled.
2022-04-04 00:19:31 +02:00
Wim
c6716e030c Update dependencies (#1784) 2022-04-01 00:23:19 +02:00
Alexander
4ab72acec6 Ignore sending file with comment, if comment contains IgnoreMessages value (#1783)
* Ignore sending file with comment, if comment contains message to ignore

* Fix linter issue
2022-03-31 23:50:38 +02:00
Alexander
30aae8e257 Multiple media in one message (telegram) (#1779)
* Send multiple images/video/documents as media group

* Fix media caption quotting

* Fix errors handling

* Refactor parent id detection

* Try to reduce cognitive complexity of code

* Remove unused conditional
2022-03-30 22:23:52 +02:00
Alexander
d7b7ff7bb4 Preserve threading for messages with files (slack) (#1781)
* Preserve threading for slack messages with files

* Update bridge/slack/slack.go

Co-authored-by: Wim <wim@42.be>
2022-03-30 22:22:37 +02:00
Alexander
6fe0cff342 Use slack real name as user name (slack) (#1775)
* Use slack real name as user name

* Change slack option UseRealName to UseFullName
2022-03-26 20:52:24 +01:00
Wim
5f75f9886d Update lrstanley/girc dep (#1773) 2022-03-25 22:01:02 +01:00
Alexander
5d9604cd15 Preserve threading from telegram replies (telegram) (#1776)
* Preserve threading from telegram replies

* Add fallback for unthreaded telegram message

* Fix linter issue
2022-03-25 21:58:52 +01:00
Alexander
cc36ebf1c9 Add UseFullName option (telegram) (#1777) 2022-03-25 21:42:28 +01:00
Tobias Niepel
e6adecfd81 Add Dockerfile_whatsappmulti for building with WhatsApp Multi-Device support (Whatsmeow) (#1774)
Co-authored-by: Tobias Niepel <tobias.niepel@obi.de>
2022-03-22 10:05:32 +01:00
Wim
5c8f224e3b Update README 2022-03-20 17:04:33 +01:00
Wim
952221d3b9 Fix linting (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
496d5b4ec7 Add whatsappmulti buildflag for whatsapp with multidevice support (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
2623a412c4 Update vendor (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
d64eed49bc Fix linting (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
fffa29c2f3 Fix channel in video/audio/image/document handling (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
4da1444ffc Check for Conversation on receiving messages (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
21c4e56d16 Use Conversation instead of ExtendedTextMessage (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
5356b3856a Update vendor (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
320c996a21 Refactor login logic (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
69c74be7bb Add busy_timeout which fixes SQLITE_BUSY errors (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
aefa70891c Update vendor (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
1b9877fda4 Fetch avatars synchronous (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
0205a67309 Refactor JoinChannel (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
e3cafeaf92 Add dependencies/vendor (whatsapp) 2022-03-20 14:57:48 +01:00
Wim
e7b193788a Rewrite whatsapp bridge to use whatsmeow 2022-03-20 14:57:48 +01:00
Wim
17da95b094 Remove go replace by fork (matrix) (#1771) 2022-03-20 01:43:26 +01:00
Wim
c5e49eec96 Bump version 2022-03-19 23:47:50 +01:00
1749 changed files with 4064936 additions and 8280 deletions

14
Dockerfile_whatsappmulti Normal file
View File

@@ -0,0 +1,14 @@
FROM alpine AS builder
COPY . /go/src/matterbridge
RUN apk --no-cache add go git \
&& cd /go/src/matterbridge \
&& CGO_ENABLED=0 go build -tags whatsappmulti -mod vendor -ldflags "-X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
FROM alpine
RUN apk --no-cache add ca-certificates mailcap
COPY --from=builder /bin/matterbridge /bin/matterbridge
RUN mkdir /etc/matterbridge \
&& touch /etc/matterbridge/matterbridge.toml \
&& ln -sf /matterbridge.toml /etc/matterbridge/matterbridge.toml
ENTRYPOINT ["/bin/matterbridge", "-conf", "/etc/matterbridge/matterbridge.toml"]

View File

@@ -58,21 +58,22 @@ And more...
- [Binaries](#binaries)
- [Packages](#packages)
- [Building](#building)
- [Building with whatsapp (beta) multidevice support](#building-with-whatsapp-beta-multidevice-support)
- [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)
- [Systemd](#systemd)
- [Changelog](#changelog)
- [FAQ](#faq)
- [Related projects](#related-projects)
- [Articles / Tutorials](#articles--tutorials)
- [Thanks](#thanks)
- [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)
- [Systemd](#systemd)
- [Changelog](#changelog)
- [FAQ](#faq)
- [Related projects](#related-projects)
- [Articles / Tutorials](#articles--tutorials)
- [Thanks](#thanks)
## Features
@@ -89,6 +90,7 @@ And more...
- [Discord](https://discordapp.com)
- [Gitter](https://gitter.im)
- [Harmony](https://harmonyapp.io)
- [IRC](http://www.mirc.com/servers.html)
- [Keybase](https://keybase.io)
- [Matrix](https://matrix.org)
@@ -105,6 +107,8 @@ And more...
- [Twitch](https://twitch.tv)
- [VK](https://vk.com/)
- [WhatsApp](https://www.whatsapp.com/)
- Whatsapp legacy is natively supported
- Whatsapp multidevice beta is natively supported but you need to build yourself, see [here](#building-with-whatsapp-beta-multidevice-support)
- [XMPP](https://xmpp.org)
- [Zulip](https://zulipchat.com)
@@ -120,6 +124,8 @@ And more...
- [Counter-Strike, half-life and more](https://forums.alliedmods.net/showthread.php?t=319430)
- [MatterAMXX](https://github.com/GabeIggy/MatterAMXX)
- [Vintage Story](https://github.com/NikkyAI/vs-matterbridge)
- [Ultima Online Emulator](https://github.com/kuoushi/ServUO-Matterbridge)
- [Teamspeak](https://github.com/Archeb/ts-matterbridge)
### API
@@ -138,6 +144,8 @@ Used by the projects below. Feel free to make a PR to add your project to this l
- [matterbabble](https://github.com/DeclanHoare/matterbabble) (Discourse support)
- [MatterAMXX](https://forums.alliedmods.net/showthread.php?t=319430) (Counter-Strike, half-life and more via AMXX mod)
- [Vintage Story](https://github.com/NikkyAI/vs-matterbridge)
- [ServUO-matterbridge](https://github.com/kuoushi/ServUO-Matterbridge) (A matterbridge connector for ServUO servers)
- [ts-matterbridge](https://github.com/Archeb/ts-matterbridge) (Integrate teamspeak chat with matterbridge)
## Chat with us
@@ -164,10 +172,10 @@ See <https://github.com/42wim/matterbridge/wiki>
### Binaries
- Latest stable release [v1.24.1](https://github.com/42wim/matterbridge/releases/latest)
- Latest stable release [v1.25.1](https://github.com/42wim/matterbridge/releases/latest)
- Development releases (follows master) can be downloaded [here](https://github.com/42wim/matterbridge/actions) selecting the latest green build and then artifacts.
To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest). On \*nix platforms you may need to make the binary executable - you can do this by running `chmod a+x` on the binary (example: `chmod a+x matterbridge-1.20.0-linux-64bit`). After downloading (and making the binary executable, if necessary), 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.
To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest). On \*nix platforms you may need to make the binary executable - you can do this by running `chmod a+x` on the binary (example: `chmod a+x matterbridge-1.24.1-linux-64bit`). After downloading (and making the binary executable, if necessary), 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.
### Packages
@@ -182,16 +190,53 @@ Most people just want to use binaries, you can find those [here](https://github.
If you really want to build from source, follow these instructions:
Go 1.17+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed.
Building the binary with **all** the bridges enabled needs about 3GB RAM to compile.
You can reduce this memory requirement to 0,5GB RAM by adding the `nomsteams` tag if you don't need/use the Microsoft Teams bridge.
Matterbridge can be build without gcc/c-compiler: If you're running on windows first run `set CGO_ENABLED=0` on other platforms you prepend `CGO_ENABLED=0` to the `go build` command. (eg `CGO_ENABLED=0 go install github.com/42wim/matterbridge`)
To install the latest stable run:
```bash
go install github.com/42wim/matterbridge@v1.24.1
go install github.com/42wim/matterbridge
```
To install the latest dev run:
```bash
go install github.com/42wim/matterbridge@latest
go install github.com/42wim/matterbridge@master
```
To install the latest stable run without msteams or zulip bridge:
```bash
go install -tags nomsteams,nozulip github.com/42wim/matterbridge
```
You should now have matterbridge binary in the ~/go/bin directory:
```bash
$ ls ~/go/bin/
matterbridge
```
## Building with whatsapp (beta) multidevice support
Because the library we use for Whatsapp multidevice support includes a GPL3 library we can not provide you binaries.
(as this would require the Matterbridge to change it license to GPL)
Matterbridge can be build without gcc/c-compiler: If you're running on windows first run `set CGO_ENABLED=0` on other platforms you prepend `CGO_ENABLED=0` to the `go build` command. (eg `CGO_ENABLED=0 go install github.com/42wim/matterbridge`)
So this means you have to build it yourself using the instructions below:
```bash
go install -tags whatsappmulti github.com/42wim/matterbridge@master
```
If you're low on memory and don't need msteams:
```bash
go install -tags nomsteams,whatsappmulti github.com/42wim/matterbridge@master
```
You should now have matterbridge binary in the ~/go/bin directory:
@@ -323,6 +368,8 @@ See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ)
- [nextcloud talk](https://github.com/nextcloud/talk_matterbridge) (Integrates matterbridge in Nextcloud Talk)
- [mattercraft](https://github.com/raws/mattercraft) (Minecraft bridge)
- [vs-matterbridge](https://github.com/NikkyAI/vs-matterbridge) (Vintage Story bridge)
- [ServUO-matterbridge](https://github.com/kuoushi/ServUO-Matterbridge) (A matterbridge connector for ServUO servers)
- [ts-matterbridge](https://github.com/Archeb/ts-matterbridge) (Integrate teamspeak chat with matterbridge)
## Articles / Tutorials
@@ -356,6 +403,7 @@ Matterbridge wouldn't exist without these libraries:
- gops - <https://github.com/google/gops>
- gozulipbot - <https://github.com/ifo/gozulipbot>
- gumble - <https://github.com/layeh/gumble>
- harmony - <https://github.com/harmony-development/shibshib>
- irc - <https://github.com/lrstanley/girc>
- keybase - <https://github.com/keybase/go-keybase-chat-bot>
- matrix - <https://github.com/matrix-org/gomatrix>
@@ -363,6 +411,7 @@ Matterbridge wouldn't exist without these libraries:
- msgraph.go - <https://github.com/yaegashi/msgraph.go>
- mumble - <https://github.com/layeh/gumble>
- nctalk - <https://github.com/gary-kim/go-nc-talk>
- rocketchat - <https://github.com/RocketChat/Rocket.Chat.Go.SDK>
- slack - <https://github.com/nlopes/slack>
- sshchat - <https://github.com/shazow/ssh-chat>
- steam - <https://github.com/Philipp15b/go-steam>
@@ -370,6 +419,7 @@ Matterbridge wouldn't exist without these libraries:
- tengo - <https://github.com/d5/tengo>
- vk - <https://github.com/SevereCloud/vksdk>
- whatsapp - <https://github.com/Rhymen/go-whatsapp>
- whatsapp - <https://github.com/tulir/whatsmeow>
- xmpp - <https://github.com/mattn/go-xmpp>
- zulip - <https://github.com/ifo/gozulipbot>

View File

@@ -272,7 +272,6 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {
// Handle prefix hint for unthreaded messages.
if msg.ParentNotFound() {
msg.ParentID = ""
msg.Text = fmt.Sprintf("[thread]: %s", msg.Text)
}
// Use webhook to send the message

View File

@@ -8,7 +8,7 @@ import (
"strings"
"time"
matrix "github.com/matrix-org/gomatrix"
matrix "github.com/matterbridge/gomatrix"
)
func newMatrixUsername(username string) *matrixUsername {

View File

@@ -12,7 +12,7 @@ import (
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
matrix "github.com/matrix-org/gomatrix"
matrix "github.com/matterbridge/gomatrix"
)
var (
@@ -428,12 +428,15 @@ func (b *Bmatrix) handleReply(ev *matrix.Event, rmsg config.Message) bool {
}
body := rmsg.Text
for strings.HasPrefix(body, "> ") {
lineIdx := strings.IndexRune(body, '\n')
if lineIdx == -1 {
body = ""
} else {
body = body[(lineIdx + 1):]
if !b.GetBool("keepquotedreply") {
for strings.HasPrefix(body, "> ") {
lineIdx := strings.IndexRune(body, '\n')
if lineIdx == -1 {
body = ""
} else {
body = body[(lineIdx + 1):]
}
}
}

View File

@@ -183,6 +183,7 @@ func (b *Bmattermost) sendWebhook(msg config.Message) (string, error) {
if b.GetBool("PrefixMessagesWithNick") {
msg.Text = msg.Username + msg.Text
}
if msg.Extra != nil {
// this sends a message only if we received a config.EVENT_FILE_FAILURE_SIZE
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
@@ -206,7 +207,7 @@ func (b *Bmattermost) sendWebhook(msg config.Message) (string, error) {
for _, f := range msg.Extra["file"] {
fi := f.(config.FileInfo)
if fi.URL != "" {
msg.Text += fi.URL
msg.Text += " " + fi.URL
}
}
}

View File

@@ -282,6 +282,13 @@ func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message)
return false
}
func getMessageTitle(attach *slack.Attachment) string {
if attach.TitleLink != "" {
return fmt.Sprintf("[%s](%s)\n", attach.Title, attach.TitleLink)
}
return attach.Title
}
func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message) {
// File comments are set by the system (because there is no username given).
if ev.SubType == sFileComment {
@@ -290,12 +297,15 @@ func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message)
// See if we have some text in the attachments.
if rmsg.Text == "" {
for _, attach := range ev.Attachments {
for i, attach := range ev.Attachments {
if attach.Text != "" {
if attach.Title != "" {
rmsg.Text = attach.Title + "\n"
rmsg.Text = getMessageTitle(&ev.Attachments[i])
}
rmsg.Text += attach.Text
if attach.Footer != "" {
rmsg.Text += "\n\n" + attach.Footer
}
} else {
rmsg.Text = attach.Fallback
}

View File

@@ -87,6 +87,9 @@ func (b *Bslack) populateMessageWithUserInfo(ev *slack.MessageEvent, rmsg *confi
if user.Profile.DisplayName != "" {
rmsg.Username = user.Profile.DisplayName
}
if b.GetBool("UseFullName") && user.Profile.RealName != "" {
rmsg.Username = user.Profile.RealName
}
return nil
}
@@ -124,7 +127,7 @@ var (
mentionRE = regexp.MustCompile(`<@([a-zA-Z0-9]+)>`)
channelRE = regexp.MustCompile(`<#[a-zA-Z0-9]+\|(.+?)>`)
variableRE = regexp.MustCompile(`<!((?:subteam\^)?[a-zA-Z0-9]+)(?:\|@?(.+?))?>`)
urlRE = regexp.MustCompile(`<(.*?)(\|.*?)?>`)
urlRE = regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`)
codeFenceRE = regexp.MustCompile(`(?m)^` + "```" + `\w+$`)
topicOrPurposeRE = regexp.MustCompile(`(?s)(@.+) (cleared|set)(?: the)? channel (topic|purpose)(?:: (.*))?`)
)
@@ -178,14 +181,7 @@ func (b *Bslack) replaceVariable(text string) string {
// @see https://api.slack.com/docs/message-formatting#linking_to_urls
func (b *Bslack) replaceURL(text string) string {
for _, r := range urlRE.FindAllStringSubmatch(text, -1) {
if len(strings.TrimSpace(r[2])) == 1 { // A display text separator was found, but the text was blank
text = strings.Replace(text, r[0], "", 1)
} else {
text = strings.Replace(text, r[0], r[1], 1)
}
}
return text
return urlRE.ReplaceAllString(text, "[${2}](${1})")
}
func (b *Bslack) replaceb0rkedMarkDown(text string) string {

View File

@@ -321,7 +321,7 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) {
}
// Upload a file if it exists.
if msg.Extra != nil {
if len(msg.Extra) > 0 {
extraMsgs := helper.HandleExtra(&msg, b.General)
for i := range extraMsgs {
rmsg := &extraMsgs[i]
@@ -332,7 +332,7 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) {
}
}
// Upload files if necessary (from Slack, Telegram or Mattermost).
b.uploadFile(&msg, channelInfo.ID)
return b.uploadFile(&msg, channelInfo.ID)
}
// Post message.
@@ -443,7 +443,8 @@ func (b *Bslack) postMessage(msg *config.Message, channelInfo *slack.Channel) (s
}
// uploadFile handles native upload of files
func (b *Bslack) uploadFile(msg *config.Message, channelID string) {
func (b *Bslack) uploadFile(msg *config.Message, channelID string) (string, error) {
var messageID string
for _, f := range msg.Extra["file"] {
fi, ok := f.(config.FileInfo)
if !ok {
@@ -471,13 +472,22 @@ func (b *Bslack) uploadFile(msg *config.Message, channelID string) {
})
if err != nil {
b.Log.Errorf("uploadfile %#v", err)
return
return "", err
}
if res.ID != "" {
b.Log.Debugf("Adding file ID %s to cache with timestamp %s", res.ID, ts.String())
b.cache.Add("file"+res.ID, ts)
// search for message id by uploaded file in private/public channels, get thread timestamp from uploaded file
if v, ok := res.Shares.Private[channelID]; ok && len(v) > 0 {
messageID = v[0].Ts
}
if v, ok := res.Shares.Public[channelID]; ok && len(v) > 0 {
messageID = v[0].Ts
}
}
}
return messageID, nil
}
func (b *Bslack) prepareMessageOptions(msg *config.Message) []slack.MsgOption {

View File

@@ -71,6 +71,9 @@ func (b *Btelegram) handleForwarded(rmsg *config.Message, message *tgbotapi.Mess
if b.GetBool("UseFirstName") {
usernameForward = message.ForwardFrom.FirstName
}
if b.GetBool("UseFullName") {
usernameForward = message.ForwardFrom.FirstName + " " + message.ForwardFrom.LastName
}
if usernameForward == "" {
usernameForward = message.ForwardFrom.UserName
@@ -94,6 +97,9 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag
if b.GetBool("UseFirstName") {
usernameReply = message.ReplyToMessage.From.FirstName
}
if b.GetBool("UseFullName") {
usernameReply = message.ReplyToMessage.From.FirstName + " " + message.ReplyToMessage.From.LastName
}
if usernameReply == "" {
usernameReply = message.ReplyToMessage.From.UserName
if usernameReply == "" {
@@ -105,7 +111,11 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag
usernameReply = unknownUser
}
if !b.GetBool("QuoteDisable") {
rmsg.Text = b.handleQuote(rmsg.Text, usernameReply, message.ReplyToMessage.Text)
quote := message.ReplyToMessage.Text
if quote == "" {
quote = message.ReplyToMessage.Caption
}
rmsg.Text = b.handleQuote(rmsg.Text, usernameReply, quote)
}
}
}
@@ -117,6 +127,9 @@ func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Messa
if b.GetBool("UseFirstName") {
rmsg.Username = message.From.FirstName
}
if b.GetBool("UseFullName") {
rmsg.Username = message.From.FirstName + " " + message.From.LastName
}
if rmsg.Username == "" {
rmsg.Username = message.From.UserName
if rmsg.Username == "" {
@@ -134,6 +147,9 @@ func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Messa
if b.GetBool("UseFirstName") {
rmsg.Username = message.SenderChat.FirstName
}
if b.GetBool("UseFullName") {
rmsg.Username = message.SenderChat.FirstName + " " + message.SenderChat.LastName
}
if rmsg.Username == "" || rmsg.Username == "Channel_Bot" {
rmsg.Username = message.SenderChat.UserName
@@ -187,6 +203,11 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
rmsg.ID = strconv.Itoa(message.MessageID)
rmsg.Channel = strconv.FormatInt(message.Chat.ID, 10)
// preserve threading from telegram reply
if message.ReplyToMessage != nil {
rmsg.ParentID = strconv.Itoa(message.ReplyToMessage.MessageID)
}
// handle entities (adding URLs)
b.handleEntities(&rmsg, message)
@@ -364,7 +385,7 @@ func (b *Btelegram) getDownloadInfo(id string, suffix string, urlpart bool) (str
urlPart := strings.Split(url, "/")
name = urlPart[len(urlPart)-1]
}
if suffix != "" && !strings.HasSuffix(name, suffix) {
if suffix != "" && !strings.HasSuffix(name, suffix) && !strings.HasSuffix(name, ".webm") {
name += suffix
}
text := " " + url
@@ -383,7 +404,7 @@ func (b *Btelegram) handleDelete(msg *config.Message, chatid int64) (string, err
}
cfg := tgbotapi.NewDeleteMessage(chatid, msgid)
_, err = b.c.Send(cfg)
_, err = b.c.Request(cfg)
return "", err
}
@@ -422,8 +443,8 @@ func (b *Btelegram) handleEdit(msg *config.Message, chatid int64) (string, error
}
// handleUploadFile handles native upload of files
func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string {
var c tgbotapi.Chattable
func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64, parentID int) (string, error) {
var media []interface{}
for _, f := range msg.Extra["file"] {
fi := f.(config.FileInfo)
file := tgbotapi.FileBytes{
@@ -432,32 +453,42 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string {
}
switch filepath.Ext(fi.Name) {
case ".jpg", ".jpe", ".png":
pc := tgbotapi.NewPhoto(chatid, file)
pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
c = pc
pc := tgbotapi.NewInputMediaPhoto(file)
if fi.Comment != "" {
pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
}
media = append(media, pc)
case ".mp4", ".m4v":
vc := tgbotapi.NewVideo(chatid, file)
vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
c = vc
vc := tgbotapi.NewInputMediaVideo(file)
if fi.Comment != "" {
vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
}
media = append(media, vc)
case ".mp3", ".oga":
ac := tgbotapi.NewAudio(chatid, file)
ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
c = ac
ac := tgbotapi.NewInputMediaAudio(file)
if fi.Comment != "" {
ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
}
media = append(media, ac)
case ".ogg":
voc := tgbotapi.NewVoice(chatid, file)
voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
c = voc
voc.ReplyToMessageID = parentID
res, err := b.c.Send(voc)
if err != nil {
return "", err
}
return strconv.Itoa(res.MessageID), nil
default:
dc := tgbotapi.NewDocument(chatid, file)
dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
c = dc
}
_, err := b.c.Send(c)
if err != nil {
b.Log.Errorf("file upload failed: %#v", err)
dc := tgbotapi.NewInputMediaDocument(file)
if fi.Comment != "" {
dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
}
media = append(media, dc)
}
}
return ""
return b.sendMediaFiles(msg, chatid, parentID, media)
}
func (b *Btelegram) handleQuote(message, quoteNick, quoteMessage string) string {
@@ -486,8 +517,8 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa
}
indexMovedBy := 0
prevLinkOffset := -1
// for now only do URL replacements
for _, e := range message.Entities {
asRunes := utf16.Encode([]rune(rmsg.Text))
@@ -506,6 +537,11 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa
}
rmsg.Text = string(utf16.Decode(asRunes[:offset+e.Length])) + " (" + url.String() + ")" + string(utf16.Decode(asRunes[offset+e.Length:]))
indexMovedBy += len(url.String()) + 3
prevLinkOffset = e.Offset
}
if e.Offset == prevLinkOffset {
continue
}
if e.Type == "code" {

View File

@@ -1,6 +1,7 @@
package btelegram
import (
"fmt"
"html"
"log"
"strconv"
@@ -108,16 +109,27 @@ func (b *Btelegram) Send(msg config.Message) (string, error) {
return b.handleDelete(&msg, chatid)
}
// Handle prefix hint for unthreaded messages.
if msg.ParentNotFound() {
msg.ParentID = ""
msg.Text = fmt.Sprintf("[reply]: %s", msg.Text)
}
var parentID int
if msg.ParentID != "" {
parentID, _ = b.intParentID(msg.ParentID)
}
// Upload a file if it exists
if msg.Extra != nil {
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
if _, msgErr := b.sendMessage(chatid, rmsg.Username, rmsg.Text); msgErr != nil {
if _, msgErr := b.sendMessage(chatid, rmsg.Username, rmsg.Text, parentID); msgErr != nil {
b.Log.Errorf("sendMessage failed: %s", msgErr)
}
}
// check if we have files to upload (from slack, telegram or mattermost)
if len(msg.Extra["file"]) > 0 {
b.handleUploadFile(&msg, chatid)
return b.handleUploadFile(&msg, chatid, parentID)
}
}
@@ -131,7 +143,7 @@ func (b *Btelegram) Send(msg config.Message) (string, error) {
// Ignore empty text field needs for prevent double messages from whatsapp to telegram
// when sending media with text caption
if msg.Text != "" {
return b.sendMessage(chatid, msg.Username, msg.Text)
return b.sendMessage(chatid, msg.Username, msg.Text, parentID)
}
return "", nil
@@ -145,10 +157,10 @@ func (b *Btelegram) getFileDirectURL(id string) string {
return res
}
func (b *Btelegram) sendMessage(chatid int64, username, text string) (string, error) {
func (b *Btelegram) sendMessage(chatid int64, username, text string, parentID int) (string, error) {
m := tgbotapi.NewMessage(chatid, "")
m.Text, m.ParseMode = TGGetParseMode(b, username, text)
m.ReplyToMessageID = parentID
m.DisableWebPagePreview = b.GetBool("DisableWebPagePreview")
res, err := b.c.Send(m)
@@ -158,6 +170,29 @@ func (b *Btelegram) sendMessage(chatid int64, username, text string) (string, er
return strconv.Itoa(res.MessageID), nil
}
// sendMediaFiles native upload media files via media group
func (b *Btelegram) sendMediaFiles(msg *config.Message, chatid int64, parentID int, media []interface{}) (string, error) {
if len(media) == 0 {
return "", nil
}
mg := tgbotapi.MediaGroupConfig{ChatID: chatid, ChannelUsername: msg.Username, Media: media, ReplyToMessageID: parentID}
messages, err := b.c.SendMediaGroup(mg)
if err != nil {
return "", err
}
// return first message id
return strconv.Itoa(messages[0].MessageID), nil
}
// intParentID return integer parent id for telegram message
func (b *Btelegram) intParentID(parentID string) (int, error) {
pid, err := strconv.Atoi(parentID)
if err != nil {
return 0, err
}
return pid, nil
}
func (b *Btelegram) cacheAvatar(msg *config.Message) (string, error) {
fi := msg.Extra["file"][0].(config.FileInfo)
/* if we have a sha we have successfully uploaded the file to the media server,

View File

@@ -64,7 +64,7 @@ func (b *Bvk) Connect() error {
go func() {
err := b.lp.Run()
if err != nil {
b.Log.Fatal("Enable longpoll in group management")
b.Log.WithError(err).Fatal("Enable longpoll in group management")
}
}()
@@ -223,7 +223,7 @@ func (b *Bvk) uploadFiles(extra map[string][]interface{}, peerID int) (string, s
}
a, err := b.uploadFile(fi, peerID)
if err != nil {
b.Log.Error("File upload error ", fi.Name)
b.Log.WithError(err).Error("File upload error ", fi.Name)
}
attachments = append(attachments, a)
@@ -237,7 +237,8 @@ func (b *Bvk) uploadFile(file config.FileInfo, peerID int) (string, error) {
photoRE := regexp.MustCompile(".(jpg|jpe|png)$")
if photoRE.MatchString(file.Name) {
p, err := b.c.UploadMessagesPhoto(peerID, r)
// BUG(VK): for community chat peerID=0
p, err := b.c.UploadMessagesPhoto(0, r)
if err != nil {
return "", err
}

View File

@@ -1,3 +1,4 @@
// nolint:goconst
package bwhatsapp
import (
@@ -134,6 +135,7 @@ func (b *Bwhatsapp) HandleTextMessage(message whatsapp.TextMessage) {
}
// HandleImageMessage sent from WhatsApp, relay it to the brige
// nolint:funlen
func (b *Bwhatsapp) HandleImageMessage(message whatsapp.ImageMessage) {
if message.Info.FromMe || message.Info.Timestamp < b.startedAt {
return

View File

@@ -111,8 +111,7 @@ func (b *Bwhatsapp) getSenderName(senderJid string) string {
}
// try to reload this contact
_, err := b.conn.Contacts()
if err != nil {
if _, err := b.conn.Contacts(); err != nil {
b.Log.Errorf("error on update of contacts: %v", err)
}

View File

@@ -40,6 +40,11 @@ type Bwhatsapp struct {
func New(cfg *bridge.Config) bridge.Bridger {
number := cfg.GetString(cfgNumber)
cfg.Log.Warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
cfg.Log.Warn("This bridge is deprecated and not supported anymore. Use the new multidevice whatsapp bridge")
cfg.Log.Warn("See https://github.com/42wim/matterbridge#building-with-whatsapp-beta-multidevice-support for more info")
cfg.Log.Warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
if number == "" {
cfg.Log.Fatalf("Missing configuration for WhatsApp bridge: Number")
}

View File

@@ -0,0 +1,344 @@
// +build whatsappmulti
package bwhatsapp
import (
"fmt"
"mime"
"strings"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"go.mau.fi/whatsmeow/binary/proto"
"go.mau.fi/whatsmeow/types"
"go.mau.fi/whatsmeow/types/events"
)
// nolint:gocritic
func (b *Bwhatsapp) eventHandler(evt interface{}) {
switch e := evt.(type) {
case *events.Message:
b.handleMessage(e)
}
}
func (b *Bwhatsapp) handleMessage(message *events.Message) {
msg := message.Message
switch {
case msg == nil, message.Info.IsFromMe, message.Info.Timestamp.Before(b.startedAt):
return
}
b.Log.Infof("Receiving message %#v", msg)
switch {
case msg.Conversation != nil || msg.ExtendedTextMessage != nil:
b.handleTextMessage(message.Info, msg)
case msg.VideoMessage != nil:
b.handleVideoMessage(message)
case msg.AudioMessage != nil:
b.handleAudioMessage(message)
case msg.DocumentMessage != nil:
b.handleDocumentMessage(message)
case msg.ImageMessage != nil:
b.handleImageMessage(message)
}
}
// nolint:funlen
func (b *Bwhatsapp) handleTextMessage(messageInfo types.MessageInfo, msg *proto.Message) {
senderJID := messageInfo.Sender
channel := messageInfo.Chat
senderName := b.getSenderName(messageInfo.Sender)
if senderName == "" {
senderName = "Someone" // don't expose telephone number
}
if msg.GetExtendedTextMessage() == nil && msg.GetConversation() == "" {
b.Log.Debugf("message without text content? %#v", msg)
return
}
var text string
// nolint:nestif
if msg.GetExtendedTextMessage() == nil {
text = msg.GetConversation()
} else {
text = msg.GetExtendedTextMessage().GetText()
ci := msg.GetExtendedTextMessage().GetContextInfo()
if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
}
if ci.MentionedJid != nil {
// handle user mentions
for _, mentionedJID := range ci.MentionedJid {
numberAndSuffix := strings.SplitN(mentionedJID, "@", 2)
// mentions comes as telephone numbers and we don't want to expose it to other bridges
// replace it with something more meaninful to others
mention := b.getSenderNotify(types.NewJID(numberAndSuffix[0], types.DefaultUserServer))
if mention == "" {
mention = "someone"
}
text = strings.Replace(text, "@"+numberAndSuffix[0], "@"+mention, 1)
}
}
}
rmsg := config.Message{
UserID: senderJID.String(),
Username: senderName,
Text: text,
Channel: channel.String(),
Account: b.Account,
Protocol: b.Protocol,
Extra: make(map[string][]interface{}),
// ParentID: TODO, // TODO handle thread replies // map from Info.QuotedMessageID string
ID: messageInfo.ID,
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
rmsg.Avatar = avatarURL
}
b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}
// HandleImageMessage sent from WhatsApp, relay it to the brige
func (b *Bwhatsapp) handleImageMessage(msg *events.Message) {
imsg := msg.Message.GetImageMessage()
senderJID := msg.Info.Sender
senderName := b.getSenderName(senderJID)
ci := imsg.GetContextInfo()
if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
}
rmsg := config.Message{
UserID: senderJID.String(),
Username: senderName,
Channel: msg.Info.Chat.String(),
Account: b.Account,
Protocol: b.Protocol,
Extra: make(map[string][]interface{}),
ID: msg.Info.ID,
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
rmsg.Avatar = avatarURL
}
fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
if err != nil {
b.Log.Errorf("Mimetype detection error: %s", err)
return
}
// rename .jfif to .jpg https://github.com/42wim/matterbridge/issues/1292
if fileExt[0] == ".jfif" {
fileExt[0] = ".jpg"
}
// rename .jpe to .jpg https://github.com/42wim/matterbridge/issues/1463
if fileExt[0] == ".jpe" {
fileExt[0] = ".jpg"
}
filename := fmt.Sprintf("%v%v", msg.Info.ID, fileExt[0])
b.Log.Debugf("Trying to download %s with type %s", filename, imsg.GetMimetype())
data, err := b.wc.Download(imsg)
if err != nil {
b.Log.Errorf("Download image failed: %s", err)
return
}
// Move file to bridge storage
helper.HandleDownloadData(b.Log, &rmsg, filename, imsg.GetCaption(), "", &data, b.General)
b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}
// HandleVideoMessage downloads video messages
func (b *Bwhatsapp) handleVideoMessage(msg *events.Message) {
imsg := msg.Message.GetVideoMessage()
senderJID := msg.Info.Sender
senderName := b.getSenderName(senderJID)
ci := imsg.GetContextInfo()
if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
}
rmsg := config.Message{
UserID: senderJID.String(),
Username: senderName,
Channel: msg.Info.Chat.String(),
Account: b.Account,
Protocol: b.Protocol,
Extra: make(map[string][]interface{}),
ID: msg.Info.ID,
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
rmsg.Avatar = avatarURL
}
fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
if err != nil {
b.Log.Errorf("Mimetype detection error: %s", err)
return
}
if len(fileExt) == 0 {
fileExt = append(fileExt, ".mp4")
}
filename := fmt.Sprintf("%v%v", msg.Info.ID, fileExt[0])
b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, imsg.GetFileLength(), imsg.GetMimetype())
data, err := b.wc.Download(imsg)
if err != nil {
b.Log.Errorf("Download video failed: %s", err)
return
}
// Move file to bridge storage
helper.HandleDownloadData(b.Log, &rmsg, filename, imsg.GetCaption(), "", &data, b.General)
b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}
// HandleAudioMessage downloads audio messages
func (b *Bwhatsapp) handleAudioMessage(msg *events.Message) {
imsg := msg.Message.GetAudioMessage()
senderJID := msg.Info.Sender
senderName := b.getSenderName(senderJID)
ci := imsg.GetContextInfo()
if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
}
rmsg := config.Message{
UserID: senderJID.String(),
Username: senderName,
Channel: msg.Info.Chat.String(),
Account: b.Account,
Protocol: b.Protocol,
Extra: make(map[string][]interface{}),
ID: msg.Info.ID,
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
rmsg.Avatar = avatarURL
}
fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
if err != nil {
b.Log.Errorf("Mimetype detection error: %s", err)
return
}
if len(fileExt) == 0 {
fileExt = append(fileExt, ".ogg")
}
filename := fmt.Sprintf("%v%v", msg.Info.ID, fileExt[0])
b.Log.Debugf("Trying to download %s with size %#v and type %s", filename, imsg.GetFileLength(), imsg.GetMimetype())
data, err := b.wc.Download(imsg)
if err != nil {
b.Log.Errorf("Download video failed: %s", err)
return
}
// Move file to bridge storage
helper.HandleDownloadData(b.Log, &rmsg, filename, "audio message", "", &data, b.General)
b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}
// HandleDocumentMessage downloads documents
func (b *Bwhatsapp) handleDocumentMessage(msg *events.Message) {
imsg := msg.Message.GetDocumentMessage()
senderJID := msg.Info.Sender
senderName := b.getSenderName(senderJID)
ci := imsg.GetContextInfo()
if senderJID == (types.JID{}) && ci.Participant != nil {
senderJID = types.NewJID(ci.GetParticipant(), types.DefaultUserServer)
}
rmsg := config.Message{
UserID: senderJID.String(),
Username: senderName,
Channel: msg.Info.Chat.String(),
Account: b.Account,
Protocol: b.Protocol,
Extra: make(map[string][]interface{}),
ID: msg.Info.ID,
}
if avatarURL, exists := b.userAvatars[senderJID.String()]; exists {
rmsg.Avatar = avatarURL
}
fileExt, err := mime.ExtensionsByType(imsg.GetMimetype())
if err != nil {
b.Log.Errorf("Mimetype detection error: %s", err)
return
}
filename := fmt.Sprintf("%v", imsg.GetFileName())
b.Log.Debugf("Trying to download %s with extension %s and type %s", filename, fileExt, imsg.GetMimetype())
data, err := b.wc.Download(imsg)
if err != nil {
b.Log.Errorf("Download document message failed: %s", err)
return
}
// Move file to bridge storage
helper.HandleDownloadData(b.Log, &rmsg, filename, "document", "", &data, b.General)
b.Log.Debugf("<= Sending message from %s on %s to gateway", senderJID, b.Account)
b.Log.Debugf("<= Message is %#v", rmsg)
b.Remote <- rmsg
}

View File

@@ -0,0 +1,108 @@
// +build whatsappmulti
package bwhatsapp
import (
"fmt"
"strings"
"go.mau.fi/whatsmeow/store"
"go.mau.fi/whatsmeow/store/sqlstore"
"go.mau.fi/whatsmeow/types"
)
type ProfilePicInfo struct {
URL string `json:"eurl"`
Tag string `json:"tag"`
Status int16 `json:"status"`
}
func (b *Bwhatsapp) getSenderName(senderJid types.JID) string {
if sender, exists := b.contacts[senderJid]; exists {
if sender.FullName != "" {
return sender.FullName
}
// if user is not in phone contacts
// it is the most obvious scenario unless you sync your phone contacts with some remote updated source
// users can change it in their WhatsApp settings -> profile -> click on Avatar
if sender.PushName != "" {
return sender.PushName
}
if sender.FirstName != "" {
return sender.FirstName
}
}
// try to reload this contact
if _, err := b.wc.Store.Contacts.GetAllContacts(); err != nil {
b.Log.Errorf("error on update of contacts: %v", err)
}
allcontacts, err := b.wc.Store.Contacts.GetAllContacts()
if err != nil {
b.Log.Errorf("error on update of contacts: %v", err)
}
if len(allcontacts) > 0 {
b.contacts = allcontacts
}
if sender, exists := b.contacts[senderJid]; exists {
if sender.FullName != "" {
return sender.FullName
}
// if user is not in phone contacts
// it is the most obvious scenario unless you sync your phone contacts with some remote updated source
// users can change it in their WhatsApp settings -> profile -> click on Avatar
if sender.PushName != "" {
return sender.PushName
}
if sender.FirstName != "" {
return sender.FirstName
}
}
return "Someone"
}
func (b *Bwhatsapp) getSenderNotify(senderJid types.JID) string {
if sender, exists := b.contacts[senderJid]; exists {
return sender.PushName
}
return ""
}
func (b *Bwhatsapp) GetProfilePicThumb(jid string) (*types.ProfilePictureInfo, error) {
pjid, _ := types.ParseJID(jid)
info, err := b.wc.GetProfilePictureInfo(pjid, true)
if err != nil {
return nil, fmt.Errorf("failed to get avatar: %v", err)
}
return info, nil
}
func isGroupJid(identifier string) bool {
return strings.HasSuffix(identifier, "@g.us") ||
strings.HasSuffix(identifier, "@temp") ||
strings.HasSuffix(identifier, "@broadcast")
}
func (b *Bwhatsapp) getDevice() (*store.Device, error) {
device := &store.Device{}
storeContainer, err := sqlstore.New("sqlite", "file:"+b.Config.GetString("sessionfile")+".db?_foreign_keys=on&_pragma=busy_timeout=10000", nil)
if err != nil {
return device, fmt.Errorf("failed to connect to database: %v", err)
}
device, err = storeContainer.GetFirstDevice()
if err != nil {
return device, fmt.Errorf("failed to get device: %v", err)
}
return device, nil
}

View File

@@ -0,0 +1,333 @@
// +build whatsappmulti
package bwhatsapp
import (
"context"
"errors"
"fmt"
"mime"
"os"
"path/filepath"
"time"
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/mdp/qrterminal"
"go.mau.fi/whatsmeow"
"go.mau.fi/whatsmeow/binary/proto"
"go.mau.fi/whatsmeow/types"
waLog "go.mau.fi/whatsmeow/util/log"
goproto "google.golang.org/protobuf/proto"
_ "modernc.org/sqlite" // needed for sqlite
)
const (
// Account config parameters
cfgNumber = "Number"
)
// Bwhatsapp Bridge structure keeping all the information needed for relying
type Bwhatsapp struct {
*bridge.Config
startedAt time.Time
wc *whatsmeow.Client
contacts map[types.JID]types.ContactInfo
users map[string]types.ContactInfo
userAvatars map[string]string
}
// New Create a new WhatsApp bridge. This will be called for each [whatsapp.<server>] entry you have in the config file
func New(cfg *bridge.Config) bridge.Bridger {
number := cfg.GetString(cfgNumber)
if number == "" {
cfg.Log.Fatalf("Missing configuration for WhatsApp bridge: Number")
}
b := &Bwhatsapp{
Config: cfg,
users: make(map[string]types.ContactInfo),
userAvatars: make(map[string]string),
}
return b
}
// Connect to WhatsApp. Required implementation of the Bridger interface
func (b *Bwhatsapp) Connect() error {
device, err := b.getDevice()
if err != nil {
return err
}
number := b.GetString(cfgNumber)
if number == "" {
return errors.New("whatsapp's telephone number need to be configured")
}
b.Log.Debugln("Connecting to WhatsApp..")
b.wc = whatsmeow.NewClient(device, waLog.Stdout("Client", "INFO", true))
b.wc.AddEventHandler(b.eventHandler)
firstlogin := false
var qrChan <-chan whatsmeow.QRChannelItem
if b.wc.Store.ID == nil {
firstlogin = true
qrChan, err = b.wc.GetQRChannel(context.Background())
if err != nil && !errors.Is(err, whatsmeow.ErrQRStoreContainsID) {
return errors.New("failed to to get QR channel:" + err.Error())
}
}
err = b.wc.Connect()
if err != nil {
return errors.New("failed to connect to WhatsApp: " + err.Error())
}
if b.wc.Store.ID == nil {
for evt := range qrChan {
if evt.Event == "code" {
qrterminal.GenerateHalfBlock(evt.Code, qrterminal.L, os.Stdout)
} else {
b.Log.Infof("QR channel result: %s", evt.Event)
}
}
}
// disconnect and reconnect on our first login/pairing
// for some reason the GetJoinedGroups in JoinChannel doesn't work on first login
if firstlogin {
b.wc.Disconnect()
time.Sleep(time.Second)
err = b.wc.Connect()
if err != nil {
return errors.New("failed to connect to WhatsApp: " + err.Error())
}
}
b.Log.Infoln("WhatsApp connection successful")
b.contacts, err = b.wc.Store.Contacts.GetAllContacts()
if err != nil {
return errors.New("failed to get contacts: " + err.Error())
}
b.startedAt = time.Now()
// map all the users
for id, contact := range b.contacts {
if !isGroupJid(id.String()) && id.String() != "status@broadcast" {
// it is user
b.users[id.String()] = contact
}
}
// get user avatar asynchronously
b.Log.Info("Getting user avatars..")
for jid := range b.users {
info, err := b.GetProfilePicThumb(jid)
if err != nil {
b.Log.Warnf("Could not get profile photo of %s: %v", jid, err)
} else {
b.Lock()
if info != nil {
b.userAvatars[jid] = info.URL
}
b.Unlock()
}
}
b.Log.Info("Finished getting avatars..")
return nil
}
// Disconnect is called while reconnecting to the bridge
// Required implementation of the Bridger interface
func (b *Bwhatsapp) Disconnect() error {
b.wc.Disconnect()
return nil
}
// JoinChannel Join a WhatsApp group specified in gateway config as channel='number-id@g.us' or channel='Channel name'
// Required implementation of the Bridger interface
// https://github.com/42wim/matterbridge/blob/2cfd880cdb0df29771bf8f31df8d990ab897889d/bridge/bridge.go#L11-L16
func (b *Bwhatsapp) JoinChannel(channel config.ChannelInfo) error {
byJid := isGroupJid(channel.Name)
groups, err := b.wc.GetJoinedGroups()
if err != nil {
return err
}
// verify if we are member of the given group
if byJid {
gJID, err := types.ParseJID(channel.Name)
if err != nil {
return err
}
for _, group := range groups {
if group.JID == gJID {
return nil
}
}
}
foundGroups := []string{}
for _, group := range groups {
if group.Name == channel.Name {
foundGroups = append(foundGroups, group.Name)
}
}
switch len(foundGroups) {
case 0:
// didn't match any group - print out possibilites
for _, group := range groups {
b.Log.Infof("%s %s", group.JID, group.Name)
}
return fmt.Errorf("please specify group's JID from the list above instead of the name '%s'", channel.Name)
case 1:
return fmt.Errorf("group name might change. Please configure gateway with channel=\"%v\" instead of channel=\"%v\"", foundGroups[0], channel.Name)
default:
return fmt.Errorf("there is more than one group with name '%s'. Please specify one of JIDs as channel name: %v", channel.Name, foundGroups)
}
}
// Post a document message from the bridge to WhatsApp
func (b *Bwhatsapp) PostDocumentMessage(msg config.Message, filetype string) (string, error) {
groupJID, _ := types.ParseJID(msg.Channel)
fi := msg.Extra["file"][0].(config.FileInfo)
resp, err := b.wc.Upload(context.Background(), *fi.Data, whatsmeow.MediaDocument)
if err != nil {
return "", err
}
// Post document message
var message proto.Message
message.DocumentMessage = &proto.DocumentMessage{
Title: &fi.Name,
FileName: &fi.Name,
Mimetype: &filetype,
MediaKey: resp.MediaKey,
FileEncSha256: resp.FileEncSHA256,
FileSha256: resp.FileSHA256,
FileLength: goproto.Uint64(resp.FileLength),
Url: &resp.URL,
}
b.Log.Debugf("=> Sending %#v", msg)
ID := whatsmeow.GenerateMessageID()
_, err = b.wc.SendMessage(groupJID, ID, &message)
return ID, err
}
// Post an image message from the bridge to WhatsApp
// Handle, for sure image/jpeg, image/png and image/gif MIME types
func (b *Bwhatsapp) PostImageMessage(msg config.Message, filetype string) (string, error) {
groupJID, _ := types.ParseJID(msg.Channel)
fi := msg.Extra["file"][0].(config.FileInfo)
caption := msg.Username + fi.Comment
resp, err := b.wc.Upload(context.Background(), *fi.Data, whatsmeow.MediaImage)
if err != nil {
return "", err
}
var message proto.Message
message.ImageMessage = &proto.ImageMessage{
Mimetype: &filetype,
Caption: &caption,
MediaKey: resp.MediaKey,
FileEncSha256: resp.FileEncSHA256,
FileSha256: resp.FileSHA256,
FileLength: goproto.Uint64(resp.FileLength),
Url: &resp.URL,
}
b.Log.Debugf("=> Sending %#v", msg)
ID := whatsmeow.GenerateMessageID()
_, err = b.wc.SendMessage(groupJID, ID, &message)
return ID, err
}
// Send a message from the bridge to WhatsApp
func (b *Bwhatsapp) Send(msg config.Message) (string, error) {
groupJID, _ := types.ParseJID(msg.Channel)
b.Log.Debugf("=> Receiving %#v", msg)
// Delete message
if msg.Event == config.EventMsgDelete {
if msg.ID == "" {
// No message ID in case action is executed on a message sent before the bridge was started
// and then the bridge cache doesn't have this message ID mapped
return "", nil
}
_, err := b.wc.RevokeMessage(groupJID, msg.ID)
return "", err
}
// Edit message
if msg.ID != "" {
b.Log.Debugf("updating message with id %s", msg.ID)
if b.GetString("editsuffix") != "" {
msg.Text += b.GetString("EditSuffix")
} else {
msg.Text += " (edited)"
}
}
// Handle Upload a file
if msg.Extra["file"] != nil {
fi := msg.Extra["file"][0].(config.FileInfo)
filetype := mime.TypeByExtension(filepath.Ext(fi.Name))
b.Log.Debugf("Extra file is %#v", filetype)
// TODO: add different types
// TODO: add webp conversion
switch filetype {
case "image/jpeg", "image/png", "image/gif":
return b.PostImageMessage(msg, filetype)
default:
return b.PostDocumentMessage(msg, filetype)
}
}
text := msg.Username + msg.Text
var message proto.Message
message.Conversation = &text
ID := whatsmeow.GenerateMessageID()
_, err := b.wc.SendMessage(groupJID, ID, &message)
return ID, err
}

View File

@@ -1,3 +1,55 @@
# v1.25.1
## Enhancements
- matrix: Add KeepQuotedReply option for matrix to fix regression (#1823)
- slack: Improve Slack attachments formatting (slack) (#1807)
## Bugfix
- general: Update dependencies (#1813,#1822,#1833)
- mattermost: Add space between filename and URL (mattermost). Fixes #1820
- matrix: Update matterbridge/gomatrix. Fixes #1772 (#1803)
- telegram: Do not modify .webm files (telegram). Fixes #17**88 (#1802)
- telegram: Do not apply any markup to URL entities (telegram) (#1808)
- telegram: Fix telegram message deletion request (#1818)
- vk: Fix UploadMessagesPhoto for vk community chat (vk) (#1812)
This release couldn't exist without the following contributors:
@bd808, @chugunov, @sas1024, @SevereCloud, @ValdikSS
# v1.25.0
## Breaking changes
- whatsapp: deprecated, the library <https://github.com/Rhymen/go-whatsapp> isn't maintained anymore.
We're switching to <https://github.com/tulir/whatsmeow> but as this uses a GPL3 licensed library we can't provide you with binaries.
You'll need to build it yourself. More information about this can be found here: <https://github.com/42wim/matterbridge#building-with-whatsapp-beta-multidevice-support>
## New features
- whatsappmulti: whatsapp multidevice support added - more info <https://github.com/42wim/matterbridge#building-with-whatsapp-beta-multidevice-support>
- general: Add Dockerfile_whatsappmulti for building with WhatsApp Multi-Device support (Whatsmeow) (#1774)
- telegram: Add UseFullName option (telegram) (#1777)
- slack: Use slack real name as user name (slack) (#1775)
## Enhancements
- general: Ignore sending file with comment, if comment contains IgnoreMessages value (#1783)
- general: Update dependencies (#1784)
- irc: Update lrstanley/girc dep (#1773)
- slack: Preserve threading for messages with files (slack) (#1781)
- telegram: Preserve threading from telegram replies (telegram) (#1776)
- telegram: Multiple media in one message (telegram) (#1779)
- whatsapp: Add whatsapp deprecation warning (#1792)
## Bugfix
- discord: Change discord non-native threading behaviour (discord) (#1791)
This release couldn't exist without the following contributors:
@sas1024, @tpxtron
# v1.24.1
## Enhancements

View File

@@ -1,4 +1,5 @@
// +build !nowhatsapp
// +build !whatsappmulti
package bridgemap

View File

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

View File

@@ -299,13 +299,30 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
igNicks := strings.Fields(gw.Bridges[msg.Account].GetString("IgnoreNicks"))
igMessages := strings.Fields(gw.Bridges[msg.Account].GetString("IgnoreMessages"))
if gw.ignoreTextEmpty(msg) || gw.ignoreText(msg.Username, igNicks) || gw.ignoreText(msg.Text, igMessages) {
if gw.ignoreTextEmpty(msg) || gw.ignoreText(msg.Username, igNicks) || gw.ignoreText(msg.Text, igMessages) || gw.ignoreFilesComment(msg.Extra, igMessages) {
return true
}
return false
}
// ignoreFilesComment returns true if we need to ignore a file with matched comment.
func (gw *Gateway) ignoreFilesComment(extra map[string][]interface{}, igMessages []string) bool {
if extra == nil {
return false
}
for _, f := range extra["file"] {
fi, ok := f.(config.FileInfo)
if !ok {
continue
}
if gw.ignoreText(fi.Comment, igMessages) {
return true
}
}
return false
}
func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) string {
if dest.GetBool("StripNick") {
re := regexp.MustCompile("[^a-zA-Z0-9]+")

85
go.mod
View File

@@ -6,55 +6,60 @@ require (
github.com/Benau/tgsconverter v0.0.0-20210809170556-99f4a4f6337f
github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560
github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c
github.com/SevereCloud/vksdk/v2 v2.13.1
github.com/bwmarrin/discordgo v0.24.0
github.com/SevereCloud/vksdk/v2 v2.14.0
github.com/bwmarrin/discordgo v0.25.0
github.com/d5/tengo/v2 v2.10.1
github.com/davecgh/go-spew v1.1.1
github.com/fsnotify/fsnotify v1.5.1
github.com/fsnotify/fsnotify v1.5.4
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
github.com/gomarkdown/markdown v0.0.0-20220310201231-552c6011c0b8
github.com/google/gops v0.3.22
github.com/gomarkdown/markdown v0.0.0-20220509074759-a57bf950ab8c
github.com/google/gops v0.3.23
github.com/gorilla/schema v1.2.0
github.com/gorilla/websocket v1.5.0
github.com/harmony-development/shibshib v0.0.0-20220101224523-c98059d09cfa
github.com/hashicorp/golang-lru v0.5.4
github.com/jpillora/backoff v1.0.0
github.com/keybase/go-keybase-chat-bot v0.0.0-20211201215354-ee4b23828b55
github.com/keybase/go-keybase-chat-bot v0.0.0-20220322223021-75d497527469
github.com/kyokomi/emoji/v2 v2.2.9
github.com/labstack/echo/v4 v4.7.0
github.com/lrstanley/girc v0.0.0-20211023233735-147f0ff77566
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
github.com/labstack/echo/v4 v4.7.2
github.com/lrstanley/girc v0.0.0-20220507183218-96757fe3d2a2
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696
github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be
github.com/matterbridge/gomatrix v0.0.0-20220411225302-271e5088ea27
github.com/matterbridge/gozulipbot v0.0.0-20211023205727-a19d6c1f3b75
github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba
github.com/matterbridge/matterclient v0.0.0-20211107234719-faca3cd42315
github.com/matterbridge/matterclient v0.0.0-20220430213656-07aca2731bc9
github.com/mattermost/mattermost-server/v5 v5.39.3
github.com/mattermost/mattermost-server/v6 v6.4.2
github.com/mattermost/mattermost-server/v6 v6.6.1
github.com/mattn/godown v0.0.1
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9
github.com/mdp/qrterminal v1.0.1
github.com/nelsonken/gomf v0.0.0-20190423072027-c65cc0469e94
github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
github.com/rs/xid v1.3.0
github.com/rs/xid v1.4.0
github.com/russross/blackfriday v1.6.0
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
github.com/shazow/ssh-chat v1.10.1
github.com/sirupsen/logrus v1.8.1
github.com/slack-go/slack v0.10.2
github.com/spf13/viper v1.10.1
github.com/stretchr/testify v1.7.0
github.com/slack-go/slack v0.10.3
github.com/spf13/viper v1.11.0
github.com/stretchr/testify v1.7.1
github.com/vincent-petithory/dataurl v1.0.0
github.com/writeas/go-strip-markdown v2.0.1+incompatible
github.com/yaegashi/msgraph.go v0.1.4
github.com/zfjagann/golang-ring v0.0.0-20210116075443-7c86fdb43134
golang.org/x/image v0.0.0-20220302094943-723b81ca9867
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
github.com/zfjagann/golang-ring v0.0.0-20220330170733-19bcea1b6289
go.mau.fi/whatsmeow v0.0.0-20220504135614-f1f2a9d231fb
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
golang.org/x/text v0.3.7
gomod.garykim.dev/nc-talk v0.3.0
google.golang.org/protobuf v1.28.0
gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376
layeh.com/gumble v0.0.0-20200818122324-146f9205029b
modernc.org/sqlite v1.17.2
)
require (
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/Benau/go_rlottie v0.0.0-20210807002906-98c1b2421989 // indirect
github.com/Jeffail/gabs v1.4.0 // indirect
github.com/apex/log v1.9.0 // indirect
@@ -68,15 +73,17 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gopackage/ddp v0.0.3 // indirect
github.com/graph-gophers/graphql-go v1.3.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kettek/apng v0.0.0-20191108220231-414630eed80f // indirect
github.com/klauspost/compress v1.14.2 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/klauspost/compress v1.15.1 // indirect
github.com/klauspost/cpuid/v2 v2.0.11 // indirect
github.com/labstack/gommon v0.3.1 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d // indirect
github.com/mattermost/logr v1.0.13 // indirect
@@ -86,7 +93,7 @@ require (
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.16 // indirect
github.com/minio/minio-go/v7 v7.0.23 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
@@ -95,18 +102,21 @@ require (
github.com/monaco-io/request v1.0.5 // indirect
github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d // indirect
github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pborman/uuid v1.2.1 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect
github.com/philhofer/fwd v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rickb777/date v1.12.4 // indirect
github.com/rickb777/plural v1.2.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/shazow/rateio v0.0.0-20200113175441-4461efc8bdc4 // indirect
github.com/sizeofint/webpanimation v0.0.0-20210809145948-1d2b32119882 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
@@ -119,22 +129,35 @@ require (
github.com/wiggin77/cfg v1.0.2 // indirect
github.com/wiggin77/merror v1.0.3 // indirect
github.com/wiggin77/srslog v1.0.1 // indirect
go.mau.fi/libsignal v0.0.0-20220425070825-c40c839ee6a0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.17.0 // indirect
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
golang.org/x/mod v0.5.1 // indirect
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
golang.org/x/tools v0.1.9 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
lukechampine.com/uint128 v1.1.1 // indirect
modernc.org/cc/v3 v3.36.0 // indirect
modernc.org/ccgo/v3 v3.16.6 // indirect
modernc.org/libc v1.16.7 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.1.1 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/strutil v1.1.1 // indirect
modernc.org/token v1.0.0 // indirect
rsc.io/qr v0.2.0 // indirect
)
replace github.com/matrix-org/gomatrix => github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419
//replace github.com/matrix-org/gomatrix => github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419
go 1.17

401
go.sum
View File

@@ -7,6 +7,7 @@ cloud.google.com/go v0.37.1/go.mod h1:SAbnLi6YTSPKSI0dTUEOVLCkyPfKXK8n4ibqiMoj4o
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
@@ -21,6 +22,7 @@ cloud.google.com/go v0.64.0/go.mod h1:xfORb36jGvE+6EexW71nMEtL025s3x6xvuYUKM4JLv
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
@@ -32,13 +34,18 @@ cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aD
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
@@ -54,6 +61,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
code.sajari.com/docconv v1.1.1-0.20210427001343-7b3472bc323a/go.mod h1:KPNt2zuWplps1W0TpOb6ltHj4Xu+j6h7a+YkqGHrxQE=
code.sajari.com/docconv v1.2.0/go.mod h1:r8yfCP6OKbZ9Xkd87aBa4nfpk6ud/PoyLwex3n6cXSc=
contrib.go.opencensus.io/exporter/ocagent v0.4.9/go.mod h1:ueLzZcP7LPhPulEBukGn4aLh7Mx9YJwpVJ9nL2FYltw=
@@ -62,6 +70,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
@@ -112,7 +122,7 @@ github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2o
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Masterminds/squirrel v1.5.1/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Masterminds/squirrel v1.5.2/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
@@ -149,8 +159,8 @@ github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c/go.mod h1:DNS
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/RoaringBitmap/roaring v0.8.0/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I=
github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
github.com/SevereCloud/vksdk/v2 v2.13.1 h1:D11NaP275mW01v2hRF0ycDHdJaIyZEvasZV4MSkg5Sk=
github.com/SevereCloud/vksdk/v2 v2.13.1/go.mod h1:UyOgSj/CYt2dByu3Fyf/y1yT1NoahVi4zECvvrbtPU4=
github.com/SevereCloud/vksdk/v2 v2.14.0 h1:1lciJC4FWhSQIjjFb3NGyJI7x9sPKk/P6aAvR0ibh1o=
github.com/SevereCloud/vksdk/v2 v2.14.0/go.mod h1:J/iPooVfldjVADo47G5aNxkvlRWAsZnMHpri8sZmck4=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
@@ -206,7 +216,7 @@ github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
github.com/aws/aws-sdk-go v1.19.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.38.67/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.42.11/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
github.com/aws/aws-sdk-go v1.43.6/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go-v2 v1.8.0/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0=
github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2/config v1.6.0/go.mod h1:TNtBVmka80lRPk5+S9ZqVfFszOQAGJJ9KbT3EM3CHNU=
@@ -234,6 +244,7 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21
github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -252,7 +263,7 @@ github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blevesearch/bleve v1.0.14/go.mod h1:e/LJTr+E7EaoVdkQZTfoz7dt4KoDNvDbLb8MSKuNTLQ=
github.com/blevesearch/bleve/v2 v2.3.0/go.mod h1:egW/6gZEhM3oBvRjuHXGvGb92cKZ9867OqPZAmCG8MQ=
github.com/blevesearch/bleve/v2 v2.3.1/go.mod h1:kAJuWn2L1TNSUyxtPJD4AGma2/PgMSm7GBlx61F9OBs=
github.com/blevesearch/bleve_index_api v1.0.1/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
github.com/blevesearch/blevex v1.0.0/go.mod h1:2rNVqoG2BZI8t1/P1awgTKnGlx5MP9ZbtEciQaNhswc=
github.com/blevesearch/cld2 v0.0.0-20200327141045-8b5f551d37f5/go.mod h1:PN0QNTLs9+j1bKy3d/GB/59wsNBFC4sWLWG3k69lWbc=
@@ -269,11 +280,11 @@ github.com/blevesearch/zap/v12 v12.0.14/go.mod h1:rOnuZOiMKPQj18AEKEHJxuI14236tT
github.com/blevesearch/zap/v13 v13.0.6/go.mod h1:L89gsjdRKGyGrRN6nCpIScCvvkyxvmeDCwZRcjjPCrw=
github.com/blevesearch/zap/v14 v14.0.5/go.mod h1:bWe8S7tRrSBTIaZ6cLRbgNH4TUDaC9LZSpRGs85AsGY=
github.com/blevesearch/zap/v15 v15.0.3/go.mod h1:iuwQrImsh1WjWJ0Ue2kBqY83a0rFtJTqfa9fp1rbVVU=
github.com/blevesearch/zapx/v11 v11.3.2/go.mod h1:YzTfUm4kS3e8OmTXDHVV8OzC5MWPO/VPJZQgPNVb4Lc=
github.com/blevesearch/zapx/v12 v12.3.2/go.mod h1:RMl6lOZqF+sTxKvhQDJ5yK2LT3Mu7E2p/jGdjAaiRxs=
github.com/blevesearch/zapx/v13 v13.3.2/go.mod h1:eppobNM35U4C22yDvTuxV9xPqo10pwfP/jugL4INWG4=
github.com/blevesearch/zapx/v14 v14.3.2/go.mod h1:zXNcVzukh0AvG57oUtT1T0ndi09H0kELNaNmekEy0jw=
github.com/blevesearch/zapx/v15 v15.3.2/go.mod h1:C+f/97ZzTzK6vt/7sVlZdzZxKu+5+j4SrGCvr9dJzaY=
github.com/blevesearch/zapx/v11 v11.3.3/go.mod h1:YzTfUm4kS3e8OmTXDHVV8OzC5MWPO/VPJZQgPNVb4Lc=
github.com/blevesearch/zapx/v12 v12.3.3/go.mod h1:RMl6lOZqF+sTxKvhQDJ5yK2LT3Mu7E2p/jGdjAaiRxs=
github.com/blevesearch/zapx/v13 v13.3.3/go.mod h1:eppobNM35U4C22yDvTuxV9xPqo10pwfP/jugL4INWG4=
github.com/blevesearch/zapx/v14 v14.3.3/go.mod h1:zXNcVzukh0AvG57oUtT1T0ndi09H0kELNaNmekEy0jw=
github.com/blevesearch/zapx/v15 v15.3.3/go.mod h1:C+f/97ZzTzK6vt/7sVlZdzZxKu+5+j4SrGCvr9dJzaY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
@@ -283,8 +294,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/bwmarrin/discordgo v0.24.0 h1:Gw4MYxqHdvhO99A3nXnSLy97z5pmIKHZVJ1JY5ZDPqY=
github.com/bwmarrin/discordgo v0.24.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/bwmarrin/discordgo v0.25.0 h1:NXhdfHRNxtwso6FPdzW2i3uBvvU7UIQTghmV2T4nqAs=
github.com/bwmarrin/discordgo v0.25.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -433,6 +444,7 @@ github.com/couchbase/vellum v1.0.2/go.mod h1:FcwrEivFpNi24R3jLOs3n+fs5RnuQnQqCLB
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -537,8 +549,9 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
@@ -547,13 +560,12 @@ github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYis
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/getsentry/sentry-go v0.11.0/go.mod h1:KBQIxiZAetw62Cj8Ri964vAEWVdgfaUCn30Q3bCvANo=
github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gigawattio/window v0.0.0-20180317192513-0f5467e35573/go.mod h1:eBvb3i++NHDH4Ugo9qCvMw8t0mTSctaEa5blJbWcNxs=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
@@ -580,7 +592,6 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-morph/morph v0.2.3-0.20220126093237-74bffc135498/go.mod h1:XQh5WcM351wOV3z3zEWRM8RaJ65E2p4P7WWbmFAi8x4=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.2.6-0.20210915003542-8b1f7f90f6b1/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
@@ -590,8 +601,6 @@ github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL9
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-redis/redis/v8 v8.0.0/go.mod h1:isLoQT/NFSP7V67lyvM9GmdvLdyZ7pEhsXvvyQtnQTo=
github.com/go-redis/redis/v8 v8.10.0/go.mod h1:vXLTvigok0VtUX0znvbcEW1SOt4OA9CU1ZfnOtKOaiM=
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
@@ -702,8 +711,8 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomarkdown/markdown v0.0.0-20220310201231-552c6011c0b8 h1:YVvt637ygnOO9qjLBVmPOvrUmCz/i8YECSu/8UlOQW0=
github.com/gomarkdown/markdown v0.0.0-20220310201231-552c6011c0b8/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/gomarkdown/markdown v0.0.0-20220509074759-a57bf950ab8c h1:yGxnjZegu9T/94575b5UGf2uDDYN3elzreWYpkhw2f4=
github.com/gomarkdown/markdown v0.0.0-20220509074759-a57bf950ab8c/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -722,15 +731,16 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-github/v35 v35.2.0/go.mod h1:s0515YVTI+IMrDoy9Y4pHt9ShGpzHvHO8rZ7L7acgvs=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gops v0.3.22 h1:lyvhDxfPLHAOR2xIYwjPhN387qHxyU21Sk9sz/GhmhQ=
github.com/google/gops v0.3.22/go.mod h1:7diIdLsqpCihPSX3fQagksT/Ku/y4RL9LHTlKyEUDl8=
github.com/google/gops v0.3.23 h1:OjsHRINl5FiIyTc8jivIg4UN0GY6Nh32SL8KRbl8GQo=
github.com/google/gops v0.3.23/go.mod h1:7diIdLsqpCihPSX3fQagksT/Ku/y4RL9LHTlKyEUDl8=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -744,6 +754,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
@@ -763,15 +774,19 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopackage/ddp v0.0.3 h1:fd0DxScoiS+ogq22ktey6DjDSDybtJPAn69geMpUtFc=
github.com/gopackage/ddp v0.0.3/go.mod h1:3hUXYG6C/6JsoxKsQaK7st09+GP9RZBFPzyAlU/0SLg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20210621113107-84c6004145de/go.mod h1:MtKwTfDNYAP5EtbQSMYjTSqvj1aXJKQRASWq3bwaP+g=
github.com/gopherjs/gopherjs v0.0.0-20211111143520-d0d5ecc1a356 h1:d3wWSjdOuGrMHa8+Tvw3z9EGPzATpzVq1BmGK3+IyeU=
github.com/gopherjs/gopherjs v0.0.0-20211111143520-d0d5ecc1a356/go.mod h1:cz9oNYuRUWGdHmLF2IodMLkAhcPtXeULvcBNagUrxTI=
github.com/gopherjs/gopherjs v0.0.0-20220221023154-0b2280d3ff96 h1:QJq7UBOuoynsywLk+aC75rC2Cbi2+lQRDaLaizhA+fA=
github.com/gopherjs/gopherjs v0.0.0-20220221023154-0b2280d3ff96/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
@@ -788,6 +803,8 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0=
github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
@@ -806,6 +823,7 @@ github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1p
github.com/harmony-development/shibshib v0.0.0-20220101224523-c98059d09cfa h1:0EefSRfsNrdEwmoGVz4+cMG8++5M2XhvJ1tTRmmrJu8=
github.com/harmony-development/shibshib v0.0.0-20220101224523-c98059d09cfa/go.mod h1:+KEOMb29OC2kRa5BajwNM2NEjHTbQA/Z3gKYARLHREI=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
@@ -820,6 +838,8 @@ github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.1.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
@@ -850,12 +870,17 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/memberlist v0.2.4/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20210316155119-a95892c5f864/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
@@ -974,11 +999,12 @@ github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYb
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kettek/apng v0.0.0-20191108220231-414630eed80f h1:dnCYnTSltLuPMfc7dMrkz2uBUcEf/OFBR8yRh3oRT98=
github.com/kettek/apng v0.0.0-20191108220231-414630eed80f/go.mod h1:x78/VRQYKuCftMWS0uK5e+F5RJ7S4gSlESRWI0Prl6Q=
github.com/keybase/go-keybase-chat-bot v0.0.0-20211201215354-ee4b23828b55 h1:4UNIfjcTO4D6RmO7QhXxh4IyM5yANg6pwBldHR4a27w=
github.com/keybase/go-keybase-chat-bot v0.0.0-20211201215354-ee4b23828b55/go.mod h1:0tIbyC7O87PimRbeghiJW5JAsmdKwNmAoNWFczKDZUA=
github.com/keybase/go-keybase-chat-bot v0.0.0-20220322223021-75d497527469 h1:TNT0A/iqWZhj0T82eaSxwgjtvkhUPsx4W2HMC3079Mw=
github.com/keybase/go-keybase-chat-bot v0.0.0-20220322223021-75d497527469/go.mod h1:0tIbyC7O87PimRbeghiJW5JAsmdKwNmAoNWFczKDZUA=
github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@@ -996,8 +1022,9 @@ github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw=
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
@@ -1006,8 +1033,8 @@ github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.11 h1:i2lw1Pm7Yi/4O6XCSyJWqEHI2MDw2FzUK6o/D21xn2A=
github.com/klauspost/cpuid/v2 v2.0.11/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw=
@@ -1032,15 +1059,15 @@ github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq
github.com/kyokomi/emoji/v2 v2.2.9 h1:UWYkjplPZ4rMPvLxc+/e12/xTqoRcn55oUySkpZ554g=
github.com/kyokomi/emoji/v2 v2.2.9/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/echo/v4 v4.7.0 h1:8wHgZhoE9OT1NSLw6sfrX7ZGpWMtO5Zlfr68+BIo180=
github.com/labstack/echo/v4 v4.7.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/ledongthuc/pdf v0.0.0-20210621053716-e28cb8259002/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/levigross/exp-html v0.0.0-20120902181939-8df60c69a8f5/go.mod h1:QMe2wuKJ0o7zIVE8AqiT8rd8epmm6WDIZ2wyuBqYPzM=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -1050,14 +1077,15 @@ github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lrstanley/girc v0.0.0-20211023233735-147f0ff77566 h1:tseAo8DbdhZa+PLuJW0p/P8b7I9LUiVpIpboAHkLsoM=
github.com/lrstanley/girc v0.0.0-20211023233735-147f0ff77566/go.mod h1:liX5MxHPrwgHaKowoLkYGwbXfYABh1jbZ6FpElbGF1I=
github.com/lrstanley/girc v0.0.0-20220507183218-96757fe3d2a2 h1:iqJKGIChW2+aPIpnofEZAKgCNwG2tqytB2a1rJS6B6w=
github.com/lrstanley/girc v0.0.0-20220507183218-96757fe3d2a2/go.mod h1:lgrnhcF8bg/Bd5HA5DOb4Z+uGqUqGnp4skr+J2GwVgI=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -1072,14 +1100,14 @@ github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696 h1
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be h1:zlirT+LngOJ60G6FVzI87DljGZLUnfNzmXja61EjtYM=
github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q=
github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419 h1:dx8x2J3EsVwP3hBGNmVT/otz4b42p7TRQ6Cu4BK2910=
github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419/go.mod h1:/x38AoZf70fK9yZ5gs3BNCaF7/J4QEo4ZpwtLjX95eQ=
github.com/matterbridge/gomatrix v0.0.0-20220411225302-271e5088ea27 h1:9XSppnbvvReVom+wphkeF4lbhuT6vCYIdyzpwFtW89c=
github.com/matterbridge/gomatrix v0.0.0-20220411225302-271e5088ea27/go.mod h1:/x38AoZf70fK9yZ5gs3BNCaF7/J4QEo4ZpwtLjX95eQ=
github.com/matterbridge/gozulipbot v0.0.0-20211023205727-a19d6c1f3b75 h1:GslZKF7lW7oSisycGLpxPO+TnKJuA4VZuTWIfYZrClc=
github.com/matterbridge/gozulipbot v0.0.0-20211023205727-a19d6c1f3b75/go.mod h1:yAjnZ34DuDyPHMPHHjOsTk/FefW4JJjoMMCGt/8uuQA=
github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba h1:XleOY4IjAEIcxAh+IFwT5JT5Ze3RHiYz6m+4ZfZ0rc0=
github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba/go.mod h1:iXGEotOvwI1R1SjLxRc+BF5rUORTMtE0iMZBT2lxqAU=
github.com/matterbridge/matterclient v0.0.0-20211107234719-faca3cd42315 h1:vkdXJ8GsuIR0JH9e4eHomVliTou08PMqAImZNBlLd/A=
github.com/matterbridge/matterclient v0.0.0-20211107234719-faca3cd42315/go.mod h1:Gh3tFUjkcPIBBeEkfXBbGio4ONMMKNmlmGECvXLY0TE=
github.com/matterbridge/matterclient v0.0.0-20220430213656-07aca2731bc9 h1:EOwZ5yJv4o2px4TEJh15aqbZsKoY9MVunan6ngqs0Rk=
github.com/matterbridge/matterclient v0.0.0-20220430213656-07aca2731bc9/go.mod h1:Gh3tFUjkcPIBBeEkfXBbGio4ONMMKNmlmGECvXLY0TE=
github.com/mattermost/go-i18n v1.11.0/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34=
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 h1:Khvh6waxG1cHc4Cz5ef9n3XVCxRWpAKUtqg9PJl5+y8=
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34=
@@ -1097,8 +1125,9 @@ github.com/mattermost/logr/v2 v2.0.15/go.mod h1:mpPp935r5dIkFDo2y9Q87cQWhFR/4xXp
github.com/mattermost/mattermost-server/v5 v5.39.3 h1:A5z/NlR4Xcwxx5UnlaNgUGP5hgj4KOV/CwpFg3OtlvQ=
github.com/mattermost/mattermost-server/v5 v5.39.3/go.mod h1:MDmVSmsSsqwNkuZ7rQ0osuXVCzrR1IUqGR7I0QU91sY=
github.com/mattermost/mattermost-server/v6 v6.0.0/go.mod h1:+S8CsNEPv1FOl1usaPBQ6Gu9+Sm1Cc9YdU/Qh1YMGVI=
github.com/mattermost/mattermost-server/v6 v6.4.2 h1:UyrYoBYrV7dB7JWSEOPXKZaTyYZE2PRDysqx/54ayng=
github.com/mattermost/mattermost-server/v6 v6.4.2/go.mod h1:5dOl/bx4N9iTytZ4p44xfGiOiZelbdap42FbEjmN+FU=
github.com/mattermost/mattermost-server/v6 v6.6.1 h1:jza7N9OMqFe+z7s9LZeSj1M4E/2DOV/llIUpi9VWg2U=
github.com/mattermost/mattermost-server/v6 v6.6.1/go.mod h1:oR6UCRo+SEvnfN2FEOdzHs1UljrskyCKU8tWeKlxgMo=
github.com/mattermost/morph v0.0.0-20220401091636-39f834798da8/go.mod h1:jxM3g1bx+k2Thz7jofcHguBS8TZn5Pc+o5MGmORObhw=
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0/go.mod h1:nV5bfVpT//+B1RPD2JvRnxbkLmJEYXmRaaVl15fsXjs=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
@@ -1135,12 +1164,17 @@ github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vq
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/godown v0.0.1 h1:39uk50ufLVQFs0eapIJVX5fCS74a1Fs2g5f1MVqIHdE=
github.com/mattn/godown v0.0.1/go.mod h1:/ivCKurgV/bx6yqtP/Jtc2Xmrv3beCYBvlfAUl4X5g4=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mdp/qrterminal v1.0.1 h1:07+fzVDlPuBlXS8tB0ktTAyf+Lp1j2+2zK3fBOL5b7c=
github.com/mdp/qrterminal v1.0.1/go.mod h1:Z33WhxQe9B6CdW37HaVqcRKzP+kByF3q/qLxOGe12xQ=
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
@@ -1149,23 +1183,29 @@ github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXd
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.46/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.11/go.mod h1:WoyW+ySKAKjY98B9+7ZbI8z8S3jaxaisdcvj9TGlazA=
github.com/minio/minio-go/v7 v7.0.16 h1:GspaSBS8lOuEUCAqMe0W3UxSoyOA4b4F8PTspRVI+k4=
github.com/minio/minio-go/v7 v7.0.16/go.mod h1:pUV0Pc+hPd1nccgmzQF/EXh48l/Z/yps6QPF1aaie4g=
github.com/minio/minio-go/v7 v7.0.23 h1:NleyGQvAn9VQMU+YHVrgV4CX+EPtxPt/78lHOOTncy4=
github.com/minio/minio-go/v7 v7.0.23/go.mod h1:ei5JjmxwHaMrgsMrn4U/+Nmg+d8MKS1U2DAn1ou4+Do=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -1224,8 +1264,8 @@ github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 h1:mp6tU1r0xLostUGLkTspf/9/AiHuVD7ptyXhySkDEsE=
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9/go.mod h1:A5SRAcpTemjGgIuBq6Kic2yHcoeUFWUinOAlMP/i9xo=
github.com/nelsonken/gomf v0.0.0-20190423072027-c65cc0469e94 h1:GRBho7BMw6le5OVegxDeFX+Ul1WPykzQs9CVrifrjik=
github.com/nelsonken/gomf v0.0.0-20190423072027-c65cc0469e94/go.mod h1:UT7a3UHzG7jEEeoW/AI2/e0RuLbkntdsiY94qt6Jv7Q=
github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
@@ -1271,6 +1311,7 @@ github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/oov/psd v0.0.0-20210618170533-9fb823ddb631/go.mod h1:GHI1bnmAcbp96z6LNfBJvtrjxhaXGkbsk967utPlvL8=
github.com/oov/psd v0.0.0-20220121172623-5db5eafcecbb/go.mod h1:GHI1bnmAcbp96z6LNfBJvtrjxhaXGkbsk967utPlvL8=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -1294,6 +1335,8 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
@@ -1316,6 +1359,8 @@ github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrap
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.0-beta.8 h1:dy81yyLYJDwMTifq24Oi/IslOslRrDSb3jwDggjz3Z0=
github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/peterbourgon/diskv v0.0.0-20171120014656-2973218375c3/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
@@ -1327,7 +1372,7 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.11/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
@@ -1339,6 +1384,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@@ -1355,6 +1401,7 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O
github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -1391,8 +1438,10 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/reflog/dateconstraints v0.2.1/go.mod h1:Ax8AxTBcJc3E/oVS2hd2j7RDM/5MDtuPwuR7lIHtPLo=
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rickb777/date v1.12.4 h1:+6IzcCCS/1t17DrmnEvrznyq7nM8vPwir6/UhlyohKw=
github.com/rickb777/date v1.12.4/go.mod h1:xP0eo/I5qmUt97yRGClHZfyLZ3ikMw6v6SU5MOGZTE0=
@@ -1412,25 +1461,29 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rudderlabs/analytics-go v3.3.1+incompatible/go.mod h1:LF8/ty9kUX4PTY3l5c97K3nZZaX5Hwsvt+NBaRL/f30=
github.com/rudderlabs/analytics-go v3.3.2+incompatible/go.mod h1:LF8/ty9kUX4PTY3l5c97K3nZZaX5Hwsvt+NBaRL/f30=
github.com/russellhaering/goxmldsig v1.1.0/go.mod h1:QK8GhXPB3+AfuCrfo0oRISa9NfzeCpWmxeGnqEpDF9o=
github.com/russellhaering/goxmldsig v1.1.1/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/satori/go.uuid v0.0.0-20180103174451-36e9d2ebbde5/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
@@ -1489,10 +1542,10 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sizeofint/webpanimation v0.0.0-20210809145948-1d2b32119882 h1:A7o8tOERTtpD/poS+2VoassCjXpjHn916luXbf5QKD0=
github.com/sizeofint/webpanimation v0.0.0-20210809145948-1d2b32119882/go.mod h1:5IwJoz9Pw7JsrCN4/skkxUtSWT7myuUPLhCgv6Q5vvQ=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/slack-go/slack v0.10.2 h1:KMN/h2sgUninHXvQI8PrR/PHBUuWp2NPvz2Kr66tki4=
github.com/slack-go/slack v0.10.2/go.mod h1:5FLdBRv7VW/d9EBxx/eEktOptWygbA9K2QK/KW7ds1s=
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.10.3 h1:kKYwlKY73AfSrtAk9UHWCXXfitudkDztNI9GYBviLxw=
github.com/slack-go/slack v0.10.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
@@ -1511,8 +1564,9 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
@@ -1523,6 +1577,7 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@@ -1536,8 +1591,9 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk=
github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU=
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
github.com/spf13/viper v1.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44=
github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk=
github.com/splitio/go-client/v6 v6.1.0/go.mod h1:CEGAEFT99Fwb32ZIRcnZoXTMXddtB6IIpTmt3RP8mnM=
github.com/splitio/go-split-commons/v3 v3.1.0/go.mod h1:29NCy20oAS4ZMy4qkwTd6277eieVDonx4V/aeDU/wUQ=
github.com/splitio/go-toolkit/v4 v4.2.0/go.mod h1:EdIHN0yzB1GTXDYQc0KdKvnjkO/jfUM2YqHVYfhD3Wo=
@@ -1557,8 +1613,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@@ -1571,7 +1628,7 @@ github.com/tebeka/snowball v0.4.2/go.mod h1:4IfL14h1lvwZcp1sfXuuc7/7yCsvVffTWxWx
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
github.com/throttled/throttled v2.2.5+incompatible/go.mod h1:0BjlrEGQmvxps+HuXLsyRdqpSRvJpq0PNIsOtqP9Nos=
github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk=
github.com/tidwall/gjson v1.11.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
@@ -1595,6 +1652,7 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/tylerb/graceful v1.2.15/go.mod h1:LPYTbOYmUTdabwRt0TGhLllQ0MUNbs0Y5q1WXJOI9II=
github.com/uber/jaeger-client-go v2.29.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
@@ -1676,14 +1734,14 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.7/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/zfjagann/golang-ring v0.0.0-20210116075443-7c86fdb43134 h1:itYC8Ycx8aVBN7a8q1Yr187W5WmQthvYU13+f4rOWkU=
github.com/zfjagann/golang-ring v0.0.0-20210116075443-7c86fdb43134/go.mod h1:0MsIttMJIF/8Y7x0XjonJP7K99t3sR6bjj4m5S4JmqU=
github.com/zfjagann/golang-ring v0.0.0-20220330170733-19bcea1b6289 h1:dEdcEes8Aki8XrgZFyrZvtazFlW4U7eNvX9NuyFJAtQ=
github.com/zfjagann/golang-ring v0.0.0-20220330170733-19bcea1b6289/go.mod h1:0MsIttMJIF/8Y7x0XjonJP7K99t3sR6bjj4m5S4JmqU=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@@ -1693,10 +1751,17 @@ go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
go.etcd.io/etcd/client/v2 v2.305.2/go.mod h1:2D7ZejHVMIfog1221iLSYlQRzrtECw3kz4I4VAQm3qI=
go.mau.fi/libsignal v0.0.0-20220425070825-c40c839ee6a0 h1:3IQF2bgAyibdo77hTejwuJe4jlypj9QaE4xCQuxrThM=
go.mau.fi/libsignal v0.0.0-20220425070825-c40c839ee6a0/go.mod h1:kBOXTvYyDG/q1Ihgvd4J6WenGPh7wtEGvPKF6vmf5ak=
go.mau.fi/whatsmeow v0.0.0-20220504135614-f1f2a9d231fb h1:xI4HiJwBMmztBXFzjKWt7Ea8xmOO7LyYCYV0/ROU7kY=
go.mau.fi/whatsmeow v0.0.0-20220504135614-f1f2a9d231fb/go.mod h1:iUBgOLNaqShLrR17u0kIiRptIGFH+nbT1tRhaWBEX/c=
go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
@@ -1777,8 +1842,10 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1807,8 +1874,8 @@ golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 h1:TcHcE0vrmgzNH1v3ppjcMGbhG5+9fMuvOmUYwNEF4q4=
golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 h1:LRtI4W37N+KFebI/qV0OFiLUv4GLOWeEW5hn/KEJvxE=
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1836,6 +1903,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1908,16 +1976,19 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211013171255-e13a2654a71e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4=
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1941,8 +2012,10 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
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=
@@ -2053,16 +2126,17 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -2073,7 +2147,6 @@ golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210818153620-00dd8d7831e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -2083,11 +2156,20 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
@@ -2190,20 +2272,24 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomod.garykim.dev/nc-talk v0.3.0 h1:MZxLc/gX2/+bdOw4xt6pi+qQFUQld1woGfw1hEJ0fbM=
gomod.garykim.dev/nc-talk v0.3.0/go.mod h1:q/Adot/H7iqi+H4lANopV7/xcMf+sX3AZXUXqiITwok=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
@@ -2250,7 +2336,12 @@ google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -2312,8 +2403,10 @@ google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@@ -2341,8 +2434,19 @@ google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -2381,7 +2485,8 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -2395,8 +2500,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
@@ -2412,16 +2518,15 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.64.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
@@ -2497,35 +2602,167 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
layeh.com/gopus v0.0.0-20161224163843-0ebf989153aa/go.mod h1:AOef7vHz0+v4sWwJnr0jSyHiX/1NgsMoaxl+rEPz/I0=
layeh.com/gumble v0.0.0-20200818122324-146f9205029b h1:Kne6wkHqbqrygRsqs5XUNhSs84DFG5TYMeCkCbM56sY=
layeh.com/gumble v0.0.0-20200818122324-146f9205029b/go.mod h1:tWPVA9ZAfImNwabjcd9uDE+Mtz0Hfs7a7G3vxrnrwyc=
lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg=
modernc.org/cc/v3 v3.32.4/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878=
modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.33.11/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.34.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.4/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.5/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.7/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.8/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.10/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/cc/v3 v3.36.0 h1:0kmRkTmqNidmu3c7BNDSdVHCxXCkWLmWmCIVX4LUboo=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
modernc.org/ccgo/v3 v3.9.2/go.mod h1:gnJpy6NIVqkETT+L5zPsQFj7L2kkhfPMzOghRNv/CFo=
modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw=
modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI=
modernc.org/ccgo/v3 v3.11.1/go.mod h1:lWHxfsn13L3f7hgGsGlU28D9eUOf6y3ZYHKoPaKU0ag=
modernc.org/ccgo/v3 v3.11.3/go.mod h1:0oHunRBMBiXOKdaglfMlRPBALQqsfrCKXgw9okQ3GEw=
modernc.org/ccgo/v3 v3.12.4/go.mod h1:Bk+m6m2tsooJchP/Yk5ji56cClmN6R1cqc9o/YtbgBQ=
modernc.org/ccgo/v3 v3.12.6/go.mod h1:0Ji3ruvpFPpz+yu+1m0wk68pdr/LENABhTrDkMDWH6c=
modernc.org/ccgo/v3 v3.12.8/go.mod h1:Hq9keM4ZfjCDuDXxaHptpv9N24JhgBZmUG5q60iLgUo=
modernc.org/ccgo/v3 v3.12.11/go.mod h1:0jVcmyDwDKDGWbcrzQ+xwJjbhZruHtouiBEvDfoIsdg=
modernc.org/ccgo/v3 v3.12.14/go.mod h1:GhTu1k0YCpJSuWwtRAEHAol5W7g1/RRfS4/9hc9vF5I=
modernc.org/ccgo/v3 v3.12.18/go.mod h1:jvg/xVdWWmZACSgOiAhpWpwHWylbJaSzayCqNOJKIhs=
modernc.org/ccgo/v3 v3.12.20/go.mod h1:aKEdssiu7gVgSy/jjMastnv/q6wWGRbszbheXgWRHc8=
modernc.org/ccgo/v3 v3.12.21/go.mod h1:ydgg2tEprnyMn159ZO/N4pLBqpL7NOkJ88GT5zNU2dE=
modernc.org/ccgo/v3 v3.12.22/go.mod h1:nyDVFMmMWhMsgQw+5JH6B6o4MnZ+UQNw1pp52XYFPRk=
modernc.org/ccgo/v3 v3.12.25/go.mod h1:UaLyWI26TwyIT4+ZFNjkyTbsPsY3plAEB6E7L/vZV3w=
modernc.org/ccgo/v3 v3.12.29/go.mod h1:FXVjG7YLf9FetsS2OOYcwNhcdOLGt8S9bQ48+OP75cE=
modernc.org/ccgo/v3 v3.12.36/go.mod h1:uP3/Fiezp/Ga8onfvMLpREq+KUjUmYMxXPO8tETHtA8=
modernc.org/ccgo/v3 v3.12.38/go.mod h1:93O0G7baRST1vNj4wnZ49b1kLxt0xCW5Hsa2qRaZPqc=
modernc.org/ccgo/v3 v3.12.43/go.mod h1:k+DqGXd3o7W+inNujK15S5ZYuPoWYLpF5PYougCmthU=
modernc.org/ccgo/v3 v3.12.46/go.mod h1:UZe6EvMSqOxaJ4sznY7b23/k13R8XNlyWsO5bAmSgOE=
modernc.org/ccgo/v3 v3.12.47/go.mod h1:m8d6p0zNps187fhBwzY/ii6gxfjob1VxWb919Nk1HUk=
modernc.org/ccgo/v3 v3.12.50/go.mod h1:bu9YIwtg+HXQxBhsRDE+cJjQRuINuT9PUK4orOco/JI=
modernc.org/ccgo/v3 v3.12.51/go.mod h1:gaIIlx4YpmGO2bLye04/yeblmvWEmE4BBBls4aJXFiE=
modernc.org/ccgo/v3 v3.12.53/go.mod h1:8xWGGTFkdFEWBEsUmi+DBjwu/WLy3SSOrqEmKUjMeEg=
modernc.org/ccgo/v3 v3.12.54/go.mod h1:yANKFTm9llTFVX1FqNKHE0aMcQb1fuPJx6p8AcUx+74=
modernc.org/ccgo/v3 v3.12.55/go.mod h1:rsXiIyJi9psOwiBkplOaHye5L4MOOaCjHg1Fxkj7IeU=
modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU=
modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc=
modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM=
modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ=
modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84=
modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ=
modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
modernc.org/ccgo/v3 v3.12.84/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
modernc.org/ccgo/v3 v3.12.86/go.mod h1:dN7S26DLTgVSni1PVA3KxxHTcykyDurf3OgUzNqTSrU=
modernc.org/ccgo/v3 v3.12.88/go.mod h1:0MFzUHIuSIthpVZyMWiFYMwjiFnhrN5MkvBrUwON+ZM=
modernc.org/ccgo/v3 v3.12.90/go.mod h1:obhSc3CdivCRpYZmrvO88TXlW0NvoSVvdh/ccRjJYko=
modernc.org/ccgo/v3 v3.12.92/go.mod h1:5yDdN7ti9KWPi5bRVWPl8UNhpEAtCjuEE7ayQnzzqHA=
modernc.org/ccgo/v3 v3.12.95/go.mod h1:ZcLyvtocXYi8uF+9Ebm3G8EF8HNY5hGomBqthDp4eC8=
modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccgo/v3 v3.16.6 h1:3l18poV+iUemQ98O3X5OMr97LOqlzis+ytivU4NqGhA=
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8=
modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw=
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM=
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.5/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg=
modernc.org/libc v1.11.2/go.mod h1:ioIyrl3ETkugDO3SGZ+6EOKvlP3zSOycUETe4XM4n8M=
modernc.org/libc v1.11.5/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU=
modernc.org/libc v1.11.6/go.mod h1:ddqmzR6p5i4jIGK1d/EiSw97LBcE3dK24QEwCFvgNgE=
modernc.org/libc v1.11.11/go.mod h1:lXEp9QOOk4qAYOtL3BmMve99S5Owz7Qyowzvg6LiZso=
modernc.org/libc v1.11.13/go.mod h1:ZYawJWlXIzXy2Pzghaf7YfM8OKacP3eZQI81PDLFdY8=
modernc.org/libc v1.11.16/go.mod h1:+DJquzYi+DMRUtWI1YNxrlQO6TcA5+dRRiq8HWBWRC8=
modernc.org/libc v1.11.19/go.mod h1:e0dgEame6mkydy19KKaVPBeEnyJB4LGNb0bBH1EtQ3I=
modernc.org/libc v1.11.24/go.mod h1:FOSzE0UwookyT1TtCJrRkvsOrX2k38HoInhw+cSCUGk=
modernc.org/libc v1.11.26/go.mod h1:SFjnYi9OSd2W7f4ct622o/PAYqk7KHv6GS8NZULIjKY=
modernc.org/libc v1.11.27/go.mod h1:zmWm6kcFXt/jpzeCgfvUNswM0qke8qVwxqZrnddlDiE=
modernc.org/libc v1.11.28/go.mod h1:Ii4V0fTFcbq3qrv3CNn+OGHAvzqMBvC7dBNyC4vHZlg=
modernc.org/libc v1.11.31/go.mod h1:FpBncUkEAtopRNJj8aRo29qUiyx5AvAlAxzlx9GNaVM=
modernc.org/libc v1.11.34/go.mod h1:+Tzc4hnb1iaX/SKAutJmfzES6awxfU1BPvrrJO0pYLg=
modernc.org/libc v1.11.37/go.mod h1:dCQebOwoO1046yTrfUE5nX1f3YpGZQKNcITUYWlrAWo=
modernc.org/libc v1.11.39/go.mod h1:mV8lJMo2S5A31uD0k1cMu7vrJbSA3J3waQJxpV4iqx8=
modernc.org/libc v1.11.42/go.mod h1:yzrLDU+sSjLE+D4bIhS7q1L5UwXDOw99PLSX0BlZvSQ=
modernc.org/libc v1.11.44/go.mod h1:KFq33jsma7F5WXiYelU8quMJasCCTnHK0mkri4yPHgA=
modernc.org/libc v1.11.45/go.mod h1:Y192orvfVQQYFzCNsn+Xt0Hxt4DiO4USpLNXBlXg/tM=
modernc.org/libc v1.11.47/go.mod h1:tPkE4PzCTW27E6AIKIR5IwHAQKCAtudEIeAV1/SiyBg=
modernc.org/libc v1.11.49/go.mod h1:9JrJuK5WTtoTWIFQ7QjX2Mb/bagYdZdscI3xrvHbXjE=
modernc.org/libc v1.11.51/go.mod h1:R9I8u9TS+meaWLdbfQhq2kFknTW0O3aw3kEMqDDxMaM=
modernc.org/libc v1.11.53/go.mod h1:5ip5vWYPAoMulkQ5XlSJTy12Sz5U6blOQiYasilVPsU=
modernc.org/libc v1.11.54/go.mod h1:S/FVnskbzVUrjfBqlGFIPA5m7UwB3n9fojHhCNfSsnw=
modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M=
modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18=
modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8=
modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw=
modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0=
modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY=
modernc.org/libc v1.11.88/go.mod h1:h3oIVe8dxmTcchcFuCcJ4nAWaoiwzKCdv82MM0oiIdQ=
modernc.org/libc v1.11.90/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c=
modernc.org/libc v1.11.98/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c=
modernc.org/libc v1.11.99/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI=
modernc.org/libc v1.11.101/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI=
modernc.org/libc v1.11.104/go.mod h1:2MH3DaF/gCU8i/UBiVE1VFRos4o523M7zipmwH8SIgQ=
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
modernc.org/libc v1.16.7 h1:qzQtHhsZNpVPpeCu+aMIQldXeV1P0vRhSqCL0nOIJOA=
modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU=
modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY=
modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k=
modernc.org/sqlite v1.10.6/go.mod h1:Z9FEjUtZP4qFEg6/SiADg9XCER7aYy9a/j7Pg9P7CPs=
modernc.org/sqlite v1.14.3/go.mod h1:xMpicS1i2MJ4C8+Ap0vYBqTwYfpFvdnPE6brbFOtV2Y=
modernc.org/sqlite v1.17.2 h1:TjmF36Wi5QcPYqRoAacV1cAyJ7xB/CD0ExpVUEMebnw=
modernc.org/sqlite v1.17.2/go.mod h1:GOQmuiXd6pTTes1Fi2s9apiCcD/wbKQtBZ0Nw6/etjM=
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.5.2/go.mod h1:pmJYOLgpiys3oI4AeAafkcUfE+TKKilminxNyU/+Zlo=
modernc.org/tcl v1.9.2/go.mod h1:aw7OnlIoiuJgu1gwbTZtrKnGpDqH9wyH++jZcxdqNsg=
modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao=
modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.2.20/go.mod h1:zU9FiF4PbHdOTUxw+IF8j7ArBMRPsHgq10uVPt6xTzo=
modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM=
modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=
modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=

View File

@@ -862,6 +862,10 @@ ShowUserTyping=false
#Default "<clipped message>"
MessageClipped="<clipped message>"
#If enabled use the slack "Real Name" as username.
#OPTIONAL (default false)
UseFullName=false
###################################################################
#discord section
###################################################################
@@ -1036,6 +1040,12 @@ DisableWebPagePreview=false
#OPTIONAL (default false)
UseFirstName=false
#If enabled use the "Full Name" as username. If this is empty use the Username
#If disabled use the "Username" as username. If this is empty use the First Name and Last Name as Full Name
#If all names are empty, username will be "unknown"
#OPTIONAL (default false)
UseFullName=false
#WARNING! If enabled this will relay GIF/stickers/documents and other attachments as URLs
#Those URLs will contain your bot-token. This may not be what you want.
#For now there is no secure way to relay GIF/stickers/documents without seeing your token.
@@ -1141,6 +1151,12 @@ StripNick=false
#OPTIONAL (default false)
ShowTopicChange=false
#Opportunistically preserve threaded replies between Telegram groups.
#This only works if the parent message is still in the cache.
#Cache is flushed between restarts.
#OPTIONAL (default false)
PreserveThreading=false
###################################################################
#rocketchat section
###################################################################
@@ -1312,6 +1328,15 @@ HTMLDisable=false
# UseUserName shows the username instead of the server nickname
UseUserName=false
# Matrix quotes replies and as of matterbridge 1.24.0 we strip those as this causes
# issues with bridges support threading and have PreserveThreading enabled.
# But if you for example use mattermost or discord with webhooks you'll need to enable
# this (and keep PreserveThreading disabled) if you want something that looks like a reply from matrix.
# See issues:
# - https://github.com/42wim/matterbridge/issues/1819
# - https://github.com/42wim/matterbridge/issues/1780
KeepQuotedReply=false
#Nicks you want to ignore.
#Regular expressions supported
#Messages from those users will not be sent to other bridges.

27
vendor/filippo.io/edwards25519/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

14
vendor/filippo.io/edwards25519/README.md generated vendored Normal file
View File

@@ -0,0 +1,14 @@
# filippo.io/edwards25519
```
import "filippo.io/edwards25519"
```
This library implements the edwards25519 elliptic curve, exposing the necessary APIs to build a wide array of higher-level primitives.
Read the docs at [pkg.go.dev/filippo.io/edwards25519](https://pkg.go.dev/filippo.io/edwards25519).
The code is originally derived from Adam Langley's internal implementation in the Go standard library, and includes George Tankersley's [performance improvements](https://golang.org/cl/71950). It was then further developed by Henry de Valence for use in ristretto255.
Most users don't need this package, and should instead use `crypto/ed25519` for signatures, `golang.org/x/crypto/curve25519` for Diffie-Hellman, or `github.com/gtank/ristretto255` for prime order group logic. However, for anyone currently using a fork of `crypto/ed25519/internal/edwards25519` or `github.com/agl/edwards25519`, this package should be a safer, faster, and more powerful alternative.
Since this package is meant to curb proliferation of edwards25519 implementations in the Go ecosystem, it welcomes requests for new APIs or reviewable performance improvements.

20
vendor/filippo.io/edwards25519/doc.go generated vendored Normal file
View File

@@ -0,0 +1,20 @@
// Copyright (c) 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package edwards25519 implements group logic for the twisted Edwards curve
//
// -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2
//
// This is better known as the Edwards curve equivalent to Curve25519, and is
// the curve used by the Ed25519 signature scheme.
//
// Most users don't need this package, and should instead use crypto/ed25519 for
// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or
// github.com/gtank/ristretto255 for prime order group logic.
//
// However, developers who do need to interact with low-level edwards25519
// operations can use this package, which is an extended version of
// crypto/ed25519/internal/edwards25519 from the standard library repackaged as
// an importable module.
package edwards25519

428
vendor/filippo.io/edwards25519/edwards25519.go generated vendored Normal file
View File

@@ -0,0 +1,428 @@
// Copyright (c) 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package edwards25519
import (
"errors"
"filippo.io/edwards25519/field"
)
// Point types.
type projP1xP1 struct {
X, Y, Z, T field.Element
}
type projP2 struct {
X, Y, Z field.Element
}
// Point represents a point on the edwards25519 curve.
//
// This type works similarly to math/big.Int, and all arguments and receivers
// are allowed to alias.
//
// The zero value is NOT valid, and it may be used only as a receiver.
type Point struct {
// The point is internally represented in extended coordinates (X, Y, Z, T)
// where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522.
x, y, z, t field.Element
// Make the type not comparable (i.e. used with == or as a map key), as
// equivalent points can be represented by different Go values.
_ incomparable
}
type incomparable [0]func()
func checkInitialized(points ...*Point) {
for _, p := range points {
if p.x == (field.Element{}) && p.y == (field.Element{}) {
panic("edwards25519: use of uninitialized Point")
}
}
}
type projCached struct {
YplusX, YminusX, Z, T2d field.Element
}
type affineCached struct {
YplusX, YminusX, T2d field.Element
}
// Constructors.
func (v *projP2) Zero() *projP2 {
v.X.Zero()
v.Y.One()
v.Z.One()
return v
}
// identity is the point at infinity.
var identity, _ = new(Point).SetBytes([]byte{
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
// NewIdentityPoint returns a new Point set to the identity.
func NewIdentityPoint() *Point {
return new(Point).Set(identity)
}
// generator is the canonical curve basepoint. See TestGenerator for the
// correspondence of this encoding with the values in RFC 8032.
var generator, _ = new(Point).SetBytes([]byte{
0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66})
// NewGeneratorPoint returns a new Point set to the canonical generator.
func NewGeneratorPoint() *Point {
return new(Point).Set(generator)
}
func (v *projCached) Zero() *projCached {
v.YplusX.One()
v.YminusX.One()
v.Z.One()
v.T2d.Zero()
return v
}
func (v *affineCached) Zero() *affineCached {
v.YplusX.One()
v.YminusX.One()
v.T2d.Zero()
return v
}
// Assignments.
// Set sets v = u, and returns v.
func (v *Point) Set(u *Point) *Point {
*v = *u
return v
}
// Encoding.
// Bytes returns the canonical 32-byte encoding of v, according to RFC 8032,
// Section 5.1.2.
func (v *Point) Bytes() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var buf [32]byte
return v.bytes(&buf)
}
func (v *Point) bytes(buf *[32]byte) []byte {
checkInitialized(v)
var zInv, x, y field.Element
zInv.Invert(&v.z) // zInv = 1 / Z
x.Multiply(&v.x, &zInv) // x = X / Z
y.Multiply(&v.y, &zInv) // y = Y / Z
out := copyFieldElement(buf, &y)
out[31] |= byte(x.IsNegative() << 7)
return out
}
var feOne = new(field.Element).One()
// SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not
// represent a valid point on the curve, SetBytes returns nil and an error and
// the receiver is unchanged. Otherwise, SetBytes returns v.
//
// Note that SetBytes accepts all non-canonical encodings of valid points.
// That is, it follows decoding rules that match most implementations in
// the ecosystem rather than RFC 8032.
func (v *Point) SetBytes(x []byte) (*Point, error) {
// Specifically, the non-canonical encodings that are accepted are
// 1) the ones where the field element is not reduced (see the
// (*field.Element).SetBytes docs) and
// 2) the ones where the x-coordinate is zero and the sign bit is set.
//
// This is consistent with crypto/ed25519/internal/edwards25519. Read more
// at https://hdevalence.ca/blog/2020-10-04-its-25519am, specifically the
// "Canonical A, R" section.
y, err := new(field.Element).SetBytes(x)
if err != nil {
return nil, errors.New("edwards25519: invalid point encoding length")
}
// -x² + y² = 1 + dx²y²
// x² + dx²y² = x²(dy² + 1) = y² - 1
// x² = (y² - 1) / (dy² + 1)
// u = y² - 1
y2 := new(field.Element).Square(y)
u := new(field.Element).Subtract(y2, feOne)
// v = dy² + 1
vv := new(field.Element).Multiply(y2, d)
vv = vv.Add(vv, feOne)
// x = +√(u/v)
xx, wasSquare := new(field.Element).SqrtRatio(u, vv)
if wasSquare == 0 {
return nil, errors.New("edwards25519: invalid point encoding")
}
// Select the negative square root if the sign bit is set.
xxNeg := new(field.Element).Negate(xx)
xx = xx.Select(xxNeg, xx, int(x[31]>>7))
v.x.Set(xx)
v.y.Set(y)
v.z.One()
v.t.Multiply(xx, y) // xy = T / Z
return v, nil
}
func copyFieldElement(buf *[32]byte, v *field.Element) []byte {
copy(buf[:], v.Bytes())
return buf[:]
}
// Conversions.
func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 {
v.X.Multiply(&p.X, &p.T)
v.Y.Multiply(&p.Y, &p.Z)
v.Z.Multiply(&p.Z, &p.T)
return v
}
func (v *projP2) FromP3(p *Point) *projP2 {
v.X.Set(&p.x)
v.Y.Set(&p.y)
v.Z.Set(&p.z)
return v
}
func (v *Point) fromP1xP1(p *projP1xP1) *Point {
v.x.Multiply(&p.X, &p.T)
v.y.Multiply(&p.Y, &p.Z)
v.z.Multiply(&p.Z, &p.T)
v.t.Multiply(&p.X, &p.Y)
return v
}
func (v *Point) fromP2(p *projP2) *Point {
v.x.Multiply(&p.X, &p.Z)
v.y.Multiply(&p.Y, &p.Z)
v.z.Square(&p.Z)
v.t.Multiply(&p.X, &p.Y)
return v
}
// d is a constant in the curve equation.
var d, _ = new(field.Element).SetBytes([]byte{
0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75,
0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00,
0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c,
0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52})
var d2 = new(field.Element).Add(d, d)
func (v *projCached) FromP3(p *Point) *projCached {
v.YplusX.Add(&p.y, &p.x)
v.YminusX.Subtract(&p.y, &p.x)
v.Z.Set(&p.z)
v.T2d.Multiply(&p.t, d2)
return v
}
func (v *affineCached) FromP3(p *Point) *affineCached {
v.YplusX.Add(&p.y, &p.x)
v.YminusX.Subtract(&p.y, &p.x)
v.T2d.Multiply(&p.t, d2)
var invZ field.Element
invZ.Invert(&p.z)
v.YplusX.Multiply(&v.YplusX, &invZ)
v.YminusX.Multiply(&v.YminusX, &invZ)
v.T2d.Multiply(&v.T2d, &invZ)
return v
}
// (Re)addition and subtraction.
// Add sets v = p + q, and returns v.
func (v *Point) Add(p, q *Point) *Point {
checkInitialized(p, q)
qCached := new(projCached).FromP3(q)
result := new(projP1xP1).Add(p, qCached)
return v.fromP1xP1(result)
}
// Subtract sets v = p - q, and returns v.
func (v *Point) Subtract(p, q *Point) *Point {
checkInitialized(p, q)
qCached := new(projCached).FromP3(q)
result := new(projP1xP1).Sub(p, qCached)
return v.fromP1xP1(result)
}
func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
YplusX.Add(&p.y, &p.x)
YminusX.Subtract(&p.y, &p.x)
PP.Multiply(&YplusX, &q.YplusX)
MM.Multiply(&YminusX, &q.YminusX)
TT2d.Multiply(&p.t, &q.T2d)
ZZ2.Multiply(&p.z, &q.Z)
ZZ2.Add(&ZZ2, &ZZ2)
v.X.Subtract(&PP, &MM)
v.Y.Add(&PP, &MM)
v.Z.Add(&ZZ2, &TT2d)
v.T.Subtract(&ZZ2, &TT2d)
return v
}
func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
YplusX.Add(&p.y, &p.x)
YminusX.Subtract(&p.y, &p.x)
PP.Multiply(&YplusX, &q.YminusX) // flipped sign
MM.Multiply(&YminusX, &q.YplusX) // flipped sign
TT2d.Multiply(&p.t, &q.T2d)
ZZ2.Multiply(&p.z, &q.Z)
ZZ2.Add(&ZZ2, &ZZ2)
v.X.Subtract(&PP, &MM)
v.Y.Add(&PP, &MM)
v.Z.Subtract(&ZZ2, &TT2d) // flipped sign
v.T.Add(&ZZ2, &TT2d) // flipped sign
return v
}
func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
YplusX.Add(&p.y, &p.x)
YminusX.Subtract(&p.y, &p.x)
PP.Multiply(&YplusX, &q.YplusX)
MM.Multiply(&YminusX, &q.YminusX)
TT2d.Multiply(&p.t, &q.T2d)
Z2.Add(&p.z, &p.z)
v.X.Subtract(&PP, &MM)
v.Y.Add(&PP, &MM)
v.Z.Add(&Z2, &TT2d)
v.T.Subtract(&Z2, &TT2d)
return v
}
func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
YplusX.Add(&p.y, &p.x)
YminusX.Subtract(&p.y, &p.x)
PP.Multiply(&YplusX, &q.YminusX) // flipped sign
MM.Multiply(&YminusX, &q.YplusX) // flipped sign
TT2d.Multiply(&p.t, &q.T2d)
Z2.Add(&p.z, &p.z)
v.X.Subtract(&PP, &MM)
v.Y.Add(&PP, &MM)
v.Z.Subtract(&Z2, &TT2d) // flipped sign
v.T.Add(&Z2, &TT2d) // flipped sign
return v
}
// Doubling.
func (v *projP1xP1) Double(p *projP2) *projP1xP1 {
var XX, YY, ZZ2, XplusYsq field.Element
XX.Square(&p.X)
YY.Square(&p.Y)
ZZ2.Square(&p.Z)
ZZ2.Add(&ZZ2, &ZZ2)
XplusYsq.Add(&p.X, &p.Y)
XplusYsq.Square(&XplusYsq)
v.Y.Add(&YY, &XX)
v.Z.Subtract(&YY, &XX)
v.X.Subtract(&XplusYsq, &v.Y)
v.T.Subtract(&ZZ2, &v.Z)
return v
}
// Negation.
// Negate sets v = -p, and returns v.
func (v *Point) Negate(p *Point) *Point {
checkInitialized(p)
v.x.Negate(&p.x)
v.y.Set(&p.y)
v.z.Set(&p.z)
v.t.Negate(&p.t)
return v
}
// Equal returns 1 if v is equivalent to u, and 0 otherwise.
func (v *Point) Equal(u *Point) int {
checkInitialized(v, u)
var t1, t2, t3, t4 field.Element
t1.Multiply(&v.x, &u.z)
t2.Multiply(&u.x, &v.z)
t3.Multiply(&v.y, &u.z)
t4.Multiply(&u.y, &v.z)
return t1.Equal(&t2) & t3.Equal(&t4)
}
// Constant-time operations
// Select sets v to a if cond == 1 and to b if cond == 0.
func (v *projCached) Select(a, b *projCached, cond int) *projCached {
v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
v.Z.Select(&a.Z, &b.Z, cond)
v.T2d.Select(&a.T2d, &b.T2d, cond)
return v
}
// Select sets v to a if cond == 1 and to b if cond == 0.
func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached {
v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
v.T2d.Select(&a.T2d, &b.T2d, cond)
return v
}
// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
func (v *projCached) CondNeg(cond int) *projCached {
v.YplusX.Swap(&v.YminusX, cond)
v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
return v
}
// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
func (v *affineCached) CondNeg(cond int) *affineCached {
v.YplusX.Swap(&v.YminusX, cond)
v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
return v
}

343
vendor/filippo.io/edwards25519/extra.go generated vendored Normal file
View File

@@ -0,0 +1,343 @@
// Copyright (c) 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package edwards25519
// This file contains additional functionality that is not included in the
// upstream crypto/ed25519/internal/edwards25519 package.
import (
"errors"
"filippo.io/edwards25519/field"
)
// ExtendedCoordinates returns v in extended coordinates (X:Y:Z:T) where
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap. Don't change the style without making
// sure it doesn't increase the inliner cost.
var e [4]field.Element
X, Y, Z, T = v.extendedCoordinates(&e)
return
}
func (v *Point) extendedCoordinates(e *[4]field.Element) (X, Y, Z, T *field.Element) {
checkInitialized(v)
X = e[0].Set(&v.x)
Y = e[1].Set(&v.y)
Z = e[2].Set(&v.z)
T = e[3].Set(&v.t)
return
}
// SetExtendedCoordinates sets v = (X:Y:Z:T) in extended coordinates where
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
//
// If the coordinates are invalid or don't represent a valid point on the curve,
// SetExtendedCoordinates returns nil and an error and the receiver is
// unchanged. Otherwise, SetExtendedCoordinates returns v.
func (v *Point) SetExtendedCoordinates(X, Y, Z, T *field.Element) (*Point, error) {
if !isOnCurve(X, Y, Z, T) {
return nil, errors.New("edwards25519: invalid point coordinates")
}
v.x.Set(X)
v.y.Set(Y)
v.z.Set(Z)
v.t.Set(T)
return v, nil
}
func isOnCurve(X, Y, Z, T *field.Element) bool {
var lhs, rhs field.Element
XX := new(field.Element).Square(X)
YY := new(field.Element).Square(Y)
ZZ := new(field.Element).Square(Z)
TT := new(field.Element).Square(T)
// -x² + y² = 1 + dx²y²
// -(X/Z)² + (Y/Z)² = 1 + d(T/Z)²
// -X² + Y² = Z² + dT²
lhs.Subtract(YY, XX)
rhs.Multiply(d, TT).Add(&rhs, ZZ)
if lhs.Equal(&rhs) != 1 {
return false
}
// xy = T/Z
// XY/Z² = T/Z
// XY = TZ
lhs.Multiply(X, Y)
rhs.Multiply(T, Z)
return lhs.Equal(&rhs) == 1
}
// BytesMontgomery converts v to a point on the birationally-equivalent
// Curve25519 Montgomery curve, and returns its canonical 32 bytes encoding
// according to RFC 7748.
//
// Note that BytesMontgomery only encodes the u-coordinate, so v and -v encode
// to the same value. If v is the identity point, BytesMontgomery returns 32
// zero bytes, analogously to the X25519 function.
func (v *Point) BytesMontgomery() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var buf [32]byte
return v.bytesMontgomery(&buf)
}
func (v *Point) bytesMontgomery(buf *[32]byte) []byte {
checkInitialized(v)
// RFC 7748, Section 4.1 provides the bilinear map to calculate the
// Montgomery u-coordinate
//
// u = (1 + y) / (1 - y)
//
// where y = Y / Z.
var y, recip, u field.Element
y.Multiply(&v.y, y.Invert(&v.z)) // y = Y / Z
recip.Invert(recip.Subtract(feOne, &y)) // r = 1/(1 - y)
u.Multiply(u.Add(feOne, &y), &recip) // u = (1 + y)*r
return copyFieldElement(buf, &u)
}
// MultByCofactor sets v = 8 * p, and returns v.
func (v *Point) MultByCofactor(p *Point) *Point {
checkInitialized(p)
result := projP1xP1{}
pp := (&projP2{}).FromP3(p)
result.Double(pp)
pp.FromP1xP1(&result)
result.Double(pp)
pp.FromP1xP1(&result)
result.Double(pp)
return v.fromP1xP1(&result)
}
// Given k > 0, set s = s**(2*i).
func (s *Scalar) pow2k(k int) {
for i := 0; i < k; i++ {
s.Multiply(s, s)
}
}
// Invert sets s to the inverse of a nonzero scalar v, and returns s.
//
// If t is zero, Invert returns zero.
func (s *Scalar) Invert(t *Scalar) *Scalar {
// Uses a hardcoded sliding window of width 4.
var table [8]Scalar
var tt Scalar
tt.Multiply(t, t)
table[0] = *t
for i := 0; i < 7; i++ {
table[i+1].Multiply(&table[i], &tt)
}
// Now table = [t**1, t**3, t**7, t**11, t**13, t**15]
// so t**k = t[k/2] for odd k
// To compute the sliding window digits, use the following Sage script:
// sage: import itertools
// sage: def sliding_window(w,k):
// ....: digits = []
// ....: while k > 0:
// ....: if k % 2 == 1:
// ....: kmod = k % (2**w)
// ....: digits.append(kmod)
// ....: k = k - kmod
// ....: else:
// ....: digits.append(0)
// ....: k = k // 2
// ....: return digits
// Now we can compute s roughly as follows:
// sage: s = 1
// sage: for coeff in reversed(sliding_window(4,l-2)):
// ....: s = s*s
// ....: if coeff > 0 :
// ....: s = s*t**coeff
// This works on one bit at a time, with many runs of zeros.
// The digits can be collapsed into [(count, coeff)] as follows:
// sage: [(len(list(group)),d) for d,group in itertools.groupby(sliding_window(4,l-2))]
// Entries of the form (k, 0) turn into pow2k(k)
// Entries of the form (1, coeff) turn into a squaring and then a table lookup.
// We can fold the squaring into the previous pow2k(k) as pow2k(k+1).
*s = table[1/2]
s.pow2k(127 + 1)
s.Multiply(s, &table[1/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[9/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[11/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[13/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[7/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[5/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[1/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[7/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[11/2])
s.pow2k(5 + 1)
s.Multiply(s, &table[11/2])
s.pow2k(9 + 1)
s.Multiply(s, &table[9/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[9/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[7/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[3/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[13/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[7/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[9/2])
s.pow2k(3 + 1)
s.Multiply(s, &table[15/2])
s.pow2k(4 + 1)
s.Multiply(s, &table[11/2])
return s
}
// MultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
//
// Execution time depends only on the lengths of the two slices, which must match.
func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point {
if len(scalars) != len(points) {
panic("edwards25519: called MultiScalarMult with different size inputs")
}
checkInitialized(points...)
// Proceed as in the single-base case, but share doublings
// between each point in the multiscalar equation.
// Build lookup tables for each point
tables := make([]projLookupTable, len(points))
for i := range tables {
tables[i].FromP3(points[i])
}
// Compute signed radix-16 digits for each scalar
digits := make([][64]int8, len(scalars))
for i := range digits {
digits[i] = scalars[i].signedRadix16()
}
// Unwrap first loop iteration to save computing 16*identity
multiple := &projCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
// Lookup-and-add the appropriate multiple of each input point
for j := range tables {
tables[j].SelectInto(multiple, digits[j][63])
tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords
v.fromP1xP1(tmp1) // update v
}
tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
for i := 62; i >= 0; i-- {
tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords
// Lookup-and-add the appropriate multiple of each input point
for j := range tables {
tables[j].SelectInto(multiple, digits[j][i])
tmp1.Add(v, multiple) // tmp1 = v + x_(j,i)*Q in P1xP1 coords
v.fromP1xP1(tmp1) // update v
}
tmp2.FromP3(v) // set up tmp2 = v in P2 coords for next iteration
}
return v
}
// VarTimeMultiScalarMult sets v = sum(scalars[i] * points[i]), and returns v.
//
// Execution time depends on the inputs.
func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Point {
if len(scalars) != len(points) {
panic("edwards25519: called VarTimeMultiScalarMult with different size inputs")
}
checkInitialized(points...)
// Generalize double-base NAF computation to arbitrary sizes.
// Here all the points are dynamic, so we only use the smaller
// tables.
// Build lookup tables for each point
tables := make([]nafLookupTable5, len(points))
for i := range tables {
tables[i].FromP3(points[i])
}
// Compute a NAF for each scalar
nafs := make([][256]int8, len(scalars))
for i := range nafs {
nafs[i] = scalars[i].nonAdjacentForm(5)
}
multiple := &projCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
tmp2.Zero()
// Move from high to low bits, doubling the accumulator
// at each iteration and checking whether there is a nonzero
// coefficient to look up a multiple of.
//
// Skip trying to find the first nonzero coefficent, because
// searching might be more work than a few extra doublings.
for i := 255; i >= 0; i-- {
tmp1.Double(tmp2)
for j := range nafs {
if nafs[j][i] > 0 {
v.fromP1xP1(tmp1)
tables[j].SelectInto(multiple, nafs[j][i])
tmp1.Add(v, multiple)
} else if nafs[j][i] < 0 {
v.fromP1xP1(tmp1)
tables[j].SelectInto(multiple, -nafs[j][i])
tmp1.Sub(v, multiple)
}
}
tmp2.FromP1xP1(tmp1)
}
v.fromP2(tmp2)
return v
}

419
vendor/filippo.io/edwards25519/field/fe.go generated vendored Normal file
View File

@@ -0,0 +1,419 @@
// Copyright (c) 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package field implements fast arithmetic modulo 2^255-19.
package field
import (
"crypto/subtle"
"encoding/binary"
"errors"
"math/bits"
)
// Element represents an element of the field GF(2^255-19). Note that this
// is not a cryptographically secure group, and should only be used to interact
// with edwards25519.Point coordinates.
//
// This type works similarly to math/big.Int, and all arguments and receivers
// are allowed to alias.
//
// The zero value is a valid zero element.
type Element struct {
// An element t represents the integer
// t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
//
// Between operations, all limbs are expected to be lower than 2^52.
l0 uint64
l1 uint64
l2 uint64
l3 uint64
l4 uint64
}
const maskLow51Bits uint64 = (1 << 51) - 1
var feZero = &Element{0, 0, 0, 0, 0}
// Zero sets v = 0, and returns v.
func (v *Element) Zero() *Element {
*v = *feZero
return v
}
var feOne = &Element{1, 0, 0, 0, 0}
// One sets v = 1, and returns v.
func (v *Element) One() *Element {
*v = *feOne
return v
}
// reduce reduces v modulo 2^255 - 19 and returns it.
func (v *Element) reduce() *Element {
v.carryPropagate()
// After the light reduction we now have a field element representation
// v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
// If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
// generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
c := (v.l0 + 19) >> 51
c = (v.l1 + c) >> 51
c = (v.l2 + c) >> 51
c = (v.l3 + c) >> 51
c = (v.l4 + c) >> 51
// If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
// effectively applying the reduction identity to the carry.
v.l0 += 19 * c
v.l1 += v.l0 >> 51
v.l0 = v.l0 & maskLow51Bits
v.l2 += v.l1 >> 51
v.l1 = v.l1 & maskLow51Bits
v.l3 += v.l2 >> 51
v.l2 = v.l2 & maskLow51Bits
v.l4 += v.l3 >> 51
v.l3 = v.l3 & maskLow51Bits
// no additional carry
v.l4 = v.l4 & maskLow51Bits
return v
}
// Add sets v = a + b, and returns v.
func (v *Element) Add(a, b *Element) *Element {
v.l0 = a.l0 + b.l0
v.l1 = a.l1 + b.l1
v.l2 = a.l2 + b.l2
v.l3 = a.l3 + b.l3
v.l4 = a.l4 + b.l4
// Using the generic implementation here is actually faster than the
// assembly. Probably because the body of this function is so simple that
// the compiler can figure out better optimizations by inlining the carry
// propagation.
return v.carryPropagateGeneric()
}
// Subtract sets v = a - b, and returns v.
func (v *Element) Subtract(a, b *Element) *Element {
// We first add 2 * p, to guarantee the subtraction won't underflow, and
// then subtract b (which can be up to 2^255 + 2^13 * 19).
v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
return v.carryPropagate()
}
// Negate sets v = -a, and returns v.
func (v *Element) Negate(a *Element) *Element {
return v.Subtract(feZero, a)
}
// Invert sets v = 1/z mod p, and returns v.
//
// If z == 0, Invert returns v = 0.
func (v *Element) Invert(z *Element) *Element {
// Inversion is implemented as exponentiation with exponent p 2. It uses the
// same sequence of 255 squarings and 11 multiplications as [Curve25519].
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
z2.Square(z) // 2
t.Square(&z2) // 4
t.Square(&t) // 8
z9.Multiply(&t, z) // 9
z11.Multiply(&z9, &z2) // 11
t.Square(&z11) // 22
z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
t.Square(&z2_5_0) // 2^6 - 2^1
for i := 0; i < 4; i++ {
t.Square(&t) // 2^10 - 2^5
}
z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
t.Square(&z2_10_0) // 2^11 - 2^1
for i := 0; i < 9; i++ {
t.Square(&t) // 2^20 - 2^10
}
z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
t.Square(&z2_20_0) // 2^21 - 2^1
for i := 0; i < 19; i++ {
t.Square(&t) // 2^40 - 2^20
}
t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
t.Square(&t) // 2^41 - 2^1
for i := 0; i < 9; i++ {
t.Square(&t) // 2^50 - 2^10
}
z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
t.Square(&z2_50_0) // 2^51 - 2^1
for i := 0; i < 49; i++ {
t.Square(&t) // 2^100 - 2^50
}
z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
t.Square(&z2_100_0) // 2^101 - 2^1
for i := 0; i < 99; i++ {
t.Square(&t) // 2^200 - 2^100
}
t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
t.Square(&t) // 2^201 - 2^1
for i := 0; i < 49; i++ {
t.Square(&t) // 2^250 - 2^50
}
t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
t.Square(&t) // 2^251 - 2^1
t.Square(&t) // 2^252 - 2^2
t.Square(&t) // 2^253 - 2^3
t.Square(&t) // 2^254 - 2^4
t.Square(&t) // 2^255 - 2^5
return v.Multiply(&t, &z11) // 2^255 - 21
}
// Set sets v = a, and returns v.
func (v *Element) Set(a *Element) *Element {
*v = *a
return v
}
// SetBytes sets v to x, where x is a 32-byte little-endian encoding. If x is
// not of the right length, SetUniformBytes returns nil and an error, and the
// receiver is unchanged.
//
// Consistent with RFC 7748, the most significant bit (the high bit of the
// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
// are accepted. Note that this is laxer than specified by RFC 8032.
func (v *Element) SetBytes(x []byte) (*Element, error) {
if len(x) != 32 {
return nil, errors.New("edwards25519: invalid field element input size")
}
// Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
v.l0 = binary.LittleEndian.Uint64(x[0:8])
v.l0 &= maskLow51Bits
// Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
v.l1 &= maskLow51Bits
// Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
v.l2 &= maskLow51Bits
// Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
v.l3 &= maskLow51Bits
// Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51).
// Note: not bytes 25:33, shift 4, to avoid overread.
v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
v.l4 &= maskLow51Bits
return v, nil
}
// Bytes returns the canonical 32-byte little-endian encoding of v.
func (v *Element) Bytes() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var out [32]byte
return v.bytes(&out)
}
func (v *Element) bytes(out *[32]byte) []byte {
t := *v
t.reduce()
var buf [8]byte
for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
bitsOffset := i * 51
binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
for i, bb := range buf {
off := bitsOffset/8 + i
if off >= len(out) {
break
}
out[off] |= bb
}
}
return out[:]
}
// Equal returns 1 if v and u are equal, and 0 otherwise.
func (v *Element) Equal(u *Element) int {
sa, sv := u.Bytes(), v.Bytes()
return subtle.ConstantTimeCompare(sa, sv)
}
// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
// Select sets v to a if cond == 1, and to b if cond == 0.
func (v *Element) Select(a, b *Element, cond int) *Element {
m := mask64Bits(cond)
v.l0 = (m & a.l0) | (^m & b.l0)
v.l1 = (m & a.l1) | (^m & b.l1)
v.l2 = (m & a.l2) | (^m & b.l2)
v.l3 = (m & a.l3) | (^m & b.l3)
v.l4 = (m & a.l4) | (^m & b.l4)
return v
}
// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
func (v *Element) Swap(u *Element, cond int) {
m := mask64Bits(cond)
t := m & (v.l0 ^ u.l0)
v.l0 ^= t
u.l0 ^= t
t = m & (v.l1 ^ u.l1)
v.l1 ^= t
u.l1 ^= t
t = m & (v.l2 ^ u.l2)
v.l2 ^= t
u.l2 ^= t
t = m & (v.l3 ^ u.l3)
v.l3 ^= t
u.l3 ^= t
t = m & (v.l4 ^ u.l4)
v.l4 ^= t
u.l4 ^= t
}
// IsNegative returns 1 if v is negative, and 0 otherwise.
func (v *Element) IsNegative() int {
return int(v.Bytes()[0] & 1)
}
// Absolute sets v to |u|, and returns v.
func (v *Element) Absolute(u *Element) *Element {
return v.Select(new(Element).Negate(u), u, u.IsNegative())
}
// Multiply sets v = x * y, and returns v.
func (v *Element) Multiply(x, y *Element) *Element {
feMul(v, x, y)
return v
}
// Square sets v = x * x, and returns v.
func (v *Element) Square(x *Element) *Element {
feSquare(v, x)
return v
}
// Mult32 sets v = x * y, and returns v.
func (v *Element) Mult32(x *Element, y uint32) *Element {
x0lo, x0hi := mul51(x.l0, y)
x1lo, x1hi := mul51(x.l1, y)
x2lo, x2hi := mul51(x.l2, y)
x3lo, x3hi := mul51(x.l3, y)
x4lo, x4hi := mul51(x.l4, y)
v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
v.l1 = x1lo + x0hi
v.l2 = x2lo + x1hi
v.l3 = x3lo + x2hi
v.l4 = x4lo + x3hi
// The hi portions are going to be only 32 bits, plus any previous excess,
// so we can skip the carry propagation.
return v
}
// mul51 returns lo + hi * 2⁵¹ = a * b.
func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
mh, ml := bits.Mul64(a, uint64(b))
lo = ml & maskLow51Bits
hi = (mh << 13) | (ml >> 51)
return
}
// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
func (v *Element) Pow22523(x *Element) *Element {
var t0, t1, t2 Element
t0.Square(x) // x^2
t1.Square(&t0) // x^4
t1.Square(&t1) // x^8
t1.Multiply(x, &t1) // x^9
t0.Multiply(&t0, &t1) // x^11
t0.Square(&t0) // x^22
t0.Multiply(&t1, &t0) // x^31
t1.Square(&t0) // x^62
for i := 1; i < 5; i++ { // x^992
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1
t1.Square(&t0) // 2^11 - 2
for i := 1; i < 10; i++ { // 2^20 - 2^10
t1.Square(&t1)
}
t1.Multiply(&t1, &t0) // 2^20 - 1
t2.Square(&t1) // 2^21 - 2
for i := 1; i < 20; i++ { // 2^40 - 2^20
t2.Square(&t2)
}
t1.Multiply(&t2, &t1) // 2^40 - 1
t1.Square(&t1) // 2^41 - 2
for i := 1; i < 10; i++ { // 2^50 - 2^10
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // 2^50 - 1
t1.Square(&t0) // 2^51 - 2
for i := 1; i < 50; i++ { // 2^100 - 2^50
t1.Square(&t1)
}
t1.Multiply(&t1, &t0) // 2^100 - 1
t2.Square(&t1) // 2^101 - 2
for i := 1; i < 100; i++ { // 2^200 - 2^100
t2.Square(&t2)
}
t1.Multiply(&t2, &t1) // 2^200 - 1
t1.Square(&t1) // 2^201 - 2
for i := 1; i < 50; i++ { // 2^250 - 2^50
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // 2^250 - 1
t0.Square(&t0) // 2^251 - 2
t0.Square(&t0) // 2^252 - 4
return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
}
// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
var sqrtM1 = &Element{1718705420411056, 234908883556509,
2233514472574048, 2117202627021982, 765476049583133}
// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
//
// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
// and returns r and 0.
func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) {
var a, b Element
// r = (u * v3) * (u * v7)^((p-5)/8)
v2 := a.Square(v)
uv3 := b.Multiply(u, b.Multiply(v2, v))
uv7 := a.Multiply(uv3, a.Square(v2))
r.Multiply(uv3, r.Pow22523(uv7))
check := a.Multiply(v, a.Square(r)) // check = v * r^2
uNeg := b.Negate(u)
correctSignSqrt := check.Equal(u)
flippedSignSqrt := check.Equal(uNeg)
flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1))
rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r
// r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI)
r.Absolute(r) // Choose the nonnegative square root.
return r, correctSignSqrt | flippedSignSqrt
}

13
vendor/filippo.io/edwards25519/field/fe_amd64.go generated vendored Normal file
View File

@@ -0,0 +1,13 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
// +build amd64,gc,!purego
package field
// feMul sets out = a * b. It works like feMulGeneric.
//go:noescape
func feMul(out *Element, a *Element, b *Element)
// feSquare sets out = a * a. It works like feSquareGeneric.
//go:noescape
func feSquare(out *Element, a *Element)

378
vendor/filippo.io/edwards25519/field/fe_amd64.s generated vendored Normal file
View File

@@ -0,0 +1,378 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
// +build amd64,gc,!purego
#include "textflag.h"
// func feMul(out *Element, a *Element, b *Element)
TEXT ·feMul(SB), NOSPLIT, $0-24
MOVQ a+8(FP), CX
MOVQ b+16(FP), BX
// r0 = a0×b0
MOVQ (CX), AX
MULQ (BX)
MOVQ AX, DI
MOVQ DX, SI
// r0 += 19×a1×b4
MOVQ 8(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, DI
ADCQ DX, SI
// r0 += 19×a2×b3
MOVQ 16(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(BX)
ADDQ AX, DI
ADCQ DX, SI
// r0 += 19×a3×b2
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 16(BX)
ADDQ AX, DI
ADCQ DX, SI
// r0 += 19×a4×b1
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 8(BX)
ADDQ AX, DI
ADCQ DX, SI
// r1 = a0×b1
MOVQ (CX), AX
MULQ 8(BX)
MOVQ AX, R9
MOVQ DX, R8
// r1 += a1×b0
MOVQ 8(CX), AX
MULQ (BX)
ADDQ AX, R9
ADCQ DX, R8
// r1 += 19×a2×b4
MOVQ 16(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, R9
ADCQ DX, R8
// r1 += 19×a3×b3
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(BX)
ADDQ AX, R9
ADCQ DX, R8
// r1 += 19×a4×b2
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 16(BX)
ADDQ AX, R9
ADCQ DX, R8
// r2 = a0×b2
MOVQ (CX), AX
MULQ 16(BX)
MOVQ AX, R11
MOVQ DX, R10
// r2 += a1×b1
MOVQ 8(CX), AX
MULQ 8(BX)
ADDQ AX, R11
ADCQ DX, R10
// r2 += a2×b0
MOVQ 16(CX), AX
MULQ (BX)
ADDQ AX, R11
ADCQ DX, R10
// r2 += 19×a3×b4
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, R11
ADCQ DX, R10
// r2 += 19×a4×b3
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(BX)
ADDQ AX, R11
ADCQ DX, R10
// r3 = a0×b3
MOVQ (CX), AX
MULQ 24(BX)
MOVQ AX, R13
MOVQ DX, R12
// r3 += a1×b2
MOVQ 8(CX), AX
MULQ 16(BX)
ADDQ AX, R13
ADCQ DX, R12
// r3 += a2×b1
MOVQ 16(CX), AX
MULQ 8(BX)
ADDQ AX, R13
ADCQ DX, R12
// r3 += a3×b0
MOVQ 24(CX), AX
MULQ (BX)
ADDQ AX, R13
ADCQ DX, R12
// r3 += 19×a4×b4
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(BX)
ADDQ AX, R13
ADCQ DX, R12
// r4 = a0×b4
MOVQ (CX), AX
MULQ 32(BX)
MOVQ AX, R15
MOVQ DX, R14
// r4 += a1×b3
MOVQ 8(CX), AX
MULQ 24(BX)
ADDQ AX, R15
ADCQ DX, R14
// r4 += a2×b2
MOVQ 16(CX), AX
MULQ 16(BX)
ADDQ AX, R15
ADCQ DX, R14
// r4 += a3×b1
MOVQ 24(CX), AX
MULQ 8(BX)
ADDQ AX, R15
ADCQ DX, R14
// r4 += a4×b0
MOVQ 32(CX), AX
MULQ (BX)
ADDQ AX, R15
ADCQ DX, R14
// First reduction chain
MOVQ $0x0007ffffffffffff, AX
SHLQ $0x0d, DI, SI
SHLQ $0x0d, R9, R8
SHLQ $0x0d, R11, R10
SHLQ $0x0d, R13, R12
SHLQ $0x0d, R15, R14
ANDQ AX, DI
IMUL3Q $0x13, R14, R14
ADDQ R14, DI
ANDQ AX, R9
ADDQ SI, R9
ANDQ AX, R11
ADDQ R8, R11
ANDQ AX, R13
ADDQ R10, R13
ANDQ AX, R15
ADDQ R12, R15
// Second reduction chain (carryPropagate)
MOVQ DI, SI
SHRQ $0x33, SI
MOVQ R9, R8
SHRQ $0x33, R8
MOVQ R11, R10
SHRQ $0x33, R10
MOVQ R13, R12
SHRQ $0x33, R12
MOVQ R15, R14
SHRQ $0x33, R14
ANDQ AX, DI
IMUL3Q $0x13, R14, R14
ADDQ R14, DI
ANDQ AX, R9
ADDQ SI, R9
ANDQ AX, R11
ADDQ R8, R11
ANDQ AX, R13
ADDQ R10, R13
ANDQ AX, R15
ADDQ R12, R15
// Store output
MOVQ out+0(FP), AX
MOVQ DI, (AX)
MOVQ R9, 8(AX)
MOVQ R11, 16(AX)
MOVQ R13, 24(AX)
MOVQ R15, 32(AX)
RET
// func feSquare(out *Element, a *Element)
TEXT ·feSquare(SB), NOSPLIT, $0-16
MOVQ a+8(FP), CX
// r0 = l0×l0
MOVQ (CX), AX
MULQ (CX)
MOVQ AX, SI
MOVQ DX, BX
// r0 += 38×l1×l4
MOVQ 8(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 32(CX)
ADDQ AX, SI
ADCQ DX, BX
// r0 += 38×l2×l3
MOVQ 16(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 24(CX)
ADDQ AX, SI
ADCQ DX, BX
// r1 = 2×l0×l1
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 8(CX)
MOVQ AX, R8
MOVQ DX, DI
// r1 += 38×l2×l4
MOVQ 16(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 32(CX)
ADDQ AX, R8
ADCQ DX, DI
// r1 += 19×l3×l3
MOVQ 24(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 24(CX)
ADDQ AX, R8
ADCQ DX, DI
// r2 = 2×l0×l2
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 16(CX)
MOVQ AX, R10
MOVQ DX, R9
// r2 += l1×l1
MOVQ 8(CX), AX
MULQ 8(CX)
ADDQ AX, R10
ADCQ DX, R9
// r2 += 38×l3×l4
MOVQ 24(CX), AX
IMUL3Q $0x26, AX, AX
MULQ 32(CX)
ADDQ AX, R10
ADCQ DX, R9
// r3 = 2×l0×l3
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 24(CX)
MOVQ AX, R12
MOVQ DX, R11
// r3 += 2×l1×l2
MOVQ 8(CX), AX
IMUL3Q $0x02, AX, AX
MULQ 16(CX)
ADDQ AX, R12
ADCQ DX, R11
// r3 += 19×l4×l4
MOVQ 32(CX), AX
IMUL3Q $0x13, AX, AX
MULQ 32(CX)
ADDQ AX, R12
ADCQ DX, R11
// r4 = 2×l0×l4
MOVQ (CX), AX
SHLQ $0x01, AX
MULQ 32(CX)
MOVQ AX, R14
MOVQ DX, R13
// r4 += 2×l1×l3
MOVQ 8(CX), AX
IMUL3Q $0x02, AX, AX
MULQ 24(CX)
ADDQ AX, R14
ADCQ DX, R13
// r4 += l2×l2
MOVQ 16(CX), AX
MULQ 16(CX)
ADDQ AX, R14
ADCQ DX, R13
// First reduction chain
MOVQ $0x0007ffffffffffff, AX
SHLQ $0x0d, SI, BX
SHLQ $0x0d, R8, DI
SHLQ $0x0d, R10, R9
SHLQ $0x0d, R12, R11
SHLQ $0x0d, R14, R13
ANDQ AX, SI
IMUL3Q $0x13, R13, R13
ADDQ R13, SI
ANDQ AX, R8
ADDQ BX, R8
ANDQ AX, R10
ADDQ DI, R10
ANDQ AX, R12
ADDQ R9, R12
ANDQ AX, R14
ADDQ R11, R14
// Second reduction chain (carryPropagate)
MOVQ SI, BX
SHRQ $0x33, BX
MOVQ R8, DI
SHRQ $0x33, DI
MOVQ R10, R9
SHRQ $0x33, R9
MOVQ R12, R11
SHRQ $0x33, R11
MOVQ R14, R13
SHRQ $0x33, R13
ANDQ AX, SI
IMUL3Q $0x13, R13, R13
ADDQ R13, SI
ANDQ AX, R8
ADDQ BX, R8
ANDQ AX, R10
ADDQ DI, R10
ANDQ AX, R12
ADDQ R9, R12
ANDQ AX, R14
ADDQ R11, R14
// Store output
MOVQ out+0(FP), AX
MOVQ SI, (AX)
MOVQ R8, 8(AX)
MOVQ R10, 16(AX)
MOVQ R12, 24(AX)
MOVQ R14, 32(AX)
RET

12
vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !amd64 || !gc || purego
// +build !amd64 !gc purego
package field
func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
func feSquare(v, x *Element) { feSquareGeneric(v, x) }

16
vendor/filippo.io/edwards25519/field/fe_arm64.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
// Copyright (c) 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build arm64 && gc && !purego
// +build arm64,gc,!purego
package field
//go:noescape
func carryPropagate(v *Element)
func (v *Element) carryPropagate() *Element {
carryPropagate(v)
return v
}

42
vendor/filippo.io/edwards25519/field/fe_arm64.s generated vendored Normal file
View File

@@ -0,0 +1,42 @@
// Copyright (c) 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build arm64,gc,!purego
#include "textflag.h"
// carryPropagate works exactly like carryPropagateGeneric and uses the
// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but
// avoids loading R0-R4 twice and uses LDP and STP.
//
// See https://golang.org/issues/43145 for the main compiler issue.
//
// func carryPropagate(v *Element)
TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8
MOVD v+0(FP), R20
LDP 0(R20), (R0, R1)
LDP 16(R20), (R2, R3)
MOVD 32(R20), R4
AND $0x7ffffffffffff, R0, R10
AND $0x7ffffffffffff, R1, R11
AND $0x7ffffffffffff, R2, R12
AND $0x7ffffffffffff, R3, R13
AND $0x7ffffffffffff, R4, R14
ADD R0>>51, R11, R11
ADD R1>>51, R12, R12
ADD R2>>51, R13, R13
ADD R3>>51, R14, R14
// R4>>51 * 19 + R10 -> R10
LSR $51, R4, R21
MOVD $19, R22
MADD R22, R10, R21, R10
STP (R10, R11), 0(R20)
STP (R12, R13), 16(R20)
MOVD R14, 32(R20)
RET

12
vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
// Copyright (c) 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !arm64 || !gc || purego
// +build !arm64 !gc purego
package field
func (v *Element) carryPropagate() *Element {
return v.carryPropagateGeneric()
}

264
vendor/filippo.io/edwards25519/field/fe_generic.go generated vendored Normal file
View File

@@ -0,0 +1,264 @@
// Copyright (c) 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package field
import "math/bits"
// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
// bits.Mul64 and bits.Add64 intrinsics.
type uint128 struct {
lo, hi uint64
}
// mul64 returns a * b.
func mul64(a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
return uint128{lo, hi}
}
// addMul64 returns v + a * b.
func addMul64(v uint128, a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
lo, c := bits.Add64(lo, v.lo, 0)
hi, _ = bits.Add64(hi, v.hi, c)
return uint128{lo, hi}
}
// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
func shiftRightBy51(a uint128) uint64 {
return (a.hi << (64 - 51)) | (a.lo >> 51)
}
func feMulGeneric(v, a, b *Element) {
a0 := a.l0
a1 := a.l1
a2 := a.l2
a3 := a.l3
a4 := a.l4
b0 := b.l0
b1 := b.l1
b2 := b.l2
b3 := b.l3
b4 := b.l4
// Limb multiplication works like pen-and-paper columnar multiplication, but
// with 51-bit limbs instead of digits.
//
// a4 a3 a2 a1 a0 x
// b4 b3 b2 b1 b0 =
// ------------------------
// a4b0 a3b0 a2b0 a1b0 a0b0 +
// a4b1 a3b1 a2b1 a1b1 a0b1 +
// a4b2 a3b2 a2b2 a1b2 a0b2 +
// a4b3 a3b3 a2b3 a1b3 a0b3 +
// a4b4 a3b4 a2b4 a1b4 a0b4 =
// ----------------------------------------------
// r8 r7 r6 r5 r4 r3 r2 r1 r0
//
// We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
// reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
// r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
//
// Reduction can be carried out simultaneously to multiplication. For
// example, we do not compute r5: whenever the result of a multiplication
// belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
//
// a4b0 a3b0 a2b0 a1b0 a0b0 +
// a3b1 a2b1 a1b1 a0b1 19×a4b1 +
// a2b2 a1b2 a0b2 19×a4b2 19×a3b2 +
// a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 +
// a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 =
// --------------------------------------
// r4 r3 r2 r1 r0
//
// Finally we add up the columns into wide, overlapping limbs.
a1_19 := a1 * 19
a2_19 := a2 * 19
a3_19 := a3 * 19
a4_19 := a4 * 19
// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
r0 := mul64(a0, b0)
r0 = addMul64(r0, a1_19, b4)
r0 = addMul64(r0, a2_19, b3)
r0 = addMul64(r0, a3_19, b2)
r0 = addMul64(r0, a4_19, b1)
// r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
r1 := mul64(a0, b1)
r1 = addMul64(r1, a1, b0)
r1 = addMul64(r1, a2_19, b4)
r1 = addMul64(r1, a3_19, b3)
r1 = addMul64(r1, a4_19, b2)
// r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
r2 := mul64(a0, b2)
r2 = addMul64(r2, a1, b1)
r2 = addMul64(r2, a2, b0)
r2 = addMul64(r2, a3_19, b4)
r2 = addMul64(r2, a4_19, b3)
// r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
r3 := mul64(a0, b3)
r3 = addMul64(r3, a1, b2)
r3 = addMul64(r3, a2, b1)
r3 = addMul64(r3, a3, b0)
r3 = addMul64(r3, a4_19, b4)
// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
r4 := mul64(a0, b4)
r4 = addMul64(r4, a1, b3)
r4 = addMul64(r4, a2, b2)
r4 = addMul64(r4, a3, b1)
r4 = addMul64(r4, a4, b0)
// After the multiplication, we need to reduce (carry) the five coefficients
// to obtain a result with limbs that are at most slightly larger than 2⁵¹,
// to respect the Element invariant.
//
// Overall, the reduction works the same as carryPropagate, except with
// wider inputs: we take the carry for each coefficient by shifting it right
// by 51, and add it to the limb above it. The top carry is multiplied by 19
// according to the reduction identity and added to the lowest limb.
//
// The largest coefficient (r0) will be at most 111 bits, which guarantees
// that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
//
// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
// r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
// r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
// r0 < 2⁷ × 2⁵² × 2⁵²
// r0 < 2¹¹¹
//
// Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
// 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
// allows us to easily apply the reduction identity.
//
// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
// r4 < 5 × 2⁵² × 2⁵²
// r4 < 2¹⁰⁷
//
c0 := shiftRightBy51(r0)
c1 := shiftRightBy51(r1)
c2 := shiftRightBy51(r2)
c3 := shiftRightBy51(r3)
c4 := shiftRightBy51(r4)
rr0 := r0.lo&maskLow51Bits + c4*19
rr1 := r1.lo&maskLow51Bits + c0
rr2 := r2.lo&maskLow51Bits + c1
rr3 := r3.lo&maskLow51Bits + c2
rr4 := r4.lo&maskLow51Bits + c3
// Now all coefficients fit into 64-bit registers but are still too large to
// be passed around as a Element. We therefore do one last carry chain,
// where the carries will be small enough to fit in the wiggle room above 2⁵¹.
*v = Element{rr0, rr1, rr2, rr3, rr4}
v.carryPropagate()
}
func feSquareGeneric(v, a *Element) {
l0 := a.l0
l1 := a.l1
l2 := a.l2
l3 := a.l3
l4 := a.l4
// Squaring works precisely like multiplication above, but thanks to its
// symmetry we get to group a few terms together.
//
// l4 l3 l2 l1 l0 x
// l4 l3 l2 l1 l0 =
// ------------------------
// l4l0 l3l0 l2l0 l1l0 l0l0 +
// l4l1 l3l1 l2l1 l1l1 l0l1 +
// l4l2 l3l2 l2l2 l1l2 l0l2 +
// l4l3 l3l3 l2l3 l1l3 l0l3 +
// l4l4 l3l4 l2l4 l1l4 l0l4 =
// ----------------------------------------------
// r8 r7 r6 r5 r4 r3 r2 r1 r0
//
// l4l0 l3l0 l2l0 l1l0 l0l0 +
// l3l1 l2l1 l1l1 l0l1 19×l4l1 +
// l2l2 l1l2 l0l2 19×l4l2 19×l3l2 +
// l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 +
// l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 =
// --------------------------------------
// r4 r3 r2 r1 r0
//
// With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
// only three Mul64 and four Add64, instead of five and eight.
l0_2 := l0 * 2
l1_2 := l1 * 2
l1_38 := l1 * 38
l2_38 := l2 * 38
l3_38 := l3 * 38
l3_19 := l3 * 19
l4_19 := l4 * 19
// r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
r0 := mul64(l0, l0)
r0 = addMul64(r0, l1_38, l4)
r0 = addMul64(r0, l2_38, l3)
// r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
r1 := mul64(l0_2, l1)
r1 = addMul64(r1, l2_38, l4)
r1 = addMul64(r1, l3_19, l3)
// r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
r2 := mul64(l0_2, l2)
r2 = addMul64(r2, l1, l1)
r2 = addMul64(r2, l3_38, l4)
// r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
r3 := mul64(l0_2, l3)
r3 = addMul64(r3, l1_2, l2)
r3 = addMul64(r3, l4_19, l4)
// r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
r4 := mul64(l0_2, l4)
r4 = addMul64(r4, l1_2, l3)
r4 = addMul64(r4, l2, l2)
c0 := shiftRightBy51(r0)
c1 := shiftRightBy51(r1)
c2 := shiftRightBy51(r2)
c3 := shiftRightBy51(r3)
c4 := shiftRightBy51(r4)
rr0 := r0.lo&maskLow51Bits + c4*19
rr1 := r1.lo&maskLow51Bits + c0
rr2 := r2.lo&maskLow51Bits + c1
rr3 := r3.lo&maskLow51Bits + c2
rr4 := r4.lo&maskLow51Bits + c3
*v = Element{rr0, rr1, rr2, rr3, rr4}
v.carryPropagate()
}
// carryPropagate brings the limbs below 52 bits by applying the reduction
// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry.
func (v *Element) carryPropagateGeneric() *Element {
c0 := v.l0 >> 51
c1 := v.l1 >> 51
c2 := v.l2 >> 51
c3 := v.l3 >> 51
c4 := v.l4 >> 51
v.l0 = v.l0&maskLow51Bits + c4*19
v.l1 = v.l1&maskLow51Bits + c0
v.l2 = v.l2&maskLow51Bits + c1
v.l3 = v.l3&maskLow51Bits + c2
v.l4 = v.l4&maskLow51Bits + c3
return v
}

1027
vendor/filippo.io/edwards25519/scalar.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

214
vendor/filippo.io/edwards25519/scalarmult.go generated vendored Normal file
View File

@@ -0,0 +1,214 @@
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package edwards25519
import "sync"
// basepointTable is a set of 32 affineLookupTables, where table i is generated
// from 256i * basepoint. It is precomputed the first time it's used.
func basepointTable() *[32]affineLookupTable {
basepointTablePrecomp.initOnce.Do(func() {
p := NewGeneratorPoint()
for i := 0; i < 32; i++ {
basepointTablePrecomp.table[i].FromP3(p)
for j := 0; j < 8; j++ {
p.Add(p, p)
}
}
})
return &basepointTablePrecomp.table
}
var basepointTablePrecomp struct {
table [32]affineLookupTable
initOnce sync.Once
}
// ScalarBaseMult sets v = x * B, where B is the canonical generator, and
// returns v.
//
// The scalar multiplication is done in constant time.
func (v *Point) ScalarBaseMult(x *Scalar) *Point {
basepointTable := basepointTable()
// Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i )
// as described in the Ed25519 paper
//
// Group even and odd coefficients
// x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
// + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B
// x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
// + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B)
//
// We use a lookup table for each i to get x_i*16^(2*i)*B
// and do four doublings to multiply by 16.
digits := x.signedRadix16()
multiple := &affineCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
// Accumulate the odd components first
v.Set(NewIdentityPoint())
for i := 1; i < 64; i += 2 {
basepointTable[i/2].SelectInto(multiple, digits[i])
tmp1.AddAffine(v, multiple)
v.fromP1xP1(tmp1)
}
// Multiply by 16
tmp2.FromP3(v) // tmp2 = v in P2 coords
tmp1.Double(tmp2) // tmp1 = 2*v in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 2*v in P2 coords
tmp1.Double(tmp2) // tmp1 = 4*v in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 4*v in P2 coords
tmp1.Double(tmp2) // tmp1 = 8*v in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 8*v in P2 coords
tmp1.Double(tmp2) // tmp1 = 16*v in P1xP1 coords
v.fromP1xP1(tmp1) // now v = 16*(odd components)
// Accumulate the even components
for i := 0; i < 64; i += 2 {
basepointTable[i/2].SelectInto(multiple, digits[i])
tmp1.AddAffine(v, multiple)
v.fromP1xP1(tmp1)
}
return v
}
// ScalarMult sets v = x * q, and returns v.
//
// The scalar multiplication is done in constant time.
func (v *Point) ScalarMult(x *Scalar, q *Point) *Point {
checkInitialized(q)
var table projLookupTable
table.FromP3(q)
// Write x = sum(x_i * 16^i)
// so x*Q = sum( Q*x_i*16^i )
// = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... )
// <------compute inside out---------
//
// We use the lookup table to get the x_i*Q values
// and do four doublings to compute 16*Q
digits := x.signedRadix16()
// Unwrap first loop iteration to save computing 16*identity
multiple := &projCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
table.SelectInto(multiple, digits[63])
v.Set(NewIdentityPoint())
tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords
for i := 62; i >= 0; i-- {
tmp2.FromP1xP1(tmp1) // tmp2 = (prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords
tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords
table.SelectInto(multiple, digits[i])
tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords
}
v.fromP1xP1(tmp1)
return v
}
// basepointNafTable is the nafLookupTable8 for the basepoint.
// It is precomputed the first time it's used.
func basepointNafTable() *nafLookupTable8 {
basepointNafTablePrecomp.initOnce.Do(func() {
basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint())
})
return &basepointNafTablePrecomp.table
}
var basepointNafTablePrecomp struct {
table nafLookupTable8
initOnce sync.Once
}
// VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical
// generator, and returns v.
//
// Execution time depends on the inputs.
func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point {
checkInitialized(A)
// Similarly to the single variable-base approach, we compute
// digits and use them with a lookup table. However, because
// we are allowed to do variable-time operations, we don't
// need constant-time lookups or constant-time digit
// computations.
//
// So we use a non-adjacent form of some width w instead of
// radix 16. This is like a binary representation (one digit
// for each binary place) but we allow the digits to grow in
// magnitude up to 2^{w-1} so that the nonzero digits are as
// sparse as possible. Intuitively, this "condenses" the
// "mass" of the scalar onto sparse coefficients (meaning
// fewer additions).
basepointNafTable := basepointNafTable()
var aTable nafLookupTable5
aTable.FromP3(A)
// Because the basepoint is fixed, we can use a wider NAF
// corresponding to a bigger table.
aNaf := a.nonAdjacentForm(5)
bNaf := b.nonAdjacentForm(8)
// Find the first nonzero coefficient.
i := 255
for j := i; j >= 0; j-- {
if aNaf[j] != 0 || bNaf[j] != 0 {
break
}
}
multA := &projCached{}
multB := &affineCached{}
tmp1 := &projP1xP1{}
tmp2 := &projP2{}
tmp2.Zero()
// Move from high to low bits, doubling the accumulator
// at each iteration and checking whether there is a nonzero
// coefficient to look up a multiple of.
for ; i >= 0; i-- {
tmp1.Double(tmp2)
// Only update v if we have a nonzero coeff to add in.
if aNaf[i] > 0 {
v.fromP1xP1(tmp1)
aTable.SelectInto(multA, aNaf[i])
tmp1.Add(v, multA)
} else if aNaf[i] < 0 {
v.fromP1xP1(tmp1)
aTable.SelectInto(multA, -aNaf[i])
tmp1.Sub(v, multA)
}
if bNaf[i] > 0 {
v.fromP1xP1(tmp1)
basepointNafTable.SelectInto(multB, bNaf[i])
tmp1.AddAffine(v, multB)
} else if bNaf[i] < 0 {
v.fromP1xP1(tmp1)
basepointNafTable.SelectInto(multB, -bNaf[i])
tmp1.SubAffine(v, multB)
}
tmp2.FromP1xP1(tmp1)
}
v.fromP2(tmp2)
return v
}

129
vendor/filippo.io/edwards25519/tables.go generated vendored Normal file
View File

@@ -0,0 +1,129 @@
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package edwards25519
import (
"crypto/subtle"
)
// A dynamic lookup table for variable-base, constant-time scalar muls.
type projLookupTable struct {
points [8]projCached
}
// A precomputed lookup table for fixed-base, constant-time scalar muls.
type affineLookupTable struct {
points [8]affineCached
}
// A dynamic lookup table for variable-base, variable-time scalar muls.
type nafLookupTable5 struct {
points [8]projCached
}
// A precomputed lookup table for fixed-base, variable-time scalar muls.
type nafLookupTable8 struct {
points [64]affineCached
}
// Constructors.
// Builds a lookup table at runtime. Fast.
func (v *projLookupTable) FromP3(q *Point) {
// Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
// This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
v.points[0].FromP3(q)
tmpP3 := Point{}
tmpP1xP1 := projP1xP1{}
for i := 0; i < 7; i++ {
// Compute (i+1)*Q as Q + i*Q and convert to a ProjCached
// This is needlessly complicated because the API has explicit
// recievers instead of creating stack objects and relying on RVO
v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
}
}
// This is not optimised for speed; fixed-base tables should be precomputed.
func (v *affineLookupTable) FromP3(q *Point) {
// Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
// This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
v.points[0].FromP3(q)
tmpP3 := Point{}
tmpP1xP1 := projP1xP1{}
for i := 0; i < 7; i++ {
// Compute (i+1)*Q as Q + i*Q and convert to AffineCached
v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
}
}
// Builds a lookup table at runtime. Fast.
func (v *nafLookupTable5) FromP3(q *Point) {
// Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q
// This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q
v.points[0].FromP3(q)
q2 := Point{}
q2.Add(q, q)
tmpP3 := Point{}
tmpP1xP1 := projP1xP1{}
for i := 0; i < 7; i++ {
v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
}
}
// This is not optimised for speed; fixed-base tables should be precomputed.
func (v *nafLookupTable8) FromP3(q *Point) {
v.points[0].FromP3(q)
q2 := Point{}
q2.Add(q, q)
tmpP3 := Point{}
tmpP1xP1 := projP1xP1{}
for i := 0; i < 63; i++ {
v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
}
}
// Selectors.
// Set dest to x*Q, where -8 <= x <= 8, in constant time.
func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
// Compute xabs = |x|
xmask := x >> 7
xabs := uint8((x + xmask) ^ xmask)
dest.Zero()
for j := 1; j <= 8; j++ {
// Set dest = j*Q if |x| = j
cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
dest.Select(&v.points[j-1], dest, cond)
}
// Now dest = |x|*Q, conditionally negate to get x*Q
dest.CondNeg(int(xmask & 1))
}
// Set dest to x*Q, where -8 <= x <= 8, in constant time.
func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
// Compute xabs = |x|
xmask := x >> 7
xabs := uint8((x + xmask) ^ xmask)
dest.Zero()
for j := 1; j <= 8; j++ {
// Set dest = j*Q if |x| = j
cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
dest.Select(&v.points[j-1], dest, cond)
}
// Now dest = |x|*Q, conditionally negate to get x*Q
dest.CondNeg(int(xmask & 1))
}
// Given odd x with 0 < x < 2^4, return x*Q (in variable time).
func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
*dest = v.points[x/2]
}
// Given odd x with 0 < x < 2^7, return x*Q (in variable time).
func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
*dest = v.points[x/2]
}

View File

@@ -1,7 +1,7 @@
# VK SDK for Golang
[![PkgGoDev](https://pkg.go.dev/badge/github.com/SevereCloud/vksdk/v2/v2)](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2?tab=subdirectories)
[![VK Developers](https://img.shields.io/badge/developers-%234a76a8.svg?logo=VK&logoColor=white)](https://vk.com/dev/)
[![VK Developers](https://img.shields.io/badge/developers-%234a76a8.svg?logo=VK&logoColor=white)](https://dev.vk.com/)
[![codecov](https://codecov.io/gh/SevereCloud/vksdk/branch/master/graph/badge.svg)](https://codecov.io/gh/SevereCloud/vksdk)
[![VK chat](https://img.shields.io/badge/VK%20chat-%234a76a8.svg?logo=VK&logoColor=white)](https://vk.me/join/AJQ1d6Or8Q00Y_CSOESfbqGt)
[![release](https://img.shields.io/github/v/tag/SevereCloud/vksdk?label=release)](https://github.com/SevereCloud/vksdk/releases)

View File

@@ -141,6 +141,8 @@ func (vk *VK) AccountSetInfo(params Params) (response int, err error) {
// AccountSetNameInMenu sets an application screen name
// (up to 17 characters), that is shown to the user in the left menu.
//
// Deprecated: This method is deprecated and may be disabled soon, please avoid
//
// https://vk.com/dev/account.setNameInMenu
func (vk *VK) AccountSetNameInMenu(params Params) (response int, err error) {
err = vk.RequestUnmarshal("account.setNameInMenu", &response, params)

View File

@@ -1,4 +1,4 @@
package api // import "github.com/SevereCloud/vksdk/api"
package api // import "github.com/SevereCloud/vksdk/v2/api"
import (
"github.com/SevereCloud/vksdk/v2/object"

View File

@@ -235,6 +235,17 @@ func (vk *VK) VideoGetCommentsExtended(params Params) (response VideoGetComments
return
}
// VideoLiveGetCategoriesResponse struct.
type VideoLiveGetCategoriesResponse []object.VideoLiveCategory
// VideoLiveGetCategories method.
//
// https://vk.com/dev/video.liveGetCategories
func (vk *VK) VideoLiveGetCategories(params Params) (response VideoLiveGetCategoriesResponse, err error) {
err = vk.RequestUnmarshal("video.liveGetCategories", &response, params)
return
}
// VideoRemoveFromAlbum allows you to remove the video from the album.
//
// https://vk.com/dev/video.removeFromAlbum
@@ -336,3 +347,27 @@ func (vk *VK) VideoSearchExtended(params Params) (response VideoSearchExtendedRe
return
}
// VideoStartStreamingResponse struct.
type VideoStartStreamingResponse object.VideoLive
// VideoStartStreaming method.
//
// https://vk.com/dev/video.startStreaming
func (vk *VK) VideoStartStreaming(params Params) (response VideoStartStreamingResponse, err error) {
err = vk.RequestUnmarshal("video.startStreaming", &response, params)
return
}
// VideoStopStreamingResponse struct.
type VideoStopStreamingResponse struct {
UniqueViewers int `json:"unique_viewers"`
}
// VideoStopStreaming method.
//
// https://vk.com/dev/video.stopStreaming
func (vk *VK) VideoStopStreaming(params Params) (response VideoStopStreamingResponse, err error) {
err = vk.RequestUnmarshal("video.stopStreaming", &response, params)
return
}

View File

@@ -7,6 +7,6 @@ package vksdk
// Module constants.
const (
Version = "2.13.1"
Version = "2.14.0"
API = "5.131"
)

View File

@@ -15,3 +15,8 @@ func GroupIDFromContext(ctx context.Context) int {
func EventIDFromContext(ctx context.Context) string {
return ctx.Value(internal.EventIDKey).(string)
}
// VersionFromContext returns the version from context.
func VersionFromContext(ctx context.Context) string {
return ctx.Value(internal.EventVersionKey).(string)
}

View File

@@ -81,6 +81,7 @@ type GroupEvent struct {
Object json.RawMessage `json:"object"`
GroupID int `json:"group_id"`
EventID string `json:"event_id"`
V string `json:"v"`
Secret string `json:"secret"`
}
@@ -158,6 +159,7 @@ func NewFuncList() *FuncList {
func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { // nolint:gocyclo
ctx = context.WithValue(ctx, internal.GroupIDKey, e.GroupID)
ctx = context.WithValue(ctx, internal.EventIDKey, e.EventID)
ctx = context.WithValue(ctx, internal.EventVersionKey, e.V)
if sliceFunc, ok := fl.special[e.Type]; ok {
for _, f := range sliceFunc {

View File

@@ -28,6 +28,7 @@ const (
CallbackRetryCounterKey
CallbackRetryAfterKey
CallbackRemove
EventVersionKey
)
// ContextClient return *http.Client.

View File

@@ -84,7 +84,6 @@ type AccountAccountCounters struct {
// AccountInfo struct.
type AccountInfo struct {
// Country code.
Country string `json:"country"`

View File

@@ -409,7 +409,6 @@ type MessageContentSource struct {
Type string `json:"type"`
MessageContentSourceMessage // type message
MessageContentSourceURL // type url
}
// NewMessageContentSourceMessage ...

View File

@@ -24,110 +24,113 @@ const (
// UsersUser struct.
type UsersUser struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
FirstNameNom string `json:"first_name_nom"`
FirstNameGen string `json:"first_name_gen"`
FirstNameDat string `json:"first_name_dat"`
FirstNameAcc string `json:"first_name_acc"`
FirstNameIns string `json:"first_name_ins"`
FirstNameAbl string `json:"first_name_abl"`
LastNameNom string `json:"last_name_nom"`
LastNameGen string `json:"last_name_gen"`
LastNameDat string `json:"last_name_dat"`
LastNameAcc string `json:"last_name_acc"`
LastNameIns string `json:"last_name_ins"`
LastNameAbl string `json:"last_name_abl"`
MaidenName string `json:"maiden_name"`
Sex int `json:"sex"`
Nickname string `json:"nickname"`
Domain string `json:"domain"`
ScreenName string `json:"screen_name"`
Bdate string `json:"bdate"`
City BaseObject `json:"city"`
Country BaseObject `json:"country"`
Photo50 string `json:"photo_50"`
Photo100 string `json:"photo_100"`
Photo200 string `json:"photo_200"`
PhotoMax string `json:"photo_max"`
Photo200Orig string `json:"photo_200_orig"`
Photo400Orig string `json:"photo_400_orig"`
PhotoMaxOrig string `json:"photo_max_orig"`
PhotoID string `json:"photo_id"`
FriendStatus int `json:"friend_status"` // see FriendStatus const
OnlineApp int `json:"online_app"`
Online BaseBoolInt `json:"online"`
OnlineMobile BaseBoolInt `json:"online_mobile"`
HasPhoto BaseBoolInt `json:"has_photo"`
HasMobile BaseBoolInt `json:"has_mobile"`
IsClosed BaseBoolInt `json:"is_closed"`
IsFriend BaseBoolInt `json:"is_friend"`
IsFavorite BaseBoolInt `json:"is_favorite"`
IsHiddenFromFeed BaseBoolInt `json:"is_hidden_from_feed"`
CanAccessClosed BaseBoolInt `json:"can_access_closed"`
CanBeInvitedGroup BaseBoolInt `json:"can_be_invited_group"`
CanPost BaseBoolInt `json:"can_post"`
CanSeeAllPosts BaseBoolInt `json:"can_see_all_posts"`
CanSeeAudio BaseBoolInt `json:"can_see_audio"`
CanWritePrivateMessage BaseBoolInt `json:"can_write_private_message"`
CanSendFriendRequest BaseBoolInt `json:"can_send_friend_request"`
CanCallFromGroup BaseBoolInt `json:"can_call_from_group"`
Verified BaseBoolInt `json:"verified"`
Trending BaseBoolInt `json:"trending"`
Blacklisted BaseBoolInt `json:"blacklisted"`
BlacklistedByMe BaseBoolInt `json:"blacklisted_by_me"`
Facebook string `json:"facebook"`
FacebookName string `json:"facebook_name"`
Twitter string `json:"twitter"`
Instagram string `json:"instagram"`
Site string `json:"site"`
Status string `json:"status"`
StatusAudio AudioAudio `json:"status_audio"`
LastSeen UsersLastSeen `json:"last_seen"`
CropPhoto UsersCropPhoto `json:"crop_photo"`
FollowersCount int `json:"followers_count"`
CommonCount int `json:"common_count"`
Occupation UsersOccupation `json:"occupation"`
Career []UsersCareer `json:"career"`
Military []UsersMilitary `json:"military"`
University int `json:"university"`
UniversityName string `json:"university_name"`
Faculty int `json:"faculty"`
FacultyName string `json:"faculty_name"`
Graduation int `json:"graduation"`
EducationForm string `json:"education_form"`
EducationStatus string `json:"education_status"`
HomeTown string `json:"home_town"`
Relation int `json:"relation"`
Personal UsersPersonal `json:"personal"`
Interests string `json:"interests"`
Music string `json:"music"`
Activities string `json:"activities"`
Movies string `json:"movies"`
Tv string `json:"tv"`
Books string `json:"books"`
Games string `json:"games"`
Universities []UsersUniversity `json:"universities"`
Schools []UsersSchool `json:"schools"`
About string `json:"about"`
Relatives []UsersRelative `json:"relatives"`
Quotes string `json:"quotes"`
Lists []int `json:"lists"`
Deactivated string `json:"deactivated"`
WallDefault string `json:"wall_default"`
Timezone int `json:"timezone"`
Exports UsersExports `json:"exports"`
Counters UsersUserCounters `json:"counters"`
MobilePhone string `json:"mobile_phone"`
HomePhone string `json:"home_phone"`
FoundWith int `json:"found_with"` // TODO: check it
OnlineInfo UsersOnlineInfo `json:"online_info"`
Mutual FriendsRequestsMutual `json:"mutual"`
TrackCode string `json:"track_code"`
RelationPartner UsersUserMin `json:"relation_partner"`
Type string `json:"type"`
Skype string `json:"skype"`
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
FirstNameNom string `json:"first_name_nom"`
FirstNameGen string `json:"first_name_gen"`
FirstNameDat string `json:"first_name_dat"`
FirstNameAcc string `json:"first_name_acc"`
FirstNameIns string `json:"first_name_ins"`
FirstNameAbl string `json:"first_name_abl"`
LastNameNom string `json:"last_name_nom"`
LastNameGen string `json:"last_name_gen"`
LastNameDat string `json:"last_name_dat"`
LastNameAcc string `json:"last_name_acc"`
LastNameIns string `json:"last_name_ins"`
LastNameAbl string `json:"last_name_abl"`
MaidenName string `json:"maiden_name"`
Sex int `json:"sex"`
Nickname string `json:"nickname"`
Domain string `json:"domain"`
ScreenName string `json:"screen_name"`
Bdate string `json:"bdate"`
City BaseObject `json:"city"`
Country BaseObject `json:"country"`
Photo50 string `json:"photo_50"`
Photo100 string `json:"photo_100"`
Photo200 string `json:"photo_200"`
PhotoMax string `json:"photo_max"`
Photo200Orig string `json:"photo_200_orig"`
Photo400Orig string `json:"photo_400_orig"`
PhotoMaxOrig string `json:"photo_max_orig"`
PhotoID string `json:"photo_id"`
FriendStatus int `json:"friend_status"` // see FriendStatus const
OnlineApp int `json:"online_app"`
Online BaseBoolInt `json:"online"`
OnlineMobile BaseBoolInt `json:"online_mobile"`
HasPhoto BaseBoolInt `json:"has_photo"`
HasMobile BaseBoolInt `json:"has_mobile"`
IsClosed BaseBoolInt `json:"is_closed"`
IsFriend BaseBoolInt `json:"is_friend"`
IsFavorite BaseBoolInt `json:"is_favorite"`
IsHiddenFromFeed BaseBoolInt `json:"is_hidden_from_feed"`
CanAccessClosed BaseBoolInt `json:"can_access_closed"`
CanBeInvitedGroup BaseBoolInt `json:"can_be_invited_group"`
CanPost BaseBoolInt `json:"can_post"`
CanSeeAllPosts BaseBoolInt `json:"can_see_all_posts"`
CanSeeAudio BaseBoolInt `json:"can_see_audio"`
CanWritePrivateMessage BaseBoolInt `json:"can_write_private_message"`
CanSendFriendRequest BaseBoolInt `json:"can_send_friend_request"`
CanCallFromGroup BaseBoolInt `json:"can_call_from_group"`
Verified BaseBoolInt `json:"verified"`
Trending BaseBoolInt `json:"trending"`
Blacklisted BaseBoolInt `json:"blacklisted"`
BlacklistedByMe BaseBoolInt `json:"blacklisted_by_me"`
// Deprecated: Facebook и Instagram запрещены в России, Meta признана экстремистской организацией...
Facebook string `json:"facebook"`
// Deprecated: Facebook и Instagram запрещены в России, Meta признана экстремистской организацией...
FacebookName string `json:"facebook_name"`
// Deprecated: Facebook и Instagram запрещены в России, Meta признана экстремистской организацией...
Instagram string `json:"instagram"`
Twitter string `json:"twitter"`
Site string `json:"site"`
Status string `json:"status"`
StatusAudio AudioAudio `json:"status_audio"`
LastSeen UsersLastSeen `json:"last_seen"`
CropPhoto UsersCropPhoto `json:"crop_photo"`
FollowersCount int `json:"followers_count"`
CommonCount int `json:"common_count"`
Occupation UsersOccupation `json:"occupation"`
Career []UsersCareer `json:"career"`
Military []UsersMilitary `json:"military"`
University int `json:"university"`
UniversityName string `json:"university_name"`
Faculty int `json:"faculty"`
FacultyName string `json:"faculty_name"`
Graduation int `json:"graduation"`
EducationForm string `json:"education_form"`
EducationStatus string `json:"education_status"`
HomeTown string `json:"home_town"`
Relation int `json:"relation"`
Personal UsersPersonal `json:"personal"`
Interests string `json:"interests"`
Music string `json:"music"`
Activities string `json:"activities"`
Movies string `json:"movies"`
Tv string `json:"tv"`
Books string `json:"books"`
Games string `json:"games"`
Universities []UsersUniversity `json:"universities"`
Schools []UsersSchool `json:"schools"`
About string `json:"about"`
Relatives []UsersRelative `json:"relatives"`
Quotes string `json:"quotes"`
Lists []int `json:"lists"`
Deactivated string `json:"deactivated"`
WallDefault string `json:"wall_default"`
Timezone int `json:"timezone"`
Exports UsersExports `json:"exports"`
Counters UsersUserCounters `json:"counters"`
MobilePhone string `json:"mobile_phone"`
HomePhone string `json:"home_phone"`
FoundWith int `json:"found_with"` // TODO: check it
OnlineInfo UsersOnlineInfo `json:"online_info"`
Mutual FriendsRequestsMutual `json:"mutual"`
TrackCode string `json:"track_code"`
RelationPartner UsersUserMin `json:"relation_partner"`
Type string `json:"type"`
Skype string `json:"skype"`
}
// ToMention return mention.

View File

@@ -297,3 +297,27 @@ type VideoVideoImage struct {
BaseImage
WithPadding BaseBoolInt `json:"with_padding"`
}
// VideoLive struct.
type VideoLive struct {
OwnerID int `json:"owner_id"`
VideoID int `json:"video_id"`
Name string `json:"name"`
Description string `json:"description"`
AccessKey string `json:"access_key"`
Stream VideoLiveStream `json:"stream"`
}
// VideoLiveStream struct.
type VideoLiveStream struct {
URL string `json:"url"`
Key string `json:"key"`
OKMPURL string `json:"okmp_url"`
}
// VideoLiveCategory struct.
type VideoLiveCategory struct {
ID int `json:"id"`
Label string `json:"label"`
Sublist []VideoLiveCategory `json:"sublist,omitempty"`
}

View File

@@ -4,6 +4,8 @@ go:
- 1.14.x
- 1.15.x
- 1.16.x
- 1.17.x
- 1.18.x
env:
- GO111MODULE=on
install:

View File

@@ -70,7 +70,7 @@ type ActionsRow struct {
func (r ActionsRow) MarshalJSON() ([]byte, error) {
type actionsRow ActionsRow
return json.Marshal(struct {
return Marshal(struct {
actionsRow
Type ComponentType `json:"type"`
}{
@@ -145,7 +145,7 @@ func (b Button) MarshalJSON() ([]byte, error) {
b.Style = PrimaryButton
}
return json.Marshal(struct {
return Marshal(struct {
button
Type ComponentType `json:"type"`
}{
@@ -192,7 +192,7 @@ func (SelectMenu) Type() ComponentType {
func (m SelectMenu) MarshalJSON() ([]byte, error) {
type selectMenu SelectMenu
return json.Marshal(struct {
return Marshal(struct {
selectMenu
Type ComponentType `json:"type"`
}{
@@ -208,7 +208,7 @@ type TextInput struct {
Style TextInputStyle `json:"style"`
Placeholder string `json:"placeholder,omitempty"`
Value string `json:"value,omitempty"`
Required bool `json:"required,omitempty"`
Required bool `json:"required"`
MinLength int `json:"min_length,omitempty"`
MaxLength int `json:"max_length,omitempty"`
}
@@ -222,7 +222,7 @@ func (TextInput) Type() ComponentType {
func (m TextInput) MarshalJSON() ([]byte, error) {
type inputText TextInput
return json.Marshal(struct {
return Marshal(struct {
inputText
Type ComponentType `json:"type"`
}{

View File

@@ -20,7 +20,7 @@ import (
)
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
const VERSION = "0.24.0"
const VERSION = "0.25.0"
// New creates a new Discord session with provided token.
// If the token is for a bot, it must be prefixed with "Bot "
@@ -36,6 +36,7 @@ func New(token string) (s *Session, err error) {
StateEnabled: true,
Compress: true,
ShouldReconnectOnError: true,
ShouldRetryOnRateLimit: true,
ShardID: 0,
ShardCount: 1,
MaxRestRetries: 3,
@@ -49,7 +50,6 @@ func New(token string) (s *Session, err error) {
// These can be modified prior to calling Open()
s.Identify.Compress = true
s.Identify.LargeThreshold = 250
s.Identify.GuildSubscriptions = true
s.Identify.Properties.OS = runtime.GOOS
s.Identify.Properties.Browser = "DiscordGo v" + VERSION
s.Identify.Intents = IntentsAllWithoutPrivileged

View File

@@ -23,15 +23,16 @@ var (
EndpointSmActive = EndpointSm + "active.json"
EndpointSmUpcoming = EndpointSm + "upcoming.json"
EndpointDiscord = "https://discord.com/"
EndpointAPI = EndpointDiscord + "api/v" + APIVersion + "/"
EndpointGuilds = EndpointAPI + "guilds/"
EndpointChannels = EndpointAPI + "channels/"
EndpointUsers = EndpointAPI + "users/"
EndpointGateway = EndpointAPI + "gateway"
EndpointGatewayBot = EndpointGateway + "/bot"
EndpointWebhooks = EndpointAPI + "webhooks/"
EndpointStickers = EndpointAPI + "stickers/"
EndpointDiscord = "https://discord.com/"
EndpointAPI = EndpointDiscord + "api/v" + APIVersion + "/"
EndpointGuilds = EndpointAPI + "guilds/"
EndpointChannels = EndpointAPI + "channels/"
EndpointUsers = EndpointAPI + "users/"
EndpointGateway = EndpointAPI + "gateway"
EndpointGatewayBot = EndpointGateway + "/bot"
EndpointWebhooks = EndpointAPI + "webhooks/"
EndpointStickers = EndpointAPI + "stickers/"
EndpointStageInstances = EndpointAPI + "stage-instances"
EndpointCDN = "https://cdn.discordapp.com/"
EndpointCDNAttachments = EndpointCDN + "attachments/"
@@ -72,6 +73,7 @@ var (
EndpointGuildPreview = func(gID string) string { return EndpointGuilds + gID + "/preview" }
EndpointGuildChannels = func(gID string) string { return EndpointGuilds + gID + "/channels" }
EndpointGuildMembers = func(gID string) string { return EndpointGuilds + gID + "/members" }
EndpointGuildMembersSearch = func(gID string) string { return EndpointGuildMembers(gID) + "/search" }
EndpointGuildMember = func(gID, uID string) string { return EndpointGuilds + gID + "/members/" + uID }
EndpointGuildMemberRole = func(gID, uID, rID string) string { return EndpointGuilds + gID + "/members/" + uID + "/roles/" + rID }
EndpointGuildBans = func(gID string) string { return EndpointGuilds + gID + "/bans" }
@@ -94,6 +96,7 @@ var (
EndpointGuildBanner = func(gID, hash string) string { return EndpointCDNBanners + gID + "/" + hash + ".png" }
EndpointGuildStickers = func(gID string) string { return EndpointGuilds + gID + "/stickers" }
EndpointGuildSticker = func(gID, sID string) string { return EndpointGuilds + gID + "/stickers/" + sID }
EndpointStageInstance = func(cID string) string { return EndpointStageInstances + "/" + cID }
EndpointGuildScheduledEvents = func(gID string) string { return EndpointGuilds + gID + "/scheduled-events" }
EndpointGuildScheduledEvent = func(gID, eID string) string { return EndpointGuilds + gID + "/scheduled-events/" + eID }
EndpointGuildScheduledEventUsers = func(gID, eID string) string { return EndpointGuildScheduledEvent(gID, eID) + "/users" }

View File

@@ -7,62 +7,67 @@ package discordgo
// Event type values are used to match the events returned by Discord.
// EventTypes surrounded by __ are synthetic and are internal to DiscordGo.
const (
channelCreateEventType = "CHANNEL_CREATE"
channelDeleteEventType = "CHANNEL_DELETE"
channelPinsUpdateEventType = "CHANNEL_PINS_UPDATE"
channelUpdateEventType = "CHANNEL_UPDATE"
connectEventType = "__CONNECT__"
disconnectEventType = "__DISCONNECT__"
eventEventType = "__EVENT__"
guildBanAddEventType = "GUILD_BAN_ADD"
guildBanRemoveEventType = "GUILD_BAN_REMOVE"
guildCreateEventType = "GUILD_CREATE"
guildDeleteEventType = "GUILD_DELETE"
guildEmojisUpdateEventType = "GUILD_EMOJIS_UPDATE"
guildIntegrationsUpdateEventType = "GUILD_INTEGRATIONS_UPDATE"
guildMemberAddEventType = "GUILD_MEMBER_ADD"
guildMemberRemoveEventType = "GUILD_MEMBER_REMOVE"
guildMemberUpdateEventType = "GUILD_MEMBER_UPDATE"
guildMembersChunkEventType = "GUILD_MEMBERS_CHUNK"
guildRoleCreateEventType = "GUILD_ROLE_CREATE"
guildRoleDeleteEventType = "GUILD_ROLE_DELETE"
guildRoleUpdateEventType = "GUILD_ROLE_UPDATE"
guildUpdateEventType = "GUILD_UPDATE"
guildScheduledEventCreateEventType = "GUILD_SCHEDULED_EVENT_CREATE"
guildScheduledEventUpdateEventType = "GUILD_SCHEDULED_EVENT_UPDATE"
guildScheduledEventDeleteEventType = "GUILD_SCHEDULED_EVENT_DELETE"
interactionCreateEventType = "INTERACTION_CREATE"
inviteCreateEventType = "INVITE_CREATE"
inviteDeleteEventType = "INVITE_DELETE"
messageAckEventType = "MESSAGE_ACK"
messageCreateEventType = "MESSAGE_CREATE"
messageDeleteEventType = "MESSAGE_DELETE"
messageDeleteBulkEventType = "MESSAGE_DELETE_BULK"
messageReactionAddEventType = "MESSAGE_REACTION_ADD"
messageReactionRemoveEventType = "MESSAGE_REACTION_REMOVE"
messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL"
messageUpdateEventType = "MESSAGE_UPDATE"
presenceUpdateEventType = "PRESENCE_UPDATE"
presencesReplaceEventType = "PRESENCES_REPLACE"
rateLimitEventType = "__RATE_LIMIT__"
readyEventType = "READY"
relationshipAddEventType = "RELATIONSHIP_ADD"
relationshipRemoveEventType = "RELATIONSHIP_REMOVE"
resumedEventType = "RESUMED"
threadCreateEventType = "THREAD_CREATE"
threadDeleteEventType = "THREAD_DELETE"
threadListSyncEventType = "THREAD_LIST_SYNC"
threadMemberUpdateEventType = "THREAD_MEMBER_UPDATE"
threadMembersUpdateEventType = "THREAD_MEMBERS_UPDATE"
threadUpdateEventType = "THREAD_UPDATE"
typingStartEventType = "TYPING_START"
userGuildSettingsUpdateEventType = "USER_GUILD_SETTINGS_UPDATE"
userNoteUpdateEventType = "USER_NOTE_UPDATE"
userSettingsUpdateEventType = "USER_SETTINGS_UPDATE"
userUpdateEventType = "USER_UPDATE"
voiceServerUpdateEventType = "VOICE_SERVER_UPDATE"
voiceStateUpdateEventType = "VOICE_STATE_UPDATE"
webhooksUpdateEventType = "WEBHOOKS_UPDATE"
channelCreateEventType = "CHANNEL_CREATE"
channelDeleteEventType = "CHANNEL_DELETE"
channelPinsUpdateEventType = "CHANNEL_PINS_UPDATE"
channelUpdateEventType = "CHANNEL_UPDATE"
connectEventType = "__CONNECT__"
disconnectEventType = "__DISCONNECT__"
eventEventType = "__EVENT__"
guildBanAddEventType = "GUILD_BAN_ADD"
guildBanRemoveEventType = "GUILD_BAN_REMOVE"
guildCreateEventType = "GUILD_CREATE"
guildDeleteEventType = "GUILD_DELETE"
guildEmojisUpdateEventType = "GUILD_EMOJIS_UPDATE"
guildIntegrationsUpdateEventType = "GUILD_INTEGRATIONS_UPDATE"
guildMemberAddEventType = "GUILD_MEMBER_ADD"
guildMemberRemoveEventType = "GUILD_MEMBER_REMOVE"
guildMemberUpdateEventType = "GUILD_MEMBER_UPDATE"
guildMembersChunkEventType = "GUILD_MEMBERS_CHUNK"
guildRoleCreateEventType = "GUILD_ROLE_CREATE"
guildRoleDeleteEventType = "GUILD_ROLE_DELETE"
guildRoleUpdateEventType = "GUILD_ROLE_UPDATE"
guildStageInstanceCreateEventType = "STAGE_INSTANCE_CREATE"
guildStageInstanceUpdateEventType = "STAGE_INSTANCE_UPDATE"
guildStageInstanceDeleteEventType = "STAGE_INSTANCE_DELETE"
guildScheduledEventCreateEventType = "GUILD_SCHEDULED_EVENT_CREATE"
guildScheduledEventDeleteEventType = "GUILD_SCHEDULED_EVENT_DELETE"
guildScheduledEventUpdateEventType = "GUILD_SCHEDULED_EVENT_UPDATE"
guildScheduledEventUserAddEventType = "GUILD_SCHEDULED_EVENT_USER_ADD"
guildScheduledEventUserRemoveEventType = "GUILD_SCHEDULED_EVENT_USER_REMOVE"
guildUpdateEventType = "GUILD_UPDATE"
interactionCreateEventType = "INTERACTION_CREATE"
inviteCreateEventType = "INVITE_CREATE"
inviteDeleteEventType = "INVITE_DELETE"
messageAckEventType = "MESSAGE_ACK"
messageCreateEventType = "MESSAGE_CREATE"
messageDeleteEventType = "MESSAGE_DELETE"
messageDeleteBulkEventType = "MESSAGE_DELETE_BULK"
messageReactionAddEventType = "MESSAGE_REACTION_ADD"
messageReactionRemoveEventType = "MESSAGE_REACTION_REMOVE"
messageReactionRemoveAllEventType = "MESSAGE_REACTION_REMOVE_ALL"
messageUpdateEventType = "MESSAGE_UPDATE"
presenceUpdateEventType = "PRESENCE_UPDATE"
presencesReplaceEventType = "PRESENCES_REPLACE"
rateLimitEventType = "__RATE_LIMIT__"
readyEventType = "READY"
relationshipAddEventType = "RELATIONSHIP_ADD"
relationshipRemoveEventType = "RELATIONSHIP_REMOVE"
resumedEventType = "RESUMED"
threadCreateEventType = "THREAD_CREATE"
threadDeleteEventType = "THREAD_DELETE"
threadListSyncEventType = "THREAD_LIST_SYNC"
threadMemberUpdateEventType = "THREAD_MEMBER_UPDATE"
threadMembersUpdateEventType = "THREAD_MEMBERS_UPDATE"
threadUpdateEventType = "THREAD_UPDATE"
typingStartEventType = "TYPING_START"
userGuildSettingsUpdateEventType = "USER_GUILD_SETTINGS_UPDATE"
userNoteUpdateEventType = "USER_NOTE_UPDATE"
userSettingsUpdateEventType = "USER_SETTINGS_UPDATE"
userUpdateEventType = "USER_UPDATE"
voiceServerUpdateEventType = "VOICE_SERVER_UPDATE"
voiceStateUpdateEventType = "VOICE_STATE_UPDATE"
webhooksUpdateEventType = "WEBHOOKS_UPDATE"
)
// channelCreateEventHandler is an event handler for ChannelCreate events.
@@ -310,66 +315,6 @@ func (eh guildIntegrationsUpdateEventHandler) Handle(s *Session, i interface{})
}
}
// guildScheduledEventCreateEventHandler is an event handler for GuildScheduledEventCreate events.
type guildScheduledEventCreateEventHandler func(*Session, *GuildScheduledEventCreate)
// Type returns the event type for GuildScheduledEventCreate events.
func (eh guildScheduledEventCreateEventHandler) Type() string {
return guildScheduledEventCreateEventType
}
// New returns a new instance of GuildScheduledEventCreate.
func (eh guildScheduledEventCreateEventHandler) New() interface{} {
return &GuildScheduledEventCreate{}
}
// Handle is the handler for GuildScheduledEventCreate events.
func (eh guildScheduledEventCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventCreate); ok {
eh(s, t)
}
}
// guildScheduledEventUpdateEventHandler is an event handler for GuildScheduledEventUpdate events.
type guildScheduledEventUpdateEventHandler func(*Session, *GuildScheduledEventUpdate)
// Type returns the event type for GuildScheduledEventUpdate events.
func (eh guildScheduledEventUpdateEventHandler) Type() string {
return guildScheduledEventUpdateEventType
}
// New returns a new instance of GuildScheduledEventUpdate.
func (eh guildScheduledEventUpdateEventHandler) New() interface{} {
return &GuildScheduledEventUpdate{}
}
// Handle is the handler for GuildScheduledEventUpdate events.
func (eh guildScheduledEventUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventUpdate); ok {
eh(s, t)
}
}
// guildScheduledEventDeleteEventHandler is an event handler for GuildScheduledEventDelete events.
type guildScheduledEventDeleteEventHandler func(*Session, *GuildScheduledEventDelete)
// Type returns the event type for GuildScheduledEventDelete events.
func (eh guildScheduledEventDeleteEventHandler) Type() string {
return guildScheduledEventDeleteEventType
}
// New returns a new instance of GuildScheduledEventDelete.
func (eh guildScheduledEventDeleteEventHandler) New() interface{} {
return &GuildScheduledEventDelete{}
}
// Handle is the handler for GuildScheduledEventDelete events.
func (eh guildScheduledEventDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventDelete); ok {
eh(s, t)
}
}
// guildMemberAddEventHandler is an event handler for GuildMemberAdd events.
type guildMemberAddEventHandler func(*Session, *GuildMemberAdd)
@@ -510,6 +455,166 @@ func (eh guildRoleUpdateEventHandler) Handle(s *Session, i interface{}) {
}
}
// guildStageInstanceEventCreateHandler is an event handler for StageInstanceEventCreate events.
type guildStageInstanceEventCreateHandler func(*Session, *StageInstanceEventCreate)
// Type returns the event type for StageInstanceEventCreate events.
func (eh guildStageInstanceEventCreateHandler) Type() string {
return guildStageInstanceCreateEventType
}
// New returns a new instance of StageInstanceEventCreate.
func (eh guildStageInstanceEventCreateHandler) New() interface{} {
return &StageInstanceEventCreate{}
}
// Handle is the handler for StageInstanceEventCreate events.
func (eh guildStageInstanceEventCreateHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*StageInstanceEventCreate); ok {
eh(s, t)
}
}
// guildStageInstanceEventUpdateHandler is an event handler for StageInstanceEventUpdate events.
type guildStageInstanceEventUpdateHandler func(*Session, *StageInstanceEventUpdate)
// Type returns the event type for StageInstanceEventUpdate events.
func (eh guildStageInstanceEventUpdateHandler) Type() string {
return guildStageInstanceCreateEventType
}
// New returns a new instance of StageInstanceEventUpdate.
func (eh guildStageInstanceEventUpdateHandler) New() interface{} {
return &StageInstanceEventUpdate{}
}
// Handle is the handler for StageInstanceEventUpdate events.
func (eh guildStageInstanceEventUpdateHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*StageInstanceEventUpdate); ok {
eh(s, t)
}
}
// guildStageInstanceEventDeleteHandler is an event handler for StageInstanceEventDelete events.
type guildStageInstanceEventDeleteHandler func(*Session, *StageInstanceEventDelete)
// Type returns the event type for StageInstanceEventDelete events.
func (eh guildStageInstanceEventDeleteHandler) Type() string {
return guildStageInstanceCreateEventType
}
// New returns a new instance of StageInstanceEventDelete.
func (eh guildStageInstanceEventDeleteHandler) New() interface{} {
return &StageInstanceEventDelete{}
}
// Handle is the handler for StageInstanceEventDelete events.
func (eh guildStageInstanceEventDeleteHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*StageInstanceEventDelete); ok {
eh(s, t)
}
}
// guildScheduledEventCreateEventHandler is an event handler for GuildScheduledEventCreate events.
type guildScheduledEventCreateEventHandler func(*Session, *GuildScheduledEventCreate)
// Type returns the event type for GuildScheduledEventCreate events.
func (eh guildScheduledEventCreateEventHandler) Type() string {
return guildScheduledEventCreateEventType
}
// New returns a new instance of GuildScheduledEventCreate.
func (eh guildScheduledEventCreateEventHandler) New() interface{} {
return &GuildScheduledEventCreate{}
}
// Handle is the handler for GuildScheduledEventCreate events.
func (eh guildScheduledEventCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventCreate); ok {
eh(s, t)
}
}
// guildScheduledEventDeleteEventHandler is an event handler for GuildScheduledEventDelete events.
type guildScheduledEventDeleteEventHandler func(*Session, *GuildScheduledEventDelete)
// Type returns the event type for GuildScheduledEventDelete events.
func (eh guildScheduledEventDeleteEventHandler) Type() string {
return guildScheduledEventDeleteEventType
}
// New returns a new instance of GuildScheduledEventDelete.
func (eh guildScheduledEventDeleteEventHandler) New() interface{} {
return &GuildScheduledEventDelete{}
}
// Handle is the handler for GuildScheduledEventDelete events.
func (eh guildScheduledEventDeleteEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventDelete); ok {
eh(s, t)
}
}
// guildScheduledEventUpdateEventHandler is an event handler for GuildScheduledEventUpdate events.
type guildScheduledEventUpdateEventHandler func(*Session, *GuildScheduledEventUpdate)
// Type returns the event type for GuildScheduledEventUpdate events.
func (eh guildScheduledEventUpdateEventHandler) Type() string {
return guildScheduledEventUpdateEventType
}
// New returns a new instance of GuildScheduledEventUpdate.
func (eh guildScheduledEventUpdateEventHandler) New() interface{} {
return &GuildScheduledEventUpdate{}
}
// Handle is the handler for GuildScheduledEventUpdate events.
func (eh guildScheduledEventUpdateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventUpdate); ok {
eh(s, t)
}
}
// guildScheduledEventUserAddEventHandler is an event handler for GuildScheduledEventUserAdd events.
type guildScheduledEventUserAddEventHandler func(*Session, *GuildScheduledEventUserAdd)
// Type returns the event type for GuildScheduledEventUserAdd events.
func (eh guildScheduledEventUserAddEventHandler) Type() string {
return guildScheduledEventUserAddEventType
}
// New returns a new instance of GuildScheduledEventUserAdd.
func (eh guildScheduledEventUserAddEventHandler) New() interface{} {
return &GuildScheduledEventUserAdd{}
}
// Handle is the handler for GuildScheduledEventUserAdd events.
func (eh guildScheduledEventUserAddEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventUserAdd); ok {
eh(s, t)
}
}
// guildScheduledEventUserRemoveEventHandler is an event handler for GuildScheduledEventUserRemove events.
type guildScheduledEventUserRemoveEventHandler func(*Session, *GuildScheduledEventUserRemove)
// Type returns the event type for GuildScheduledEventUserRemove events.
func (eh guildScheduledEventUserRemoveEventHandler) Type() string {
return guildScheduledEventUserRemoveEventType
}
// New returns a new instance of GuildScheduledEventUserRemove.
func (eh guildScheduledEventUserRemoveEventHandler) New() interface{} {
return &GuildScheduledEventUserRemove{}
}
// Handle is the handler for GuildScheduledEventUserRemove events.
func (eh guildScheduledEventUserRemoveEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildScheduledEventUserRemove); ok {
eh(s, t)
}
}
// guildUpdateEventHandler is an event handler for GuildUpdate events.
type guildUpdateEventHandler func(*Session, *GuildUpdate)
@@ -1195,12 +1300,6 @@ func handlerForInterface(handler interface{}) EventHandler {
return guildEmojisUpdateEventHandler(v)
case func(*Session, *GuildIntegrationsUpdate):
return guildIntegrationsUpdateEventHandler(v)
case func(*Session, *GuildScheduledEventCreate):
return guildScheduledEventCreateEventHandler(v)
case func(*Session, *GuildScheduledEventUpdate):
return guildScheduledEventUpdateEventHandler(v)
case func(*Session, *GuildScheduledEventDelete):
return guildScheduledEventDeleteEventHandler(v)
case func(*Session, *GuildMemberAdd):
return guildMemberAddEventHandler(v)
case func(*Session, *GuildMemberRemove):
@@ -1215,6 +1314,16 @@ func handlerForInterface(handler interface{}) EventHandler {
return guildRoleDeleteEventHandler(v)
case func(*Session, *GuildRoleUpdate):
return guildRoleUpdateEventHandler(v)
case func(*Session, *GuildScheduledEventCreate):
return guildScheduledEventCreateEventHandler(v)
case func(*Session, *GuildScheduledEventDelete):
return guildScheduledEventDeleteEventHandler(v)
case func(*Session, *GuildScheduledEventUpdate):
return guildScheduledEventUpdateEventHandler(v)
case func(*Session, *GuildScheduledEventUserAdd):
return guildScheduledEventUserAddEventHandler(v)
case func(*Session, *GuildScheduledEventUserRemove):
return guildScheduledEventUserRemoveEventHandler(v)
case func(*Session, *GuildUpdate):
return guildUpdateEventHandler(v)
case func(*Session, *InteractionCreate):
@@ -1297,9 +1406,6 @@ func init() {
registerInterfaceProvider(guildDeleteEventHandler(nil))
registerInterfaceProvider(guildEmojisUpdateEventHandler(nil))
registerInterfaceProvider(guildIntegrationsUpdateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventCreateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventUpdateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventDeleteEventHandler(nil))
registerInterfaceProvider(guildMemberAddEventHandler(nil))
registerInterfaceProvider(guildMemberRemoveEventHandler(nil))
registerInterfaceProvider(guildMemberUpdateEventHandler(nil))
@@ -1307,6 +1413,11 @@ func init() {
registerInterfaceProvider(guildRoleCreateEventHandler(nil))
registerInterfaceProvider(guildRoleDeleteEventHandler(nil))
registerInterfaceProvider(guildRoleUpdateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventCreateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventDeleteEventHandler(nil))
registerInterfaceProvider(guildScheduledEventUpdateEventHandler(nil))
registerInterfaceProvider(guildScheduledEventUserAddEventHandler(nil))
registerInterfaceProvider(guildScheduledEventUserRemoveEventHandler(nil))
registerInterfaceProvider(guildUpdateEventHandler(nil))
registerInterfaceProvider(interactionCreateEventHandler(nil))
registerInterfaceProvider(inviteCreateEventHandler(nil))

View File

@@ -191,7 +191,9 @@ type GuildMembersChunk struct {
Members []*Member `json:"members"`
ChunkIndex int `json:"chunk_index"`
ChunkCount int `json:"chunk_count"`
NotFound []string `json:"not_found,omitempty"`
Presences []*Presence `json:"presences,omitempty"`
Nonce string `json:"nonce,omitempty"`
}
// GuildIntegrationsUpdate is the data for a GuildIntegrationsUpdate event.
@@ -199,6 +201,21 @@ type GuildIntegrationsUpdate struct {
GuildID string `json:"guild_id"`
}
// StageInstanceEventCreate is the data for a StageInstanceEventCreate event.
type StageInstanceEventCreate struct {
*StageInstance
}
// StageInstanceEventUpdate is the data for a StageInstanceEventUpdate event.
type StageInstanceEventUpdate struct {
*StageInstance
}
// StageInstanceEventDelete is the data for a StageInstanceEventDelete event.
type StageInstanceEventDelete struct {
*StageInstance
}
// GuildScheduledEventCreate is the data for a GuildScheduledEventCreate event.
type GuildScheduledEventCreate struct {
*GuildScheduledEvent
@@ -214,6 +231,20 @@ type GuildScheduledEventDelete struct {
*GuildScheduledEvent
}
// GuildScheduledEventUserAdd is the data for a GuildScheduledEventUserAdd event.
type GuildScheduledEventUserAdd struct {
GuildScheduledEventID string `json:"guild_scheduled_event_id"`
UserID string `json:"user_id"`
GuildID string `json:"guild_id"`
}
// GuildScheduledEventUserRemove is the data for a GuildScheduledEventUserRemove event.
type GuildScheduledEventUserRemove struct {
GuildScheduledEventID string `json:"guild_scheduled_event_id"`
UserID string `json:"user_id"`
GuildID string `json:"guild_id"`
}
// MessageAck is the data for a MessageAck event.
type MessageAck struct {
MessageID string `json:"message_id"`

View File

@@ -35,12 +35,14 @@ type ApplicationCommand struct {
Version string `json:"version,omitempty"`
Type ApplicationCommandType `json:"type,omitempty"`
Name string `json:"name"`
NameLocalizations *map[Locale]string `json:"name_localizations,omitempty"`
DefaultPermission *bool `json:"default_permission,omitempty"`
// NOTE: Chat commands only. Otherwise it mustn't be set.
Description string `json:"description,omitempty"`
Options []*ApplicationCommandOption `json:"options"`
Description string `json:"description,omitempty"`
DescriptionLocalizations *map[Locale]string `json:"description_localizations,omitempty"`
Options []*ApplicationCommandOption `json:"options"`
}
// ApplicationCommandOptionType indicates the type of a slash command's option.
@@ -91,9 +93,11 @@ func (t ApplicationCommandOptionType) String() string {
// ApplicationCommandOption represents an option/subcommand/subcommands group.
type ApplicationCommandOption struct {
Type ApplicationCommandOptionType `json:"type"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Type ApplicationCommandOptionType `json:"type"`
Name string `json:"name"`
NameLocalizations map[Locale]string `json:"name_localizations,omitempty"`
Description string `json:"description,omitempty"`
DescriptionLocalizations map[Locale]string `json:"description_localizations,omitempty"`
// NOTE: This feature was on the API, but at some point developers decided to remove it.
// So I commented it, until it will be officially on the docs.
// Default bool `json:"default"`
@@ -113,8 +117,9 @@ type ApplicationCommandOption struct {
// ApplicationCommandOptionChoice represents a slash command option choice.
type ApplicationCommandOptionChoice struct {
Name string `json:"name"`
Value interface{} `json:"value"`
Name string `json:"name"`
NameLocalizations map[Locale]string `json:"name_localizations,omitempty"`
Value interface{} `json:"value"`
}
// ApplicationCommandPermissions represents a single user or role permission for a command.
@@ -175,6 +180,7 @@ func (t InteractionType) String() string {
// Interaction represents data of an interaction.
type Interaction struct {
ID string `json:"id"`
AppID string `json:"application_id"`
Type InteractionType `json:"type"`
Data InteractionData `json:"data"`
GuildID string `json:"guild_id"`
@@ -509,7 +515,7 @@ type InteractionResponseData struct {
TTS bool `json:"tts"`
Content string `json:"content"`
Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds,omitempty"`
Embeds []*MessageEmbed `json:"embeds"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
Flags uint64 `json:"flags,omitempty"`
Files []*File `json:"-"`

View File

@@ -199,7 +199,9 @@ const (
MessageFlagsCrossPosted MessageFlags = 1 << 0
// MessageFlagsIsCrossPosted this message originated from a message in another channel (via Channel Following).
MessageFlagsIsCrossPosted MessageFlags = 1 << 1
// MessageFlagsSupressEmbeds do not include any embeds when serializing this message.
// MessageFlagsSuppressEmbeds do not include any embeds when serializing this message.
MessageFlagsSuppressEmbeds MessageFlags = 1 << 2
// TODO: deprecated, remove when compatibility is not needed
MessageFlagsSupressEmbeds MessageFlags = 1 << 2
// MessageFlagsSourceMessageDeleted the source message for this crosspost has been deleted (via Channel Following).
MessageFlagsSourceMessageDeleted MessageFlags = 1 << 3
@@ -225,7 +227,7 @@ type File struct {
// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
type MessageSend struct {
Content string `json:"content,omitempty"`
Embeds []*MessageEmbed `json:"embeds,omitempty"`
Embeds []*MessageEmbed `json:"embeds"`
TTS bool `json:"tts"`
Components []MessageComponent `json:"components"`
Files []*File `json:"-"`
@@ -244,8 +246,9 @@ type MessageSend struct {
type MessageEdit struct {
Content *string `json:"content,omitempty"`
Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds,omitempty"`
Embeds []*MessageEmbed `json:"embeds"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
Flags MessageFlags `json:"flags,omitempty"`
ID string
Channel string
@@ -342,7 +345,7 @@ type MessageEmbedFooter struct {
// MessageEmbedImage is a part of a MessageEmbed struct.
type MessageEmbedImage struct {
URL string `json:"url,omitempty"`
URL string `json:"url"`
ProxyURL string `json:"proxy_url,omitempty"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
@@ -350,7 +353,7 @@ type MessageEmbedImage struct {
// MessageEmbedThumbnail is a part of a MessageEmbed struct.
type MessageEmbedThumbnail struct {
URL string `json:"url,omitempty"`
URL string `json:"url"`
ProxyURL string `json:"proxy_url,omitempty"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
@@ -372,7 +375,7 @@ type MessageEmbedProvider struct {
// MessageEmbedAuthor is a part of a MessageEmbed struct.
type MessageEmbedAuthor struct {
URL string `json:"url,omitempty"`
Name string `json:"name,omitempty"`
Name string `json:"name"`
IconURL string `json:"icon_url,omitempty"`
ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

View File

@@ -39,6 +39,59 @@ var (
ErrUnauthorized = errors.New("HTTP request was unauthorized. This could be because the provided token was not a bot token. Please add \"Bot \" to the start of your token. https://discord.com/developers/docs/reference#authentication-example-bot-token-authorization-header")
)
var (
// Marshal defines function used to encode JSON payloads
Marshal func(v interface{}) ([]byte, error) = json.Marshal
// Unmarshal defines function used to decode JSON payloads
Unmarshal func(src []byte, v interface{}) error = json.Unmarshal
)
// RESTError stores error information about a request with a bad response code.
// Message is not always present, there are cases where api calls can fail
// without returning a json message.
type RESTError struct {
Request *http.Request
Response *http.Response
ResponseBody []byte
Message *APIErrorMessage // Message may be nil.
}
// newRestError returns a new REST API error.
func newRestError(req *http.Request, resp *http.Response, body []byte) *RESTError {
restErr := &RESTError{
Request: req,
Response: resp,
ResponseBody: body,
}
// Attempt to decode the error and assume no message was provided if it fails
var msg *APIErrorMessage
err := Unmarshal(body, &msg)
if err == nil {
restErr.Message = msg
}
return restErr
}
// Error returns a Rest API Error with its status code and body.
func (r RESTError) Error() string {
return "HTTP " + r.Response.Status + ", " + string(r.ResponseBody)
}
// RateLimitError is returned when a request exceeds a rate limit
// and ShouldRetryOnRateLimit is false. The request may be manually
// retried after waiting the duration specified by RetryAfter.
type RateLimitError struct {
*RateLimit
}
// Error returns a rate limit error with rate limited endpoint and retry time.
func (e RateLimitError) Error() string {
return "Rate limit exceeded on " + e.URL + ", retry after " + e.RetryAfter.String()
}
// Request is the same as RequestWithBucketID but the bucket id is the same as the urlStr
func (s *Session) Request(method, urlStr string, data interface{}) (response []byte, err error) {
return s.RequestWithBucketID(method, urlStr, data, strings.SplitN(urlStr, "?", 2)[0])
@@ -48,7 +101,7 @@ func (s *Session) Request(method, urlStr string, data interface{}) (response []b
func (s *Session) RequestWithBucketID(method, urlStr string, data interface{}, bucketID string) (response []byte, err error) {
var body []byte
if data != nil {
body, err = json.Marshal(data)
body, err = Marshal(data)
if err != nil {
return
}
@@ -108,7 +161,7 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
}
defer func() {
err2 := resp.Body.Close()
if err2 != nil {
if s.Debug && err2 != nil {
log.Println("error closing resp body")
}
}()
@@ -147,19 +200,24 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
}
case 429: // TOO MANY REQUESTS - Rate limiting
rl := TooManyRequests{}
err = json.Unmarshal(response, &rl)
err = Unmarshal(response, &rl)
if err != nil {
s.log(LogError, "rate limit unmarshal error, %s", err)
return
}
s.log(LogInformational, "Rate Limiting %s, retry in %v", urlStr, rl.RetryAfter)
s.handleEvent(rateLimitEventType, &RateLimit{TooManyRequests: &rl, URL: urlStr})
time.Sleep(rl.RetryAfter)
// we can make the above smarter
// this method can cause longer delays than required
if s.ShouldRetryOnRateLimit {
s.log(LogInformational, "Rate Limiting %s, retry in %v", urlStr, rl.RetryAfter)
s.handleEvent(rateLimitEventType, &RateLimit{TooManyRequests: &rl, URL: urlStr})
response, err = s.RequestWithLockedBucket(method, urlStr, contentType, b, s.Ratelimiter.LockBucketObject(bucket), sequence)
time.Sleep(rl.RetryAfter)
// we can make the above smarter
// this method can cause longer delays than required
response, err = s.RequestWithLockedBucket(method, urlStr, contentType, b, s.Ratelimiter.LockBucketObject(bucket), sequence)
} else {
err = &RateLimitError{&RateLimit{TooManyRequests: &rl, URL: urlStr}}
}
case http.StatusUnauthorized:
if strings.Index(s.Token, "Bot ") != 0 {
s.log(LogInformational, ErrUnauthorized.Error())
@@ -174,7 +232,7 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
}
func unmarshal(data []byte, v interface{}) error {
err := json.Unmarshal(data, v)
err := Unmarshal(data, v)
if err != nil {
return fmt.Errorf("%w: %s", ErrJSONUnmarshal, err)
}
@@ -438,6 +496,19 @@ func (s *Session) Guild(guildID string) (st *Guild, err error) {
return
}
// GuildWithCounts returns a Guild structure of a specific Guild with approximate member and presence counts.
// guildID : The ID of a Guild
func (s *Session) GuildWithCounts(guildID string) (st *Guild, err error) {
body, err := s.RequestWithBucketID("GET", EndpointGuild(guildID)+"?with_counts=true", nil, EndpointGuild(guildID))
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// GuildPreview returns a GuildPreview structure of a specific public Guild.
// guildID : The ID of a Guild
func (s *Session) GuildPreview(guildID string) (st *GuildPreview, err error) {
@@ -481,7 +552,7 @@ func (s *Session) GuildEdit(guildID string, g GuildParams) (st *Guild, err error
}
}
//Bounds checking for regions
// Bounds checking for regions
if g.Region != "" {
isValid := false
regions, _ := s.VoiceRegions()
@@ -530,12 +601,30 @@ func (s *Session) GuildLeave(guildID string) (err error) {
return
}
// GuildBans returns an array of GuildBan structures for all bans of a
// given guild.
// guildID : The ID of a Guild.
func (s *Session) GuildBans(guildID string) (st []*GuildBan, err error) {
// GuildBans returns an array of GuildBan structures for bans in the given guild.
// guildID : The ID of a Guild
// limit : Max number of bans to return (max 1000)
// beforeID : If not empty all returned users will be after the given id
// afterID : If not empty all returned users will be before the given id
func (s *Session) GuildBans(guildID string, limit int, beforeID, afterID string) (st []*GuildBan, err error) {
uri := EndpointGuildBans(guildID)
body, err := s.RequestWithBucketID("GET", EndpointGuildBans(guildID), nil, EndpointGuildBans(guildID))
v := url.Values{}
if limit != 0 {
v.Set("limit", strconv.Itoa(limit))
}
if beforeID != "" {
v.Set("before", beforeID)
}
if afterID != "" {
v.Set("after", afterID)
}
if len(v) > 0 {
uri += "?" + v.Encode()
}
body, err := s.RequestWithBucketID("GET", uri, nil, EndpointGuildBans(guildID))
if err != nil {
return
}
@@ -631,6 +720,29 @@ func (s *Session) GuildMembers(guildID string, after string, limit int) (st []*M
return
}
// GuildMembersSearch returns a list of guild member objects whose username or nickname starts with a provided string
// guildID : The ID of a Guild
// query : Query string to match username(s) and nickname(s) against
// limit : Max number of members to return (default 1, min 1, max 1000)
func (s *Session) GuildMembersSearch(guildID, query string, limit int) (st []*Member, err error) {
uri := EndpointGuildMembersSearch(guildID)
queryParams := url.Values{}
queryParams.Set("query", query)
if limit > 1 {
queryParams.Set("limit", strconv.Itoa(limit))
}
body, err := s.RequestWithBucketID("GET", uri+"?"+queryParams.Encode(), nil, uri)
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// GuildMember returns a member of a guild.
// guildID : The ID of a Guild.
// userID : The ID of a User
@@ -710,6 +822,21 @@ func (s *Session) GuildMemberEdit(guildID, userID string, roles []string) (err e
return
}
// GuildMemberEditComplex edits the nickname and roles of a member.
// guildID : The ID of a Guild.
// userID : The ID of a User.
// data : A GuildMemberEditData struct with the new nickname and roles
func (s *Session) GuildMemberEditComplex(guildID, userID string, data GuildMemberParams) (st *Member, err error) {
var body []byte
body, err = s.RequestWithBucketID("PATCH", EndpointGuildMember(guildID, userID), data, EndpointGuildMember(guildID, ""))
if err != nil {
return nil, err
}
err = unmarshal(body, &st)
return
}
// GuildMemberMove moves a guild member from one voice channel to another/none
// guildID : The ID of a Guild.
// userID : The ID of a User.
@@ -1218,6 +1345,20 @@ func (s *Session) GuildEmojis(guildID string) (emoji []*Emoji, err error) {
return
}
// GuildEmoji returns specified emoji.
// guildID : The ID of a Guild
// emojiID : The ID of an Emoji to retrieve
func (s *Session) GuildEmoji(guildID, emojiID string) (emoji *Emoji, err error) {
var body []byte
body, err = s.RequestWithBucketID("GET", EndpointGuildEmoji(guildID, emojiID), nil, EndpointGuildEmoji(guildID, emojiID))
if err != nil {
return
}
err = unmarshal(body, &emoji)
return
}
// GuildEmojiCreate creates a new emoji
// guildID : The ID of a Guild.
// name : The Name of the Emoji.
@@ -1244,12 +1385,12 @@ func (s *Session) GuildEmojiCreate(guildID, name, image string, roles []string)
// guildID : The ID of a Guild.
// emojiID : The ID of an Emoji.
// name : The Name of the Emoji.
// roles : The roles for which this emoji will be whitelisted, can be nil.
// roles : The roles for which this emoji will be whitelisted, if nil or empty the roles will be reset.
func (s *Session) GuildEmojiEdit(guildID, emojiID, name string, roles []string) (emoji *Emoji, err error) {
data := struct {
Name string `json:"name"`
Roles []string `json:"roles,omitempty"`
Roles []string `json:"roles"`
}{name, roles}
body, err := s.RequestWithBucketID("PATCH", EndpointGuildEmoji(guildID, emojiID), data, EndpointGuildEmojis(guildID))
@@ -1851,6 +1992,37 @@ func (s *Session) InviteWithCounts(inviteID string) (st *Invite, err error) {
return
}
// InviteComplex returns an Invite structure of the given invite including specified fields.
// inviteID : The invite code
// guildScheduledEventID : If specified, includes specified guild scheduled event.
// withCounts : Whether to include approximate member counts or not
// withExpiration : Whether to include expiration time or not
func (s *Session) InviteComplex(inviteID, guildScheduledEventID string, withCounts, withExpiration bool) (st *Invite, err error) {
endpoint := EndpointInvite(inviteID)
v := url.Values{}
if guildScheduledEventID != "" {
v.Set("guild_scheduled_event_id", guildScheduledEventID)
}
if withCounts {
v.Set("with_counts", "true")
}
if withExpiration {
v.Set("with_expiration", "true")
}
if len(v) != 0 {
endpoint += "?" + v.Encode()
}
body, err := s.RequestWithBucketID("GET", endpoint, nil, EndpointInvite(""))
if err != nil {
return
}
err = unmarshal(body, &st)
return
}
// InviteDelete deletes an existing invite
// inviteID : the code of an invite
func (s *Session) InviteDelete(inviteID string) (st *Invite, err error) {
@@ -2158,7 +2330,7 @@ func (s *Session) WebhookMessage(webhookID, token, messageID string) (message *M
return
}
err = json.Unmarshal(body, &message)
err = Unmarshal(body, &message)
return
}
@@ -2207,7 +2379,7 @@ func (s *Session) WebhookMessageDelete(webhookID, token, messageID string) (err
// MessageReactionAdd creates an emoji reaction to a message.
// channelID : The channel ID.
// messageID : The message ID.
// emojiID : Either the unicode emoji for the reaction, or a guild emoji identifier.
// emojiID : Either the unicode emoji for the reaction, or a guild emoji identifier in name:id format (e.g. "hello:1234567654321")
func (s *Session) MessageReactionAdd(channelID, messageID, emojiID string) error {
// emoji such as #⃣ need to have # escaped
@@ -2687,10 +2859,9 @@ func (s *Session) ApplicationCommandPermissionsBatchEdit(appID, guildID string,
}
// InteractionRespond creates the response to an interaction.
// appID : The application ID.
// interaction : Interaction instance.
// resp : Response message data.
func (s *Session) InteractionRespond(interaction *Interaction, resp *InteractionResponse) (err error) {
func (s *Session) InteractionRespond(interaction *Interaction, resp *InteractionResponse) error {
endpoint := EndpointInteractionResponse(interaction.ID, interaction.Token)
if resp.Data != nil && len(resp.Data.Files) > 0 {
@@ -2700,32 +2871,30 @@ func (s *Session) InteractionRespond(interaction *Interaction, resp *Interaction
}
_, err = s.request("POST", endpoint, contentType, body, endpoint, 0)
} else {
_, err = s.RequestWithBucketID("POST", endpoint, *resp, endpoint)
return err
}
_, err := s.RequestWithBucketID("POST", endpoint, *resp, endpoint)
return err
}
// InteractionResponse gets the response to an interaction.
// appID : The application ID.
// interaction : Interaction instance.
func (s *Session) InteractionResponse(appID string, interaction *Interaction) (*Message, error) {
return s.WebhookMessage(appID, interaction.Token, "@original")
func (s *Session) InteractionResponse(interaction *Interaction) (*Message, error) {
return s.WebhookMessage(interaction.AppID, interaction.Token, "@original")
}
// InteractionResponseEdit edits the response to an interaction.
// appID : The application ID.
// interaction : Interaction instance.
// newresp : Updated response message data.
func (s *Session) InteractionResponseEdit(appID string, interaction *Interaction, newresp *WebhookEdit) (*Message, error) {
return s.WebhookMessageEdit(appID, interaction.Token, "@original", newresp)
func (s *Session) InteractionResponseEdit(interaction *Interaction, newresp *WebhookEdit) (*Message, error) {
return s.WebhookMessageEdit(interaction.AppID, interaction.Token, "@original", newresp)
}
// InteractionResponseDelete deletes the response to an interaction.
// appID : The application ID.
// interaction : Interaction instance.
func (s *Session) InteractionResponseDelete(appID string, interaction *Interaction) error {
endpoint := EndpointInteractionResponseActions(appID, interaction.Token)
func (s *Session) InteractionResponseDelete(interaction *Interaction) error {
endpoint := EndpointInteractionResponseActions(interaction.AppID, interaction.Token)
_, err := s.RequestWithBucketID("DELETE", endpoint, nil, endpoint)
@@ -2733,29 +2902,76 @@ func (s *Session) InteractionResponseDelete(appID string, interaction *Interacti
}
// FollowupMessageCreate creates the followup message for an interaction.
// appID : The application ID.
// interaction : Interaction instance.
// wait : Waits for server confirmation of message send and ensures that the return struct is populated (it is nil otherwise)
// data : Data of the message to send.
func (s *Session) FollowupMessageCreate(appID string, interaction *Interaction, wait bool, data *WebhookParams) (*Message, error) {
return s.WebhookExecute(appID, interaction.Token, wait, data)
func (s *Session) FollowupMessageCreate(interaction *Interaction, wait bool, data *WebhookParams) (*Message, error) {
return s.WebhookExecute(interaction.AppID, interaction.Token, wait, data)
}
// FollowupMessageEdit edits a followup message of an interaction.
// appID : The application ID.
// interaction : Interaction instance.
// messageID : The followup message ID.
// data : Data to update the message
func (s *Session) FollowupMessageEdit(appID string, interaction *Interaction, messageID string, data *WebhookEdit) (*Message, error) {
return s.WebhookMessageEdit(appID, interaction.Token, messageID, data)
func (s *Session) FollowupMessageEdit(interaction *Interaction, messageID string, data *WebhookEdit) (*Message, error) {
return s.WebhookMessageEdit(interaction.AppID, interaction.Token, messageID, data)
}
// FollowupMessageDelete deletes a followup message of an interaction.
// appID : The application ID.
// interaction : Interaction instance.
// messageID : The followup message ID.
func (s *Session) FollowupMessageDelete(appID string, interaction *Interaction, messageID string) error {
return s.WebhookMessageDelete(appID, interaction.Token, messageID)
func (s *Session) FollowupMessageDelete(interaction *Interaction, messageID string) error {
return s.WebhookMessageDelete(interaction.AppID, interaction.Token, messageID)
}
// ------------------------------------------------------------------------------------------------
// Functions specific to stage instances
// ------------------------------------------------------------------------------------------------
// StageInstanceCreate creates and returns a new Stage instance associated to a Stage channel.
// data : Parameters needed to create a stage instance.
// data : The data of the Stage instance to create
func (s *Session) StageInstanceCreate(data *StageInstanceParams) (si *StageInstance, err error) {
body, err := s.RequestWithBucketID("POST", EndpointStageInstances, data, EndpointStageInstances)
if err != nil {
return
}
err = unmarshal(body, &si)
return
}
// StageInstance will retrieve a Stage instance by ID of the Stage channel.
// channelID : The ID of the Stage channel
func (s *Session) StageInstance(channelID string) (si *StageInstance, err error) {
body, err := s.RequestWithBucketID("GET", EndpointStageInstance(channelID), nil, EndpointStageInstance(channelID))
if err != nil {
return
}
err = unmarshal(body, &si)
return
}
// StageInstanceEdit will edit a Stage instance by ID of the Stage channel.
// channelID : The ID of the Stage channel
// data : The data to edit the Stage instance
func (s *Session) StageInstanceEdit(channelID string, data *StageInstanceParams) (si *StageInstance, err error) {
body, err := s.RequestWithBucketID("PATCH", EndpointStageInstance(channelID), data, EndpointStageInstance(channelID))
if err != nil {
return
}
err = unmarshal(body, &si)
return
}
// StageInstanceDelete will delete a Stage instance by ID of the Stage channel.
// channelID : The ID of the Stage channel
func (s *Session) StageInstanceDelete(channelID string) (err error) {
_, err = s.RequestWithBucketID("DELETE", EndpointStageInstance(channelID), nil, EndpointStageInstance(channelID))
return
}
// ------------------------------------------------------------------------------------------------

View File

@@ -979,8 +979,9 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
err = s.GuildRemove(t.Guild)
case *GuildMemberAdd:
var guild *Guild
// Updates the MemberCount of the guild.
guild, err := s.Guild(t.Member.GuildID)
guild, err = s.Guild(t.Member.GuildID)
if err != nil {
return err
}
@@ -995,8 +996,9 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
err = s.MemberAdd(t.Member)
}
case *GuildMemberRemove:
var guild *Guild
// Updates the MemberCount of the guild.
guild, err := s.Guild(t.Member.GuildID)
guild, err = s.Guild(t.Member.GuildID)
if err != nil {
return err
}

View File

@@ -43,6 +43,9 @@ type Session struct {
// Should the session reconnect the websocket on errors.
ShouldReconnectOnError bool
// Should the session retry requests when rate limited.
ShouldRetryOnRateLimit bool
// Identify is sent during initial handshake with the discord gateway.
// https://discord.com/developers/docs/topics/gateway#identify
Identify Identify
@@ -260,6 +263,7 @@ const (
ChannelTypeGuildNewsThread ChannelType = 10
ChannelTypeGuildPublicThread ChannelType = 11
ChannelTypeGuildPrivateThread ChannelType = 12
ChannelTypeGuildStageVoice ChannelType = 13
)
// A Channel holds all data related to an individual Discord channel.
@@ -360,7 +364,7 @@ type ChannelEdit struct {
UserLimit int `json:"user_limit,omitempty"`
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"`
ParentID string `json:"parent_id,omitempty"`
RateLimitPerUser int `json:"rate_limit_per_user,omitempty"`
RateLimitPerUser *int `json:"rate_limit_per_user,omitempty"`
// NOTE: threads only
@@ -552,6 +556,17 @@ const (
ExplicitContentFilterAllMembers ExplicitContentFilterLevel = 2
)
// GuildNSFWLevel type definition
type GuildNSFWLevel int
// Constants for GuildNSFWLevel levels from 0 to 3 inclusive
const (
GuildNSFWLevelDefault GuildNSFWLevel = 0
GuildNSFWLevelExplicit GuildNSFWLevel = 1
GuildNSFWLevelSafe GuildNSFWLevel = 2
GuildNSFWLevelAgeRestricted GuildNSFWLevel = 3
)
// MfaLevel type definition
type MfaLevel int
@@ -675,6 +690,9 @@ type Guild struct {
// The explicit content filter level
ExplicitContentFilter ExplicitContentFilterLevel `json:"explicit_content_filter"`
// The NSFW Level of the guild
NSFWLevel GuildNSFWLevel `json:"nsfw_level"`
// The list of enabled guild features
Features []string `json:"features"`
@@ -731,6 +749,9 @@ type Guild struct {
// Permissions of our user
Permissions int64 `json:"permissions,string"`
// Stage instances in the guild
StageInstances []*StageInstance `json:"stage_instances"`
}
// A GuildPreview holds data related to a specific public Discord Guild, even if the user is not in the guild.
@@ -757,16 +778,31 @@ type GuildPreview struct {
// The list of enabled guild features
Features []string `json:"features"`
// Approximate number of members in this guild, returned from the GET /guild/<id> endpoint when with_counts is true
// Approximate number of members in this guild
// NOTE: this field is only filled when using GuildWithCounts
ApproximateMemberCount int `json:"approximate_member_count"`
// Approximate number of non-offline members in this guild, returned from the GET /guild/<id> endpoint when with_counts is true
// Approximate number of non-offline members in this guild
// NOTE: this field is only filled when using GuildWithCounts
ApproximatePresenceCount int `json:"approximate_presence_count"`
// the description for the guild
Description string `json:"description"`
}
// IconURL returns a URL to the guild's icon.
func (g *GuildPreview) IconURL() string {
if g.Icon == "" {
return ""
}
if strings.HasPrefix(g.Icon, "a_") {
return EndpointGuildIconAnimated(g.ID, g.Icon)
}
return EndpointGuildIcon(g.ID, g.Icon)
}
// GuildScheduledEvent is a representation of a scheduled event in a guild. Only for retrieval of the data.
// https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event
type GuildScheduledEvent struct {
@@ -842,7 +878,7 @@ func (p GuildScheduledEventParams) MarshalJSON() ([]byte, error) {
type guildScheduledEventParams GuildScheduledEventParams
if p.EntityType == GuildScheduledEventEntityTypeExternal && p.ChannelID == "" {
return json.Marshal(struct {
return Marshal(struct {
guildScheduledEventParams
ChannelID json.RawMessage `json:"channel_id"`
}{
@@ -851,7 +887,7 @@ func (p GuildScheduledEventParams) MarshalJSON() ([]byte, error) {
})
}
return json.Marshal(guildScheduledEventParams(p))
return Marshal(guildScheduledEventParams(p))
}
// GuildScheduledEventEntityMetadata holds additional metadata for guild scheduled event.
@@ -1093,7 +1129,7 @@ func (t *TimeStamps) UnmarshalJSON(b []byte) error {
End float64 `json:"end,omitempty"`
Start float64 `json:"start,omitempty"`
}{}
err := json.Unmarshal(b, &temp)
err := Unmarshal(b, &temp)
if err != nil {
return err
}
@@ -1231,7 +1267,7 @@ func (t *TooManyRequests) UnmarshalJSON(b []byte) error {
Message string `json:"message"`
RetryAfter float64 `json:"retry_after"`
}{}
err := json.Unmarshal(b, &u)
err := Unmarshal(b, &u)
if err != nil {
return err
}
@@ -1566,6 +1602,15 @@ type UserGuildSettingsEdit struct {
ChannelOverrides map[string]*UserGuildSettingsChannelOverride `json:"channel_overrides"`
}
// GuildMemberParams stores data needed to update a member
// https://discord.com/developers/docs/resources/guild#modify-guild-member
type GuildMemberParams struct {
// Value to set user's nickname to
Nick string `json:"nick,omitempty"`
// Array of role ids the member is assigned
Roles *[]string `json:"roles,omitempty"`
}
// An APIErrorMessage is an api error message returned from discord
type APIErrorMessage struct {
Code int `json:"code"`
@@ -1642,7 +1687,7 @@ func (activity *Activity) UnmarshalJSON(b []byte) error {
Instance bool `json:"instance,omitempty"`
Flags int `json:"flags,omitempty"`
}{}
err := json.Unmarshal(b, &temp)
err := Unmarshal(b, &temp)
if err != nil {
return err
}
@@ -1695,14 +1740,13 @@ const (
// Identify is sent during initial handshake with the discord gateway.
// https://discord.com/developers/docs/topics/gateway#identify
type Identify struct {
Token string `json:"token"`
Properties IdentifyProperties `json:"properties"`
Compress bool `json:"compress"`
LargeThreshold int `json:"large_threshold"`
Shard *[2]int `json:"shard,omitempty"`
Presence GatewayStatusUpdate `json:"presence,omitempty"`
GuildSubscriptions bool `json:"guild_subscriptions"`
Intents Intent `json:"intents"`
Token string `json:"token"`
Properties IdentifyProperties `json:"properties"`
Compress bool `json:"compress"`
LargeThreshold int `json:"large_threshold"`
Shard *[2]int `json:"shard,omitempty"`
Presence GatewayStatusUpdate `json:"presence,omitempty"`
Intents Intent `json:"intents"`
}
// IdentifyProperties contains the "properties" portion of an Identify packet
@@ -1715,6 +1759,49 @@ type IdentifyProperties struct {
ReferringDomain string `json:"$referring_domain"`
}
// StageInstance holds information about a live stage.
// https://discord.com/developers/docs/resources/stage-instance#stage-instance-resource
type StageInstance struct {
// The id of this Stage instance
ID string `json:"id"`
// The guild id of the associated Stage channel
GuildID string `json:"guild_id"`
// The id of the associated Stage channel
ChannelID string `json:"channel_id"`
// The topic of the Stage instance (1-120 characters)
Topic string `json:"topic"`
// The privacy level of the Stage instance
// https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level
PrivacyLevel StageInstancePrivacyLevel `json:"privacy_level"`
// Whether or not Stage Discovery is disabled (deprecated)
DiscoverableDisabled bool `json:"discoverable_disabled"`
// The id of the scheduled event for this Stage instance
GuildScheduledEventID string `json:"guild_scheduled_event_id"`
}
// StageInstanceParams represents the parameters needed to create or edit a stage instance
type StageInstanceParams struct {
// ChannelID represents the id of the Stage channel
ChannelID string `json:"channel_id,omitempty"`
// Topic of the Stage instance (1-120 characters)
Topic string `json:"topic,omitempty"`
// PrivacyLevel of the Stage instance (default GUILD_ONLY)
PrivacyLevel StageInstancePrivacyLevel `json:"privacy_level,omitempty"`
// SendStartNotification will notify @everyone that a Stage instance has started
SendStartNotification bool `json:"send_start_notification,omitempty"`
}
// StageInstancePrivacyLevel represents the privacy level of a Stage instance
// https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level
type StageInstancePrivacyLevel int
const (
// StageInstancePrivacyLevelPublic The Stage instance is visible publicly. (deprecated)
StageInstancePrivacyLevelPublic StageInstancePrivacyLevel = 1
// StageInstancePrivacyLevelGuildOnly The Stage instance is visible to only guild members.
StageInstancePrivacyLevelGuildOnly StageInstancePrivacyLevel = 2
)
// Constants for the different bit offsets of text channel permissions
const (
// Deprecated: PermissionReadMessages has been replaced with PermissionViewChannel for text and voice channels
@@ -1731,6 +1818,7 @@ const (
PermissionManageThreads = 0x0000000400000000
PermissionCreatePublicThreads = 0x0000000800000000
PermissionCreatePrivateThreads = 0x0000001000000000
PermissionUseExternalStickers = 0x0000002000000000
PermissionSendMessagesInThreads = 0x0000004000000000
)
@@ -1745,6 +1833,7 @@ const (
PermissionVoiceMoveMembers = 0x0000000001000000
PermissionVoiceUseVAD = 0x0000000002000000
PermissionVoiceRequestToSpeak = 0x0000000100000000
PermissionUseActivities = 0x0000008000000000
)
// Constants for general management.
@@ -1754,6 +1843,7 @@ const (
PermissionManageRoles = 0x0000000010000000
PermissionManageWebhooks = 0x0000000020000000
PermissionManageEmojis = 0x0000000040000000
PermissionManageEvents = 0x0000000200000000
)
// Constants for the different bit offsets of general permissions

View File

@@ -1,47 +0,0 @@
// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo
// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains custom types, currently only a timestamp wrapper.
package discordgo
import (
"encoding/json"
"net/http"
)
// RESTError stores error information about a request with a bad response code.
// Message is not always present, there are cases where api calls can fail
// without returning a json message.
type RESTError struct {
Request *http.Request
Response *http.Response
ResponseBody []byte
Message *APIErrorMessage // Message may be nil.
}
func newRestError(req *http.Request, resp *http.Response, body []byte) *RESTError {
restErr := &RESTError{
Request: req,
Response: resp,
ResponseBody: body,
}
// Attempt to decode the error and assume no message was provided if it fails
var msg *APIErrorMessage
err := json.Unmarshal(body, &msg)
if err == nil {
restErr.Message = msg
}
return restErr
}
func (r RESTError) Error() string {
return "HTTP " + r.Response.Status + ", " + string(r.ResponseBody)
}

View File

@@ -2,7 +2,6 @@ package discordgo
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
@@ -30,7 +29,7 @@ func MultipartBodyWithJSON(data interface{}, files []*File) (requestContentType
body := &bytes.Buffer{}
bodywriter := multipart.NewWriter(body)
payload, err := json.Marshal(data)
payload, err := Marshal(data)
if err != nil {
return
}

View File

@@ -409,10 +409,13 @@ func (s *Session) UpdateStatusComplex(usd UpdateStatusData) (err error) {
}
type requestGuildMembersData struct {
GuildIDs []string `json:"guild_id"`
Query string `json:"query"`
Limit int `json:"limit"`
Presences bool `json:"presences"`
// TODO: Deprecated. Use string instead of []string
GuildIDs []string `json:"guild_id"`
Query *string `json:"query,omitempty"`
UserIDs *[]string `json:"user_ids,omitempty"`
Limit int `json:"limit"`
Nonce string `json:"nonce,omitempty"`
Presences bool `json:"presences"`
}
type requestGuildMembersOp struct {
@@ -425,16 +428,21 @@ type requestGuildMembersOp struct {
// guildID : Single Guild ID to request members of
// query : String that username starts with, leave empty to return all members
// limit : Max number of items to return, or 0 to request all members matched
// nonce : Nonce to identify the Guild Members Chunk response
// presences : Whether to request presences of guild members
func (s *Session) RequestGuildMembers(guildID string, query string, limit int, presences bool) (err error) {
data := requestGuildMembersData{
GuildIDs: []string{guildID},
Query: query,
Limit: limit,
Presences: presences,
}
err = s.requestGuildMembers(data)
return
func (s *Session) RequestGuildMembers(guildID, query string, limit int, nonce string, presences bool) error {
return s.RequestGuildMembersBatch([]string{guildID}, query, limit, nonce, presences)
}
// RequestGuildMembersList requests guild members from the gateway
// The gateway responds with GuildMembersChunk events
// guildID : Single Guild ID to request members of
// userIDs : IDs of users to fetch
// limit : Max number of items to return, or 0 to request all members matched
// nonce : Nonce to identify the Guild Members Chunk response
// presences : Whether to request presences of guild members
func (s *Session) RequestGuildMembersList(guildID string, userIDs []string, limit int, nonce string, presences bool) error {
return s.RequestGuildMembersBatchList([]string{guildID}, userIDs, limit, nonce, presences)
}
// RequestGuildMembersBatch requests guild members from the gateway
@@ -442,12 +450,37 @@ func (s *Session) RequestGuildMembers(guildID string, query string, limit int, p
// guildID : Slice of guild IDs to request members of
// query : String that username starts with, leave empty to return all members
// limit : Max number of items to return, or 0 to request all members matched
// nonce : Nonce to identify the Guild Members Chunk response
// presences : Whether to request presences of guild members
func (s *Session) RequestGuildMembersBatch(guildIDs []string, query string, limit int, presences bool) (err error) {
//
// NOTE: this function is deprecated, please use RequestGuildMembers instead
func (s *Session) RequestGuildMembersBatch(guildIDs []string, query string, limit int, nonce string, presences bool) (err error) {
data := requestGuildMembersData{
GuildIDs: guildIDs,
Query: query,
Query: &query,
Limit: limit,
Nonce: nonce,
Presences: presences,
}
err = s.requestGuildMembers(data)
return
}
// RequestGuildMembersBatchList requests guild members from the gateway
// The gateway responds with GuildMembersChunk events
// guildID : Slice of guild IDs to request members of
// userIDs : IDs of users to fetch
// limit : Max number of items to return, or 0 to request all members matched
// nonce : Nonce to identify the Guild Members Chunk response
// presences : Whether to request presences of guild members
//
// NOTE: this function is deprecated, please use RequestGuildMembersList instead
func (s *Session) RequestGuildMembersBatchList(guildIDs []string, userIDs []string, limit int, nonce string, presences bool) (err error) {
data := requestGuildMembersData{
GuildIDs: guildIDs,
UserIDs: &userIDs,
Limit: limit,
Nonce: nonce,
Presences: presences,
}
err = s.requestGuildMembers(data)

View File

@@ -7,9 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [1.5.4] - 2022-04-25
* Windows: add missing defer to `Watcher.WatchList` [#447](https://github.com/fsnotify/fsnotify/pull/447)
* go.mod: use latest x/sys [#444](https://github.com/fsnotify/fsnotify/pull/444)
* Fix compilation for OpenBSD [#443](https://github.com/fsnotify/fsnotify/pull/443)
## [1.5.3] - 2022-04-22
* This version is retracted. An incorrect branch is published accidentally [#445](https://github.com/fsnotify/fsnotify/issues/445)
## [1.5.2] - 2022-04-21
* Add a feature to return the directories and files that are being monitored [#374](https://github.com/fsnotify/fsnotify/pull/374)
* Fix potential crash on windows if `raw.FileNameLength` exceeds `syscall.MAX_PATH` [#361](https://github.com/fsnotify/fsnotify/pull/361)
* Allow build on unsupported GOOS [#424](https://github.com/fsnotify/fsnotify/pull/424)
* Don't set `poller.fd` twice in `newFdPoller` [#406](https://github.com/fsnotify/fsnotify/pull/406)
* fix go vet warnings: call to `(*T).Fatalf` from a non-test goroutine [#416](https://github.com/fsnotify/fsnotify/pull/416)
## [1.5.1] - 2021-08-24
* Revert Add AddRaw to not follow symlinks
* Revert Add AddRaw to not follow symlinks [#394](https://github.com/fsnotify/fsnotify/pull/394)
## [1.5.0] - 2021-08-20

View File

@@ -48,18 +48,6 @@ fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Win
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
* When you're done, you will want to halt or destroy the Vagrant boxes.
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
### Maintainers
Help maintaining fsnotify is welcome. To be a maintainer:
@@ -67,11 +55,6 @@ Help maintaining fsnotify is welcome. To be a maintainer:
* Submit a pull request and sign the CLA as above.
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
All code changes should be internal pull requests.
Releases are tagged using [Semantic Versioning](http://semver.org/).
[hub]: https://github.com/github/hub
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs

View File

@@ -1,12 +1,8 @@
# File system notifications for Go
[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
[![Go Reference](https://pkg.go.dev/badge/github.com/fsnotify/fsnotify.svg)](https://pkg.go.dev/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify) [![Maintainers Wanted](https://img.shields.io/badge/maintainers-wanted-red.svg)](https://github.com/fsnotify/fsnotify/issues/413)
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
```console
go get -u golang.org/x/sys/...
```
fsnotify utilizes [`golang.org/x/sys`](https://pkg.go.dev/golang.org/x/sys) rather than [`syscall`](https://pkg.go.dev/syscall) from the standard library.
Cross platform: Windows, Linux, BSD and macOS.
@@ -16,22 +12,20 @@ Cross platform: Windows, Linux, BSD and macOS.
| kqueue | BSD, macOS, iOS\* | Supported |
| ReadDirectoryChangesW | Windows | Supported |
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/issues/12) |
| fanotify | Linux 2.6.37+ | [Planned](https://github.com/fsnotify/fsnotify/issues/114) |
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/pull/371) |
| fanotify | Linux 2.6.37+ | [Maybe](https://github.com/fsnotify/fsnotify/issues/114) |
| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
\* Android and iOS are untested.
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
Please see [the documentation](https://pkg.go.dev/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
## API stability
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
fsnotify is a fork of [howeyc/fsnotify](https://github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/).
## Usage
@@ -84,10 +78,6 @@ func main() {
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
## Example
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
## FAQ
**When a file is moved to another directory is it still being watched?**

View File

@@ -0,0 +1,36 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows
// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
package fsnotify
import (
"fmt"
"runtime"
)
// Watcher watches a set of files, delivering events to a channel.
type Watcher struct{}
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
func NewWatcher() (*Watcher, error) {
return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS)
}
// Close removes all watches and closes the events channel.
func (w *Watcher) Close() error {
return nil
}
// Add starts watching the named file or directory (non-recursively).
func (w *Watcher) Add(name string) error {
return nil
}
// Remove stops watching the the named file or directory (non-recursively).
func (w *Watcher) Remove(name string) error {
return nil
}

View File

@@ -163,6 +163,19 @@ func (w *Watcher) Remove(name string) error {
return nil
}
// WatchList returns the directories and files that are being monitered.
func (w *Watcher) WatchList() []string {
w.mu.Lock()
defer w.mu.Unlock()
entries := make([]string, 0, len(w.watches))
for pathname := range w.watches {
entries = append(entries, pathname)
}
return entries
}
type watch struct {
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)

View File

@@ -38,7 +38,6 @@ func newFdPoller(fd int) (*fdPoller, error) {
poller.close()
}
}()
poller.fd = fd
// Create epoll fd
poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC)

View File

@@ -148,6 +148,19 @@ func (w *Watcher) Remove(name string) error {
return nil
}
// WatchList returns the directories and files that are being monitered.
func (w *Watcher) WatchList() []string {
w.mu.Lock()
defer w.mu.Unlock()
entries := make([]string, 0, len(w.watches))
for pathname := range w.watches {
entries = append(entries, pathname)
}
return entries
}
// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME

View File

@@ -12,6 +12,7 @@ import (
"fmt"
"os"
"path/filepath"
"reflect"
"runtime"
"sync"
"syscall"
@@ -96,6 +97,21 @@ func (w *Watcher) Remove(name string) error {
return <-in.reply
}
// WatchList returns the directories and files that are being monitered.
func (w *Watcher) WatchList() []string {
w.mu.Lock()
defer w.mu.Unlock()
entries := make([]string, 0, len(w.watches))
for _, entry := range w.watches {
for _, watchEntry := range entry {
entries = append(entries, watchEntry.path)
}
}
return entries
}
const (
// Options for AddWatch
sysFSONESHOT = 0x80000000
@@ -452,8 +468,16 @@ func (w *Watcher) readEvents() {
// Point "raw" to the event in the buffer
raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
// TODO: Consider using unsafe.Slice that is available from go1.17
// https://stackoverflow.com/questions/51187973/how-to-create-an-array-or-a-slice-from-an-array-unsafe-pointer-in-golang
// instead of using a fixed syscall.MAX_PATH buf, we create a buf that is the size of the path name
size := int(raw.FileNameLength / 2)
var buf []uint16
sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
sh.Data = uintptr(unsafe.Pointer(&raw.FileName))
sh.Len = size
sh.Cap = size
name := syscall.UTF16ToString(buf)
fullname := filepath.Join(watch.path, name)
var mask uint64

View File

@@ -1,6 +1,6 @@
# Markdown Parser and HTML Renderer for Go
[![pkg.go.dev](https://pkg.go.dev/badge/github.com/gomarkdown/markdown)](https://pkg.go.dev/badge/github.com/gomarkdown/markdown)
[![pkg.go.dev](https://pkg.go.dev/badge/github.com/gomarkdown/markdown)](https://pkg.go.dev/github.com/gomarkdown/markdown)
Package `github.com/gomarkdown/markdown` is a very fast Go library for parsing [Markdown](https://daringfireball.net/projects/markdown/) documents and rendering them to HTML.

View File

@@ -26,8 +26,8 @@ links or code blocks.
// a very dummy render hook that will output "code_replacements" instead of
// <code>${content}</code> emitted by html.Renderer
func renderHookCodeBlock(w io.Writer, node *ast.Node, entering bool) (ast.WalkStatus, bool) {
_, ok := node.Data.(*ast.CodeBlockData)
func renderHookCodeBlock(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {
_, ok := node.(*ast.CodeBlock)
if !ok {
return ast.GoToNext, false
}

View File

@@ -858,12 +858,9 @@ func isFenceLine(data []byte, syntax *string, oldmarker string) (end int, marker
return 0, ""
}
// TODO(shurcooL): It's probably a good idea to simplify the 2 code paths here
// into one, always get the syntax, and discard it if the caller doesn't care.
if syntax != nil {
syn := 0
// if just read the beginning marker, read the syntax
if oldmarker == "" {
i = skipChar(data, i, ' ')
if i >= n {
if i == n {
return i, marker
@@ -871,41 +868,15 @@ func isFenceLine(data []byte, syntax *string, oldmarker string) (end int, marker
return 0, ""
}
syntaxStart := i
if data[i] == '{' {
i++
syntaxStart++
for i < n && data[i] != '}' && data[i] != '\n' {
syn++
i++
}
if i >= n || data[i] != '}' {
return 0, ""
}
// strip all whitespace at the beginning and the end
// of the {} block
for syn > 0 && isSpace(data[syntaxStart]) {
syntaxStart++
syn--
}
for syn > 0 && isSpace(data[syntaxStart+syn-1]) {
syn--
}
i++
} else {
for i < n && !isSpace(data[i]) {
syn++
i++
}
syntaxStart, syntaxLen := syntaxRange(data, &i)
if syntaxStart == 0 && syntaxLen == 0 {
return 0, ""
}
*syntax = string(data[syntaxStart : syntaxStart+syn])
// caller wants the syntax
if syntax != nil {
*syntax = string(data[syntaxStart : syntaxStart+syntaxLen])
}
}
i = skipChar(data, i, ' ')
@@ -918,6 +889,47 @@ func isFenceLine(data []byte, syntax *string, oldmarker string) (end int, marker
return i + 1, marker // Take newline into account.
}
func syntaxRange(data []byte, iout *int) (int, int) {
n := len(data)
syn := 0
i := *iout
syntaxStart := i
if data[i] == '{' {
i++
syntaxStart++
for i < n && data[i] != '}' && data[i] != '\n' {
syn++
i++
}
if i >= n || data[i] != '}' {
return 0, 0
}
// strip all whitespace at the beginning and the end
// of the {} block
for syn > 0 && isSpace(data[syntaxStart]) {
syntaxStart++
syn--
}
for syn > 0 && isSpace(data[syntaxStart+syn-1]) {
syn--
}
i++
} else {
for i < n && !isSpace(data[i]) {
syn++
i++
}
}
*iout = i
return syntaxStart, syn
}
// fencedCodeBlock returns the end index if data contains a fenced code block at the beginning,
// or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects.
// If doRender is true, a final newline is mandatory to recognize the fenced code block.
@@ -1416,7 +1428,7 @@ gatherlines:
// we need to add leadingWhiteSpaces + 1 spaces in the beginning of the chunk
if indentIndex >= 4 && p.dliPrefix(chunk) <= 0 {
leadingWhiteSpaces := skipChar(chunk, 0, ' ')
chunk = data[ line+indentIndex - (leadingWhiteSpaces + 1) : i]
chunk = data[line+indentIndex-(leadingWhiteSpaces+1) : i]
}
// to be a nested list, it must be indented more

View File

@@ -131,7 +131,11 @@ func codeSpan(p *Parser, data []byte, offset int) (int, ast.Node) {
// find the next delimiter
i, end := 0, 0
hasLFBeforeDelimiter := false
for end = nb; end < len(data) && i < nb; end++ {
if data[end] == '\n' {
hasLFBeforeDelimiter = true
}
if data[end] == '`' {
i++
} else {
@@ -144,6 +148,18 @@ func codeSpan(p *Parser, data []byte, offset int) (int, ast.Node) {
return 0, nil
}
// If there are non-space chars after the ending delimiter and before a '\n',
// flag that this is not a well formed fenced code block.
hasCharsAfterDelimiter := false
for j := end; j < len(data); j++ {
if data[j] == '\n' {
break
}
if !isSpace(data[j]) {
hasCharsAfterDelimiter = true
}
}
// trim outside whitespace
fBegin := nb
for fBegin < end && data[fBegin] == ' ' {
@@ -155,14 +171,31 @@ func codeSpan(p *Parser, data []byte, offset int) (int, ast.Node) {
fEnd--
}
// render the code span
if fBegin != fEnd {
code := &ast.Code{}
code.Literal = data[fBegin:fEnd]
return end, code
if fBegin == fEnd {
return end, nil
}
return end, nil
// if delimiter has 3 backticks
if nb == 3 {
i := fBegin
syntaxStart, syntaxLen := syntaxRange(data, &i)
// If we found a '\n' before the end marker and there are only spaces
// after the end marker, then this is a code block.
if hasLFBeforeDelimiter && !hasCharsAfterDelimiter {
codeblock := &ast.CodeBlock{
IsFenced: true,
Info: data[syntaxStart : syntaxStart+syntaxLen],
}
codeblock.Literal = data[i:fEnd]
return end, codeblock
}
}
// render the code span
code := &ast.Code{}
code.Literal = data[fBegin:fEnd]
return end, code
}
// newline preceded by two spaces becomes <br>
@@ -781,7 +814,7 @@ func entity(p *Parser, data []byte, offset int) (int, ast.Node) {
codepoint, err = strconv.ParseUint(string(ent[2:len(ent)-1]), 10, 64)
}
if err == nil { // only if conversion was valid return here.
return end, newTextNode([]byte(string(codepoint)))
return end, newTextNode([]byte(string(rune(codepoint))))
}
return end, newTextNode(ent)

View File

@@ -0,0 +1,5 @@
/.idea
/.vscode
/internal/validation/testdata/graphql-js
/internal/validation/testdata/node_modules
/vendor

View File

@@ -0,0 +1,35 @@
run:
timeout: 5m
linters-settings:
gofmt:
simplify: true
govet:
check-shadowing: true
enable-all: true
disable:
- fieldalignment
- deepequalerrors # remove later
linters:
disable-all: true
enable:
- deadcode
- gofmt
- gosimple
- govet
- ineffassign
- exportloopref
- structcheck
- staticcheck
- unconvert
- unused
- varcheck
- misspell
- goimports
issues:
exclude-rules:
- linters:
- unused
path: "graphql_test.go"

View File

@@ -0,0 +1,10 @@
CHANGELOG
[v1.1.0](https://github.com/graph-gophers/graphql-go/releases/tag/v1.1.0) Release v1.1.0
* [FEATURE] Add types package #437
* [FEATURE] Expose `packer.Unmarshaler` as `decode.Unmarshaler` to the public #450
* [FEATURE] Add location fields to type definitions #454
* [FEATURE] `errors.Errorf` preserves original error similar to `fmt.Errorf` #456
* [BUGFIX] Fix duplicated __typename in response (fixes #369) #443
[v1.0.0](https://github.com/graph-gophers/graphql-go/releases/tag/v1.0.0) Initial release

View File

@@ -0,0 +1,13 @@
## Contributing
- With issues:
- Use the search tool before opening a new issue.
- Please provide source code and commit sha if you found a bug.
- Review existing issues and provide feedback or react to them.
- With pull requests:
- Open your pull request against `master`
- Your pull request should have no more than two commits, if not you should squash them.
- It should pass all tests in the available continuous integrations systems such as TravisCI.
- You should add/modify tests to cover your proposed code changes.
- If your pull request contains a new feature, please document it on the README.

24
vendor/github.com/graph-gophers/graphql-go/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,24 @@
Copyright (c) 2016 Richard Musiol. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

169
vendor/github.com/graph-gophers/graphql-go/README.md generated vendored Normal file
View File

@@ -0,0 +1,169 @@
# graphql-go [![Sourcegraph](https://sourcegraph.com/github.com/graph-gophers/graphql-go/-/badge.svg)](https://sourcegraph.com/github.com/graph-gophers/graphql-go?badge) [![Build Status](https://graph-gophers.semaphoreci.com/badges/graphql-go/branches/master.svg?style=shields)](https://graph-gophers.semaphoreci.com/projects/graphql-go) [![GoDoc](https://godoc.org/github.com/graph-gophers/graphql-go?status.svg)](https://godoc.org/github.com/graph-gophers/graphql-go)
<p align="center"><img src="docs/img/logo.png" width="300"></p>
The goal of this project is to provide full support of the [GraphQL draft specification](https://facebook.github.io/graphql/draft) with a set of idiomatic, easy to use Go packages.
While still under heavy development (`internal` APIs are almost certainly subject to change), this library is
safe for production use.
## Features
- minimal API
- support for `context.Context`
- support for the `OpenTracing` standard
- schema type-checking against resolvers
- resolvers are matched to the schema based on method sets (can resolve a GraphQL schema with a Go interface or Go struct).
- handles panics in resolvers
- parallel execution of resolvers
- subscriptions
- [sample WS transport](https://github.com/graph-gophers/graphql-transport-ws)
## Roadmap
We're trying out the GitHub Project feature to manage `graphql-go`'s [development roadmap](https://github.com/graph-gophers/graphql-go/projects/1).
Feedback is welcome and appreciated.
## (Some) Documentation
### Basic Sample
```go
package main
import (
"log"
"net/http"
graphql "github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
)
type query struct{}
func (_ *query) Hello() string { return "Hello, world!" }
func main() {
s := `
type Query {
hello: String!
}
`
schema := graphql.MustParseSchema(s, &query{})
http.Handle("/query", &relay.Handler{Schema: schema})
log.Fatal(http.ListenAndServe(":8080", nil))
}
```
To test:
```sh
curl -XPOST -d '{"query": "{ hello }"}' localhost:8080/query
```
### Resolvers
A resolver must have one method or field for each field of the GraphQL type it resolves. The method or field name has to be [exported](https://golang.org/ref/spec#Exported_identifiers) and match the schema's field's name in a non-case-sensitive way.
You can use struct fields as resolvers by using `SchemaOpt: UseFieldResolvers()`. For example,
```
opts := []graphql.SchemaOpt{graphql.UseFieldResolvers()}
schema := graphql.MustParseSchema(s, &query{}, opts...)
```
When using `UseFieldResolvers` schema option, a struct field will be used *only* when:
- there is no method for a struct field
- a struct field does not implement an interface method
- a struct field does not have arguments
The method has up to two arguments:
- Optional `context.Context` argument.
- Mandatory `*struct { ... }` argument if the corresponding GraphQL field has arguments. The names of the struct fields have to be [exported](https://golang.org/ref/spec#Exported_identifiers) and have to match the names of the GraphQL arguments in a non-case-sensitive way.
The method has up to two results:
- The GraphQL field's value as determined by the resolver.
- Optional `error` result.
Example for a simple resolver method:
```go
func (r *helloWorldResolver) Hello() string {
return "Hello world!"
}
```
The following signature is also allowed:
```go
func (r *helloWorldResolver) Hello(ctx context.Context) (string, error) {
return "Hello world!", nil
}
```
### Schema Options
- `UseStringDescriptions()` enables the usage of double quoted and triple quoted. When this is not enabled, comments are parsed as descriptions instead.
- `UseFieldResolvers()` specifies whether to use struct field resolvers.
- `MaxDepth(n int)` specifies the maximum field nesting depth in a query. The default is 0 which disables max depth checking.
- `MaxParallelism(n int)` specifies the maximum number of resolvers per request allowed to run in parallel. The default is 10.
- `Tracer(tracer trace.Tracer)` is used to trace queries and fields. It defaults to `trace.OpenTracingTracer`.
- `ValidationTracer(tracer trace.ValidationTracer)` is used to trace validation errors. It defaults to `trace.NoopValidationTracer`.
- `Logger(logger log.Logger)` is used to log panics during query execution. It defaults to `exec.DefaultLogger`.
- `PanicHandler(panicHandler errors.PanicHandler)` is used to transform panics into errors during query execution. It defaults to `errors.DefaultPanicHandler`.
- `DisableIntrospection()` disables introspection queries.
### Custom Errors
Errors returned by resolvers can include custom extensions by implementing the `ResolverError` interface:
```go
type ResolverError interface {
error
Extensions() map[string]interface{}
}
```
Example of a simple custom error:
```go
type droidNotFoundError struct {
Code string `json:"code"`
Message string `json:"message"`
}
func (e droidNotFoundError) Error() string {
return fmt.Sprintf("error [%s]: %s", e.Code, e.Message)
}
func (e droidNotFoundError) Extensions() map[string]interface{} {
return map[string]interface{}{
"code": e.Code,
"message": e.Message,
}
}
```
Which could produce a GraphQL error such as:
```go
{
"errors": [
{
"message": "error [NotFound]: This is not the droid you are looking for",
"path": [
"droid"
],
"extensions": {
"code": "NotFound",
"message": "This is not the droid you are looking for"
}
}
],
"data": null
}
```
### [Examples](https://github.com/graph-gophers/graphql-go/wiki/Examples)
### [Companies that use this library](https://github.com/graph-gophers/graphql-go/wiki/Users)

View File

@@ -0,0 +1,13 @@
package decode
// Unmarshaler defines the api of Go types mapped to custom GraphQL scalar types
type Unmarshaler interface {
// ImplementsGraphQLType maps the implementing custom Go type
// to the GraphQL scalar type in the schema.
ImplementsGraphQLType(name string) bool
// UnmarshalGraphQL is the custom unmarshaler for the implementing type
//
// This function will be called whenever you use the
// custom GraphQL scalar type as an input
UnmarshalGraphQL(input interface{}) error
}

View File

@@ -0,0 +1,59 @@
package errors
import (
"fmt"
)
type QueryError struct {
Err error `json:"-"` // Err holds underlying if available
Message string `json:"message"`
Locations []Location `json:"locations,omitempty"`
Path []interface{} `json:"path,omitempty"`
Rule string `json:"-"`
ResolverError error `json:"-"`
Extensions map[string]interface{} `json:"extensions,omitempty"`
}
type Location struct {
Line int `json:"line"`
Column int `json:"column"`
}
func (a Location) Before(b Location) bool {
return a.Line < b.Line || (a.Line == b.Line && a.Column < b.Column)
}
func Errorf(format string, a ...interface{}) *QueryError {
// similar to fmt.Errorf, Errorf will wrap the last argument if it is an instance of error
var err error
if n := len(a); n > 0 {
if v, ok := a[n-1].(error); ok {
err = v
}
}
return &QueryError{
Err: err,
Message: fmt.Sprintf(format, a...),
}
}
func (err *QueryError) Error() string {
if err == nil {
return "<nil>"
}
str := fmt.Sprintf("graphql: %s", err.Message)
for _, loc := range err.Locations {
str += fmt.Sprintf(" (line %d, column %d)", loc.Line, loc.Column)
}
return str
}
func (err *QueryError) Unwrap() error {
if err == nil {
return nil
}
return err.Err
}
var _ error = &QueryError{}

View File

@@ -0,0 +1,18 @@
package errors
import (
"context"
)
// PanicHandler is the interface used to create custom panic errors that occur during query execution
type PanicHandler interface {
MakePanicError(ctx context.Context, value interface{}) *QueryError
}
// DefaultPanicHandler is the default PanicHandler
type DefaultPanicHandler struct{}
// MakePanicError creates a new QueryError from a panic that occurred during execution
func (h *DefaultPanicHandler) MakePanicError(ctx context.Context, value interface{}) *QueryError {
return Errorf("panic occurred: %v", value)
}

339
vendor/github.com/graph-gophers/graphql-go/graphql.go generated vendored Normal file
View File

@@ -0,0 +1,339 @@
package graphql
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/graph-gophers/graphql-go/errors"
"github.com/graph-gophers/graphql-go/internal/common"
"github.com/graph-gophers/graphql-go/internal/exec"
"github.com/graph-gophers/graphql-go/internal/exec/resolvable"
"github.com/graph-gophers/graphql-go/internal/exec/selected"
"github.com/graph-gophers/graphql-go/internal/query"
"github.com/graph-gophers/graphql-go/internal/schema"
"github.com/graph-gophers/graphql-go/internal/validation"
"github.com/graph-gophers/graphql-go/introspection"
"github.com/graph-gophers/graphql-go/log"
"github.com/graph-gophers/graphql-go/trace"
"github.com/graph-gophers/graphql-go/types"
)
// ParseSchema parses a GraphQL schema and attaches the given root resolver. It returns an error if
// the Go type signature of the resolvers does not match the schema. If nil is passed as the
// resolver, then the schema can not be executed, but it may be inspected (e.g. with ToJSON).
func ParseSchema(schemaString string, resolver interface{}, opts ...SchemaOpt) (*Schema, error) {
s := &Schema{
schema: schema.New(),
maxParallelism: 10,
tracer: trace.OpenTracingTracer{},
logger: &log.DefaultLogger{},
panicHandler: &errors.DefaultPanicHandler{},
}
for _, opt := range opts {
opt(s)
}
if s.validationTracer == nil {
if tracer, ok := s.tracer.(trace.ValidationTracerContext); ok {
s.validationTracer = tracer
} else {
s.validationTracer = &validationBridgingTracer{tracer: trace.NoopValidationTracer{}}
}
}
if err := schema.Parse(s.schema, schemaString, s.useStringDescriptions); err != nil {
return nil, err
}
if err := s.validateSchema(); err != nil {
return nil, err
}
r, err := resolvable.ApplyResolver(s.schema, resolver)
if err != nil {
return nil, err
}
s.res = r
return s, nil
}
// MustParseSchema calls ParseSchema and panics on error.
func MustParseSchema(schemaString string, resolver interface{}, opts ...SchemaOpt) *Schema {
s, err := ParseSchema(schemaString, resolver, opts...)
if err != nil {
panic(err)
}
return s
}
// Schema represents a GraphQL schema with an optional resolver.
type Schema struct {
schema *types.Schema
res *resolvable.Schema
maxDepth int
maxParallelism int
tracer trace.Tracer
validationTracer trace.ValidationTracerContext
logger log.Logger
panicHandler errors.PanicHandler
useStringDescriptions bool
disableIntrospection bool
subscribeResolverTimeout time.Duration
}
func (s *Schema) ASTSchema() *types.Schema {
return s.schema
}
// SchemaOpt is an option to pass to ParseSchema or MustParseSchema.
type SchemaOpt func(*Schema)
// UseStringDescriptions enables the usage of double quoted and triple quoted
// strings as descriptions as per the June 2018 spec
// https://facebook.github.io/graphql/June2018/. When this is not enabled,
// comments are parsed as descriptions instead.
func UseStringDescriptions() SchemaOpt {
return func(s *Schema) {
s.useStringDescriptions = true
}
}
// UseFieldResolvers specifies whether to use struct field resolvers
func UseFieldResolvers() SchemaOpt {
return func(s *Schema) {
s.schema.UseFieldResolvers = true
}
}
// MaxDepth specifies the maximum field nesting depth in a query. The default is 0 which disables max depth checking.
func MaxDepth(n int) SchemaOpt {
return func(s *Schema) {
s.maxDepth = n
}
}
// MaxParallelism specifies the maximum number of resolvers per request allowed to run in parallel. The default is 10.
func MaxParallelism(n int) SchemaOpt {
return func(s *Schema) {
s.maxParallelism = n
}
}
// Tracer is used to trace queries and fields. It defaults to trace.OpenTracingTracer.
func Tracer(tracer trace.Tracer) SchemaOpt {
return func(s *Schema) {
s.tracer = tracer
}
}
// ValidationTracer is used to trace validation errors. It defaults to trace.NoopValidationTracer.
// Deprecated: context is needed to support tracing correctly. Use a Tracer which implements trace.ValidationTracerContext.
func ValidationTracer(tracer trace.ValidationTracer) SchemaOpt { //nolint:staticcheck
return func(s *Schema) {
s.validationTracer = &validationBridgingTracer{tracer: tracer}
}
}
// Logger is used to log panics during query execution. It defaults to exec.DefaultLogger.
func Logger(logger log.Logger) SchemaOpt {
return func(s *Schema) {
s.logger = logger
}
}
// PanicHandler is used to customize the panic errors during query execution.
// It defaults to errors.DefaultPanicHandler.
func PanicHandler(panicHandler errors.PanicHandler) SchemaOpt {
return func(s *Schema) {
s.panicHandler = panicHandler
}
}
// DisableIntrospection disables introspection queries.
func DisableIntrospection() SchemaOpt {
return func(s *Schema) {
s.disableIntrospection = true
}
}
// SubscribeResolverTimeout is an option to control the amount of time
// we allow for a single subscribe message resolver to complete it's job
// before it times out and returns an error to the subscriber.
func SubscribeResolverTimeout(timeout time.Duration) SchemaOpt {
return func(s *Schema) {
s.subscribeResolverTimeout = timeout
}
}
// Response represents a typical response of a GraphQL server. It may be encoded to JSON directly or
// it may be further processed to a custom response type, for example to include custom error data.
// Errors are intentionally serialized first based on the advice in https://github.com/facebook/graphql/commit/7b40390d48680b15cb93e02d46ac5eb249689876#diff-757cea6edf0288677a9eea4cfc801d87R107
type Response struct {
Errors []*errors.QueryError `json:"errors,omitempty"`
Data json.RawMessage `json:"data,omitempty"`
Extensions map[string]interface{} `json:"extensions,omitempty"`
}
// Validate validates the given query with the schema.
func (s *Schema) Validate(queryString string) []*errors.QueryError {
return s.ValidateWithVariables(queryString, nil)
}
// ValidateWithVariables validates the given query with the schema and the input variables.
func (s *Schema) ValidateWithVariables(queryString string, variables map[string]interface{}) []*errors.QueryError {
doc, qErr := query.Parse(queryString)
if qErr != nil {
return []*errors.QueryError{qErr}
}
return validation.Validate(s.schema, doc, variables, s.maxDepth)
}
// Exec executes the given query with the schema's resolver. It panics if the schema was created
// without a resolver. If the context get cancelled, no further resolvers will be called and a
// the context error will be returned as soon as possible (not immediately).
func (s *Schema) Exec(ctx context.Context, queryString string, operationName string, variables map[string]interface{}) *Response {
if !s.res.Resolver.IsValid() {
panic("schema created without resolver, can not exec")
}
return s.exec(ctx, queryString, operationName, variables, s.res)
}
func (s *Schema) exec(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, res *resolvable.Schema) *Response {
doc, qErr := query.Parse(queryString)
if qErr != nil {
return &Response{Errors: []*errors.QueryError{qErr}}
}
validationFinish := s.validationTracer.TraceValidation(ctx)
errs := validation.Validate(s.schema, doc, variables, s.maxDepth)
validationFinish(errs)
if len(errs) != 0 {
return &Response{Errors: errs}
}
op, err := getOperation(doc, operationName)
if err != nil {
return &Response{Errors: []*errors.QueryError{errors.Errorf("%s", err)}}
}
// If the optional "operationName" POST parameter is not provided then
// use the query's operation name for improved tracing.
if operationName == "" {
operationName = op.Name.Name
}
// Subscriptions are not valid in Exec. Use schema.Subscribe() instead.
if op.Type == query.Subscription {
return &Response{Errors: []*errors.QueryError{{Message: "graphql-ws protocol header is missing"}}}
}
if op.Type == query.Mutation {
if _, ok := s.schema.EntryPoints["mutation"]; !ok {
return &Response{Errors: []*errors.QueryError{{Message: "no mutations are offered by the schema"}}}
}
}
// Fill in variables with the defaults from the operation
if variables == nil {
variables = make(map[string]interface{}, len(op.Vars))
}
for _, v := range op.Vars {
if _, ok := variables[v.Name.Name]; !ok && v.Default != nil {
variables[v.Name.Name] = v.Default.Deserialize(nil)
}
}
r := &exec.Request{
Request: selected.Request{
Doc: doc,
Vars: variables,
Schema: s.schema,
DisableIntrospection: s.disableIntrospection,
},
Limiter: make(chan struct{}, s.maxParallelism),
Tracer: s.tracer,
Logger: s.logger,
PanicHandler: s.panicHandler,
}
varTypes := make(map[string]*introspection.Type)
for _, v := range op.Vars {
t, err := common.ResolveType(v.Type, s.schema.Resolve)
if err != nil {
return &Response{Errors: []*errors.QueryError{err}}
}
varTypes[v.Name.Name] = introspection.WrapType(t)
}
traceCtx, finish := s.tracer.TraceQuery(ctx, queryString, operationName, variables, varTypes)
data, errs := r.Execute(traceCtx, res, op)
finish(errs)
return &Response{
Data: data,
Errors: errs,
}
}
func (s *Schema) validateSchema() error {
// https://graphql.github.io/graphql-spec/June2018/#sec-Root-Operation-Types
// > The query root operation type must be provided and must be an Object type.
if err := validateRootOp(s.schema, "query", true); err != nil {
return err
}
// > The mutation root operation type is optional; if it is not provided, the service does not support mutations.
// > If it is provided, it must be an Object type.
if err := validateRootOp(s.schema, "mutation", false); err != nil {
return err
}
// > Similarly, the subscription root operation type is also optional; if it is not provided, the service does not
// > support subscriptions. If it is provided, it must be an Object type.
if err := validateRootOp(s.schema, "subscription", false); err != nil {
return err
}
return nil
}
type validationBridgingTracer struct {
tracer trace.ValidationTracer //nolint:staticcheck
}
func (t *validationBridgingTracer) TraceValidation(context.Context) trace.TraceValidationFinishFunc {
return t.tracer.TraceValidation()
}
func validateRootOp(s *types.Schema, name string, mandatory bool) error {
t, ok := s.EntryPoints[name]
if !ok {
if mandatory {
return fmt.Errorf("root operation %q must be defined", name)
}
return nil
}
if t.Kind() != "OBJECT" {
return fmt.Errorf("root operation %q must be an OBJECT", name)
}
return nil
}
func getOperation(document *types.ExecutableDefinition, operationName string) (*types.OperationDefinition, error) {
if len(document.Operations) == 0 {
return nil, fmt.Errorf("no operations in query document")
}
if operationName == "" {
if len(document.Operations) > 1 {
return nil, fmt.Errorf("more than one operation in query document and no operation name given")
}
for _, op := range document.Operations {
return op, nil // return the one and only operation
}
}
op := document.Operations.Get(operationName)
if op == nil {
return nil, fmt.Errorf("no operation with name %q", operationName)
}
return op, nil
}

30
vendor/github.com/graph-gophers/graphql-go/id.go generated vendored Normal file
View File

@@ -0,0 +1,30 @@
package graphql
import (
"fmt"
"strconv"
)
// ID represents GraphQL's "ID" scalar type. A custom type may be used instead.
type ID string
func (ID) ImplementsGraphQLType(name string) bool {
return name == "ID"
}
func (id *ID) UnmarshalGraphQL(input interface{}) error {
var err error
switch input := input.(type) {
case string:
*id = ID(input)
case int32:
*id = ID(strconv.Itoa(int(input)))
default:
err = fmt.Errorf("wrong type for ID: %T", input)
}
return err
}
func (id ID) MarshalJSON() ([]byte, error) {
return strconv.AppendQuote(nil, string(id)), nil
}

View File

@@ -0,0 +1,103 @@
// MIT License
//
// Copyright (c) 2019 GraphQL Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// This implementation has been adapted from the graphql-js reference implementation
// https://github.com/graphql/graphql-js/blob/5eb7c4ded7ceb83ac742149cbe0dae07a8af9a30/src/language/blockString.js
// which is released under the MIT License above.
package common
import (
"strings"
)
// Produces the value of a block string from its parsed raw value, similar to
// CoffeeScript's block string, Python's docstring trim or Ruby's strip_heredoc.
//
// This implements the GraphQL spec's BlockStringValue() static algorithm.
func blockString(raw string) string {
lines := strings.Split(raw, "\n")
// Remove common indentation from all lines except the first (which has none)
ind := blockStringIndentation(lines)
if ind > 0 {
for i := 1; i < len(lines); i++ {
l := lines[i]
if len(l) < ind {
lines[i] = ""
continue
}
lines[i] = l[ind:]
}
}
// Remove leading and trailing blank lines
trimStart := 0
for i := 0; i < len(lines) && isBlank(lines[i]); i++ {
trimStart++
}
lines = lines[trimStart:]
trimEnd := 0
for i := len(lines) - 1; i > 0 && isBlank(lines[i]); i-- {
trimEnd++
}
lines = lines[:len(lines)-trimEnd]
return strings.Join(lines, "\n")
}
func blockStringIndentation(lines []string) int {
var commonIndent *int
for i := 1; i < len(lines); i++ {
l := lines[i]
indent := leadingWhitespace(l)
if indent == len(l) {
// don't consider blank/empty lines
continue
}
if indent == 0 {
return 0
}
if commonIndent == nil || indent < *commonIndent {
commonIndent = &indent
}
}
if commonIndent == nil {
return 0
}
return *commonIndent
}
func isBlank(s string) bool {
return len(s) == 0 || leadingWhitespace(s) == len(s)
}
func leadingWhitespace(s string) int {
i := 0
for _, r := range s {
if r != '\t' && r != ' ' {
break
}
i++
}
return i
}

View File

@@ -0,0 +1,18 @@
package common
import "github.com/graph-gophers/graphql-go/types"
func ParseDirectives(l *Lexer) types.DirectiveList {
var directives types.DirectiveList
for l.Peek() == '@' {
l.ConsumeToken('@')
d := &types.Directive{}
d.Name = l.ConsumeIdentWithLoc()
d.Name.Loc.Column--
if l.Peek() == '(' {
d.Arguments = ParseArgumentList(l)
}
directives = append(directives, d)
}
return directives
}

View File

@@ -0,0 +1,229 @@
package common
import (
"bytes"
"fmt"
"strconv"
"strings"
"text/scanner"
"github.com/graph-gophers/graphql-go/errors"
"github.com/graph-gophers/graphql-go/types"
)
type syntaxError string
type Lexer struct {
sc *scanner.Scanner
next rune
comment bytes.Buffer
useStringDescriptions bool
}
type Ident struct {
Name string
Loc errors.Location
}
func NewLexer(s string, useStringDescriptions bool) *Lexer {
sc := &scanner.Scanner{
Mode: scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings,
}
sc.Init(strings.NewReader(s))
l := Lexer{sc: sc, useStringDescriptions: useStringDescriptions}
l.sc.Error = l.CatchScannerError
return &l
}
func (l *Lexer) CatchSyntaxError(f func()) (errRes *errors.QueryError) {
defer func() {
if err := recover(); err != nil {
if err, ok := err.(syntaxError); ok {
errRes = errors.Errorf("syntax error: %s", err)
errRes.Locations = []errors.Location{l.Location()}
return
}
panic(err)
}
}()
f()
return
}
func (l *Lexer) Peek() rune {
return l.next
}
// ConsumeWhitespace consumes whitespace and tokens equivalent to whitespace (e.g. commas and comments).
//
// Consumed comment characters will build the description for the next type or field encountered.
// The description is available from `DescComment()`, and will be reset every time `ConsumeWhitespace()` is
// executed unless l.useStringDescriptions is set.
func (l *Lexer) ConsumeWhitespace() {
l.comment.Reset()
for {
l.next = l.sc.Scan()
if l.next == ',' {
// Similar to white space and line terminators, commas (',') are used to improve the
// legibility of source text and separate lexical tokens but are otherwise syntactically and
// semantically insignificant within GraphQL documents.
//
// http://facebook.github.io/graphql/draft/#sec-Insignificant-Commas
continue
}
if l.next == '#' {
// GraphQL source documents may contain single-line comments, starting with the '#' marker.
//
// A comment can contain any Unicode code point except `LineTerminator` so a comment always
// consists of all code points starting with the '#' character up to but not including the
// line terminator.
l.consumeComment()
continue
}
break
}
}
// consumeDescription optionally consumes a description based on the June 2018 graphql spec if any are present.
//
// Single quote strings are also single line. Triple quote strings can be multi-line. Triple quote strings
// whitespace trimmed on both ends.
// If a description is found, consume any following comments as well
//
// http://facebook.github.io/graphql/June2018/#sec-Descriptions
func (l *Lexer) consumeDescription() string {
// If the next token is not a string, we don't consume it
if l.next != scanner.String {
return ""
}
// Triple quote string is an empty "string" followed by an open quote due to the way the parser treats strings as one token
var desc string
if l.sc.Peek() == '"' {
desc = l.consumeTripleQuoteComment()
} else {
desc = l.consumeStringComment()
}
l.ConsumeWhitespace()
return desc
}
func (l *Lexer) ConsumeIdent() string {
name := l.sc.TokenText()
l.ConsumeToken(scanner.Ident)
return name
}
func (l *Lexer) ConsumeIdentWithLoc() types.Ident {
loc := l.Location()
name := l.sc.TokenText()
l.ConsumeToken(scanner.Ident)
return types.Ident{Name: name, Loc: loc}
}
func (l *Lexer) ConsumeKeyword(keyword string) {
if l.next != scanner.Ident || l.sc.TokenText() != keyword {
l.SyntaxError(fmt.Sprintf("unexpected %q, expecting %q", l.sc.TokenText(), keyword))
}
l.ConsumeWhitespace()
}
func (l *Lexer) ConsumeLiteral() *types.PrimitiveValue {
lit := &types.PrimitiveValue{Type: l.next, Text: l.sc.TokenText()}
l.ConsumeWhitespace()
return lit
}
func (l *Lexer) ConsumeToken(expected rune) {
if l.next != expected {
l.SyntaxError(fmt.Sprintf("unexpected %q, expecting %s", l.sc.TokenText(), scanner.TokenString(expected)))
}
l.ConsumeWhitespace()
}
func (l *Lexer) DescComment() string {
comment := l.comment.String()
desc := l.consumeDescription()
if l.useStringDescriptions {
return desc
}
return comment
}
func (l *Lexer) SyntaxError(message string) {
panic(syntaxError(message))
}
func (l *Lexer) Location() errors.Location {
return errors.Location{
Line: l.sc.Line,
Column: l.sc.Column,
}
}
func (l *Lexer) consumeTripleQuoteComment() string {
l.next = l.sc.Next()
if l.next != '"' {
panic("consumeTripleQuoteComment used in wrong context: no third quote?")
}
var buf bytes.Buffer
var numQuotes int
for {
l.next = l.sc.Next()
if l.next == '"' {
numQuotes++
} else {
numQuotes = 0
}
buf.WriteRune(l.next)
if numQuotes == 3 || l.next == scanner.EOF {
break
}
}
val := buf.String()
val = val[:len(val)-numQuotes]
return blockString(val)
}
func (l *Lexer) consumeStringComment() string {
val, err := strconv.Unquote(l.sc.TokenText())
if err != nil {
panic(err)
}
return val
}
// consumeComment consumes all characters from `#` to the first encountered line terminator.
// The characters are appended to `l.comment`.
func (l *Lexer) consumeComment() {
if l.next != '#' {
panic("consumeComment used in wrong context")
}
// TODO: count and trim whitespace so we can dedent any following lines.
if l.sc.Peek() == ' ' {
l.sc.Next()
}
if l.comment.Len() > 0 {
l.comment.WriteRune('\n')
}
for {
next := l.sc.Next()
if next == '\r' || next == '\n' || next == scanner.EOF {
break
}
l.comment.WriteRune(next)
}
}
func (l *Lexer) CatchScannerError(s *scanner.Scanner, msg string) {
l.SyntaxError(msg)
}

View File

@@ -0,0 +1,58 @@
package common
import (
"text/scanner"
"github.com/graph-gophers/graphql-go/types"
)
func ParseLiteral(l *Lexer, constOnly bool) types.Value {
loc := l.Location()
switch l.Peek() {
case '$':
if constOnly {
l.SyntaxError("variable not allowed")
panic("unreachable")
}
l.ConsumeToken('$')
return &types.Variable{Name: l.ConsumeIdent(), Loc: loc}
case scanner.Int, scanner.Float, scanner.String, scanner.Ident:
lit := l.ConsumeLiteral()
if lit.Type == scanner.Ident && lit.Text == "null" {
return &types.NullValue{Loc: loc}
}
lit.Loc = loc
return lit
case '-':
l.ConsumeToken('-')
lit := l.ConsumeLiteral()
lit.Text = "-" + lit.Text
lit.Loc = loc
return lit
case '[':
l.ConsumeToken('[')
var list []types.Value
for l.Peek() != ']' {
list = append(list, ParseLiteral(l, constOnly))
}
l.ConsumeToken(']')
return &types.ListValue{Values: list, Loc: loc}
case '{':
l.ConsumeToken('{')
var fields []*types.ObjectField
for l.Peek() != '}' {
name := l.ConsumeIdentWithLoc()
l.ConsumeToken(':')
value := ParseLiteral(l, constOnly)
fields = append(fields, &types.ObjectField{Name: name, Value: value})
}
l.ConsumeToken('}')
return &types.ObjectValue{Fields: fields, Loc: loc}
default:
l.SyntaxError("invalid value")
panic("unreachable")
}
}

View File

@@ -0,0 +1,67 @@
package common
import (
"github.com/graph-gophers/graphql-go/errors"
"github.com/graph-gophers/graphql-go/types"
)
func ParseType(l *Lexer) types.Type {
t := parseNullType(l)
if l.Peek() == '!' {
l.ConsumeToken('!')
return &types.NonNull{OfType: t}
}
return t
}
func parseNullType(l *Lexer) types.Type {
if l.Peek() == '[' {
l.ConsumeToken('[')
ofType := ParseType(l)
l.ConsumeToken(']')
return &types.List{OfType: ofType}
}
return &types.TypeName{Ident: l.ConsumeIdentWithLoc()}
}
type Resolver func(name string) types.Type
// ResolveType attempts to resolve a type's name against a resolving function.
// This function is used when one needs to check if a TypeName exists in the resolver (typically a Schema).
//
// In the example below, ResolveType would be used to check if the resolving function
// returns a valid type for Dimension:
//
// type Profile {
// picture(dimensions: Dimension): Url
// }
//
// ResolveType recursively unwraps List and NonNull types until a NamedType is reached.
func ResolveType(t types.Type, resolver Resolver) (types.Type, *errors.QueryError) {
switch t := t.(type) {
case *types.List:
ofType, err := ResolveType(t.OfType, resolver)
if err != nil {
return nil, err
}
return &types.List{OfType: ofType}, nil
case *types.NonNull:
ofType, err := ResolveType(t.OfType, resolver)
if err != nil {
return nil, err
}
return &types.NonNull{OfType: ofType}, nil
case *types.TypeName:
refT := resolver(t.Name)
if refT == nil {
err := errors.Errorf("Unknown type %q.", t.Name)
err.Rule = "KnownTypeNames"
err.Locations = []errors.Location{t.Loc}
return nil, err
}
return refT, nil
default:
return t, nil
}
}

View File

@@ -0,0 +1,37 @@
package common
import (
"github.com/graph-gophers/graphql-go/types"
)
func ParseInputValue(l *Lexer) *types.InputValueDefinition {
p := &types.InputValueDefinition{}
p.Loc = l.Location()
p.Desc = l.DescComment()
p.Name = l.ConsumeIdentWithLoc()
l.ConsumeToken(':')
p.TypeLoc = l.Location()
p.Type = ParseType(l)
if l.Peek() == '=' {
l.ConsumeToken('=')
p.Default = ParseLiteral(l, true)
}
p.Directives = ParseDirectives(l)
return p
}
func ParseArgumentList(l *Lexer) types.ArgumentList {
var args types.ArgumentList
l.ConsumeToken('(')
for l.Peek() != ')' {
name := l.ConsumeIdentWithLoc()
l.ConsumeToken(':')
value := ParseLiteral(l, false)
args = append(args, &types.Argument{
Name: name,
Value: value,
})
}
l.ConsumeToken(')')
return args
}

View File

@@ -0,0 +1,381 @@
package exec
import (
"bytes"
"context"
"encoding/json"
"fmt"
"reflect"
"sync"
"time"
"github.com/graph-gophers/graphql-go/errors"
"github.com/graph-gophers/graphql-go/internal/exec/resolvable"
"github.com/graph-gophers/graphql-go/internal/exec/selected"
"github.com/graph-gophers/graphql-go/internal/query"
"github.com/graph-gophers/graphql-go/log"
"github.com/graph-gophers/graphql-go/trace"
"github.com/graph-gophers/graphql-go/types"
)
type Request struct {
selected.Request
Limiter chan struct{}
Tracer trace.Tracer
Logger log.Logger
PanicHandler errors.PanicHandler
SubscribeResolverTimeout time.Duration
}
func (r *Request) handlePanic(ctx context.Context) {
if value := recover(); value != nil {
r.Logger.LogPanic(ctx, value)
r.AddError(r.PanicHandler.MakePanicError(ctx, value))
}
}
type extensionser interface {
Extensions() map[string]interface{}
}
func (r *Request) Execute(ctx context.Context, s *resolvable.Schema, op *types.OperationDefinition) ([]byte, []*errors.QueryError) {
var out bytes.Buffer
func() {
defer r.handlePanic(ctx)
sels := selected.ApplyOperation(&r.Request, s, op)
r.execSelections(ctx, sels, nil, s, s.Resolver, &out, op.Type == query.Mutation)
}()
if err := ctx.Err(); err != nil {
return nil, []*errors.QueryError{errors.Errorf("%s", err)}
}
return out.Bytes(), r.Errs
}
type fieldToExec struct {
field *selected.SchemaField
sels []selected.Selection
resolver reflect.Value
out *bytes.Buffer
}
func resolvedToNull(b *bytes.Buffer) bool {
return bytes.Equal(b.Bytes(), []byte("null"))
}
func (r *Request) execSelections(ctx context.Context, sels []selected.Selection, path *pathSegment, s *resolvable.Schema, resolver reflect.Value, out *bytes.Buffer, serially bool) {
async := !serially && selected.HasAsyncSel(sels)
var fields []*fieldToExec
collectFieldsToResolve(sels, s, resolver, &fields, make(map[string]*fieldToExec))
if async {
var wg sync.WaitGroup
wg.Add(len(fields))
for _, f := range fields {
go func(f *fieldToExec) {
defer wg.Done()
defer r.handlePanic(ctx)
f.out = new(bytes.Buffer)
execFieldSelection(ctx, r, s, f, &pathSegment{path, f.field.Alias}, true)
}(f)
}
wg.Wait()
} else {
for _, f := range fields {
f.out = new(bytes.Buffer)
execFieldSelection(ctx, r, s, f, &pathSegment{path, f.field.Alias}, true)
}
}
out.WriteByte('{')
for i, f := range fields {
// If a non-nullable child resolved to null, an error was added to the
// "errors" list in the response, so this field resolves to null.
// If this field is non-nullable, the error is propagated to its parent.
if _, ok := f.field.Type.(*types.NonNull); ok && resolvedToNull(f.out) {
out.Reset()
out.Write([]byte("null"))
return
}
if i > 0 {
out.WriteByte(',')
}
out.WriteByte('"')
out.WriteString(f.field.Alias)
out.WriteByte('"')
out.WriteByte(':')
out.Write(f.out.Bytes())
}
out.WriteByte('}')
}
func collectFieldsToResolve(sels []selected.Selection, s *resolvable.Schema, resolver reflect.Value, fields *[]*fieldToExec, fieldByAlias map[string]*fieldToExec) {
for _, sel := range sels {
switch sel := sel.(type) {
case *selected.SchemaField:
field, ok := fieldByAlias[sel.Alias]
if !ok { // validation already checked for conflict (TODO)
field = &fieldToExec{field: sel, resolver: resolver}
fieldByAlias[sel.Alias] = field
*fields = append(*fields, field)
}
field.sels = append(field.sels, sel.Sels...)
case *selected.TypenameField:
_, ok := fieldByAlias[sel.Alias]
if !ok {
res := reflect.ValueOf(typeOf(sel, resolver))
f := s.FieldTypename
f.TypeName = res.String()
sf := &selected.SchemaField{
Field: f,
Alias: sel.Alias,
FixedResult: res,
}
field := &fieldToExec{field: sf, resolver: resolver}
*fields = append(*fields, field)
fieldByAlias[sel.Alias] = field
}
case *selected.TypeAssertion:
out := resolver.Method(sel.MethodIndex).Call(nil)
if !out[1].Bool() {
continue
}
collectFieldsToResolve(sel.Sels, s, out[0], fields, fieldByAlias)
default:
panic("unreachable")
}
}
}
func typeOf(tf *selected.TypenameField, resolver reflect.Value) string {
if len(tf.TypeAssertions) == 0 {
return tf.Name
}
for name, a := range tf.TypeAssertions {
out := resolver.Method(a.MethodIndex).Call(nil)
if out[1].Bool() {
return name
}
}
return ""
}
func execFieldSelection(ctx context.Context, r *Request, s *resolvable.Schema, f *fieldToExec, path *pathSegment, applyLimiter bool) {
if applyLimiter {
r.Limiter <- struct{}{}
}
var result reflect.Value
var err *errors.QueryError
traceCtx, finish := r.Tracer.TraceField(ctx, f.field.TraceLabel, f.field.TypeName, f.field.Name, !f.field.Async, f.field.Args)
defer func() {
finish(err)
}()
err = func() (err *errors.QueryError) {
defer func() {
if panicValue := recover(); panicValue != nil {
r.Logger.LogPanic(ctx, panicValue)
err = r.PanicHandler.MakePanicError(ctx, panicValue)
err.Path = path.toSlice()
}
}()
if f.field.FixedResult.IsValid() {
result = f.field.FixedResult
return nil
}
if err := traceCtx.Err(); err != nil {
return errors.Errorf("%s", err) // don't execute any more resolvers if context got cancelled
}
res := f.resolver
if f.field.UseMethodResolver() {
var in []reflect.Value
if f.field.HasContext {
in = append(in, reflect.ValueOf(traceCtx))
}
if f.field.ArgsPacker != nil {
in = append(in, f.field.PackedArgs)
}
callOut := res.Method(f.field.MethodIndex).Call(in)
result = callOut[0]
if f.field.HasError && !callOut[1].IsNil() {
resolverErr := callOut[1].Interface().(error)
err := errors.Errorf("%s", resolverErr)
err.Path = path.toSlice()
err.ResolverError = resolverErr
if ex, ok := callOut[1].Interface().(extensionser); ok {
err.Extensions = ex.Extensions()
}
return err
}
} else {
// TODO extract out unwrapping ptr logic to a common place
if res.Kind() == reflect.Ptr {
res = res.Elem()
}
result = res.FieldByIndex(f.field.FieldIndex)
}
return nil
}()
if applyLimiter {
<-r.Limiter
}
if err != nil {
// If an error occurred while resolving a field, it should be treated as though the field
// returned null, and an error must be added to the "errors" list in the response.
r.AddError(err)
f.out.WriteString("null")
return
}
r.execSelectionSet(traceCtx, f.sels, f.field.Type, path, s, result, f.out)
}
func (r *Request) execSelectionSet(ctx context.Context, sels []selected.Selection, typ types.Type, path *pathSegment, s *resolvable.Schema, resolver reflect.Value, out *bytes.Buffer) {
t, nonNull := unwrapNonNull(typ)
// a reflect.Value of a nil interface will show up as an Invalid value
if resolver.Kind() == reflect.Invalid || ((resolver.Kind() == reflect.Ptr || resolver.Kind() == reflect.Interface) && resolver.IsNil()) {
// If a field of a non-null type resolves to null (either because the
// function to resolve the field returned null or because an error occurred),
// add an error to the "errors" list in the response.
if nonNull {
err := errors.Errorf("graphql: got nil for non-null %q", t)
err.Path = path.toSlice()
r.AddError(err)
}
out.WriteString("null")
return
}
switch t.(type) {
case *types.ObjectTypeDefinition, *types.InterfaceTypeDefinition, *types.Union:
r.execSelections(ctx, sels, path, s, resolver, out, false)
return
}
// Any pointers or interfaces at this point should be non-nil, so we can get the actual value of them
// for serialization
if resolver.Kind() == reflect.Ptr || resolver.Kind() == reflect.Interface {
resolver = resolver.Elem()
}
switch t := t.(type) {
case *types.List:
r.execList(ctx, sels, t, path, s, resolver, out)
case *types.ScalarTypeDefinition:
v := resolver.Interface()
data, err := json.Marshal(v)
if err != nil {
panic(errors.Errorf("could not marshal %v: %s", v, err))
}
out.Write(data)
case *types.EnumTypeDefinition:
var stringer fmt.Stringer = resolver
if s, ok := resolver.Interface().(fmt.Stringer); ok {
stringer = s
}
name := stringer.String()
var valid bool
for _, v := range t.EnumValuesDefinition {
if v.EnumValue == name {
valid = true
break
}
}
if !valid {
err := errors.Errorf("Invalid value %s.\nExpected type %s, found %s.", name, t.Name, name)
err.Path = path.toSlice()
r.AddError(err)
out.WriteString("null")
return
}
out.WriteByte('"')
out.WriteString(name)
out.WriteByte('"')
default:
panic("unreachable")
}
}
func (r *Request) execList(ctx context.Context, sels []selected.Selection, typ *types.List, path *pathSegment, s *resolvable.Schema, resolver reflect.Value, out *bytes.Buffer) {
l := resolver.Len()
entryouts := make([]bytes.Buffer, l)
if selected.HasAsyncSel(sels) {
// Limit the number of concurrent goroutines spawned as it can lead to large
// memory spikes for large lists.
concurrency := cap(r.Limiter)
sem := make(chan struct{}, concurrency)
for i := 0; i < l; i++ {
sem <- struct{}{}
go func(i int) {
defer func() { <-sem }()
defer r.handlePanic(ctx)
r.execSelectionSet(ctx, sels, typ.OfType, &pathSegment{path, i}, s, resolver.Index(i), &entryouts[i])
}(i)
}
for i := 0; i < concurrency; i++ {
sem <- struct{}{}
}
} else {
for i := 0; i < l; i++ {
r.execSelectionSet(ctx, sels, typ.OfType, &pathSegment{path, i}, s, resolver.Index(i), &entryouts[i])
}
}
_, listOfNonNull := typ.OfType.(*types.NonNull)
out.WriteByte('[')
for i, entryout := range entryouts {
// If the list wraps a non-null type and one of the list elements
// resolves to null, then the entire list resolves to null.
if listOfNonNull && resolvedToNull(&entryout) {
out.Reset()
out.WriteString("null")
return
}
if i > 0 {
out.WriteByte(',')
}
out.Write(entryout.Bytes())
}
out.WriteByte(']')
}
func unwrapNonNull(t types.Type) (types.Type, bool) {
if nn, ok := t.(*types.NonNull); ok {
return nn.OfType, true
}
return t, false
}
type pathSegment struct {
parent *pathSegment
value interface{}
}
func (p *pathSegment) toSlice() []interface{} {
if p == nil {
return nil
}
return append(p.parent.toSlice(), p.value)
}

View File

@@ -0,0 +1,390 @@
package packer
import (
"fmt"
"math"
"reflect"
"strings"
"github.com/graph-gophers/graphql-go/decode"
"github.com/graph-gophers/graphql-go/errors"
"github.com/graph-gophers/graphql-go/types"
)
type packer interface {
Pack(value interface{}) (reflect.Value, error)
}
type Builder struct {
packerMap map[typePair]*packerMapEntry
structPackers []*StructPacker
}
type typePair struct {
graphQLType types.Type
resolverType reflect.Type
}
type packerMapEntry struct {
packer packer
targets []*packer
}
func NewBuilder() *Builder {
return &Builder{
packerMap: make(map[typePair]*packerMapEntry),
}
}
func (b *Builder) Finish() error {
for _, entry := range b.packerMap {
for _, target := range entry.targets {
*target = entry.packer
}
}
for _, p := range b.structPackers {
p.defaultStruct = reflect.New(p.structType).Elem()
for _, f := range p.fields {
if defaultVal := f.field.Default; defaultVal != nil {
v, err := f.fieldPacker.Pack(defaultVal.Deserialize(nil))
if err != nil {
return err
}
p.defaultStruct.FieldByIndex(f.fieldIndex).Set(v)
}
}
}
return nil
}
func (b *Builder) assignPacker(target *packer, schemaType types.Type, reflectType reflect.Type) error {
k := typePair{schemaType, reflectType}
ref, ok := b.packerMap[k]
if !ok {
ref = &packerMapEntry{}
b.packerMap[k] = ref
var err error
ref.packer, err = b.makePacker(schemaType, reflectType)
if err != nil {
return err
}
}
ref.targets = append(ref.targets, target)
return nil
}
func (b *Builder) makePacker(schemaType types.Type, reflectType reflect.Type) (packer, error) {
t, nonNull := unwrapNonNull(schemaType)
if !nonNull {
if reflectType.Kind() == reflect.Ptr {
elemType := reflectType.Elem()
addPtr := true
if _, ok := t.(*types.InputObject); ok {
elemType = reflectType // keep pointer for input objects
addPtr = false
}
elem, err := b.makeNonNullPacker(t, elemType)
if err != nil {
return nil, err
}
return &nullPacker{
elemPacker: elem,
valueType: reflectType,
addPtr: addPtr,
}, nil
} else if isNullable(reflectType) {
elemType := reflectType
addPtr := false
elem, err := b.makeNonNullPacker(t, elemType)
if err != nil {
return nil, err
}
return &nullPacker{
elemPacker: elem,
valueType: reflectType,
addPtr: addPtr,
}, nil
} else {
return nil, fmt.Errorf("%s is not a pointer or a nullable type", reflectType)
}
}
return b.makeNonNullPacker(t, reflectType)
}
func (b *Builder) makeNonNullPacker(schemaType types.Type, reflectType reflect.Type) (packer, error) {
if u, ok := reflect.New(reflectType).Interface().(decode.Unmarshaler); ok {
if !u.ImplementsGraphQLType(schemaType.String()) {
return nil, fmt.Errorf("can not unmarshal %s into %s", schemaType, reflectType)
}
return &unmarshalerPacker{
ValueType: reflectType,
}, nil
}
switch t := schemaType.(type) {
case *types.ScalarTypeDefinition:
return &ValuePacker{
ValueType: reflectType,
}, nil
case *types.EnumTypeDefinition:
if reflectType.Kind() != reflect.String {
return nil, fmt.Errorf("wrong type, expected %s", reflect.String)
}
return &ValuePacker{
ValueType: reflectType,
}, nil
case *types.InputObject:
e, err := b.MakeStructPacker(t.Values, reflectType)
if err != nil {
return nil, err
}
return e, nil
case *types.List:
if reflectType.Kind() != reflect.Slice {
return nil, fmt.Errorf("expected slice, got %s", reflectType)
}
p := &listPacker{
sliceType: reflectType,
}
if err := b.assignPacker(&p.elem, t.OfType, reflectType.Elem()); err != nil {
return nil, err
}
return p, nil
case *types.ObjectTypeDefinition, *types.InterfaceTypeDefinition, *types.Union:
return nil, fmt.Errorf("type of kind %s can not be used as input", t.Kind())
default:
panic("unreachable")
}
}
func (b *Builder) MakeStructPacker(values []*types.InputValueDefinition, typ reflect.Type) (*StructPacker, error) {
structType := typ
usePtr := false
if typ.Kind() == reflect.Ptr {
structType = typ.Elem()
usePtr = true
}
if structType.Kind() != reflect.Struct {
return nil, fmt.Errorf("expected struct or pointer to struct, got %s (hint: missing `args struct { ... }` wrapper for field arguments?)", typ)
}
var fields []*structPackerField
for _, v := range values {
fe := &structPackerField{field: v}
fx := func(n string) bool {
return strings.EqualFold(stripUnderscore(n), stripUnderscore(v.Name.Name))
}
sf, ok := structType.FieldByNameFunc(fx)
if !ok {
return nil, fmt.Errorf("%s does not define field %q (hint: missing `args struct { ... }` wrapper for field arguments, or missing field on input struct)", typ, v.Name.Name)
}
if sf.PkgPath != "" {
return nil, fmt.Errorf("field %q must be exported", sf.Name)
}
fe.fieldIndex = sf.Index
ft := v.Type
if v.Default != nil {
ft, _ = unwrapNonNull(ft)
ft = &types.NonNull{OfType: ft}
}
if err := b.assignPacker(&fe.fieldPacker, ft, sf.Type); err != nil {
return nil, fmt.Errorf("field %q: %s", sf.Name, err)
}
fields = append(fields, fe)
}
p := &StructPacker{
structType: structType,
usePtr: usePtr,
fields: fields,
}
b.structPackers = append(b.structPackers, p)
return p, nil
}
type StructPacker struct {
structType reflect.Type
usePtr bool
defaultStruct reflect.Value
fields []*structPackerField
}
type structPackerField struct {
field *types.InputValueDefinition
fieldIndex []int
fieldPacker packer
}
func (p *StructPacker) Pack(value interface{}) (reflect.Value, error) {
if value == nil {
return reflect.Value{}, errors.Errorf("got null for non-null")
}
values := value.(map[string]interface{})
v := reflect.New(p.structType)
v.Elem().Set(p.defaultStruct)
for _, f := range p.fields {
if value, ok := values[f.field.Name.Name]; ok {
packed, err := f.fieldPacker.Pack(value)
if err != nil {
return reflect.Value{}, err
}
v.Elem().FieldByIndex(f.fieldIndex).Set(packed)
}
}
if !p.usePtr {
return v.Elem(), nil
}
return v, nil
}
type listPacker struct {
sliceType reflect.Type
elem packer
}
func (e *listPacker) Pack(value interface{}) (reflect.Value, error) {
list, ok := value.([]interface{})
if !ok {
list = []interface{}{value}
}
v := reflect.MakeSlice(e.sliceType, len(list), len(list))
for i := range list {
packed, err := e.elem.Pack(list[i])
if err != nil {
return reflect.Value{}, err
}
v.Index(i).Set(packed)
}
return v, nil
}
type nullPacker struct {
elemPacker packer
valueType reflect.Type
addPtr bool
}
func (p *nullPacker) Pack(value interface{}) (reflect.Value, error) {
if value == nil && !isNullable(p.valueType) {
return reflect.Zero(p.valueType), nil
}
v, err := p.elemPacker.Pack(value)
if err != nil {
return reflect.Value{}, err
}
if p.addPtr {
ptr := reflect.New(p.valueType.Elem())
ptr.Elem().Set(v)
return ptr, nil
}
return v, nil
}
type ValuePacker struct {
ValueType reflect.Type
}
func (p *ValuePacker) Pack(value interface{}) (reflect.Value, error) {
if value == nil {
return reflect.Value{}, errors.Errorf("got null for non-null")
}
coerced, err := unmarshalInput(p.ValueType, value)
if err != nil {
return reflect.Value{}, fmt.Errorf("could not unmarshal %#v (%T) into %s: %s", value, value, p.ValueType, err)
}
return reflect.ValueOf(coerced), nil
}
type unmarshalerPacker struct {
ValueType reflect.Type
}
func (p *unmarshalerPacker) Pack(value interface{}) (reflect.Value, error) {
if value == nil && !isNullable(p.ValueType) {
return reflect.Value{}, errors.Errorf("got null for non-null")
}
v := reflect.New(p.ValueType)
if err := v.Interface().(decode.Unmarshaler).UnmarshalGraphQL(value); err != nil {
return reflect.Value{}, err
}
return v.Elem(), nil
}
func unmarshalInput(typ reflect.Type, input interface{}) (interface{}, error) {
if reflect.TypeOf(input) == typ {
return input, nil
}
switch typ.Kind() {
case reflect.Int32:
switch input := input.(type) {
case int:
if input < math.MinInt32 || input > math.MaxInt32 {
return nil, fmt.Errorf("not a 32-bit integer")
}
return int32(input), nil
case float64:
coerced := int32(input)
if input < math.MinInt32 || input > math.MaxInt32 || float64(coerced) != input {
return nil, fmt.Errorf("not a 32-bit integer")
}
return coerced, nil
}
case reflect.Float64:
switch input := input.(type) {
case int32:
return float64(input), nil
case int:
return float64(input), nil
}
case reflect.String:
if reflect.TypeOf(input).ConvertibleTo(typ) {
return reflect.ValueOf(input).Convert(typ).Interface(), nil
}
}
return nil, fmt.Errorf("incompatible type")
}
func unwrapNonNull(t types.Type) (types.Type, bool) {
if nn, ok := t.(*types.NonNull); ok {
return nn.OfType, true
}
return t, false
}
func stripUnderscore(s string) string {
return strings.Replace(s, "_", "", -1)
}
// NullUnmarshaller is an unmarshaller that can handle a nil input
type NullUnmarshaller interface {
decode.Unmarshaler
Nullable()
}
func isNullable(t reflect.Type) bool {
_, ok := reflect.New(t).Interface().(NullUnmarshaller)
return ok
}

View File

@@ -0,0 +1,70 @@
package resolvable
import (
"reflect"
"github.com/graph-gophers/graphql-go/introspection"
"github.com/graph-gophers/graphql-go/types"
)
// Meta defines the details of the metadata schema for introspection.
type Meta struct {
FieldSchema Field
FieldType Field
FieldTypename Field
Schema *Object
Type *Object
}
func newMeta(s *types.Schema) *Meta {
var err error
b := newBuilder(s)
metaSchema := s.Types["__Schema"].(*types.ObjectTypeDefinition)
so, err := b.makeObjectExec(metaSchema.Name, metaSchema.Fields, nil, false, reflect.TypeOf(&introspection.Schema{}))
if err != nil {
panic(err)
}
metaType := s.Types["__Type"].(*types.ObjectTypeDefinition)
t, err := b.makeObjectExec(metaType.Name, metaType.Fields, nil, false, reflect.TypeOf(&introspection.Type{}))
if err != nil {
panic(err)
}
if err := b.finish(); err != nil {
panic(err)
}
fieldTypename := Field{
FieldDefinition: types.FieldDefinition{
Name: "__typename",
Type: &types.NonNull{OfType: s.Types["String"]},
},
TraceLabel: "GraphQL field: __typename",
}
fieldSchema := Field{
FieldDefinition: types.FieldDefinition{
Name: "__schema",
Type: s.Types["__Schema"],
},
TraceLabel: "GraphQL field: __schema",
}
fieldType := Field{
FieldDefinition: types.FieldDefinition{
Name: "__type",
Type: s.Types["__Type"],
},
TraceLabel: "GraphQL field: __type",
}
return &Meta{
FieldSchema: fieldSchema,
FieldTypename: fieldTypename,
FieldType: fieldType,
Schema: so,
Type: t,
}
}

View File

@@ -0,0 +1,453 @@
package resolvable
import (
"context"
"fmt"
"reflect"
"strings"
"github.com/graph-gophers/graphql-go/decode"
"github.com/graph-gophers/graphql-go/internal/exec/packer"
"github.com/graph-gophers/graphql-go/types"
)
type Schema struct {
*Meta
types.Schema
Query Resolvable
Mutation Resolvable
Subscription Resolvable
Resolver reflect.Value
}
type Resolvable interface {
isResolvable()
}
type Object struct {
Name string
Fields map[string]*Field
TypeAssertions map[string]*TypeAssertion
}
type Field struct {
types.FieldDefinition
TypeName string
MethodIndex int
FieldIndex []int
HasContext bool
HasError bool
ArgsPacker *packer.StructPacker
ValueExec Resolvable
TraceLabel string
}
func (f *Field) UseMethodResolver() bool {
return len(f.FieldIndex) == 0
}
type TypeAssertion struct {
MethodIndex int
TypeExec Resolvable
}
type List struct {
Elem Resolvable
}
type Scalar struct{}
func (*Object) isResolvable() {}
func (*List) isResolvable() {}
func (*Scalar) isResolvable() {}
func ApplyResolver(s *types.Schema, resolver interface{}) (*Schema, error) {
if resolver == nil {
return &Schema{Meta: newMeta(s), Schema: *s}, nil
}
b := newBuilder(s)
var query, mutation, subscription Resolvable
if t, ok := s.EntryPoints["query"]; ok {
if err := b.assignExec(&query, t, reflect.TypeOf(resolver)); err != nil {
return nil, err
}
}
if t, ok := s.EntryPoints["mutation"]; ok {
if err := b.assignExec(&mutation, t, reflect.TypeOf(resolver)); err != nil {
return nil, err
}
}
if t, ok := s.EntryPoints["subscription"]; ok {
if err := b.assignExec(&subscription, t, reflect.TypeOf(resolver)); err != nil {
return nil, err
}
}
if err := b.finish(); err != nil {
return nil, err
}
return &Schema{
Meta: newMeta(s),
Schema: *s,
Resolver: reflect.ValueOf(resolver),
Query: query,
Mutation: mutation,
Subscription: subscription,
}, nil
}
type execBuilder struct {
schema *types.Schema
resMap map[typePair]*resMapEntry
packerBuilder *packer.Builder
}
type typePair struct {
graphQLType types.Type
resolverType reflect.Type
}
type resMapEntry struct {
exec Resolvable
targets []*Resolvable
}
func newBuilder(s *types.Schema) *execBuilder {
return &execBuilder{
schema: s,
resMap: make(map[typePair]*resMapEntry),
packerBuilder: packer.NewBuilder(),
}
}
func (b *execBuilder) finish() error {
for _, entry := range b.resMap {
for _, target := range entry.targets {
*target = entry.exec
}
}
return b.packerBuilder.Finish()
}
func (b *execBuilder) assignExec(target *Resolvable, t types.Type, resolverType reflect.Type) error {
k := typePair{t, resolverType}
ref, ok := b.resMap[k]
if !ok {
ref = &resMapEntry{}
b.resMap[k] = ref
var err error
ref.exec, err = b.makeExec(t, resolverType)
if err != nil {
return err
}
}
ref.targets = append(ref.targets, target)
return nil
}
func (b *execBuilder) makeExec(t types.Type, resolverType reflect.Type) (Resolvable, error) {
var nonNull bool
t, nonNull = unwrapNonNull(t)
switch t := t.(type) {
case *types.ObjectTypeDefinition:
return b.makeObjectExec(t.Name, t.Fields, nil, nonNull, resolverType)
case *types.InterfaceTypeDefinition:
return b.makeObjectExec(t.Name, t.Fields, t.PossibleTypes, nonNull, resolverType)
case *types.Union:
return b.makeObjectExec(t.Name, nil, t.UnionMemberTypes, nonNull, resolverType)
}
if !nonNull {
if resolverType.Kind() != reflect.Ptr {
return nil, fmt.Errorf("%s is not a pointer", resolverType)
}
resolverType = resolverType.Elem()
}
switch t := t.(type) {
case *types.ScalarTypeDefinition:
return makeScalarExec(t, resolverType)
case *types.EnumTypeDefinition:
return &Scalar{}, nil
case *types.List:
if resolverType.Kind() != reflect.Slice {
return nil, fmt.Errorf("%s is not a slice", resolverType)
}
e := &List{}
if err := b.assignExec(&e.Elem, t.OfType, resolverType.Elem()); err != nil {
return nil, err
}
return e, nil
default:
panic("invalid type: " + t.String())
}
}
func makeScalarExec(t *types.ScalarTypeDefinition, resolverType reflect.Type) (Resolvable, error) {
implementsType := false
switch r := reflect.New(resolverType).Interface().(type) {
case *int32:
implementsType = t.Name == "Int"
case *float64:
implementsType = t.Name == "Float"
case *string:
implementsType = t.Name == "String"
case *bool:
implementsType = t.Name == "Boolean"
case decode.Unmarshaler:
implementsType = r.ImplementsGraphQLType(t.Name)
}
if !implementsType {
return nil, fmt.Errorf("can not use %s as %s", resolverType, t.Name)
}
return &Scalar{}, nil
}
func (b *execBuilder) makeObjectExec(typeName string, fields types.FieldsDefinition, possibleTypes []*types.ObjectTypeDefinition,
nonNull bool, resolverType reflect.Type) (*Object, error) {
if !nonNull {
if resolverType.Kind() != reflect.Ptr && resolverType.Kind() != reflect.Interface {
return nil, fmt.Errorf("%s is not a pointer or interface", resolverType)
}
}
methodHasReceiver := resolverType.Kind() != reflect.Interface
Fields := make(map[string]*Field)
rt := unwrapPtr(resolverType)
fieldsCount := fieldCount(rt, map[string]int{})
for _, f := range fields {
var fieldIndex []int
methodIndex := findMethod(resolverType, f.Name)
if b.schema.UseFieldResolvers && methodIndex == -1 {
if fieldsCount[strings.ToLower(stripUnderscore(f.Name))] > 1 {
return nil, fmt.Errorf("%s does not resolve %q: ambiguous field %q", resolverType, typeName, f.Name)
}
fieldIndex = findField(rt, f.Name, []int{})
}
if methodIndex == -1 && len(fieldIndex) == 0 {
hint := ""
if findMethod(reflect.PtrTo(resolverType), f.Name) != -1 {
hint = " (hint: the method exists on the pointer type)"
}
return nil, fmt.Errorf("%s does not resolve %q: missing method for field %q%s", resolverType, typeName, f.Name, hint)
}
var m reflect.Method
var sf reflect.StructField
if methodIndex != -1 {
m = resolverType.Method(methodIndex)
} else {
sf = rt.FieldByIndex(fieldIndex)
}
fe, err := b.makeFieldExec(typeName, f, m, sf, methodIndex, fieldIndex, methodHasReceiver)
if err != nil {
var resolverName string
if methodIndex != -1 {
resolverName = m.Name
} else {
resolverName = sf.Name
}
return nil, fmt.Errorf("%s\n\tused by (%s).%s", err, resolverType, resolverName)
}
Fields[f.Name] = fe
}
// Check type assertions when
// 1) using method resolvers
// 2) Or resolver is not an interface type
typeAssertions := make(map[string]*TypeAssertion)
if !b.schema.UseFieldResolvers || resolverType.Kind() != reflect.Interface {
for _, impl := range possibleTypes {
methodIndex := findMethod(resolverType, "To"+impl.Name)
if methodIndex == -1 {
return nil, fmt.Errorf("%s does not resolve %q: missing method %q to convert to %q", resolverType, typeName, "To"+impl.Name, impl.Name)
}
if resolverType.Method(methodIndex).Type.NumOut() != 2 {
return nil, fmt.Errorf("%s does not resolve %q: method %q should return a value and a bool indicating success", resolverType, typeName, "To"+impl.Name)
}
a := &TypeAssertion{
MethodIndex: methodIndex,
}
if err := b.assignExec(&a.TypeExec, impl, resolverType.Method(methodIndex).Type.Out(0)); err != nil {
return nil, err
}
typeAssertions[impl.Name] = a
}
}
return &Object{
Name: typeName,
Fields: Fields,
TypeAssertions: typeAssertions,
}, nil
}
var contextType = reflect.TypeOf((*context.Context)(nil)).Elem()
var errorType = reflect.TypeOf((*error)(nil)).Elem()
func (b *execBuilder) makeFieldExec(typeName string, f *types.FieldDefinition, m reflect.Method, sf reflect.StructField,
methodIndex int, fieldIndex []int, methodHasReceiver bool) (*Field, error) {
var argsPacker *packer.StructPacker
var hasError bool
var hasContext bool
// Validate resolver method only when there is one
if methodIndex != -1 {
in := make([]reflect.Type, m.Type.NumIn())
for i := range in {
in[i] = m.Type.In(i)
}
if methodHasReceiver {
in = in[1:] // first parameter is receiver
}
hasContext = len(in) > 0 && in[0] == contextType
if hasContext {
in = in[1:]
}
if len(f.Arguments) > 0 {
if len(in) == 0 {
return nil, fmt.Errorf("must have parameter for field arguments")
}
var err error
argsPacker, err = b.packerBuilder.MakeStructPacker(f.Arguments, in[0])
if err != nil {
return nil, err
}
in = in[1:]
}
if len(in) > 0 {
return nil, fmt.Errorf("too many parameters")
}
maxNumOfReturns := 2
if m.Type.NumOut() < maxNumOfReturns-1 {
return nil, fmt.Errorf("too few return values")
}
if m.Type.NumOut() > maxNumOfReturns {
return nil, fmt.Errorf("too many return values")
}
hasError = m.Type.NumOut() == maxNumOfReturns
if hasError {
if m.Type.Out(maxNumOfReturns-1) != errorType {
return nil, fmt.Errorf(`must have "error" as its last return value`)
}
}
}
fe := &Field{
FieldDefinition: *f,
TypeName: typeName,
MethodIndex: methodIndex,
FieldIndex: fieldIndex,
HasContext: hasContext,
ArgsPacker: argsPacker,
HasError: hasError,
TraceLabel: fmt.Sprintf("GraphQL field: %s.%s", typeName, f.Name),
}
var out reflect.Type
if methodIndex != -1 {
out = m.Type.Out(0)
sub, ok := b.schema.EntryPoints["subscription"]
if ok && typeName == sub.TypeName() && out.Kind() == reflect.Chan {
out = m.Type.Out(0).Elem()
}
} else {
out = sf.Type
}
if err := b.assignExec(&fe.ValueExec, f.Type, out); err != nil {
return nil, err
}
return fe, nil
}
func findMethod(t reflect.Type, name string) int {
for i := 0; i < t.NumMethod(); i++ {
if strings.EqualFold(stripUnderscore(name), stripUnderscore(t.Method(i).Name)) {
return i
}
}
return -1
}
func findField(t reflect.Type, name string, index []int) []int {
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if field.Type.Kind() == reflect.Struct && field.Anonymous {
newIndex := findField(field.Type, name, []int{i})
if len(newIndex) > 1 {
return append(index, newIndex...)
}
}
if strings.EqualFold(stripUnderscore(name), stripUnderscore(field.Name)) {
return append(index, i)
}
}
return index
}
// fieldCount helps resolve ambiguity when more than one embedded struct contains fields with the same name.
func fieldCount(t reflect.Type, count map[string]int) map[string]int {
if t.Kind() != reflect.Struct {
return nil
}
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fieldName := strings.ToLower(stripUnderscore(field.Name))
if field.Type.Kind() == reflect.Struct && field.Anonymous {
count = fieldCount(field.Type, count)
} else {
if _, ok := count[fieldName]; !ok {
count[fieldName] = 0
}
count[fieldName]++
}
}
return count
}
func unwrapNonNull(t types.Type) (types.Type, bool) {
if nn, ok := t.(*types.NonNull); ok {
return nn.OfType, true
}
return t, false
}
func stripUnderscore(s string) string {
return strings.Replace(s, "_", "", -1)
}
func unwrapPtr(t reflect.Type) reflect.Type {
if t.Kind() == reflect.Ptr {
return t.Elem()
}
return t
}

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