Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52d4705a91 | ||
|
|
7288f71201 | ||
|
|
9c43eff753 | ||
|
|
c8d7fdeedc | ||
|
|
c211152e23 | ||
|
|
ab75d5097e | ||
|
|
c3644c8d3b | ||
|
|
6438a3dba3 | ||
|
|
4b226a6a63 | ||
|
|
4801850013 | ||
|
|
6a7412bf2b | ||
|
|
5a1fd7dadd | ||
|
|
ac06a26809 | ||
|
|
61d56f26f8 | ||
|
|
6aa05b3981 | ||
|
|
aad60c882e | ||
|
|
fecca57507 | ||
|
|
2bcad846c0 | ||
|
|
15ad0165fc | ||
|
|
2e8ab11978 | ||
|
|
9a8ce9b17e | ||
|
|
16ab4c6fed | ||
|
|
e3ee0df7ba | ||
|
|
8f7ab280e2 | ||
|
|
dbedc99421 | ||
|
|
6cb359cb80 | ||
|
|
ae2ad824a9 | ||
|
|
02e3d7852b | ||
|
|
3893a035be | ||
|
|
658bdd9faa | ||
|
|
e1eebcd4e0 | ||
|
|
062b831e88 | ||
|
|
b275efaeff | ||
|
|
80d3033456 | ||
|
|
bd0516f09a | ||
|
|
df4d76e466 | ||
|
|
dcbd7f8cad | ||
|
|
73ec02ab9d | ||
|
|
d1f8347071 | ||
|
|
8601eedada | ||
|
|
9afd33cdfc | ||
|
|
5e1be8e558 | ||
|
|
835dd2635a | ||
|
|
f65b18c2f6 | ||
|
|
b0e7b84f40 | ||
|
|
1635db93c7 | ||
|
|
c4fe462d11 | ||
|
|
b1f403165d | ||
|
|
46e4317b77 | ||
|
|
e3ffbcadd8 | ||
|
|
b7d73077e5 | ||
|
|
77f61ee20a | ||
|
|
8967f02fc9 | ||
|
|
831ff6d0a9 | ||
|
|
2199174def |
22
.github/dependabot.yml
vendored
Normal file
22
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# Docs: <https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/customizing-dependency-updates>
|
||||
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: gomod
|
||||
directory: /
|
||||
schedule: {interval: weekly}
|
||||
reviewers: [42wim]
|
||||
assignees: [42wim]
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule: {interval: weekly}
|
||||
reviewers: [42wim]
|
||||
assignees: [42wim]
|
||||
|
||||
- package-ecosystem: docker
|
||||
directory: /
|
||||
schedule: {interval: weekly}
|
||||
reviewers: [42wim]
|
||||
assignees: [42wim]
|
||||
6
.github/workflows/development.yml
vendored
6
.github/workflows/development.yml
vendored
@@ -35,9 +35,9 @@ jobs:
|
||||
run: |
|
||||
mkdir -p output/{win,lin,arm,mac}
|
||||
VERSION=$(git describe --tags)
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/lin/matterbridge-$VERSION-linux-amd64
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/win/matterbridge-$VERSION-windows-amd64.exe
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/mac/matterbridge-$VERSION-darwin-amd64
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o output/lin/matterbridge-$VERSION-linux-amd64
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o output/win/matterbridge-$VERSION-windows-amd64.exe
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o output/mac/matterbridge-$VERSION-darwin-amd64
|
||||
- name: Upload linux 64-bit
|
||||
if: startsWith(matrix.go-version,'1.17')
|
||||
uses: actions/upload-artifact@v2
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,3 +4,6 @@
|
||||
|
||||
# Exclude configuration file
|
||||
matterbridge.toml
|
||||
|
||||
# Exclude IDE Files
|
||||
.vscode
|
||||
|
||||
@@ -186,7 +186,24 @@ linters:
|
||||
- errorlint
|
||||
- nlreturn
|
||||
- exhaustivestruct
|
||||
|
||||
- forbidigo
|
||||
- wrapcheck
|
||||
- varnamelen
|
||||
- ireturn
|
||||
- errorlint
|
||||
- tparallel
|
||||
- wrapcheck
|
||||
- paralleltest
|
||||
- makezero
|
||||
- thelper
|
||||
- cyclop
|
||||
- revive
|
||||
- importas
|
||||
- gomoddirectives
|
||||
- promlinter
|
||||
- tagliatelle
|
||||
- errname
|
||||
- typecheck
|
||||
# rules to deal with reported isues
|
||||
issues:
|
||||
# List of regexps of issue texts to exclude, empty list by default.
|
||||
|
||||
@@ -22,7 +22,7 @@ builds:
|
||||
- 6
|
||||
- 7
|
||||
ldflags:
|
||||
- -s -w -X main.githash={{.ShortCommit}}
|
||||
- -s -w -X github.com/42wim/matterbridge/version.GitHash={{.ShortCommit}}
|
||||
|
||||
archives:
|
||||
-
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
FROM alpine:edge AS builder
|
||||
FROM alpine AS builder
|
||||
|
||||
COPY . /go/src/matterbridge
|
||||
RUN apk --no-cache add go git \
|
||||
&& cd /go/src/matterbridge \
|
||||
&& CGO_ENABLED=0 go build -mod vendor -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
|
||||
&& CGO_ENABLED=0 go build -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
|
||||
|
||||
@@ -164,7 +164,7 @@ See <https://github.com/42wim/matterbridge/wiki>
|
||||
|
||||
### Binaries
|
||||
|
||||
- Latest stable release [v1.23.0](https://github.com/42wim/matterbridge/releases/latest)
|
||||
- Latest stable release [v1.23.2](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.
|
||||
@@ -336,6 +336,7 @@ See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ)
|
||||
- <https://daniele.tech/2019/02/how-to-use-matterbridge-to-connect-2-different-slack-workspaces/>
|
||||
- <https://userlinux.net/mattermost-and-matterbridge.html>
|
||||
- <https://nextcloud.com/blog/bridging-chat-services-in-talk/>
|
||||
- <https://minecraftchest1.wordpress.com/2021/06/05/how-to-install-and-setup-matterbridge/>
|
||||
- Youtube: [whatsapp - telegram bridging](https://www.youtube.com/watch?v=W-VXISoKtNc)
|
||||
|
||||
## Thanks
|
||||
|
||||
@@ -23,6 +23,7 @@ const (
|
||||
EventRejoinChannels = "rejoin_channels"
|
||||
EventUserAction = "user_action"
|
||||
EventMsgDelete = "msg_delete"
|
||||
EventFileDelete = "file_delete"
|
||||
EventAPIConnected = "api_connected"
|
||||
EventUserTyping = "user_typing"
|
||||
EventGetChannelMembers = "get_channel_members"
|
||||
@@ -56,13 +57,14 @@ func (m Message) ParentValid() bool {
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
Name string
|
||||
Data *[]byte
|
||||
Comment string
|
||||
URL string
|
||||
Size int64
|
||||
Avatar bool
|
||||
SHA string
|
||||
Name string
|
||||
Data *[]byte
|
||||
Comment string
|
||||
URL string
|
||||
Size int64
|
||||
Avatar bool
|
||||
SHA string
|
||||
NativeID string
|
||||
}
|
||||
|
||||
type ChannelInfo struct {
|
||||
@@ -168,7 +170,7 @@ type Protocol struct {
|
||||
UseTLS bool // IRC
|
||||
UseDiscriminator bool // discord
|
||||
UseFirstName bool // telegram
|
||||
UseUserName bool // discord, matrix
|
||||
UseUserName bool // discord, matrix, mattermost
|
||||
UseInsecureURL bool // telegram
|
||||
UserName string // IRC
|
||||
VerboseJoinPart bool // IRC
|
||||
|
||||
@@ -10,10 +10,14 @@ import (
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/42wim/matterbridge/bridge/discord/transmitter"
|
||||
"github.com/42wim/matterbridge/bridge/helper"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/matterbridge/discordgo"
|
||||
)
|
||||
|
||||
const MessageLength = 1950
|
||||
const (
|
||||
MessageLength = 1950
|
||||
cFileUpload = "file_upload"
|
||||
)
|
||||
|
||||
type Bdiscord struct {
|
||||
*bridge.Config
|
||||
@@ -35,10 +39,20 @@ type Bdiscord struct {
|
||||
// Webhook specific logic
|
||||
useAutoWebhooks bool
|
||||
transmitter *transmitter.Transmitter
|
||||
cache *lru.Cache
|
||||
}
|
||||
|
||||
func New(cfg *bridge.Config) bridge.Bridger {
|
||||
b := &Bdiscord{Config: cfg}
|
||||
newCache, err := lru.New(5000)
|
||||
if err != nil {
|
||||
cfg.Log.Fatalf("Could not create LRU cache: %v", err)
|
||||
}
|
||||
|
||||
b := &Bdiscord{
|
||||
Config: cfg,
|
||||
cache: newCache,
|
||||
}
|
||||
|
||||
b.userMemberMap = make(map[string]*discordgo.Member)
|
||||
b.nickMemberMap = make(map[string]*discordgo.Member)
|
||||
b.channelInfoMap = make(map[string]*config.ChannelInfo)
|
||||
@@ -75,6 +89,9 @@ func (b *Bdiscord) Connect() error {
|
||||
b.c.AddHandler(b.messageDeleteBulk)
|
||||
b.c.AddHandler(b.memberAdd)
|
||||
b.c.AddHandler(b.memberRemove)
|
||||
if b.GetInt("debuglevel") == 1 {
|
||||
b.c.AddHandler(b.messageEvent)
|
||||
}
|
||||
// Add privileged intent for guild member tracking. This is needed to track nicks
|
||||
// for display names and @mention translation
|
||||
b.c.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged |
|
||||
@@ -153,7 +170,7 @@ func (b *Bdiscord) Connect() error {
|
||||
return fmt.Errorf("use of removed WebhookURL setting")
|
||||
}
|
||||
|
||||
if b.GetInt("debuglevel") > 0 {
|
||||
if b.GetInt("debuglevel") == 2 {
|
||||
b.Log.Debug("enabling even more discord debug")
|
||||
b.c.Debug = true
|
||||
}
|
||||
@@ -280,6 +297,21 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Delete a file
|
||||
if msg.Event == config.EventFileDelete {
|
||||
if msg.ID == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if fi, ok := b.cache.Get(cFileUpload + msg.ID); ok {
|
||||
err := b.c.ChannelMessageDelete(channelID, fi.(string)) // nolint:forcetypeassert
|
||||
b.cache.Remove(cFileUpload + msg.ID)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("file %s not found", msg.ID)
|
||||
}
|
||||
|
||||
// Upload a file if it exists
|
||||
if msg.Extra != nil {
|
||||
for _, rmsg := range helper.HandleExtra(msg, b.General) {
|
||||
@@ -327,7 +359,6 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st
|
||||
|
||||
// handleUploadFile handles native upload of files
|
||||
func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (string, error) {
|
||||
var err error
|
||||
for _, f := range msg.Extra["file"] {
|
||||
fi := f.(config.FileInfo)
|
||||
file := discordgo.File{
|
||||
@@ -340,10 +371,15 @@ func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (stri
|
||||
Files: []*discordgo.File{&file},
|
||||
AllowedMentions: b.getAllowedMentions(),
|
||||
}
|
||||
_, err = b.c.ChannelMessageSendComplex(channelID, &m)
|
||||
res, err := b.c.ChannelMessageSendComplex(channelID, &m)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("file upload failed: %s", err)
|
||||
}
|
||||
|
||||
// link file_upload_nativeID (file ID from the original bridge) to our upload id
|
||||
// so that we can remove this later when it eg needs to be deleted
|
||||
b.cache.Add(cFileUpload+fi.NativeID, res.ID)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package bdiscord
|
||||
|
||||
import (
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/matterbridge/discordgo"
|
||||
)
|
||||
|
||||
@@ -31,6 +32,10 @@ func (b *Bdiscord) messageDeleteBulk(s *discordgo.Session, m *discordgo.MessageD
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bdiscord) messageEvent(s *discordgo.Session, m *discordgo.Event) {
|
||||
b.Log.Debug(spew.Sdump(m.Struct))
|
||||
}
|
||||
|
||||
func (b *Bdiscord) messageTyping(s *discordgo.Session, m *discordgo.TypingStart) {
|
||||
if !b.GetBool("ShowUserTyping") {
|
||||
return
|
||||
@@ -82,8 +87,9 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
|
||||
|
||||
rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg", UserID: m.Author.ID, ID: m.ID}
|
||||
|
||||
b.Log.Debugf("== Receiving event %#v", m.Message)
|
||||
|
||||
if m.Content != "" {
|
||||
b.Log.Debugf("== Receiving event %#v", m.Message)
|
||||
m.Message.Content = b.replaceChannelMentions(m.Message.Content)
|
||||
rmsg.Text, err = m.ContentWithMoreMentionsReplaced(b.c)
|
||||
if err != nil {
|
||||
|
||||
@@ -82,10 +82,8 @@ func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordg
|
||||
ContentType: "",
|
||||
Reader: bytes.NewReader(*fi.Data),
|
||||
}
|
||||
content := ""
|
||||
if msg.Text == "" {
|
||||
content = fi.Comment
|
||||
}
|
||||
content := fi.Comment
|
||||
|
||||
_, e2 := b.transmitter.Send(
|
||||
channelID,
|
||||
&discordgo.WebhookParams{
|
||||
|
||||
252
bridge/harmony/harmony.go
Normal file
252
bridge/harmony/harmony.go
Normal file
@@ -0,0 +1,252 @@
|
||||
package harmony
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/42wim/matterbridge/bridge"
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/harmony-development/shibshib"
|
||||
chatv1 "github.com/harmony-development/shibshib/gen/chat/v1"
|
||||
typesv1 "github.com/harmony-development/shibshib/gen/harmonytypes/v1"
|
||||
profilev1 "github.com/harmony-development/shibshib/gen/profile/v1"
|
||||
)
|
||||
|
||||
type cachedProfile struct {
|
||||
data *profilev1.GetProfileResponse
|
||||
lastUpdated time.Time
|
||||
}
|
||||
|
||||
type Bharmony struct {
|
||||
*bridge.Config
|
||||
|
||||
c *shibshib.Client
|
||||
profileCache map[uint64]cachedProfile
|
||||
}
|
||||
|
||||
func uToStr(in uint64) string {
|
||||
return strconv.FormatUint(in, 10)
|
||||
}
|
||||
|
||||
func strToU(in string) (uint64, error) {
|
||||
return strconv.ParseUint(in, 10, 64)
|
||||
}
|
||||
|
||||
func New(cfg *bridge.Config) bridge.Bridger {
|
||||
b := &Bharmony{
|
||||
Config: cfg,
|
||||
profileCache: map[uint64]cachedProfile{},
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bharmony) getProfile(u uint64) (*profilev1.GetProfileResponse, error) {
|
||||
if v, ok := b.profileCache[u]; ok && time.Since(v.lastUpdated) < time.Minute*10 {
|
||||
return v.data, nil
|
||||
}
|
||||
|
||||
resp, err := b.c.ProfileKit.GetProfile(&profilev1.GetProfileRequest{
|
||||
UserId: u,
|
||||
})
|
||||
if err != nil {
|
||||
if v, ok := b.profileCache[u]; ok {
|
||||
return v.data, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
b.profileCache[u] = cachedProfile{
|
||||
data: resp,
|
||||
lastUpdated: time.Now(),
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (b *Bharmony) avatarFor(m *chatv1.Message) string {
|
||||
if m.Overrides != nil {
|
||||
return m.Overrides.GetAvatar()
|
||||
}
|
||||
|
||||
profi, err := b.getProfile(m.AuthorId)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return b.c.TransformHMCURL(profi.Profile.GetUserAvatar())
|
||||
}
|
||||
|
||||
func (b *Bharmony) usernameFor(m *chatv1.Message) string {
|
||||
if m.Overrides != nil {
|
||||
return m.Overrides.GetUsername()
|
||||
}
|
||||
|
||||
profi, err := b.getProfile(m.AuthorId)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return profi.Profile.UserName
|
||||
}
|
||||
|
||||
func (b *Bharmony) toMessage(msg *shibshib.LocatedMessage) config.Message {
|
||||
message := config.Message{}
|
||||
message.Account = b.Account
|
||||
message.UserID = uToStr(msg.Message.AuthorId)
|
||||
message.Avatar = b.avatarFor(msg.Message)
|
||||
message.Username = b.usernameFor(msg.Message)
|
||||
message.Channel = uToStr(msg.ChannelID)
|
||||
message.ID = uToStr(msg.MessageId)
|
||||
|
||||
switch content := msg.Message.Content.Content.(type) {
|
||||
case *chatv1.Content_EmbedMessage:
|
||||
message.Text = "Embed"
|
||||
case *chatv1.Content_AttachmentMessage:
|
||||
var s strings.Builder
|
||||
for idx, attach := range content.AttachmentMessage.Files {
|
||||
s.WriteString(b.c.TransformHMCURL(attach.Id))
|
||||
if idx < len(content.AttachmentMessage.Files)-1 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
}
|
||||
message.Text = s.String()
|
||||
case *chatv1.Content_PhotoMessage:
|
||||
var s strings.Builder
|
||||
for idx, attach := range content.PhotoMessage.GetPhotos() {
|
||||
s.WriteString(attach.GetCaption().GetText())
|
||||
s.WriteString("\n")
|
||||
s.WriteString(b.c.TransformHMCURL(attach.GetHmc()))
|
||||
if idx < len(content.PhotoMessage.GetPhotos())-1 {
|
||||
s.WriteString("\n\n")
|
||||
}
|
||||
}
|
||||
message.Text = s.String()
|
||||
case *chatv1.Content_TextMessage:
|
||||
message.Text = content.TextMessage.Content.Text
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
func (b *Bharmony) outputMessages() {
|
||||
for {
|
||||
msg := <-b.c.EventsStream()
|
||||
|
||||
if msg.Message.AuthorId == b.c.UserID {
|
||||
continue
|
||||
}
|
||||
|
||||
b.Remote <- b.toMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bharmony) GetUint64(conf string) uint64 {
|
||||
num, err := strToU(b.GetString(conf))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return num
|
||||
}
|
||||
|
||||
func (b *Bharmony) Connect() (err error) {
|
||||
b.c, err = shibshib.NewClient(b.GetString("Homeserver"), b.GetString("Token"), b.GetUint64("UserID"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
b.c.SubscribeToGuild(b.GetUint64("Community"))
|
||||
|
||||
go b.outputMessages()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bharmony) send(msg config.Message) (id string, err error) {
|
||||
msgChan, err := strToU(msg.Channel)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
retID, err := b.c.ChatKit.SendMessage(&chatv1.SendMessageRequest{
|
||||
GuildId: b.GetUint64("Community"),
|
||||
ChannelId: msgChan,
|
||||
Content: &chatv1.Content{
|
||||
Content: &chatv1.Content_TextMessage{
|
||||
TextMessage: &chatv1.Content_TextContent{
|
||||
Content: &chatv1.FormattedText{
|
||||
Text: msg.Text,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Overrides: &chatv1.Overrides{
|
||||
Username: &msg.Username,
|
||||
Avatar: &msg.Avatar,
|
||||
Reason: &chatv1.Overrides_Bridge{Bridge: &typesv1.Empty{}},
|
||||
},
|
||||
InReplyTo: nil,
|
||||
EchoId: nil,
|
||||
Metadata: nil,
|
||||
})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("send: error sending message: %w", err)
|
||||
log.Println(err.Error())
|
||||
}
|
||||
|
||||
return uToStr(retID.MessageId), err
|
||||
}
|
||||
|
||||
func (b *Bharmony) delete(msg config.Message) (id string, err error) {
|
||||
msgChan, err := strToU(msg.Channel)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
msgID, err := strToU(msg.ID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, err = b.c.ChatKit.DeleteMessage(&chatv1.DeleteMessageRequest{
|
||||
GuildId: b.GetUint64("Community"),
|
||||
ChannelId: msgChan,
|
||||
MessageId: msgID,
|
||||
})
|
||||
return "", err
|
||||
}
|
||||
|
||||
func (b *Bharmony) typing(msg config.Message) (id string, err error) {
|
||||
msgChan, err := strToU(msg.Channel)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
_, err = b.c.ChatKit.Typing(&chatv1.TypingRequest{
|
||||
GuildId: b.GetUint64("Community"),
|
||||
ChannelId: msgChan,
|
||||
})
|
||||
return "", err
|
||||
}
|
||||
|
||||
func (b *Bharmony) Send(msg config.Message) (id string, err error) {
|
||||
switch msg.Event {
|
||||
case "":
|
||||
return b.send(msg)
|
||||
case config.EventMsgDelete:
|
||||
return b.delete(msg)
|
||||
case config.EventUserTyping:
|
||||
return b.typing(msg)
|
||||
default:
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bharmony) JoinChannel(channel config.ChannelInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bharmony) Disconnect() error {
|
||||
return nil
|
||||
}
|
||||
@@ -80,10 +80,6 @@ func DownloadFileAuthRocket(url, token, userID string) (*[]byte, error) {
|
||||
// word boundaries when splitting but this is hard to solve without potentially
|
||||
// breaking formatting and other stylistic effects.
|
||||
func GetSubLines(message string, maxLineLength int, clippingMessage string) []string {
|
||||
if clippingMessage == "" {
|
||||
clippingMessage = " <clipped message>"
|
||||
}
|
||||
|
||||
var lines []string
|
||||
for _, line := range strings.Split(strings.TrimSpace(message), "\n") {
|
||||
if maxLineLength == 0 || len([]byte(line)) <= maxLineLength {
|
||||
@@ -98,8 +94,8 @@ func GetSubLines(message string, maxLineLength int, clippingMessage string) []st
|
||||
var splitStart int
|
||||
var startOfPreviousRune int
|
||||
for i := range line {
|
||||
if i-splitStart > maxLineLength-len([]byte(clippingMessage)) {
|
||||
lines = append(lines, line[splitStart:startOfPreviousRune]+clippingMessage)
|
||||
if i-splitStart > maxLineLength {
|
||||
lines = append(lines, line[splitStart:startOfPreviousRune])
|
||||
splitStart = startOfPreviousRune
|
||||
}
|
||||
startOfPreviousRune = i
|
||||
@@ -168,17 +164,23 @@ func HandleDownloadSize(logger *logrus.Entry, msg *config.Message, name string,
|
||||
|
||||
// HandleDownloadData adds the data for a remote file into a Matterbridge gateway message.
|
||||
func HandleDownloadData(logger *logrus.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) {
|
||||
HandleDownloadData2(logger, msg, name, "", comment, url, data, general)
|
||||
}
|
||||
|
||||
// HandleDownloadData adds the data for a remote file into a Matterbridge gateway message.
|
||||
func HandleDownloadData2(logger *logrus.Entry, msg *config.Message, name, id, comment, url string, data *[]byte, general *config.Protocol) {
|
||||
var avatar bool
|
||||
logger.Debugf("Download OK %#v %#v", name, len(*data))
|
||||
if msg.Event == config.EventAvatarDownload {
|
||||
avatar = true
|
||||
}
|
||||
msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{
|
||||
Name: name,
|
||||
Data: data,
|
||||
URL: url,
|
||||
Comment: comment,
|
||||
Avatar: avatar,
|
||||
Name: name,
|
||||
Data: data,
|
||||
URL: url,
|
||||
Comment: comment,
|
||||
Avatar: avatar,
|
||||
NativeID: id,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package birc
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io/ioutil"
|
||||
@@ -24,7 +25,7 @@ import (
|
||||
|
||||
type Birc struct {
|
||||
i *girc.Client
|
||||
Nick string
|
||||
Nick, MessageClipped string
|
||||
names map[string][]string
|
||||
connected chan error
|
||||
Local chan config.Message // local queue for flood control
|
||||
@@ -72,6 +73,10 @@ func (b *Birc) Command(msg *config.Message) string {
|
||||
}
|
||||
|
||||
func (b *Birc) Connect() error {
|
||||
if b.GetBool("UseSASL") && b.GetString("TLSClientCertificate") != "" {
|
||||
return errors.New("you can't enable SASL and TLSClientCertificate at the same time")
|
||||
}
|
||||
|
||||
b.Local = make(chan config.Message, b.MessageQueue+10)
|
||||
b.Log.Infof("Connecting %s", b.GetString("Server"))
|
||||
|
||||
@@ -167,10 +172,11 @@ func (b *Birc) Send(msg config.Message) (string, error) {
|
||||
}
|
||||
|
||||
if b.GetBool("MessageSplit") {
|
||||
msgLines = helper.GetSubLines(msg.Text, b.MessageLength, b.GetString("MessageClipped"))
|
||||
msgLines = helper.GetSubLines(msg.Text, b.MessageLength, "")
|
||||
} else {
|
||||
msgLines = helper.GetSubLines(msg.Text, 0, b.GetString("MessageClipped"))
|
||||
msgLines = []string{helper.GetSubLines(msg.Text, b.MessageLength, "")[0] + b.getMessageClipped()}
|
||||
}
|
||||
|
||||
for i := range msgLines {
|
||||
if len(b.Local) >= b.MessageQueue {
|
||||
b.Log.Debugf("flooding, dropping message (queue at %d)", len(b.Local))
|
||||
@@ -300,6 +306,11 @@ func (b *Birc) getClient() (*girc.Client, error) {
|
||||
|
||||
b.Log.Debugf("setting pingdelay to %s", pingDelay)
|
||||
|
||||
tlsConfig, err := b.getTLSConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := girc.New(girc.Config{
|
||||
Server: server,
|
||||
ServerPass: b.GetString("Password"),
|
||||
@@ -308,7 +319,8 @@ func (b *Birc) getClient() (*girc.Client, error) {
|
||||
User: user,
|
||||
Name: realName,
|
||||
SSL: b.GetBool("UseTLS"),
|
||||
TLSConfig: &tls.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), ServerName: server}, //nolint:gosec
|
||||
Bind: b.GetString("Bind"),
|
||||
TLSConfig: tlsConfig,
|
||||
PingDelay: pingDelay,
|
||||
// skip gIRC internal rate limiting, since we have our own throttling
|
||||
AllowFlood: true,
|
||||
@@ -380,3 +392,31 @@ func (b *Birc) storeNames(client *girc.Client, event girc.Event) {
|
||||
func (b *Birc) formatnicks(nicks []string) string {
|
||||
return strings.Join(nicks, ", ") + " currently on IRC"
|
||||
}
|
||||
|
||||
func (b *Birc) getTLSConfig() (*tls.Config, error) {
|
||||
server, _, _ := net.SplitHostPort(b.GetString("server"))
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: b.GetBool("skiptlsverify"), //nolint:gosec
|
||||
ServerName: server,
|
||||
}
|
||||
|
||||
if filename := b.GetString("TLSClientCertificate"); filename != "" {
|
||||
cert, err := tls.LoadX509KeyPair(filename, filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
func (b *Birc) getMessageClipped() string {
|
||||
if b.GetString("MessageClipped") == "" {
|
||||
return " <clipped message>"
|
||||
}
|
||||
|
||||
return " " + b.GetString("MessageClipped")
|
||||
}
|
||||
|
||||
@@ -48,8 +48,10 @@ type matrixUsername struct {
|
||||
|
||||
// SubTextMessage represents the new content of the message in edit messages.
|
||||
type SubTextMessage struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
FormattedBody string `json:"formatted_body,omitempty"`
|
||||
Format string `json:"format,omitempty"`
|
||||
}
|
||||
|
||||
// MessageRelation explains how the current message relates to a previous message.
|
||||
@@ -65,6 +67,19 @@ type EditedMessage struct {
|
||||
matrix.TextMessage
|
||||
}
|
||||
|
||||
type InReplyToRelationContent struct {
|
||||
EventID string `json:"event_id"`
|
||||
}
|
||||
|
||||
type InReplyToRelation struct {
|
||||
InReplyTo InReplyToRelationContent `json:"m.in_reply_to"`
|
||||
}
|
||||
|
||||
type ReplyMessage struct {
|
||||
RelatedTo InReplyToRelation `json:"m.relates_to"`
|
||||
matrix.TextMessage
|
||||
}
|
||||
|
||||
func New(cfg *bridge.Config) bridge.Bridger {
|
||||
b := &Bmatrix{Config: cfg}
|
||||
b.RoomMap = make(map[string]string)
|
||||
@@ -138,7 +153,13 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||
m := matrix.TextMessage{
|
||||
MsgType: "m.emote",
|
||||
Body: username.plain + msg.Text,
|
||||
FormattedBody: username.formatted + msg.Text,
|
||||
FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text),
|
||||
Format: "org.matrix.custom.html",
|
||||
}
|
||||
|
||||
if b.GetBool("HTMLDisable") {
|
||||
m.Format = ""
|
||||
m.FormattedBody = ""
|
||||
}
|
||||
|
||||
msgID := ""
|
||||
@@ -201,20 +222,29 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||
|
||||
// Edit message if we have an ID
|
||||
if msg.ID != "" {
|
||||
rmsg := EditedMessage{TextMessage: matrix.TextMessage{
|
||||
Body: username.plain + msg.Text,
|
||||
MsgType: "m.text",
|
||||
}}
|
||||
if b.GetBool("HTMLDisable") {
|
||||
rmsg.TextMessage.FormattedBody = username.formatted + "* " + msg.Text
|
||||
} else {
|
||||
rmsg.Format = "org.matrix.custom.html"
|
||||
rmsg.TextMessage.FormattedBody = username.formatted + "* " + helper.ParseMarkdown(msg.Text)
|
||||
rmsg := EditedMessage{
|
||||
TextMessage: matrix.TextMessage{
|
||||
Body: username.plain + msg.Text,
|
||||
MsgType: "m.text",
|
||||
Format: "org.matrix.custom.html",
|
||||
FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text),
|
||||
},
|
||||
}
|
||||
|
||||
rmsg.NewContent = SubTextMessage{
|
||||
Body: rmsg.TextMessage.Body,
|
||||
MsgType: "m.text",
|
||||
Body: rmsg.TextMessage.Body,
|
||||
FormattedBody: rmsg.TextMessage.FormattedBody,
|
||||
Format: rmsg.TextMessage.Format,
|
||||
MsgType: "m.text",
|
||||
}
|
||||
|
||||
if b.GetBool("HTMLDisable") {
|
||||
rmsg.TextMessage.Format = ""
|
||||
rmsg.TextMessage.FormattedBody = ""
|
||||
rmsg.NewContent.Format = ""
|
||||
rmsg.NewContent.FormattedBody = ""
|
||||
}
|
||||
|
||||
rmsg.RelatedTo = MessageRelation{
|
||||
EventID: msg.ID,
|
||||
Type: "m.replace",
|
||||
@@ -238,6 +268,50 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||
MsgType: "m.notice",
|
||||
Body: username.plain + msg.Text,
|
||||
FormattedBody: username.formatted + msg.Text,
|
||||
Format: "org.matrix.custom.html",
|
||||
}
|
||||
|
||||
if b.GetBool("HTMLDisable") {
|
||||
m.Format = ""
|
||||
m.FormattedBody = ""
|
||||
}
|
||||
|
||||
var (
|
||||
resp *matrix.RespSendEvent
|
||||
err error
|
||||
)
|
||||
|
||||
err = b.retry(func() error {
|
||||
resp, err = b.mc.SendMessageEvent(channel, "m.room.message", m)
|
||||
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.EventID, err
|
||||
}
|
||||
|
||||
if msg.ParentValid() {
|
||||
m := ReplyMessage{
|
||||
TextMessage: matrix.TextMessage{
|
||||
MsgType: "m.text",
|
||||
Body: username.plain + msg.Text,
|
||||
FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text),
|
||||
Format: "org.matrix.custom.html",
|
||||
},
|
||||
}
|
||||
|
||||
if b.GetBool("HTMLDisable") {
|
||||
m.TextMessage.Format = ""
|
||||
m.TextMessage.FormattedBody = ""
|
||||
}
|
||||
|
||||
m.RelatedTo = InReplyToRelation{
|
||||
InReplyTo: InReplyToRelationContent{
|
||||
EventID: msg.ParentID,
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -301,6 +375,9 @@ func (b *Bmatrix) handlematrix() {
|
||||
syncer.OnEventType("m.room.member", b.handleMemberChange)
|
||||
go func() {
|
||||
for {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
if err := b.mc.Sync(); err != nil {
|
||||
b.Log.Println("Sync() returned ", err)
|
||||
}
|
||||
@@ -338,6 +415,35 @@ func (b *Bmatrix) handleEdit(ev *matrix.Event, rmsg config.Message) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *Bmatrix) handleReply(ev *matrix.Event, rmsg config.Message) bool {
|
||||
relationInterface, present := ev.Content["m.relates_to"]
|
||||
if !present {
|
||||
return false
|
||||
}
|
||||
|
||||
var relation InReplyToRelation
|
||||
if err := interface2Struct(relationInterface, &relation); err != nil {
|
||||
// probably fine
|
||||
return false
|
||||
}
|
||||
|
||||
body := rmsg.Text
|
||||
for strings.HasPrefix(body, "> ") {
|
||||
lineIdx := strings.IndexRune(body, '\n')
|
||||
if lineIdx == -1 {
|
||||
body = ""
|
||||
} else {
|
||||
body = body[(lineIdx + 1):]
|
||||
}
|
||||
}
|
||||
|
||||
rmsg.Text = body
|
||||
rmsg.ParentID = relation.InReplyTo.EventID
|
||||
b.Remote <- rmsg
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *Bmatrix) handleMemberChange(ev *matrix.Event) {
|
||||
// Update the displayname on join messages, according to https://matrix.org/docs/spec/client_server/r0.6.1#events-on-change-of-profile-information
|
||||
if ev.Content["membership"] == "join" {
|
||||
@@ -400,6 +506,11 @@ func (b *Bmatrix) handleEvent(ev *matrix.Event) {
|
||||
return
|
||||
}
|
||||
|
||||
// Is it a reply?
|
||||
if b.handleReply(ev, rmsg) {
|
||||
return
|
||||
}
|
||||
|
||||
// Do we have attachments
|
||||
if b.containsAttachment(ev.Content) {
|
||||
err := b.handleDownloadFile(&rmsg, ev.Content)
|
||||
|
||||
@@ -140,9 +140,14 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) {
|
||||
continue
|
||||
}
|
||||
|
||||
channelName := b.getChannelName(message.Post.ChannelId)
|
||||
if channelName == "" {
|
||||
channelName = message.Channel
|
||||
}
|
||||
|
||||
// only download avatars if we have a place to upload them (configured mediaserver)
|
||||
if b.General.MediaServerUpload != "" || b.General.MediaDownloadPath != "" {
|
||||
b.handleDownloadAvatar(message.UserID, message.Channel)
|
||||
b.handleDownloadAvatar(message.UserID, channelName)
|
||||
}
|
||||
|
||||
b.Log.Debugf("== Receiving event %#v", message)
|
||||
@@ -150,7 +155,7 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) {
|
||||
rmsg := &config.Message{
|
||||
Username: message.Username,
|
||||
UserID: message.UserID,
|
||||
Channel: message.Channel,
|
||||
Channel: channelName,
|
||||
Text: message.Text,
|
||||
ID: message.Post.Id,
|
||||
ParentID: message.Post.RootId, // ParentID is obsolete with mattermost
|
||||
@@ -177,8 +182,10 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) {
|
||||
}
|
||||
|
||||
// Use nickname instead of username if defined
|
||||
if nick := b.mc.GetNickName(rmsg.UserID); nick != "" {
|
||||
rmsg.Username = nick
|
||||
if !b.GetBool("useusername") {
|
||||
if nick := b.mc.GetNickName(rmsg.UserID); nick != "" {
|
||||
rmsg.Username = nick
|
||||
}
|
||||
}
|
||||
|
||||
messages <- rmsg
|
||||
@@ -188,16 +195,21 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) {
|
||||
// nolint:cyclop
|
||||
func (b *Bmattermost) handleMatterClient6(messages chan *config.Message) {
|
||||
for message := range b.mc6.MessageChan {
|
||||
b.Log.Debugf("%#v", message.Raw.GetData())
|
||||
b.Log.Debugf("%#v %#v", message.Raw.GetData(), message.Raw.EventType())
|
||||
|
||||
if b.skipMessage6(message) {
|
||||
b.Log.Debugf("Skipped message: %#v", message)
|
||||
continue
|
||||
}
|
||||
|
||||
channelName := b.getChannelName(message.Post.ChannelId)
|
||||
if channelName == "" {
|
||||
channelName = message.Channel
|
||||
}
|
||||
|
||||
// only download avatars if we have a place to upload them (configured mediaserver)
|
||||
if b.General.MediaServerUpload != "" || b.General.MediaDownloadPath != "" {
|
||||
b.handleDownloadAvatar(message.UserID, message.Channel)
|
||||
b.handleDownloadAvatar(message.UserID, channelName)
|
||||
}
|
||||
|
||||
b.Log.Debugf("== Receiving event %#v", message)
|
||||
@@ -205,7 +217,7 @@ func (b *Bmattermost) handleMatterClient6(messages chan *config.Message) {
|
||||
rmsg := &config.Message{
|
||||
Username: message.Username,
|
||||
UserID: message.UserID,
|
||||
Channel: message.Channel,
|
||||
Channel: channelName,
|
||||
Text: message.Text,
|
||||
ID: message.Post.Id,
|
||||
ParentID: message.Post.RootId, // ParentID is obsolete with mattermost
|
||||
@@ -232,8 +244,10 @@ func (b *Bmattermost) handleMatterClient6(messages chan *config.Message) {
|
||||
}
|
||||
|
||||
// Use nickname instead of username if defined
|
||||
if nick := b.mc6.GetNickName(rmsg.UserID); nick != "" {
|
||||
rmsg.Username = nick
|
||||
if !b.GetBool("useusername") {
|
||||
if nick := b.mc6.GetNickName(rmsg.UserID); nick != "" {
|
||||
rmsg.Username = nick
|
||||
}
|
||||
}
|
||||
|
||||
messages <- rmsg
|
||||
@@ -244,6 +258,7 @@ func (b *Bmattermost) handleMatterHook(messages chan *config.Message) {
|
||||
for {
|
||||
message := b.mh.Receive()
|
||||
b.Log.Debugf("Receiving from matterhook %#v", message)
|
||||
|
||||
messages <- &config.Message{
|
||||
UserID: message.UserID,
|
||||
Username: message.UserName,
|
||||
@@ -261,7 +276,7 @@ func (b *Bmattermost) handleUploadFile(msg *config.Message) (string, error) {
|
||||
|
||||
var err error
|
||||
var res, id string
|
||||
channelID := b.mc.GetChannelId(msg.Channel, b.TeamID)
|
||||
channelID := b.getChannelID(msg.Channel)
|
||||
for _, f := range msg.Extra["file"] {
|
||||
fi := f.(config.FileInfo)
|
||||
id, err = b.mc.UploadFile(*fi.Data, channelID, fi.Name)
|
||||
@@ -281,7 +296,7 @@ func (b *Bmattermost) handleUploadFile(msg *config.Message) (string, error) {
|
||||
func (b *Bmattermost) handleUploadFile6(msg *config.Message) (string, error) {
|
||||
var err error
|
||||
var res, id string
|
||||
channelID := b.mc6.GetChannelID(msg.Channel, b.TeamID)
|
||||
channelID := b.getChannelID(msg.Channel)
|
||||
for _, f := range msg.Extra["file"] {
|
||||
fi := f.(config.FileInfo)
|
||||
id, err = b.mc6.UploadFile(*fi.Data, channelID, fi.Name)
|
||||
|
||||
@@ -241,11 +241,17 @@ func (b *Bmattermost) skipMessage(message *matterclient.Message) bool {
|
||||
if b.GetBool("nosendjoinpart") {
|
||||
return true
|
||||
}
|
||||
|
||||
channelName := b.getChannelName(message.Post.ChannelId)
|
||||
if channelName == "" {
|
||||
channelName = message.Channel
|
||||
}
|
||||
|
||||
b.Log.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
|
||||
b.Remote <- config.Message{
|
||||
Username: "system",
|
||||
Text: message.Text,
|
||||
Channel: message.Channel,
|
||||
Channel: channelName,
|
||||
Account: b.Account,
|
||||
Event: config.EventJoinLeave,
|
||||
}
|
||||
@@ -304,11 +310,17 @@ func (b *Bmattermost) skipMessage6(message *matterclient6.Message) bool {
|
||||
if b.GetBool("nosendjoinpart") {
|
||||
return true
|
||||
}
|
||||
|
||||
channelName := b.getChannelName(message.Post.ChannelId)
|
||||
if channelName == "" {
|
||||
channelName = message.Channel
|
||||
}
|
||||
|
||||
b.Log.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
|
||||
b.Remote <- config.Message{
|
||||
Username: "system",
|
||||
Text: message.Text,
|
||||
Channel: message.Channel,
|
||||
Channel: channelName,
|
||||
Account: b.Account,
|
||||
Event: config.EventJoinLeave,
|
||||
}
|
||||
@@ -329,13 +341,14 @@ func (b *Bmattermost) skipMessage6(message *matterclient6.Message) bool {
|
||||
// Ignore messages sent from matterbridge
|
||||
if message.Post.Props != nil {
|
||||
if _, ok := message.Post.Props["matterbridge_"+b.uuid].(bool); ok {
|
||||
b.Log.Debugf("sent by matterbridge, ignoring")
|
||||
b.Log.Debug("sent by matterbridge, ignoring")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore messages sent from a user logged in as the bot
|
||||
if b.mc6.User.Username == message.Username {
|
||||
b.Log.Debug("message from same user as bot, ignoring")
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -346,6 +359,7 @@ func (b *Bmattermost) skipMessage6(message *matterclient6.Message) bool {
|
||||
|
||||
// ignore messages from other teams than ours
|
||||
if message.Raw.GetData()["team_id"].(string) != b.TeamID {
|
||||
b.Log.Debug("message from other team, ignoring")
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -374,3 +388,30 @@ func (b *Bmattermost) getVersion() string {
|
||||
|
||||
return resp.Header.Get("X-Version-Id")
|
||||
}
|
||||
|
||||
func (b *Bmattermost) getChannelID(name string) string {
|
||||
idcheck := strings.Split(name, "ID:")
|
||||
if len(idcheck) > 1 {
|
||||
return idcheck[1]
|
||||
}
|
||||
|
||||
if b.mc6 != nil {
|
||||
return b.mc6.GetChannelID(name, b.TeamID)
|
||||
}
|
||||
|
||||
return b.mc.GetChannelId(name, b.TeamID)
|
||||
}
|
||||
|
||||
func (b *Bmattermost) getChannelName(id string) string {
|
||||
b.channelsMutex.RLock()
|
||||
defer b.channelsMutex.RUnlock()
|
||||
|
||||
for _, c := range b.channelInfoMap {
|
||||
if c.Name == "ID:"+id {
|
||||
// if we have ID: specified in our gateway configuration return this
|
||||
return c.Name
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/42wim/matterbridge/bridge"
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
@@ -22,13 +23,19 @@ type Bmattermost struct {
|
||||
uuid string
|
||||
TeamID string
|
||||
*bridge.Config
|
||||
avatarMap map[string]string
|
||||
avatarMap map[string]string
|
||||
channelsMutex sync.RWMutex
|
||||
channelInfoMap map[string]*config.ChannelInfo
|
||||
}
|
||||
|
||||
const mattermostPlugin = "mattermost.plugin"
|
||||
|
||||
func New(cfg *bridge.Config) bridge.Bridger {
|
||||
b := &Bmattermost{Config: cfg, avatarMap: make(map[string]string)}
|
||||
b := &Bmattermost{
|
||||
Config: cfg,
|
||||
avatarMap: make(map[string]string),
|
||||
channelInfoMap: make(map[string]*config.ChannelInfo),
|
||||
}
|
||||
|
||||
b.v6 = b.GetBool("v6")
|
||||
b.uuid = xid.New().String()
|
||||
@@ -113,14 +120,14 @@ func (b *Bmattermost) JoinChannel(channel config.ChannelInfo) error {
|
||||
if b.Account == mattermostPlugin {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.channelsMutex.Lock()
|
||||
b.channelInfoMap[channel.ID] = &channel
|
||||
b.channelsMutex.Unlock()
|
||||
|
||||
// we can only join channels using the API
|
||||
if b.GetString("WebhookURL") == "" && b.GetString("WebhookBindAddress") == "" {
|
||||
var id string
|
||||
if b.mc6 != nil {
|
||||
id = b.mc6.GetChannelID(channel.Name, b.TeamID)
|
||||
} else {
|
||||
id = b.mc.GetChannelId(channel.Name, b.TeamID)
|
||||
}
|
||||
id := b.getChannelID(channel.Name)
|
||||
if id == "" {
|
||||
return fmt.Errorf("Could not find channel ID for channel %s", channel.Name)
|
||||
}
|
||||
@@ -131,6 +138,7 @@ func (b *Bmattermost) JoinChannel(channel config.ChannelInfo) error {
|
||||
|
||||
return b.mc.JoinChannel(id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -180,13 +188,17 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) {
|
||||
if err != nil {
|
||||
b.Log.Errorf("getting post %s failed: %s", msg.ParentID, err)
|
||||
}
|
||||
msg.ParentID = post.RootId
|
||||
if post.RootId != "" {
|
||||
msg.ParentID = post.RootId
|
||||
}
|
||||
} else {
|
||||
post, res := b.mc.Client.GetPost(msg.ParentID, "")
|
||||
if res.Error != nil {
|
||||
b.Log.Errorf("getting post %s failed: %s", msg.ParentID, res.Error.DetailedError)
|
||||
}
|
||||
msg.ParentID = post.RootId
|
||||
if post.RootId != "" {
|
||||
msg.ParentID = post.RootId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,11 +206,11 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) {
|
||||
if msg.Extra != nil {
|
||||
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
||||
if b.mc6 != nil {
|
||||
if _, err := b.mc6.PostMessage(b.mc.GetChannelId(rmsg.Channel, b.TeamID), rmsg.Username+rmsg.Text, msg.ParentID); err != nil {
|
||||
if _, err := b.mc6.PostMessage(b.getChannelID(rmsg.Channel), rmsg.Username+rmsg.Text, msg.ParentID); err != nil {
|
||||
b.Log.Errorf("PostMessage failed: %s", err)
|
||||
}
|
||||
} else {
|
||||
if _, err := b.mc.PostMessage(b.mc.GetChannelId(rmsg.Channel, b.TeamID), rmsg.Username+rmsg.Text, msg.ParentID); err != nil {
|
||||
if _, err := b.mc.PostMessage(b.getChannelID(rmsg.Channel), rmsg.Username+rmsg.Text, msg.ParentID); err != nil {
|
||||
b.Log.Errorf("PostMessage failed: %s", err)
|
||||
}
|
||||
}
|
||||
@@ -224,8 +236,8 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) {
|
||||
|
||||
// Post normal message
|
||||
if b.mc6 != nil {
|
||||
return b.mc6.PostMessage(b.mc6.GetChannelID(msg.Channel, b.TeamID), msg.Text, msg.ParentID) // nolint:wrapcheck
|
||||
return b.mc6.PostMessage(b.getChannelID(msg.Channel), msg.Text, msg.ParentID) // nolint:wrapcheck
|
||||
}
|
||||
|
||||
return b.mc.PostMessage(b.mc.GetChannelId(msg.Channel, b.TeamID), msg.Text, msg.ParentID)
|
||||
return b.mc.PostMessage(b.getChannelID(msg.Channel), msg.Text, msg.ParentID)
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
var defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"}
|
||||
var attachRE = regexp.MustCompile(`<attachment id=.*?attachment>`)
|
||||
var (
|
||||
defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"}
|
||||
attachRE = regexp.MustCompile(`<attachment id=.*?attachment>`)
|
||||
)
|
||||
|
||||
type Bmsteams struct {
|
||||
gc *msgraph.GraphServiceRequestBuilder
|
||||
@@ -50,7 +52,7 @@ func (b *Bmsteams) Connect() error {
|
||||
b.Log.Errorf("Couldn't save sessionfile in %s: %s", tokenCachePath, err)
|
||||
}
|
||||
// make file readable only for matterbridge user
|
||||
err = os.Chmod(tokenCachePath, 0600)
|
||||
err = os.Chmod(tokenCachePath, 0o600)
|
||||
if err != nil {
|
||||
b.Log.Errorf("Couldn't change permissions for %s: %s", tokenCachePath, err)
|
||||
}
|
||||
@@ -168,7 +170,7 @@ func (b *Bmsteams) poll(channelName string) error {
|
||||
}
|
||||
|
||||
// skip non-user message for now.
|
||||
if msg.From.User == nil {
|
||||
if msg.From == nil || msg.From.User == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ func (b *Bslack) handleSlack() {
|
||||
b.Log.Debug("Start listening for Slack messages")
|
||||
for message := range messages {
|
||||
// don't do any action on deleted/typing messages
|
||||
if message.Event != config.EventUserTyping && message.Event != config.EventMsgDelete {
|
||||
if message.Event != config.EventUserTyping && message.Event != config.EventMsgDelete &&
|
||||
message.Event != config.EventFileDelete {
|
||||
b.Log.Debugf("<= Sending message from %s on %s to gateway", message.Username, b.Account)
|
||||
// cleanup the message
|
||||
message.Text = b.replaceMention(message.Text)
|
||||
@@ -76,6 +77,13 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) {
|
||||
continue
|
||||
}
|
||||
messages <- rmsg
|
||||
case *slack.FileDeletedEvent:
|
||||
rmsg, err := b.handleFileDeletedEvent(ev)
|
||||
if err != nil {
|
||||
b.Log.Errorf("%#v", err)
|
||||
continue
|
||||
}
|
||||
messages <- rmsg
|
||||
case *slack.OutgoingErrorEvent:
|
||||
b.Log.Debugf("%#v", ev.Error())
|
||||
case *slack.ChannelJoinedEvent:
|
||||
@@ -222,6 +230,26 @@ func (b *Bslack) handleMessageEvent(ev *slack.MessageEvent) (*config.Message, er
|
||||
return rmsg, nil
|
||||
}
|
||||
|
||||
func (b *Bslack) handleFileDeletedEvent(ev *slack.FileDeletedEvent) (*config.Message, error) {
|
||||
if rawChannel, ok := b.cache.Get(cfileDownloadChannel + ev.FileID); ok {
|
||||
channel, err := b.channels.getChannelByID(rawChannel.(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &config.Message{
|
||||
Event: config.EventFileDelete,
|
||||
Text: config.EventFileDelete,
|
||||
Channel: channel.Name,
|
||||
Account: b.Account,
|
||||
ID: ev.FileID,
|
||||
Protocol: b.Protocol,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("channel ID for file ID %s not found", ev.FileID)
|
||||
}
|
||||
|
||||
func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message) bool {
|
||||
switch ev.SubType {
|
||||
case sChannelJoined, sMemberJoined:
|
||||
@@ -281,6 +309,8 @@ func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message)
|
||||
|
||||
// If we have files attached, download them (in memory) and put a pointer to it in msg.Extra.
|
||||
for i := range ev.Files {
|
||||
// keep reference in cache on which channel we added this file
|
||||
b.cache.Add(cfileDownloadChannel+ev.Files[i].ID, ev.Channel)
|
||||
if err := b.handleDownloadFile(rmsg, &ev.Files[i], false); err != nil {
|
||||
b.Log.Errorf("Could not download incoming file: %#v", err)
|
||||
}
|
||||
@@ -330,7 +360,7 @@ func (b *Bslack) handleDownloadFile(rmsg *config.Message, file *slack.File, retr
|
||||
// that the comment is not duplicated.
|
||||
comment := rmsg.Text
|
||||
rmsg.Text = ""
|
||||
helper.HandleDownloadData(b.Log, rmsg, file.Name, comment, file.URLPrivateDownload, data, b.General)
|
||||
helper.HandleDownloadData2(b.Log, rmsg, file.Name, file.ID, comment, file.URLPrivateDownload, data, b.General)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -36,24 +36,25 @@ type Bslack struct {
|
||||
}
|
||||
|
||||
const (
|
||||
sHello = "hello"
|
||||
sChannelJoin = "channel_join"
|
||||
sChannelLeave = "channel_leave"
|
||||
sChannelJoined = "channel_joined"
|
||||
sMemberJoined = "member_joined_channel"
|
||||
sMessageChanged = "message_changed"
|
||||
sMessageDeleted = "message_deleted"
|
||||
sSlackAttachment = "slack_attachment"
|
||||
sPinnedItem = "pinned_item"
|
||||
sUnpinnedItem = "unpinned_item"
|
||||
sChannelTopic = "channel_topic"
|
||||
sChannelPurpose = "channel_purpose"
|
||||
sFileComment = "file_comment"
|
||||
sMeMessage = "me_message"
|
||||
sUserTyping = "user_typing"
|
||||
sLatencyReport = "latency_report"
|
||||
sSystemUser = "system"
|
||||
sSlackBotUser = "slackbot"
|
||||
sHello = "hello"
|
||||
sChannelJoin = "channel_join"
|
||||
sChannelLeave = "channel_leave"
|
||||
sChannelJoined = "channel_joined"
|
||||
sMemberJoined = "member_joined_channel"
|
||||
sMessageChanged = "message_changed"
|
||||
sMessageDeleted = "message_deleted"
|
||||
sSlackAttachment = "slack_attachment"
|
||||
sPinnedItem = "pinned_item"
|
||||
sUnpinnedItem = "unpinned_item"
|
||||
sChannelTopic = "channel_topic"
|
||||
sChannelPurpose = "channel_purpose"
|
||||
sFileComment = "file_comment"
|
||||
sMeMessage = "me_message"
|
||||
sUserTyping = "user_typing"
|
||||
sLatencyReport = "latency_report"
|
||||
sSystemUser = "system"
|
||||
sSlackBotUser = "slackbot"
|
||||
cfileDownloadChannel = "file_download_channel"
|
||||
|
||||
tokenConfig = "Token"
|
||||
incomingWebhookConfig = "WebhookBindAddress"
|
||||
|
||||
@@ -291,6 +291,7 @@ func (b *channels) populateChannels(wait bool) {
|
||||
queryParams := &slack.GetConversationsParameters{
|
||||
ExcludeArchived: true,
|
||||
Types: []string{"public_channel,private_channel"},
|
||||
Limit: 1000,
|
||||
}
|
||||
for {
|
||||
channels, nextCursor, err := b.sc.GetConversations(queryParams)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package btelegram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -9,14 +10,27 @@ import (
|
||||
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/42wim/matterbridge/bridge/helper"
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited *tgbotapi.Message) *tgbotapi.Message {
|
||||
// handle channels
|
||||
if posted != nil {
|
||||
message = posted
|
||||
rmsg.Text = message.Text
|
||||
if posted.Text == "/chatId" {
|
||||
chatID := strconv.FormatInt(posted.Chat.ID, 10)
|
||||
|
||||
_, err := b.Send(config.Message{
|
||||
Channel: chatID,
|
||||
Text: fmt.Sprintf("ID of this chat: %s", chatID),
|
||||
})
|
||||
if err != nil {
|
||||
b.Log.Warnf("Unable to send chatID to %s", chatID)
|
||||
}
|
||||
} else {
|
||||
message = posted
|
||||
rmsg.Text = message.Text
|
||||
}
|
||||
}
|
||||
|
||||
// edited channel message
|
||||
@@ -94,7 +108,7 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag
|
||||
// handleUsername handles the correct setting of the username
|
||||
func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Message) {
|
||||
if message.From != nil {
|
||||
rmsg.UserID = strconv.Itoa(message.From.ID)
|
||||
rmsg.UserID = strconv.FormatInt(message.From.ID, 10)
|
||||
if b.GetBool("UseFirstName") {
|
||||
rmsg.Username = message.From.FirstName
|
||||
}
|
||||
@@ -110,6 +124,25 @@ func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Messa
|
||||
}
|
||||
}
|
||||
|
||||
if message.SenderChat != nil { //nolint:nestif
|
||||
rmsg.UserID = strconv.FormatInt(message.SenderChat.ID, 10)
|
||||
if b.GetBool("UseFirstName") {
|
||||
rmsg.Username = message.SenderChat.FirstName
|
||||
}
|
||||
|
||||
if rmsg.Username == "" || rmsg.Username == "Channel_Bot" {
|
||||
rmsg.Username = message.SenderChat.UserName
|
||||
|
||||
if rmsg.Username == "" || rmsg.Username == "Channel_Bot" {
|
||||
rmsg.Username = message.SenderChat.FirstName
|
||||
}
|
||||
}
|
||||
// only download avatars if we have a place to upload them (configured mediaserver)
|
||||
if b.General.MediaServerUpload != "" || (b.General.MediaServerDownload != "" && b.General.MediaDownloadPath != "") {
|
||||
b.handleDownloadAvatar(message.SenderChat.ID, rmsg.Channel)
|
||||
}
|
||||
}
|
||||
|
||||
// if we really didn't find a username, set it to unknown
|
||||
if rmsg.Username == "" {
|
||||
rmsg.Username = unknownUser
|
||||
@@ -126,6 +159,10 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
|
||||
continue
|
||||
}
|
||||
|
||||
if b.GetInt("debuglevel") == 1 {
|
||||
spew.Dump(update.Message)
|
||||
}
|
||||
|
||||
var message *tgbotapi.Message
|
||||
|
||||
rmsg := config.Message{Account: b.Account, Extra: make(map[string][]interface{})}
|
||||
@@ -167,7 +204,7 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
|
||||
rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text)
|
||||
// channels don't have (always?) user information. see #410
|
||||
if message.From != nil {
|
||||
rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.Itoa(message.From.ID), b.General)
|
||||
rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.FormatInt(message.From.ID, 10), b.General)
|
||||
}
|
||||
|
||||
b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
|
||||
@@ -180,42 +217,44 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
|
||||
// handleDownloadAvatar downloads the avatar of userid from channel
|
||||
// sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful.
|
||||
// logs an error message if it fails
|
||||
func (b *Btelegram) handleDownloadAvatar(userid int, channel string) {
|
||||
func (b *Btelegram) handleDownloadAvatar(userid int64, channel string) {
|
||||
rmsg := config.Message{
|
||||
Username: "system",
|
||||
Text: "avatar",
|
||||
Channel: channel,
|
||||
Account: b.Account,
|
||||
UserID: strconv.Itoa(userid),
|
||||
UserID: strconv.FormatInt(userid, 10),
|
||||
Event: config.EventAvatarDownload,
|
||||
Extra: make(map[string][]interface{}),
|
||||
}
|
||||
|
||||
if _, ok := b.avatarMap[strconv.Itoa(userid)]; !ok {
|
||||
photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1})
|
||||
if _, ok := b.avatarMap[strconv.FormatInt(userid, 10)]; ok {
|
||||
return
|
||||
}
|
||||
|
||||
photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1})
|
||||
if err != nil {
|
||||
b.Log.Errorf("Userprofile download failed for %#v %s", userid, err)
|
||||
}
|
||||
|
||||
if len(photos.Photos) > 0 {
|
||||
photo := photos.Photos[0][0]
|
||||
url := b.getFileDirectURL(photo.FileID)
|
||||
name := strconv.FormatInt(userid, 10) + ".png"
|
||||
b.Log.Debugf("trying to download %#v fileid %#v with size %#v", name, photo.FileID, photo.FileSize)
|
||||
|
||||
err := helper.HandleDownloadSize(b.Log, &rmsg, name, int64(photo.FileSize), b.General)
|
||||
if err != nil {
|
||||
b.Log.Errorf("Userprofile download failed for %#v %s", userid, err)
|
||||
b.Log.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(photos.Photos) > 0 {
|
||||
photo := photos.Photos[0][0]
|
||||
url := b.getFileDirectURL(photo.FileID)
|
||||
name := strconv.Itoa(userid) + ".png"
|
||||
b.Log.Debugf("trying to download %#v fileid %#v with size %#v", name, photo.FileID, photo.FileSize)
|
||||
|
||||
err := helper.HandleDownloadSize(b.Log, &rmsg, name, int64(photo.FileSize), b.General)
|
||||
if err != nil {
|
||||
b.Log.Error(err)
|
||||
return
|
||||
}
|
||||
data, err := helper.DownloadFile(url)
|
||||
if err != nil {
|
||||
b.Log.Errorf("download %s failed %#v", url, err)
|
||||
return
|
||||
}
|
||||
helper.HandleDownloadData(b.Log, &rmsg, name, rmsg.Text, "", data, b.General)
|
||||
b.Remote <- rmsg
|
||||
data, err := helper.DownloadFile(url)
|
||||
if err != nil {
|
||||
b.Log.Errorf("download %s failed %#v", url, err)
|
||||
return
|
||||
}
|
||||
helper.HandleDownloadData(b.Log, &rmsg, name, rmsg.Text, "", data, b.General)
|
||||
b.Remote <- rmsg
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +311,7 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa
|
||||
name = message.Document.FileName
|
||||
text = " " + message.Document.FileName + " : " + url
|
||||
case message.Photo != nil:
|
||||
photos := *message.Photo
|
||||
photos := message.Photo
|
||||
size = photos[len(photos)-1].FileSize
|
||||
text, name, url = b.getDownloadInfo(photos[len(photos)-1].FileID, "", true)
|
||||
}
|
||||
@@ -331,11 +370,15 @@ func (b *Btelegram) handleDelete(msg *config.Message, chatid int64) (string, err
|
||||
if msg.ID == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
msgid, err := strconv.Atoi(msg.ID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = b.c.DeleteMessage(tgbotapi.DeleteMessageConfig{ChatID: chatid, MessageID: msgid})
|
||||
|
||||
cfg := tgbotapi.NewDeleteMessage(chatid, msgid)
|
||||
_, err = b.c.Send(cfg)
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -383,23 +426,23 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string {
|
||||
}
|
||||
switch filepath.Ext(fi.Name) {
|
||||
case ".jpg", ".jpe", ".png":
|
||||
pc := tgbotapi.NewPhotoUpload(chatid, file)
|
||||
pc := tgbotapi.NewPhoto(chatid, file)
|
||||
pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||
c = pc
|
||||
case ".mp4", ".m4v":
|
||||
vc := tgbotapi.NewVideoUpload(chatid, file)
|
||||
vc := tgbotapi.NewVideo(chatid, file)
|
||||
vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||
c = vc
|
||||
case ".mp3", ".oga":
|
||||
ac := tgbotapi.NewAudioUpload(chatid, file)
|
||||
ac := tgbotapi.NewAudio(chatid, file)
|
||||
ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||
c = ac
|
||||
case ".ogg":
|
||||
voc := tgbotapi.NewVoiceUpload(chatid, file)
|
||||
voc := tgbotapi.NewVoice(chatid, file)
|
||||
voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||
c = voc
|
||||
default:
|
||||
dc := tgbotapi.NewDocumentUpload(chatid, file)
|
||||
dc := tgbotapi.NewDocument(chatid, file)
|
||||
dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment)
|
||||
c = dc
|
||||
}
|
||||
@@ -435,8 +478,11 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa
|
||||
if message.Entities == nil {
|
||||
return
|
||||
}
|
||||
|
||||
indexMovedBy := 0
|
||||
|
||||
// for now only do URL replacements
|
||||
for _, e := range *message.Entities {
|
||||
for _, e := range message.Entities {
|
||||
if e.Type == "text_link" {
|
||||
url, err := e.ParseURL()
|
||||
if err != nil {
|
||||
@@ -451,5 +497,17 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa
|
||||
link := utf16.Decode(utfEncodedString[e.Offset : e.Offset+e.Length])
|
||||
rmsg.Text = strings.Replace(rmsg.Text, string(link), url.String(), 1)
|
||||
}
|
||||
|
||||
if e.Type == "code" {
|
||||
offset := e.Offset + indexMovedBy
|
||||
rmsg.Text = rmsg.Text[:offset] + "`" + rmsg.Text[offset:offset+e.Length] + "`" + rmsg.Text[offset+e.Length:]
|
||||
indexMovedBy += 2
|
||||
}
|
||||
|
||||
if e.Type == "pre" {
|
||||
offset := e.Offset + indexMovedBy
|
||||
rmsg.Text = rmsg.Text[:offset] + "```\n" + rmsg.Text[offset:offset+e.Length] + "\n```" + rmsg.Text[offset+e.Length:]
|
||||
indexMovedBy += 8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/42wim/matterbridge/bridge"
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/42wim/matterbridge/bridge/helper"
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -49,11 +49,7 @@ func (b *Btelegram) Connect() error {
|
||||
}
|
||||
u := tgbotapi.NewUpdate(0)
|
||||
u.Timeout = 60
|
||||
updates, err := b.c.GetUpdatesChan(u)
|
||||
if err != nil {
|
||||
b.Log.Debugf("%#v", err)
|
||||
return err
|
||||
}
|
||||
updates := b.c.GetUpdatesChan(u)
|
||||
b.Log.Info("Connection succeeded")
|
||||
go b.handleRecv(updates)
|
||||
return nil
|
||||
|
||||
@@ -34,6 +34,7 @@ type user struct {
|
||||
|
||||
type Bvk struct {
|
||||
c *api.VK
|
||||
lp *longpoll.LongPoll
|
||||
usernamesMap map[int]user // cache of user names and avatar URLs
|
||||
*bridge.Config
|
||||
}
|
||||
@@ -45,21 +46,23 @@ func New(cfg *bridge.Config) bridge.Bridger {
|
||||
func (b *Bvk) Connect() error {
|
||||
b.Log.Info("Connecting")
|
||||
b.c = api.NewVK(b.GetString("Token"))
|
||||
lp, err := longpoll.NewLongPoll(b.c, b.GetInt("GroupID"))
|
||||
|
||||
var err error
|
||||
b.lp, err = longpoll.NewLongPollCommunity(b.c)
|
||||
if err != nil {
|
||||
b.Log.Debugf("%#v", err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
lp.MessageNew(func(ctx context.Context, obj events.MessageNewObject) {
|
||||
b.lp.MessageNew(func(ctx context.Context, obj events.MessageNewObject) {
|
||||
b.handleMessage(obj.Message, false)
|
||||
})
|
||||
|
||||
b.Log.Info("Connection succeeded")
|
||||
|
||||
go func() {
|
||||
err := lp.Run()
|
||||
err := b.lp.Run()
|
||||
if err != nil {
|
||||
b.Log.Fatal("Enable longpoll in group management")
|
||||
}
|
||||
@@ -69,6 +72,8 @@ func (b *Bvk) Connect() error {
|
||||
}
|
||||
|
||||
func (b *Bvk) Disconnect() error {
|
||||
b.lp.Shutdown()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,6 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) {
|
||||
var msgReplaceID string
|
||||
msgID := xid.New().String()
|
||||
if msg.ID != "" {
|
||||
msgID = msg.ID
|
||||
msgReplaceID = msg.ID
|
||||
}
|
||||
b.Log.Debugf("=> Sending message %#v", msg)
|
||||
@@ -284,7 +283,13 @@ func (b *Bxmpp) handleXMPP() error {
|
||||
for {
|
||||
m, err := b.xc.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
// An error together with AvatarData is non-fatal
|
||||
switch m.(type) {
|
||||
case xmpp.AvatarData:
|
||||
continue
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
switch v := m.(type) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package bzulip
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"github.com/42wim/matterbridge/bridge"
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/42wim/matterbridge/bridge/helper"
|
||||
"github.com/42wim/matterbridge/version"
|
||||
gzb "github.com/matterbridge/gozulipbot"
|
||||
)
|
||||
|
||||
@@ -27,7 +29,7 @@ func New(cfg *bridge.Config) bridge.Bridger {
|
||||
}
|
||||
|
||||
func (b *Bzulip) Connect() error {
|
||||
bot := gzb.Bot{APIKey: b.GetString("token"), APIURL: b.GetString("server") + "/api/v1/", Email: b.GetString("login")}
|
||||
bot := gzb.Bot{APIKey: b.GetString("token"), APIURL: b.GetString("server") + "/api/v1/", Email: b.GetString("login"), UserAgent: fmt.Sprintf("matterbridge/%s", version.Release)}
|
||||
bot.Init()
|
||||
q, err := bot.RegisterAll()
|
||||
b.q = q
|
||||
@@ -125,6 +127,7 @@ func (b *Bzulip) handleQueue() error {
|
||||
b.Log.Debug("heartbeat received.")
|
||||
default:
|
||||
b.Log.Debugf("receiving error: %#v", err)
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
|
||||
24
changelog.md
24
changelog.md
@@ -1,3 +1,25 @@
|
||||
# v1.23.2
|
||||
|
||||
If you're running whatsapp you should update.
|
||||
|
||||
## Bugfix
|
||||
|
||||
- whatsapp: Update go-whatsapp version (#1630)
|
||||
|
||||
# v1.23.1
|
||||
|
||||
If you're running mattermost 6 you should update.
|
||||
|
||||
## Bugfix
|
||||
|
||||
- mattermost: Do not check cache on deleted messages (mattermost). Fixes #1555 (#1624)
|
||||
- mattermost: Fix crash on users updating info. Update matterclient dep. Fixes #1617
|
||||
- matrix: Keep the logger on a disabled bridge. Fixes #1616 (#1621)
|
||||
- msteams: Fix panic in msteams. Fixes #1588 (#1622)
|
||||
- xmpp: Do not fail on no avatar data (xmpp) #1529 (#1627)
|
||||
- xmpp: Use a new msgID when replacing messages (xmpp). Fixes #1584 (#1623)
|
||||
- zulip: Add better error handling on Zulip (#1589)
|
||||
|
||||
# v1.23.0
|
||||
|
||||
## New features
|
||||
@@ -24,8 +46,6 @@
|
||||
This release couldn't exist without the following contributors:
|
||||
@powerjungle, @gary-kim, @KingPin, @Benau, @keenan-v1, @tytan652, @KidA001,@minecraftchest1, @irydacea
|
||||
|
||||
##
|
||||
|
||||
# v1.22.3
|
||||
|
||||
## Bugfixes
|
||||
|
||||
12
gateway/bridgemap/bharmony.go
Normal file
12
gateway/bridgemap/bharmony.go
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build !noharmony
|
||||
// +build !noharmony
|
||||
|
||||
package bridgemap
|
||||
|
||||
import (
|
||||
bharmony "github.com/42wim/matterbridge/bridge/harmony"
|
||||
)
|
||||
|
||||
func init() {
|
||||
FullMap["harmony"] = bharmony.New
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func New(rootLogger *logrus.Logger, cfg *config.Gateway, r *Router) *Gateway {
|
||||
func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string {
|
||||
ID := protocol + " " + mID
|
||||
if gw.Messages.Contains(ID) {
|
||||
return mID
|
||||
return ID
|
||||
}
|
||||
|
||||
// If not keyed, iterate through cache for downstream, and infer upstream.
|
||||
@@ -75,7 +75,7 @@ func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string {
|
||||
ids := v.([]*BrMsgID)
|
||||
for _, downstreamMsgObj := range ids {
|
||||
if ID == downstreamMsgObj.ID {
|
||||
return strings.Replace(mid.(string), protocol+" ", "", 1)
|
||||
return mid.(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -447,16 +447,19 @@ func (gw *Gateway) SendMessage(
|
||||
msg.Avatar = gw.modifyAvatar(rmsg, dest)
|
||||
msg.Username = gw.modifyUsername(rmsg, dest)
|
||||
|
||||
msg.ID = gw.getDestMsgID(rmsg.Protocol+" "+rmsg.ID, dest, channel)
|
||||
// exclude file delete event as the msg ID here is the native file ID that needs to be deleted
|
||||
if msg.Event != config.EventFileDelete {
|
||||
msg.ID = gw.getDestMsgID(rmsg.Protocol+" "+rmsg.ID, dest, channel)
|
||||
}
|
||||
|
||||
// for api we need originchannel as channel
|
||||
if dest.Protocol == apiProtocol {
|
||||
msg.Channel = rmsg.Channel
|
||||
}
|
||||
|
||||
msg.ParentID = gw.getDestMsgID(rmsg.Protocol+" "+canonicalParentMsgID, dest, channel)
|
||||
msg.ParentID = gw.getDestMsgID(canonicalParentMsgID, dest, channel)
|
||||
if msg.ParentID == "" {
|
||||
msg.ParentID = canonicalParentMsgID
|
||||
msg.ParentID = strings.Replace(canonicalParentMsgID, dest.Protocol+" ", "", 1)
|
||||
}
|
||||
|
||||
// if the parentID is still empty and we have a parentID set in the original message
|
||||
|
||||
@@ -110,7 +110,9 @@ func (r *Router) disableBridge(br *bridge.Bridge, err error) bool {
|
||||
if r.BridgeValues().General.IgnoreFailureOnStart {
|
||||
r.logger.Error(err)
|
||||
// setting this bridge empty
|
||||
*br = bridge.Bridge{}
|
||||
*br = bridge.Bridge{
|
||||
Log: br.Log,
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
75
go.mod
75
go.mod
@@ -5,31 +5,32 @@ require (
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
||||
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.20210615184944-2b8a3e9b8aa2
|
||||
github.com/SevereCloud/vksdk/v2 v2.10.0
|
||||
github.com/d5/tengo/v2 v2.8.0
|
||||
github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c
|
||||
github.com/SevereCloud/vksdk/v2 v2.13.0
|
||||
github.com/d5/tengo/v2 v2.10.0
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81
|
||||
github.com/gomarkdown/markdown v0.0.0-20210918233619-6c1113f12c4a
|
||||
github.com/google/gops v0.3.21
|
||||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
|
||||
github.com/gomarkdown/markdown v0.0.0-20211207152620-5d6539fd8bfc
|
||||
github.com/google/gops v0.3.22
|
||||
github.com/gorilla/schema v1.2.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/harmony-development/shibshib v0.0.0-20211127182844-512296f7c548
|
||||
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-20211004153716-fd2ee4d6be11
|
||||
github.com/keybase/go-keybase-chat-bot v0.0.0-20211201215354-ee4b23828b55
|
||||
github.com/kyokomi/emoji/v2 v2.2.8
|
||||
github.com/labstack/echo/v4 v4.6.1
|
||||
github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b
|
||||
github.com/labstack/echo/v4 v4.6.3
|
||||
github.com/lrstanley/girc v0.0.0-20211023233735-147f0ff77566
|
||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696
|
||||
github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20210731150933-5702291c239f
|
||||
github.com/matterbridge/gozulipbot v0.0.0-20200820220548-be5824faa913
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be
|
||||
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-20211016195328-346acac403d8
|
||||
github.com/mattermost/mattermost-server/v5 v5.39.0
|
||||
github.com/mattermost/mattermost-server/v6 v6.0.0
|
||||
github.com/matterbridge/matterclient v0.0.0-20211107234719-faca3cd42315
|
||||
github.com/mattermost/mattermost-server/v5 v5.39.3
|
||||
github.com/mattermost/mattermost-server/v6 v6.3.0
|
||||
github.com/mattn/godown v0.0.1
|
||||
github.com/missdeer/golib v1.0.4
|
||||
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9
|
||||
@@ -39,15 +40,15 @@ require (
|
||||
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.9.5
|
||||
github.com/spf13/viper v1.9.0
|
||||
github.com/slack-go/slack v0.10.0
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50
|
||||
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-20210628002857-a66eb6448b8d
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||
gomod.garykim.dev/nc-talk v0.3.0
|
||||
gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376
|
||||
layeh.com/gumble v0.0.0-20200818122324-146f9205029b
|
||||
@@ -65,31 +66,32 @@ require (
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gopackage/ddp v0.0.3 // 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.11 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kettek/apng v0.0.0-20191108220231-414630eed80f // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.6 // indirect
|
||||
github.com/labstack/gommon v0.3.0 // indirect
|
||||
github.com/klauspost/compress v1.14.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/labstack/gommon v0.3.1 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mattermost/go-i18n v1.11.0 // 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
|
||||
github.com/mattermost/logr/v2 v2.0.10 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattermost/logr/v2 v2.0.15 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
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.11 // indirect
|
||||
github.com/minio/minio-go/v7 v7.0.16 // 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.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
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
|
||||
@@ -109,28 +111,31 @@ require (
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
github.com/tinylib/msgp v1.1.6 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
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.uber.org/atomic v1.8.0 // 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-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e // indirect
|
||||
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect
|
||||
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 // indirect
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // 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
|
||||
)
|
||||
|
||||
replace github.com/matrix-org/gomatrix => github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419
|
||||
|
||||
go 1.17
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Message for rocketchat outgoing webhook.
|
||||
@@ -68,7 +69,6 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
msg := Message{}
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
log.Println(string(body))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.NotFound(w, r)
|
||||
@@ -89,7 +89,11 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
msg.ChannelName = "#" + msg.ChannelName
|
||||
if c.Token != "" {
|
||||
if msg.Token != c.Token {
|
||||
log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr)
|
||||
if regexp.MustCompile(`[^a-zA-Z0-9]+`).MatchString(msg.Token) {
|
||||
log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr)
|
||||
} else {
|
||||
log.Println("invalid token from " + r.RemoteAddr)
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,15 +10,13 @@ import (
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/42wim/matterbridge/gateway"
|
||||
"github.com/42wim/matterbridge/gateway/bridgemap"
|
||||
"github.com/42wim/matterbridge/version"
|
||||
"github.com/google/gops/agent"
|
||||
prefixed "github.com/matterbridge/logrus-prefixed-formatter"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
version = "1.23.0"
|
||||
githash string
|
||||
|
||||
flagConfig = flag.String("conf", "matterbridge.toml", "config file")
|
||||
flagDebug = flag.Bool("debug", false, "enable debug")
|
||||
flagVersion = flag.Bool("version", false, "show version")
|
||||
@@ -28,7 +26,7 @@ var (
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if *flagVersion {
|
||||
fmt.Printf("version: %s %s\n", version, githash)
|
||||
fmt.Printf("version: %s %s\n", version.Release, version.GitHash)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -43,8 +41,8 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
logger.Printf("Running version %s %s", version, githash)
|
||||
if strings.Contains(version, "-dev") {
|
||||
logger.Printf("Running version %s %s", version.Release, version.GitHash)
|
||||
if strings.Contains(version.Release, "-dev") {
|
||||
logger.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.")
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,13 @@ Password=""
|
||||
#OPTIONAL (default false)
|
||||
UseTLS=false
|
||||
|
||||
#Use client certificate - see CertFP https://libera.chat/guides/certfp.html
|
||||
#Specify filename which contains private key and cert
|
||||
#OPTIONAL (default "")
|
||||
#
|
||||
#TLSClientCertificate="cert.pem"
|
||||
TLSClientCertificate=""
|
||||
|
||||
#Enable SASL (PLAIN) authentication. (libera requires this from eg AWS hosts)
|
||||
#It uses NickServNick and NickServPassword as login and password
|
||||
#OPTIONAL (default false)
|
||||
@@ -34,6 +41,11 @@ UseSASL=false
|
||||
#OPTIONAL (default false)
|
||||
SkipTLSVerify=true
|
||||
|
||||
#Local address to use for server connection
|
||||
#Note that Server and Bind must resolve to addresses of the same family.
|
||||
#OPTIONAL (default "")
|
||||
Bind=""
|
||||
|
||||
#If you know your charset, you can specify it manually.
|
||||
#Otherwise it tries to detect this automatically. Select one below
|
||||
# "iso-8859-2:1987", "iso-8859-9:1989", "866", "latin9", "iso-8859-10:1992", "iso-ir-109", "hebrew",
|
||||
@@ -396,6 +408,10 @@ SkipTLSVerify=true
|
||||
## RELOADABLE SETTINGS
|
||||
## Settings below can be reloaded by editing the file
|
||||
|
||||
# UseUserName shows the username instead of the server nickname
|
||||
# OPTIONAL (default false)
|
||||
UseUserName=false
|
||||
|
||||
#how to format the list of IRC nicks when displayed in mattermost.
|
||||
#Possible options are "table" and "plain"
|
||||
#OPTIONAL (default plain)
|
||||
@@ -1534,10 +1550,6 @@ MessageClipped="<clipped message>"
|
||||
#See https://vk.com/dev/bots_docs
|
||||
Token="Yourtokenhere"
|
||||
|
||||
#Group ID
|
||||
#For example in URL https://vk.com/public168963511 group ID is 168963511
|
||||
GroupID=123456789
|
||||
|
||||
###################################################################
|
||||
# WhatsApp
|
||||
###################################################################
|
||||
@@ -1655,6 +1667,18 @@ StripNick=false
|
||||
#OPTIONAL (default false)
|
||||
ShowTopicChange=false
|
||||
|
||||
###################################################################
|
||||
# Harmony
|
||||
###################################################################
|
||||
|
||||
[harmony.chat_harmonyapp_io]
|
||||
Homeserver = "https://chat.harmonyapp.io:2289"
|
||||
Token = "your token goes here"
|
||||
UserID = "user id of the bot account"
|
||||
Community = "community id that channels will be located in"
|
||||
UseUserName = true
|
||||
RemoteNickFormat = "{NICK}"
|
||||
|
||||
###################################################################
|
||||
#API
|
||||
###################################################################
|
||||
@@ -1700,6 +1724,7 @@ RemoteNickFormat="{NICK}"
|
||||
|
||||
#RemoteNickFormat defines how remote users appear on this bridge
|
||||
#The string "{NICK}" (case sensitive) will be replaced by the actual nick.
|
||||
#The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged.
|
||||
#The string "{USERID}" (case sensitive) will be replaced by the user ID.
|
||||
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
|
||||
#The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge
|
||||
@@ -1872,7 +1897,8 @@ enable=true
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# irc | channel | #general | The # symbol is required and should be lowercase!
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# mattermost | channel | general | This is the channel name as seen in the URL, not the display name
|
||||
# | channel | general | This is the channel name as seen in the URL, not the display name
|
||||
# mattermost | channel id | ID:oc4wifyuojgw5f3nsuweesmz8w | This is the channel ID (only use if you know what you're doing)
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# matrix | #channel:server | #yourchannel:matrix.org | Encrypted rooms are not supported in matrix
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1898,7 +1924,7 @@ enable=true
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# xmpp | channel | general | The room name
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
# zulip | stream/topic:topic | general/off-topic:food | Do not use the # when specifying a topic
|
||||
# zulip | stream/topic:topic | general/topic:food | Do not use the # when specifying a topic
|
||||
# -------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#
|
||||
@@ -1947,6 +1973,10 @@ enable=true
|
||||
account="zulip.streamchat"
|
||||
channel="general/topic:mytopic"
|
||||
|
||||
[[gateway.inout]]
|
||||
account="harmony.chat_harmonyapp_io"
|
||||
channel="channel id goes here"
|
||||
|
||||
#API example
|
||||
#[[gateway.inout]]
|
||||
#account="api.local"
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
func (m *MMClient) parseActionPost(rmsg *Message) {
|
||||
// add post to cache, if it already exists don't relay this again.
|
||||
// this should fix reposts
|
||||
if ok, _ := m.lruCache.ContainsOrAdd(digestString(rmsg.Raw.Data["post"].(string)), true); ok {
|
||||
if ok, _ := m.lruCache.ContainsOrAdd(digestString(rmsg.Raw.Data["post"].(string)), true); ok && rmsg.Raw.Event != model.WEBSOCKET_EVENT_POST_DELETED {
|
||||
m.logger.Debugf("message %#v in cache, not processing again", rmsg.Raw.Data["post"].(string))
|
||||
rmsg.Text = ""
|
||||
return
|
||||
|
||||
@@ -5,7 +5,7 @@ RUN apk add \
|
||||
go \
|
||||
git \
|
||||
&& cd /go/src/matterbridge \
|
||||
&& go build -mod vendor -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge
|
||||
&& CGO_ENABLED=0 go build -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 \
|
||||
|
||||
2
vendor/github.com/Rhymen/go-whatsapp/README.md
generated
vendored
2
vendor/github.com/Rhymen/go-whatsapp/README.md
generated
vendored
@@ -70,7 +70,7 @@ func (myHandler) HandleContactMessage(message whatsapp.ContactMessage) {
|
||||
fmt.Println(message)
|
||||
}
|
||||
|
||||
func (myHandler) HandleBatteryMessage(msg whatsapp.BatteryMessage) {
|
||||
func (myHandler) HandleBatteryMessage(message whatsapp.BatteryMessage) {
|
||||
fmt.Println(message)
|
||||
}
|
||||
|
||||
|
||||
4
vendor/github.com/Rhymen/go-whatsapp/session.go
generated
vendored
4
vendor/github.com/Rhymen/go-whatsapp/session.go
generated
vendored
@@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
//represents the WhatsAppWeb client version
|
||||
var waVersion = []int{2, 2121, 6}
|
||||
var waVersion = []int{2, 2142, 12}
|
||||
|
||||
/*
|
||||
Session contains session individual information. To be able to resume the connection without scanning the qr code
|
||||
@@ -526,5 +526,7 @@ func (wac *Conn) Logout() error {
|
||||
return fmt.Errorf("error writing logout: %v\n", err)
|
||||
}
|
||||
|
||||
wac.loggedIn = false
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
9
vendor/github.com/SevereCloud/vksdk/v2/.golangci.yml
generated
vendored
9
vendor/github.com/SevereCloud/vksdk/v2/.golangci.yml
generated
vendored
@@ -48,10 +48,15 @@ linters:
|
||||
- nilerr
|
||||
- revive
|
||||
- wastedassign
|
||||
- bidichk
|
||||
- contextcheck
|
||||
- ireturn
|
||||
- nilnil
|
||||
- tenv
|
||||
- nestif
|
||||
|
||||
# - wrapcheck # TODO: v3 Fix
|
||||
# - testpackage # TODO: Fix testpackage
|
||||
# - nestif # TODO: Fix nestif
|
||||
# - noctx # TODO: Fix noctx
|
||||
|
||||
# don't enable:
|
||||
@@ -75,6 +80,8 @@ linters:
|
||||
# - cyclop
|
||||
# - promlinter
|
||||
# - tagliatelle
|
||||
# - errname
|
||||
# - varnamelen
|
||||
|
||||
# depricated
|
||||
# - maligned
|
||||
|
||||
1
vendor/github.com/SevereCloud/vksdk/v2/.markdownlint.yml
generated
vendored
1
vendor/github.com/SevereCloud/vksdk/v2/.markdownlint.yml
generated
vendored
@@ -1,2 +1,3 @@
|
||||
---
|
||||
no-hard-tabs: false
|
||||
no-duplicate-heading: false
|
||||
|
||||
20
vendor/github.com/SevereCloud/vksdk/v2/.travis.yml
generated
vendored
20
vendor/github.com/SevereCloud/vksdk/v2/.travis.yml
generated
vendored
@@ -1,20 +0,0 @@
|
||||
---
|
||||
language: go
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.cache/go-build
|
||||
- $HOME/gopath/pkg/mod
|
||||
|
||||
go:
|
||||
- 1.x
|
||||
|
||||
before_script:
|
||||
- git fetch --depth=1 origin +refs/tags/*:refs/tags/*
|
||||
- git describe --tags $(git rev-list --tags --max-count=1) --always
|
||||
|
||||
script:
|
||||
- go test -v -race -coverprofile=coverage.txt -covermode=atomic -p=1 ./...
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
4
vendor/github.com/SevereCloud/vksdk/v2/CONTRIBUTING.md
generated
vendored
4
vendor/github.com/SevereCloud/vksdk/v2/CONTRIBUTING.md
generated
vendored
@@ -6,7 +6,7 @@
|
||||
|
||||
Требования:
|
||||
|
||||
- [Go 1.13+](https://golang.org/doc/install)
|
||||
- [Go 1.16+](https://golang.org/doc/install)
|
||||
- [golangci-lint](https://github.com/golangci/golangci-lint)
|
||||
- [global .gitignore](https://help.github.com/en/articles/ignoring-files#create-a-global-gitignore)
|
||||
|
||||
@@ -39,6 +39,7 @@ golangci-lint run
|
||||
# CLIENT_SECRET=""
|
||||
# USER_TOKEN=""
|
||||
# WIDGET_TOKEN=""
|
||||
# MARUSIA_TOKEN=""
|
||||
# CLIENT_ID="123456"
|
||||
# GROUP_ID="123456"
|
||||
# ACCOUNT_ID="123456"
|
||||
@@ -56,6 +57,7 @@ go test ./...
|
||||
"go.testEnvVars": {
|
||||
"SERVICE_TOKEN": "",
|
||||
"WIDGET_TOKEN": "",
|
||||
"MARUSIA_TOKEN": "",
|
||||
"GROUP_TOKEN": "",
|
||||
"CLIENT_SECRET": "",
|
||||
"USER_TOKEN": "",
|
||||
|
||||
252
vendor/github.com/SevereCloud/vksdk/v2/README.md
generated
vendored
252
vendor/github.com/SevereCloud/vksdk/v2/README.md
generated
vendored
@@ -1,125 +1,127 @@
|
||||
# VK SDK for Golang
|
||||
|
||||
[](https://travis-ci.com/SevereCloud/vksdk)
|
||||
[](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2?tab=subdirectories)
|
||||
[](https://vk.com/dev/)
|
||||
[](https://codecov.io/gh/SevereCloud/vksdk)
|
||||
[](https://vk.me/join/AJQ1d6Or8Q00Y_CSOESfbqGt)
|
||||
[](https://github.com/SevereCloud/vksdk/releases)
|
||||
[](https://github.com/SevereCloud/vksdk/blob/master/LICENSE)
|
||||
|
||||
**VK SDK for Golang** ready implementation of the main VK API functions for Go.
|
||||
|
||||
[Russian documentation](https://github.com/SevereCloud/vksdk/wiki)
|
||||
|
||||
## Features
|
||||
|
||||
Version API 5.131.
|
||||
|
||||
- [API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api)
|
||||
- 400+ methods
|
||||
- Ability to change the request handler
|
||||
- Ability to modify HTTP client
|
||||
- Request Limiter
|
||||
- Token pool
|
||||
- [Callback API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/callback)
|
||||
- Tracking tool for users activity in your VK communities
|
||||
- Supports all events
|
||||
- Auto setting callback
|
||||
- [Bots Long Poll API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/longpoll-bot)
|
||||
- Allows you to work with community events in real time
|
||||
- Supports all events
|
||||
- Ability to modify HTTP client
|
||||
- [User Long Poll API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/longpoll-user)
|
||||
- Allows you to work with user events in real time
|
||||
- Ability to modify HTTP client
|
||||
- [Streaming API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/streaming)
|
||||
- Receiving public data from VK by specified keywords
|
||||
- Ability to modify HTTP client
|
||||
- [FOAF](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/foaf)
|
||||
- Machine-readable ontology describing persons
|
||||
- Works with users and groups
|
||||
- The only place to get page creation date
|
||||
- [Games](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/games)
|
||||
- Checking launch parameters
|
||||
- Intermediate http handler
|
||||
- [VK Mini Apps](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/vkapps)
|
||||
- Checking launch parameters
|
||||
- Intermediate http handler
|
||||
- [Payments API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/payments)
|
||||
- Processes payment notifications
|
||||
- [Marusia Skills](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/marusia)
|
||||
- For creating Marusia Skills
|
||||
- Support SSML
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
# go mod init mymodulename
|
||||
go get github.com/SevereCloud/vksdk/v2@latest
|
||||
```
|
||||
|
||||
## Use by
|
||||
|
||||
- [Joe](https://github.com/go-joe/joe) adapter: <https://github.com/tdakkota/joe-vk-adapter>
|
||||
- [Logrus](https://github.com/sirupsen/logrus) hook: <https://github.com/SevereCloud/vkrus>
|
||||
|
||||
### Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/SevereCloud/vksdk/v2/api"
|
||||
"github.com/SevereCloud/vksdk/v2/api/params"
|
||||
"github.com/SevereCloud/vksdk/v2/events"
|
||||
"github.com/SevereCloud/vksdk/v2/longpoll-bot"
|
||||
)
|
||||
|
||||
func main() {
|
||||
token := "<TOKEN>" // use os.Getenv("TOKEN")
|
||||
vk := api.NewVK(token)
|
||||
|
||||
// get information about the group
|
||||
group, err := vk.GroupsGetByID(nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Initializing Long Poll
|
||||
lp, err := longpoll.NewLongPoll(vk, group[0].ID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// New message event
|
||||
lp.MessageNew(func(_ context.Context, obj events.MessageNewObject) {
|
||||
log.Printf("%d: %s", obj.Message.PeerID, obj.Message.Text)
|
||||
|
||||
if obj.Message.Text == "ping" {
|
||||
b := params.NewMessagesSendBuilder()
|
||||
b.Message("pong")
|
||||
b.RandomID(0)
|
||||
b.PeerID(obj.Message.PeerID)
|
||||
|
||||
_, err := vk.MessagesSend(b.Params)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Run Bots Long Poll
|
||||
log.Println("Start Long Poll")
|
||||
if err := lp.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## LICENSE
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2FSevereCloud%2Fvksdk?ref=badge_large)
|
||||
# VK SDK for Golang
|
||||
|
||||
[](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2?tab=subdirectories)
|
||||
[](https://vk.com/dev/)
|
||||
[](https://codecov.io/gh/SevereCloud/vksdk)
|
||||
[](https://vk.me/join/AJQ1d6Or8Q00Y_CSOESfbqGt)
|
||||
[](https://github.com/SevereCloud/vksdk/releases)
|
||||
[](https://github.com/SevereCloud/vksdk/blob/master/LICENSE)
|
||||
|
||||
**VK SDK for Golang** ready implementation of the main VK API functions for Go.
|
||||
|
||||
[Russian documentation](https://github.com/SevereCloud/vksdk/wiki)
|
||||
|
||||
## Features
|
||||
|
||||
Version API 5.131.
|
||||
|
||||
- [API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api)
|
||||
- 500+ methods
|
||||
- Ability to modify HTTP client
|
||||
- Request Limiter
|
||||
- Support [zstd](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api#VK.EnableZstd)
|
||||
and [MessagePack](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api#VK.EnableMessagePack)
|
||||
- Token pool
|
||||
- [OAuth](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api/oauth)
|
||||
- [Callback API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/callback)
|
||||
- Tracking tool for users activity in your VK communities
|
||||
- Supports all events
|
||||
- Auto setting callback
|
||||
- [Bots Long Poll API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/longpoll-bot)
|
||||
- Allows you to work with community events in real time
|
||||
- Supports all events
|
||||
- Ability to modify HTTP client
|
||||
- [User Long Poll API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/longpoll-user)
|
||||
- Allows you to work with user events in real time
|
||||
- Ability to modify HTTP client
|
||||
- [Streaming API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/streaming)
|
||||
- Receiving public data from VK by specified keywords
|
||||
- Ability to modify HTTP client
|
||||
- [FOAF](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/foaf)
|
||||
- Machine-readable ontology describing persons
|
||||
- Works with users and groups
|
||||
- The only place to get page creation date
|
||||
- [Games](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/games)
|
||||
- Checking launch parameters
|
||||
- Intermediate http handler
|
||||
- [VK Mini Apps](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/vkapps)
|
||||
- Checking launch parameters
|
||||
- Intermediate http handler
|
||||
- [Payments API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/payments)
|
||||
- Processes payment notifications
|
||||
- [Marusia Skills](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/marusia)
|
||||
- For creating Marusia Skills
|
||||
- Support SSML
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
# go mod init mymodulename
|
||||
go get github.com/SevereCloud/vksdk/v2@latest
|
||||
```
|
||||
|
||||
## Use by
|
||||
|
||||
- A simple chat bridge: <https://github.com/42wim/matterbridge>
|
||||
- [Joe](https://github.com/go-joe/joe) adapter: <https://github.com/tdakkota/joe-vk-adapter>
|
||||
- [Logrus](https://github.com/sirupsen/logrus) hook: <https://github.com/SevereCloud/vkrus>
|
||||
|
||||
### Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/SevereCloud/vksdk/v2/api"
|
||||
"github.com/SevereCloud/vksdk/v2/api/params"
|
||||
"github.com/SevereCloud/vksdk/v2/events"
|
||||
"github.com/SevereCloud/vksdk/v2/longpoll-bot"
|
||||
)
|
||||
|
||||
func main() {
|
||||
token := "<TOKEN>" // use os.Getenv("TOKEN")
|
||||
vk := api.NewVK(token)
|
||||
|
||||
// get information about the group
|
||||
group, err := vk.GroupsGetByID(nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Initializing Long Poll
|
||||
lp, err := longpoll.NewLongPoll(vk, group[0].ID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// New message event
|
||||
lp.MessageNew(func(_ context.Context, obj events.MessageNewObject) {
|
||||
log.Printf("%d: %s", obj.Message.PeerID, obj.Message.Text)
|
||||
|
||||
if obj.Message.Text == "ping" {
|
||||
b := params.NewMessagesSendBuilder()
|
||||
b.Message("pong")
|
||||
b.RandomID(0)
|
||||
b.PeerID(obj.Message.PeerID)
|
||||
|
||||
_, err := vk.MessagesSend(b.Params)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Run Bots Long Poll
|
||||
log.Println("Start Long Poll")
|
||||
if err := lp.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## LICENSE
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2FSevereCloud%2Fvksdk?ref=badge_large)
|
||||
|
||||
50
vendor/github.com/SevereCloud/vksdk/v2/api/README.md
generated
vendored
50
vendor/github.com/SevereCloud/vksdk/v2/api/README.md
generated
vendored
@@ -3,7 +3,7 @@
|
||||
[](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api)
|
||||
[](https://vk.com/dev/first_guide)
|
||||
|
||||
Данная библиотека поддерживает версию API **5.122**.
|
||||
Данная библиотека поддерживает версию API **5.131**.
|
||||
|
||||
## Запросы
|
||||
|
||||
@@ -80,6 +80,54 @@ if errors.As(err, &e) {
|
||||
|
||||
Для Execute существует отдельная ошибка `ExecuteErrors`
|
||||
|
||||
### Поддержка MessagePack и zstd
|
||||
|
||||
> Результат перехода с gzip (JSON) на zstd (msgpack):
|
||||
>
|
||||
> - в 7 раз быстрее сжатие (–1 мкс);
|
||||
> - на 10% меньше размер данных (8 Кбайт вместо 9 Кбайт);
|
||||
> - продуктовый эффект не статзначимый :(
|
||||
>
|
||||
> [Как мы отказались от JPEG, JSON, TCP и ускорили ВКонтакте в два раза](https://habr.com/ru/company/vk/blog/594633/)
|
||||
|
||||
VK API способно возвращать ответ в виде [MessagePack](https://msgpack.org/).
|
||||
Это эффективный формат двоичной сериализации, похожий на JSON, только быстрее
|
||||
и меньше по размеру.
|
||||
|
||||
ВНИМАНИЕ, C MessagePack НЕКОТОРЫЕ МЕТОДЫ МОГУТ ВОЗВРАЩАТЬ
|
||||
СЛОМАННУЮ КОДИРОВКУ.
|
||||
|
||||
Для сжатия, вместо классического gzip, можно использовать
|
||||
[zstd](https://github.com/facebook/zstd). Сейчас vksdk поддерживает zstd без
|
||||
словаря. Если кто знает как получать словарь,
|
||||
[отпишитесь сюда](https://github.com/SevereCloud/vksdk/issues/180).
|
||||
|
||||
```go
|
||||
vk := api.NewVK(os.Getenv("USER_TOKEN"))
|
||||
|
||||
method := "store.getStickersKeywords"
|
||||
params := api.Params{
|
||||
"aliases": true,
|
||||
"all_products": true,
|
||||
"need_stickers": true,
|
||||
}
|
||||
|
||||
r, err := vk.Request(method, params) // Content-Length: 44758
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("json:", len(r)) // json: 814231
|
||||
|
||||
vk.EnableMessagePack() // Включаем поддержку MessagePack
|
||||
vk.EnableZstd() // Включаем поддержку zstd
|
||||
|
||||
r, err = vk.Request(method, params) // Content-Length: 35755
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("msgpack:", len(r)) // msgpack: 650775
|
||||
```
|
||||
|
||||
### Запрос любого метода
|
||||
|
||||
Пример запроса [users.get](https://vk.com/dev/users.get)
|
||||
|
||||
21
vendor/github.com/SevereCloud/vksdk/v2/api/ads.go
generated
vendored
21
vendor/github.com/SevereCloud/vksdk/v2/api/ads.go
generated
vendored
@@ -1,9 +1,11 @@
|
||||
package api // import "github.com/SevereCloud/vksdk/v2/api"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/SevereCloud/vksdk/v2/object"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// AdsAddOfficeUsersItem struct.
|
||||
@@ -21,6 +23,23 @@ func (r *AdsAddOfficeUsersItem) UnmarshalJSON(data []byte) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeMsgpack func.
|
||||
func (r *AdsAddOfficeUsersItem) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
data, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if msgpack.Unmarshal(data, &r.OK) != nil {
|
||||
d := msgpack.NewDecoder(bytes.NewReader(data))
|
||||
d.SetCustomStructTag("json")
|
||||
|
||||
return d.Decode(&r.Error)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AdsAddOfficeUsersResponse struct.
|
||||
type AdsAddOfficeUsersResponse []AdsAddOfficeUsersItem
|
||||
|
||||
@@ -349,7 +368,7 @@ func (vk *VK) AdsGetAdsLayout(params Params) (response AdsGetAdsLayoutResponse,
|
||||
|
||||
// AdsGetMusiciansResponse struct.
|
||||
type AdsGetMusiciansResponse struct {
|
||||
Items []object.BaseObjectWithName
|
||||
Items []object.AdsMusician
|
||||
}
|
||||
|
||||
// AdsGetMusicians returns a list of musicians.
|
||||
|
||||
92
vendor/github.com/SevereCloud/vksdk/v2/api/api.go
generated
vendored
92
vendor/github.com/SevereCloud/vksdk/v2/api/api.go
generated
vendored
@@ -7,9 +7,11 @@ package api // import "github.com/SevereCloud/vksdk/v2/api"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -21,6 +23,8 @@ import (
|
||||
"github.com/SevereCloud/vksdk/v2"
|
||||
"github.com/SevereCloud/vksdk/v2/internal"
|
||||
"github.com/SevereCloud/vksdk/v2/object"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// Api constants.
|
||||
@@ -91,6 +95,9 @@ type VK struct {
|
||||
UserAgent string
|
||||
Handler func(method string, params ...Params) (Response, error)
|
||||
|
||||
msgpack bool
|
||||
zstd bool
|
||||
|
||||
mux sync.Mutex
|
||||
lastTime time.Time
|
||||
rps int
|
||||
@@ -98,9 +105,9 @@ type VK struct {
|
||||
|
||||
// Response struct.
|
||||
type Response struct {
|
||||
Response json.RawMessage `json:"response"`
|
||||
Error Error `json:"error"`
|
||||
ExecuteErrors ExecuteErrors `json:"execute_errors"`
|
||||
Response object.RawMessage `json:"response"`
|
||||
Error Error `json:"error"`
|
||||
ExecuteErrors ExecuteErrors `json:"execute_errors"`
|
||||
}
|
||||
|
||||
// NewVK returns a new VK.
|
||||
@@ -121,7 +128,7 @@ func NewVK(tokens ...string) *VK {
|
||||
vk.accessTokens = tokens
|
||||
vk.Version = Version
|
||||
|
||||
vk.Handler = vk.defaultHandler
|
||||
vk.Handler = vk.DefaultHandler
|
||||
|
||||
vk.MethodURL = MethodURL
|
||||
vk.Client = http.DefaultClient
|
||||
@@ -207,8 +214,8 @@ func buildQuery(sliceParams ...Params) (context.Context, url.Values) {
|
||||
return ctx, query
|
||||
}
|
||||
|
||||
// defaultHandler provides access to VK API methods.
|
||||
func (vk *VK) defaultHandler(method string, sliceParams ...Params) (Response, error) {
|
||||
// DefaultHandler provides access to VK API methods.
|
||||
func (vk *VK) DefaultHandler(method string, sliceParams ...Params) (Response, error) {
|
||||
u := vk.MethodURL + method
|
||||
ctx, query := buildQuery(sliceParams...)
|
||||
attempt := 0
|
||||
@@ -243,24 +250,52 @@ func (vk *VK) defaultHandler(method string, sliceParams ...Params) (Response, er
|
||||
return response, err
|
||||
}
|
||||
|
||||
acceptEncoding := "gzip"
|
||||
if vk.zstd {
|
||||
acceptEncoding = "zstd"
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", vk.UserAgent)
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
req.Header.Set("Accept-Encoding", acceptEncoding)
|
||||
|
||||
var reader io.Reader
|
||||
|
||||
resp, err := vk.Client.Do(req)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
mediatype, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||
if mediatype != "application/json" {
|
||||
_ = resp.Body.Close()
|
||||
return response, &InvalidContentType{mediatype}
|
||||
switch resp.Header.Get("Content-Encoding") {
|
||||
case "zstd":
|
||||
reader, _ = zstd.NewReader(resp.Body)
|
||||
case "gzip":
|
||||
reader, _ = gzip.NewReader(resp.Body)
|
||||
default:
|
||||
reader = resp.Body
|
||||
}
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(&response)
|
||||
if err != nil {
|
||||
mediatype, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||
switch mediatype {
|
||||
case "application/json":
|
||||
err = json.NewDecoder(reader).Decode(&response)
|
||||
if err != nil {
|
||||
_ = resp.Body.Close()
|
||||
return response, err
|
||||
}
|
||||
case "application/x-msgpack":
|
||||
dec := msgpack.NewDecoder(reader)
|
||||
dec.SetCustomStructTag("json")
|
||||
|
||||
err = dec.Decode(&response)
|
||||
if err != nil {
|
||||
_ = resp.Body.Close()
|
||||
return response, err
|
||||
}
|
||||
default:
|
||||
_ = resp.Body.Close()
|
||||
return response, err
|
||||
return response, &InvalidContentType{mediatype}
|
||||
}
|
||||
|
||||
_ = resp.Body.Close()
|
||||
@@ -291,6 +326,10 @@ func (vk *VK) Request(method string, sliceParams ...Params) ([]byte, error) {
|
||||
|
||||
sliceParams = append(sliceParams, reqParams)
|
||||
|
||||
if vk.msgpack {
|
||||
method += ".msgpack"
|
||||
}
|
||||
|
||||
resp, err := vk.Handler(method, sliceParams...)
|
||||
|
||||
return resp.Response, err
|
||||
@@ -303,7 +342,32 @@ func (vk *VK) RequestUnmarshal(method string, obj interface{}, sliceParams ...Pa
|
||||
return err
|
||||
}
|
||||
|
||||
return json.Unmarshal(rawResponse, &obj)
|
||||
if vk.msgpack {
|
||||
dec := msgpack.NewDecoder(bytes.NewReader(rawResponse))
|
||||
dec.SetCustomStructTag("json")
|
||||
|
||||
err = dec.Decode(&obj)
|
||||
} else {
|
||||
err = json.Unmarshal(rawResponse, &obj)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// EnableMessagePack enable using MessagePack instead of JSON.
|
||||
//
|
||||
// THIS IS EXPERIMENTAL FUNCTION! Broken encoding returned in some methods.
|
||||
//
|
||||
// See https://msgpack.org
|
||||
func (vk *VK) EnableMessagePack() {
|
||||
vk.msgpack = true
|
||||
}
|
||||
|
||||
// EnableZstd enable using zstd instead of gzip.
|
||||
//
|
||||
// This not use dict.
|
||||
func (vk *VK) EnableZstd() {
|
||||
vk.zstd = true
|
||||
}
|
||||
|
||||
func fmtReflectValue(value reflect.Value, depth int) string {
|
||||
|
||||
59
vendor/github.com/SevereCloud/vksdk/v2/api/auth.go
generated
vendored
59
vendor/github.com/SevereCloud/vksdk/v2/api/auth.go
generated
vendored
@@ -1,5 +1,9 @@
|
||||
package api // import "github.com/SevereCloud/vksdk/v2/api"
|
||||
|
||||
import (
|
||||
"github.com/SevereCloud/vksdk/v2/object"
|
||||
)
|
||||
|
||||
// AuthCheckPhone checks a user's phone number for correctness.
|
||||
//
|
||||
// https://vk.com/dev/auth.checkPhone
|
||||
@@ -24,3 +28,58 @@ func (vk *VK) AuthRestore(params Params) (response AuthRestoreResponse, err erro
|
||||
err = vk.RequestUnmarshal("auth.restore", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// AuthGetProfileInfoBySilentTokenResponse struct.
|
||||
type AuthGetProfileInfoBySilentTokenResponse struct {
|
||||
Success []object.AuthSilentTokenProfile `json:"success"`
|
||||
Errors []AuthSilentTokenError `json:"errors"`
|
||||
}
|
||||
|
||||
// AuthGetProfileInfoBySilentToken method.
|
||||
//
|
||||
// https://platform.vk.com/?p=DocsDashboard&docs=tokens_silent-token
|
||||
func (vk *VK) AuthGetProfileInfoBySilentToken(params Params) (response AuthGetProfileInfoBySilentTokenResponse, err error) {
|
||||
err = vk.RequestUnmarshal("auth.getProfileInfoBySilentToken", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// ExchangeSilentTokenSource call conditions exchangeSilentToken.
|
||||
//
|
||||
// 0 Unknown
|
||||
// 1 Silent authentication
|
||||
// 2 Auth by login and password
|
||||
// 3 Extended registration
|
||||
// 4 Auth by exchange token
|
||||
// 5 Auth by exchange token on reset password
|
||||
// 6 Auth by exchange token on unblock
|
||||
// 7 Auth by exchange token on reset session
|
||||
// 8 Auth by exchange token on change password
|
||||
// 9 Finish phone validation on authentication
|
||||
// 10 Auth by code
|
||||
// 11 Auth by external oauth
|
||||
// 12 Reactivation
|
||||
// 15 Auth by SDK temporary access-token
|
||||
type ExchangeSilentTokenSource int
|
||||
|
||||
// AuthExchangeSilentAuthTokenResponse struct.
|
||||
type AuthExchangeSilentAuthTokenResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
AccessTokenID string `json:"access_token_id"`
|
||||
UserID int `json:"user_id"`
|
||||
Phone string `json:"phone"`
|
||||
PhoneValidated interface{} `json:"phone_validated"`
|
||||
IsPartial bool `json:"is_partial"`
|
||||
IsService bool `json:"is_service"`
|
||||
AdditionalSignupRequired bool `json:"additional_signup_required"`
|
||||
Email string `json:"email"`
|
||||
Source ExchangeSilentTokenSource `json:"source"`
|
||||
SourceDescription string `json:"source_description"`
|
||||
}
|
||||
|
||||
// AuthExchangeSilentAuthToken method.
|
||||
//
|
||||
// https://platform.vk.com/?p=DocsDashboard&docs=tokens_access-token
|
||||
func (vk *VK) AuthExchangeSilentAuthToken(params Params) (response AuthExchangeSilentAuthTokenResponse, err error) {
|
||||
err = vk.RequestUnmarshal("auth.exchangeSilentAuthToken", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
82
vendor/github.com/SevereCloud/vksdk/v2/api/errors.go
generated
vendored
82
vendor/github.com/SevereCloud/vksdk/v2/api/errors.go
generated
vendored
@@ -159,6 +159,9 @@ const (
|
||||
ErrRateLimit ErrorType = 29
|
||||
ErrPrivateProfile ErrorType = 30 // This profile is private
|
||||
|
||||
// Client version deprecated.
|
||||
ErrClientVersionDeprecated ErrorType = 34
|
||||
|
||||
// Method execution was interrupted due to timeout.
|
||||
ErrExecutionTimeout ErrorType = 36
|
||||
|
||||
@@ -177,6 +180,9 @@ const (
|
||||
// Additional signup required.
|
||||
ErrAdditionalSignupRequired ErrorType = 41
|
||||
|
||||
// IP is not allowed.
|
||||
ErrIPNotAllowed ErrorType = 42
|
||||
|
||||
// One of the parameters specified was missing or invalid
|
||||
//
|
||||
// Check the required parameters list and their format on a method
|
||||
@@ -586,6 +592,18 @@ const (
|
||||
// Can't send message, reply timed out.
|
||||
ErrMessagesReplyTimedOut ErrorType = 950
|
||||
|
||||
// You can't access donut chat without subscription.
|
||||
ErrMessagesAccessDonutChat ErrorType = 962
|
||||
|
||||
// This user can't be added to the work chat, as they aren't an employe.
|
||||
ErrMessagesAccessWorkChat ErrorType = 967
|
||||
|
||||
// Message cannot be forwarded.
|
||||
ErrMessagesCantForwarded ErrorType = 969
|
||||
|
||||
// Cannot pin an expiring message.
|
||||
ErrMessagesPinExpiringMessage ErrorType = 970
|
||||
|
||||
// Invalid phone number.
|
||||
ErrParamPhone ErrorType = 1000
|
||||
|
||||
@@ -598,6 +616,12 @@ const (
|
||||
// Processing.. Try later.
|
||||
ErrAuthDelay ErrorType = 1112
|
||||
|
||||
// Anonymous token has expired.
|
||||
ErrAnonymousTokenExpired ErrorType = 1114
|
||||
|
||||
// Anonymous token is invalid.
|
||||
ErrAnonymousTokenInvalid ErrorType = 1116
|
||||
|
||||
// Invalid document id.
|
||||
ErrParamDocID ErrorType = 1150
|
||||
|
||||
@@ -724,6 +748,9 @@ const (
|
||||
// Market was already disabled in this group.
|
||||
ErrMarketAlreadyDisabled ErrorType = 1432
|
||||
|
||||
// Main album can not be hidden.
|
||||
ErrMainAlbumCantHidden ErrorType = 1446
|
||||
|
||||
// Story has already expired.
|
||||
ErrStoryExpired ErrorType = 1600
|
||||
|
||||
@@ -783,6 +810,33 @@ const (
|
||||
|
||||
// Can't set AliExpress tag to this type of object.
|
||||
ErrAliExpressTag ErrorType = 3800
|
||||
|
||||
// Invalid upload response.
|
||||
ErrInvalidUploadResponse ErrorType = 5701
|
||||
|
||||
// Invalid upload hash.
|
||||
ErrInvalidUploadHash ErrorType = 5702
|
||||
|
||||
// Invalid upload user.
|
||||
ErrInvalidUploadUser ErrorType = 5703
|
||||
|
||||
// Invalid upload group.
|
||||
ErrInvalidUploadGroup ErrorType = 5704
|
||||
|
||||
// Invalid crop data.
|
||||
ErrInvalidCropData ErrorType = 5705
|
||||
|
||||
// To small avatar.
|
||||
ErrToSmallAvatar ErrorType = 5706
|
||||
|
||||
// Photo not found.
|
||||
ErrPhotoNotFound ErrorType = 5708
|
||||
|
||||
// Invalid Photo.
|
||||
ErrInvalidPhoto ErrorType = 5709
|
||||
|
||||
// Invalid hash.
|
||||
ErrInvalidHash ErrorType = 5710
|
||||
)
|
||||
|
||||
// ErrorSubtype is the subtype of an error.
|
||||
@@ -946,3 +1000,31 @@ func (e AdsError) Is(target error) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// AuthSilentTokenError struct.
|
||||
type AuthSilentTokenError struct {
|
||||
Token string `json:"token"`
|
||||
Code ErrorType `json:"code"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// Error returns the description of a AuthSilentTokenError.
|
||||
func (e AuthSilentTokenError) Error() string {
|
||||
return "api: " + e.Description
|
||||
}
|
||||
|
||||
// Is unwraps its first argument sequentially looking for an error that matches
|
||||
// the second.
|
||||
func (e AuthSilentTokenError) Is(target error) bool {
|
||||
var tError *AuthSilentTokenError
|
||||
if errors.As(target, &tError) {
|
||||
return e.Code == tError.Code && e.Description == tError.Description
|
||||
}
|
||||
|
||||
var tErrorType ErrorType
|
||||
if errors.As(target, &tErrorType) {
|
||||
return e.Code == tErrorType
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
26
vendor/github.com/SevereCloud/vksdk/v2/api/execute.go
generated
vendored
26
vendor/github.com/SevereCloud/vksdk/v2/api/execute.go
generated
vendored
@@ -1,6 +1,11 @@
|
||||
package api
|
||||
|
||||
import "encoding/json"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// ExecuteWithArgs a universal method for calling a sequence of other methods
|
||||
// while saving and filtering interim results.
|
||||
@@ -22,10 +27,23 @@ func (vk *VK) ExecuteWithArgs(code string, params Params, obj interface{}) error
|
||||
}
|
||||
|
||||
resp, err := vk.Handler("execute", params, reqParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonErr := json.Unmarshal(resp.Response, &obj)
|
||||
if jsonErr != nil {
|
||||
return jsonErr
|
||||
var decoderErr error
|
||||
|
||||
if vk.msgpack {
|
||||
dec := msgpack.NewDecoder(bytes.NewReader(resp.Response))
|
||||
dec.SetCustomStructTag("json")
|
||||
|
||||
decoderErr = dec.Decode(&obj)
|
||||
} else {
|
||||
decoderErr = json.Unmarshal(resp.Response, &obj)
|
||||
}
|
||||
|
||||
if decoderErr != nil {
|
||||
return decoderErr
|
||||
}
|
||||
|
||||
if resp.ExecuteErrors != nil {
|
||||
|
||||
17
vendor/github.com/SevereCloud/vksdk/v2/api/market.go
generated
vendored
17
vendor/github.com/SevereCloud/vksdk/v2/api/market.go
generated
vendored
@@ -20,6 +20,7 @@ func (vk *VK) MarketAdd(params Params) (response MarketAddResponse, err error) {
|
||||
// MarketAddAlbumResponse struct.
|
||||
type MarketAddAlbumResponse struct {
|
||||
MarketAlbumID int `json:"market_album_id"` // Album ID
|
||||
AlbumsCount int `json:"albums_count"`
|
||||
}
|
||||
|
||||
// MarketAddAlbum creates new collection of items.
|
||||
@@ -318,3 +319,19 @@ func (vk *VK) MarketSearch(params Params) (response MarketSearchResponse, err er
|
||||
err = vk.RequestUnmarshal("market.search", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// MarketSearchItemsResponse struct.
|
||||
type MarketSearchItemsResponse struct {
|
||||
Count int `json:"count"`
|
||||
ViewType int `json:"view_type"`
|
||||
Items []object.MarketMarketItem `json:"items"`
|
||||
Groups []object.GroupsGroup `json:"groups,omitempty"`
|
||||
}
|
||||
|
||||
// MarketSearchItems method.
|
||||
//
|
||||
// https://vk.com/dev/market.searchItems
|
||||
func (vk *VK) MarketSearchItems(params Params) (response MarketSearchItemsResponse, err error) {
|
||||
err = vk.RequestUnmarshal("market.searchItems", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
103
vendor/github.com/SevereCloud/vksdk/v2/api/marusia.go
generated
vendored
Normal file
103
vendor/github.com/SevereCloud/vksdk/v2/api/marusia.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
package api // import "github.com/SevereCloud/vksdk/v2/api"
|
||||
|
||||
import (
|
||||
"github.com/SevereCloud/vksdk/v2/object"
|
||||
)
|
||||
|
||||
// MarusiaGetPictureUploadLinkResponse struct.
|
||||
type MarusiaGetPictureUploadLinkResponse struct {
|
||||
PictureUploadLink string `json:"picture_upload_link"` // Link
|
||||
}
|
||||
|
||||
// MarusiaGetPictureUploadLink method.
|
||||
//
|
||||
// https://vk.com/dev/marusia_skill_docs10
|
||||
func (vk *VK) MarusiaGetPictureUploadLink(params Params) (response MarusiaGetPictureUploadLinkResponse, err error) {
|
||||
err = vk.RequestUnmarshal("marusia.getPictureUploadLink", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// MarusiaSavePictureResponse struct.
|
||||
type MarusiaSavePictureResponse struct {
|
||||
AppID int `json:"app_id"`
|
||||
PhotoID int `json:"photo_id"`
|
||||
}
|
||||
|
||||
// MarusiaSavePicture method.
|
||||
//
|
||||
// https://vk.com/dev/marusia_skill_docs10
|
||||
func (vk *VK) MarusiaSavePicture(params Params) (response MarusiaSavePictureResponse, err error) {
|
||||
err = vk.RequestUnmarshal("marusia.savePicture", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// MarusiaGetPicturesResponse struct.
|
||||
type MarusiaGetPicturesResponse struct {
|
||||
Count int `json:"count"`
|
||||
Items []object.MarusiaPicture `json:"items"`
|
||||
}
|
||||
|
||||
// MarusiaGetPictures method.
|
||||
//
|
||||
// https://vk.com/dev/marusia_skill_docs10
|
||||
func (vk *VK) MarusiaGetPictures(params Params) (response MarusiaGetPicturesResponse, err error) {
|
||||
err = vk.RequestUnmarshal("marusia.getPictures", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// MarusiaDeletePicture delete picture.
|
||||
//
|
||||
// https://vk.com/dev/marusia_skill_docs10
|
||||
func (vk *VK) MarusiaDeletePicture(params Params) (response int, err error) {
|
||||
err = vk.RequestUnmarshal("marusia.deletePicture", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// MarusiaGetAudioUploadLinkResponse struct.
|
||||
type MarusiaGetAudioUploadLinkResponse struct {
|
||||
AudioUploadLink string `json:"audio_upload_link"` // Link
|
||||
}
|
||||
|
||||
// MarusiaGetAudioUploadLink method.
|
||||
//
|
||||
// https://vk.com/dev/marusia_skill_docs10
|
||||
func (vk *VK) MarusiaGetAudioUploadLink(params Params) (response MarusiaGetAudioUploadLinkResponse, err error) {
|
||||
err = vk.RequestUnmarshal("marusia.getAudioUploadLink", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// MarusiaCreateAudioResponse struct.
|
||||
type MarusiaCreateAudioResponse struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
// MarusiaCreateAudio method.
|
||||
//
|
||||
// https://vk.com/dev/marusia_skill_docs10
|
||||
func (vk *VK) MarusiaCreateAudio(params Params) (response MarusiaCreateAudioResponse, err error) {
|
||||
err = vk.RequestUnmarshal("marusia.createAudio", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// MarusiaGetAudiosResponse struct.
|
||||
type MarusiaGetAudiosResponse struct {
|
||||
Count int `json:"count"`
|
||||
Audios []object.MarusiaAudio `json:"audios"`
|
||||
}
|
||||
|
||||
// MarusiaGetAudios method.
|
||||
//
|
||||
// https://vk.com/dev/marusia_skill_docs10
|
||||
func (vk *VK) MarusiaGetAudios(params Params) (response MarusiaGetAudiosResponse, err error) {
|
||||
err = vk.RequestUnmarshal("marusia.getAudios", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
// MarusiaDeleteAudio delete audio.
|
||||
//
|
||||
// https://vk.com/dev/marusia_skill_docs10
|
||||
func (vk *VK) MarusiaDeleteAudio(params Params) (response int, err error) {
|
||||
err = vk.RequestUnmarshal("marusia.deleteAudio", &response, params)
|
||||
return
|
||||
}
|
||||
26
vendor/github.com/SevereCloud/vksdk/v2/api/messages.go
generated
vendored
26
vendor/github.com/SevereCloud/vksdk/v2/api/messages.go
generated
vendored
@@ -1,7 +1,10 @@
|
||||
package api // import "github.com/SevereCloud/vksdk/v2/api"
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/SevereCloud/vksdk/v2/object"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// MessagesAddChatUser adds a new user to a chat.
|
||||
@@ -31,11 +34,34 @@ func (vk *VK) MessagesCreateChat(params Params) (response int, err error) {
|
||||
// MessagesDeleteResponse struct.
|
||||
type MessagesDeleteResponse map[string]int
|
||||
|
||||
// DecodeMsgpack funcion.
|
||||
func (resp *MessagesDeleteResponse) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
data, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var respMap map[int]int
|
||||
|
||||
err = msgpack.Unmarshal(data, &respMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*resp = make(MessagesDeleteResponse)
|
||||
for key, val := range respMap {
|
||||
(*resp)[strconv.Itoa(key)] = val
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MessagesDelete deletes one or more messages.
|
||||
//
|
||||
// https://vk.com/dev/messages.delete
|
||||
func (vk *VK) MessagesDelete(params Params) (response MessagesDeleteResponse, err error) {
|
||||
err = vk.RequestUnmarshal("messages.delete", &response, params)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
13
vendor/github.com/SevereCloud/vksdk/v2/api/photos.go
generated
vendored
13
vendor/github.com/SevereCloud/vksdk/v2/api/photos.go
generated
vendored
@@ -571,12 +571,13 @@ func (vk *VK) PhotosSaveOwnerCoverPhoto(params Params) (response PhotosSaveOwner
|
||||
|
||||
// PhotosSaveOwnerPhotoResponse struct.
|
||||
type PhotosSaveOwnerPhotoResponse struct {
|
||||
PhotoHash string `json:"photo_hash"`
|
||||
PhotoSrc string `json:"photo_src"`
|
||||
PhotoSrcBig string `json:"photo_src_big"`
|
||||
PhotoSrcSmall string `json:"photo_src_small"`
|
||||
Saved int `json:"saved"`
|
||||
PostID int `json:"post_id"`
|
||||
PhotoHash string `json:"photo_hash"`
|
||||
// BUG(VK): returns false
|
||||
// PhotoSrc string `json:"photo_src"`
|
||||
// PhotoSrcBig string `json:"photo_src_big"`
|
||||
// PhotoSrcSmall string `json:"photo_src_small"`
|
||||
Saved int `json:"saved"`
|
||||
PostID int `json:"post_id"`
|
||||
}
|
||||
|
||||
// PhotosSaveOwnerPhoto saves a profile or community photo.
|
||||
|
||||
54
vendor/github.com/SevereCloud/vksdk/v2/api/upload.go
generated
vendored
54
vendor/github.com/SevereCloud/vksdk/v2/api/upload.go
generated
vendored
@@ -959,3 +959,57 @@ func (vk *VK) UploadGroupImage(imageType string, file io.Reader) (response objec
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UploadMarusiaPicture uploading picture.
|
||||
//
|
||||
// Limits: height not more than 600 px,
|
||||
// aspect ratio of at least 2:1.
|
||||
func (vk *VK) UploadMarusiaPicture(file io.Reader) (response MarusiaSavePictureResponse, err error) {
|
||||
uploadServer, err := vk.MarusiaGetPictureUploadLink(nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
bodyContent, err := vk.UploadFile(uploadServer.PictureUploadLink, file, "photo", "photo.jpg")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var handler object.MarusiaPictureUploadResponse
|
||||
|
||||
err = json.Unmarshal(bodyContent, &handler)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
photo, _ := json.Marshal(handler.Photo)
|
||||
|
||||
response, err = vk.MarusiaSavePicture(Params{
|
||||
"server": handler.Server,
|
||||
"photo": string(photo),
|
||||
"hash": handler.Hash,
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UploadMarusiaAudio uploading audio.
|
||||
//
|
||||
// https://vk.com/dev/marusia_skill_docs10
|
||||
func (vk *VK) UploadMarusiaAudio(file io.Reader) (response MarusiaCreateAudioResponse, err error) {
|
||||
uploadServer, err := vk.MarusiaGetAudioUploadLink(nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
bodyContent, err := vk.UploadFile(uploadServer.AudioUploadLink, file, "file", "audio.mp3")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
response, err = vk.MarusiaCreateAudio(Params{
|
||||
"audio_meta": string(bodyContent),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
36
vendor/github.com/SevereCloud/vksdk/v2/api/utils.go
generated
vendored
36
vendor/github.com/SevereCloud/vksdk/v2/api/utils.go
generated
vendored
@@ -1,9 +1,8 @@
|
||||
package api // import "github.com/SevereCloud/vksdk/v2/api"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/SevereCloud/vksdk/v2/object"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// UtilsCheckLinkResponse struct.
|
||||
@@ -89,17 +88,34 @@ func (vk *VK) UtilsGetShortLink(params Params) (response UtilsGetShortLinkRespon
|
||||
// UtilsResolveScreenNameResponse struct.
|
||||
type UtilsResolveScreenNameResponse object.UtilsDomainResolved
|
||||
|
||||
// UnmarshalJSON UtilsResolveScreenNameResponse.
|
||||
//
|
||||
// BUG(VK): UtilsResolveScreenNameResponse return [].
|
||||
func (resp *UtilsResolveScreenNameResponse) UnmarshalJSON(data []byte) error {
|
||||
var p object.UtilsDomainResolved
|
||||
err := p.UnmarshalJSON(data)
|
||||
|
||||
*resp = UtilsResolveScreenNameResponse(p)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DecodeMsgpack UtilsResolveScreenNameResponse.
|
||||
//
|
||||
// BUG(VK): UtilsResolveScreenNameResponse return [].
|
||||
func (resp *UtilsResolveScreenNameResponse) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
var p object.UtilsDomainResolved
|
||||
err := p.DecodeMsgpack(dec)
|
||||
|
||||
*resp = UtilsResolveScreenNameResponse(p)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// UtilsResolveScreenName detects a type of object (e.g., user, community, application) and its ID by screen name.
|
||||
//
|
||||
// https://vk.com/dev/utils.resolveScreenName
|
||||
func (vk *VK) UtilsResolveScreenName(params Params) (response UtilsResolveScreenNameResponse, err error) {
|
||||
rawResponse, err := vk.Request("utils.resolveScreenName", params)
|
||||
// Если короткое имя screen_name не занято, то будет возвращён пустой объект.
|
||||
if err != nil || string(rawResponse) == "[]" {
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawResponse, &response)
|
||||
|
||||
err = vk.RequestUnmarshal("utils.resolveScreenName", &response, params)
|
||||
return
|
||||
}
|
||||
|
||||
2
vendor/github.com/SevereCloud/vksdk/v2/doc.go
generated
vendored
2
vendor/github.com/SevereCloud/vksdk/v2/doc.go
generated
vendored
@@ -7,6 +7,6 @@ package vksdk
|
||||
|
||||
// Module constants.
|
||||
const (
|
||||
Version = "2.10.0"
|
||||
Version = "2.13.0"
|
||||
API = "5.131"
|
||||
)
|
||||
|
||||
2
vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/README.md
generated
vendored
2
vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/README.md
generated
vendored
@@ -10,7 +10,7 @@ Long Poll настраивается автоматически. Вам не т
|
||||
|
||||
### Версия API
|
||||
|
||||
Данная библиотека поддерживает версию API **5.122**.
|
||||
Данная библиотека поддерживает версию API **5.131**.
|
||||
|
||||
### Инициализация
|
||||
|
||||
|
||||
58
vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go
generated
vendored
58
vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go
generated
vendored
@@ -8,8 +8,11 @@ package longpoll // import "github.com/SevereCloud/vksdk/v2/longpoll-bot"
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/SevereCloud/vksdk/v2"
|
||||
"github.com/SevereCloud/vksdk/v2/api"
|
||||
@@ -117,7 +120,7 @@ func (lp *LongPoll) check(ctx context.Context) (response Response, err error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(&response)
|
||||
response, err = parseResponse(resp.Body)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -127,6 +130,59 @@ func (lp *LongPoll) check(ctx context.Context) (response Response, err error) {
|
||||
return response, err
|
||||
}
|
||||
|
||||
func parseResponse(reader io.Reader) (response Response, err error) {
|
||||
decoder := json.NewDecoder(reader)
|
||||
for decoder.More() {
|
||||
token, err := decoder.Token()
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
|
||||
return response, err
|
||||
}
|
||||
|
||||
t, ok := token.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
switch t {
|
||||
case "failed":
|
||||
raw, err := decoder.Token()
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
response.Failed = int(raw.(float64))
|
||||
case "updates":
|
||||
var updates []events.GroupEvent
|
||||
|
||||
err = decoder.Decode(&updates)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
response.Updates = updates
|
||||
case "ts":
|
||||
// can be a number in the response with "failed" field: {"ts":8,"failed":1}
|
||||
// or string, e.g. {"ts":"8","updates":[]}
|
||||
rawTs, err := decoder.Token()
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
if ts, isNumber := rawTs.(float64); isNumber {
|
||||
response.Ts = strconv.Itoa(int(ts))
|
||||
} else {
|
||||
response.Ts = rawTs.(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response, err
|
||||
}
|
||||
|
||||
func (lp *LongPoll) checkResponse(response Response) (err error) {
|
||||
switch response.Failed {
|
||||
case 0:
|
||||
|
||||
34
vendor/github.com/SevereCloud/vksdk/v2/object/account.go
generated
vendored
34
vendor/github.com/SevereCloud/vksdk/v2/object/account.go
generated
vendored
@@ -62,21 +62,24 @@ type AccountOffer struct {
|
||||
|
||||
// AccountAccountCounters struct.
|
||||
type AccountAccountCounters struct {
|
||||
AppRequests int `json:"app_requests"` // New app requests number
|
||||
Events int `json:"events"` // New events number
|
||||
Friends int `json:"friends"` // New friends requests number
|
||||
FriendsRecommendations int `json:"friends_recommendations"` // New friends recommendations number
|
||||
FriendsSuggestions int `json:"friends_suggestions"` // New friends suggestions number
|
||||
Gifts int `json:"gifts"` // New gifts number
|
||||
Groups int `json:"groups"` // New groups number
|
||||
Messages int `json:"messages"` // New messages number
|
||||
Notifications int `json:"notifications"` // New notifications number
|
||||
Photos int `json:"photos"` // New photo tags number
|
||||
SDK int `json:"sdk"` // New SDK number
|
||||
MenuDiscoverBadge int `json:"menu_discover_badge"` // New menu discover badge number
|
||||
MenuClipsBadge int `json:"menu_clips_badge"` // New menu clips badge number
|
||||
Videos int `json:"videos"` // New video tags number
|
||||
Faves int `json:"faves"` // New faves number
|
||||
AppRequests int `json:"app_requests"` // New app requests number
|
||||
Events int `json:"events"` // New events number
|
||||
Friends int `json:"friends"` // New friends requests number
|
||||
FriendsRecommendations int `json:"friends_recommendations"` // New friends recommendations number
|
||||
FriendsSuggestions int `json:"friends_suggestions"` // New friends suggestions number
|
||||
Gifts int `json:"gifts"` // New gifts number
|
||||
Groups int `json:"groups"` // New groups number
|
||||
Messages int `json:"messages"` // New messages number
|
||||
Notifications int `json:"notifications"` // New notifications number
|
||||
Photos int `json:"photos"` // New photo tags number
|
||||
SDK int `json:"sdk"` // New SDK number
|
||||
MenuDiscoverBadge int `json:"menu_discover_badge"` // New menu discover badge number
|
||||
MenuClipsBadge int `json:"menu_clips_badge"` // New menu clips badge number
|
||||
Videos int `json:"videos"` // New video tags number
|
||||
Faves int `json:"faves"` // New faves number
|
||||
Calls int `json:"calls"` // New calls number
|
||||
MenuSuperappFriendsBadge int `json:"menu_superapp_friends_badge"`
|
||||
MenuNewClipsBadge int `json:"menu_new_clips_badge"`
|
||||
}
|
||||
|
||||
// AccountInfo struct.
|
||||
@@ -107,6 +110,7 @@ type AccountInfo struct {
|
||||
IsLiveStreamingEnabled BaseBoolInt `json:"is_live_streaming_enabled"`
|
||||
IsNewLiveStreamingEnabled BaseBoolInt `json:"is_new_live_streaming_enabled"`
|
||||
LinkRedirects map[string]string `json:"link_redirects"`
|
||||
VkPayEndpointV2 string `json:"vk_pay_endpoint_v2"`
|
||||
}
|
||||
|
||||
// AccountPushSettings struct.
|
||||
|
||||
20
vendor/github.com/SevereCloud/vksdk/v2/object/ads.go
generated
vendored
20
vendor/github.com/SevereCloud/vksdk/v2/object/ads.go
generated
vendored
@@ -8,12 +8,13 @@ type AdsAccesses struct {
|
||||
|
||||
// AdsAccount struct.
|
||||
type AdsAccount struct {
|
||||
AccessRole string `json:"access_role"`
|
||||
AccountID int `json:"account_id"` // Account ID
|
||||
AccountName string `json:"account_name"`
|
||||
AccountStatus BaseBoolInt `json:"account_status"` // Information whether account is active
|
||||
CanViewBudget BaseBoolInt `json:"can_view_budget"`
|
||||
AccountType string `json:"account_type"`
|
||||
AccessRole string `json:"access_role"`
|
||||
AccountID int `json:"account_id"` // Account ID
|
||||
AccountName string `json:"account_name"`
|
||||
AccountStatus BaseBoolInt `json:"account_status"` // Information whether account is active
|
||||
CanViewBudget BaseBoolInt `json:"can_view_budget"`
|
||||
AdNetworkAllowedPotentially BaseBoolInt `json:"ad_network_allowed_potentially"`
|
||||
AccountType string `json:"account_type"`
|
||||
}
|
||||
|
||||
// AdsAdLayout struct.
|
||||
@@ -318,3 +319,10 @@ type AdsPromotedPostReach struct {
|
||||
VideoViews75p int `json:"video_views_75p"` // Video views for 75 percent
|
||||
VideoViewsStart int `json:"video_views_start"` // Video starts
|
||||
}
|
||||
|
||||
// AdsMusician struct.
|
||||
type AdsMusician struct {
|
||||
ID int `json:"id"` // Targeting music artist ID
|
||||
Name string `json:"name"` // Music artist name
|
||||
Avatar string `json:"avatar,omitempty"` // Music artist photo.
|
||||
}
|
||||
|
||||
3
vendor/github.com/SevereCloud/vksdk/v2/object/apps.go
generated
vendored
3
vendor/github.com/SevereCloud/vksdk/v2/object/apps.go
generated
vendored
@@ -60,6 +60,7 @@ type AppsApp struct {
|
||||
IsNew BaseBoolInt `json:"is_new"`
|
||||
New BaseBoolInt `json:"new"`
|
||||
IsInstalled BaseBoolInt `json:"is_installed"`
|
||||
HasVkConnect BaseBoolInt `json:"has_vk_connect"`
|
||||
LeaderboardType int `json:"leaderboard_type"`
|
||||
MembersCount int `json:"members_count"` // Members number
|
||||
PlatformID int `json:"platform_id"` // Application ID in store
|
||||
@@ -78,7 +79,7 @@ type AppsApp struct {
|
||||
|
||||
// mobile_controls_type = 0 - прозрачный элемент управления поверх области с игрой;
|
||||
// mobile_controls_type = 1 - чёрная полоска над областью с игрой;
|
||||
// mobile_controls_type = 2 - только для vk apps, без контроллов.
|
||||
// mobile_controls_type = 2 - только для vk apps, без элементов управления'.
|
||||
MobileControlsType int `json:"mobile_controls_type"`
|
||||
|
||||
// mobile_view_support_type = 0 - игра не использует нижнюю часть экрана на iPhoneX, черная полоса есть.
|
||||
|
||||
17
vendor/github.com/SevereCloud/vksdk/v2/object/auth.go
generated
vendored
Normal file
17
vendor/github.com/SevereCloud/vksdk/v2/object/auth.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package object // import "github.com/SevereCloud/vksdk/v2/object"
|
||||
|
||||
// AuthSilentTokenProfile struct.
|
||||
type AuthSilentTokenProfile struct {
|
||||
Token string `json:"token"`
|
||||
Expires int `json:"expires"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Photo50 string `json:"photo_50"`
|
||||
Photo100 string `json:"photo_100"`
|
||||
Photo200 string `json:"photo_200"`
|
||||
Phone string `json:"phone"`
|
||||
PhoneValidated interface{} `json:"phone_validated"` // int | bool
|
||||
UserID int `json:"user_id"`
|
||||
IsPartial BaseBoolInt `json:"is_partial"`
|
||||
IsService BaseBoolInt `json:"is_service"`
|
||||
}
|
||||
6
vendor/github.com/SevereCloud/vksdk/v2/object/database.go
generated
vendored
6
vendor/github.com/SevereCloud/vksdk/v2/object/database.go
generated
vendored
@@ -4,9 +4,9 @@ package object // import "github.com/SevereCloud/vksdk/v2/object"
|
||||
type DatabaseCity struct {
|
||||
ID int `json:"id"` // City ID
|
||||
Title string `json:"title"` // City title
|
||||
Area string `json:"area"`
|
||||
Region string `json:"region"`
|
||||
Important BaseBoolInt `json:"important"`
|
||||
Area string `json:"area,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
Important BaseBoolInt `json:"important,omitempty"`
|
||||
}
|
||||
|
||||
// DatabaseMetroStation struct.
|
||||
|
||||
325
vendor/github.com/SevereCloud/vksdk/v2/object/groups.go
generated
vendored
325
vendor/github.com/SevereCloud/vksdk/v2/object/groups.go
generated
vendored
@@ -1,9 +1,13 @@
|
||||
package object // import "github.com/SevereCloud/vksdk/v2/object"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
// GroupsAddress WorkInfoStatus of information about timetable.
|
||||
@@ -110,112 +114,113 @@ const (
|
||||
|
||||
// GroupsGroup struct.
|
||||
type GroupsGroup struct {
|
||||
AdminLevel int `json:"admin_level"`
|
||||
Deactivated string `json:"deactivated"` // Information whether community is banned
|
||||
FinishDate int `json:"finish_date"` // Finish date in Unixtime format
|
||||
ID int `json:"id"` // Community ID
|
||||
Name string `json:"name"` // Community name
|
||||
Photo100 string `json:"photo_100"` // URL of square photo of the community with 100 pixels in width
|
||||
Photo200 string `json:"photo_200"` // URL of square photo of the community with 200 pixels in width
|
||||
Photo50 string `json:"photo_50"` // URL of square photo of the community with 50 pixels in width
|
||||
ScreenName string `json:"screen_name"` // Domain of the community page
|
||||
StartDate int `json:"start_date"` // Start date in Unixtime format
|
||||
Type string `json:"type"`
|
||||
Market GroupsMarketInfo `json:"market"`
|
||||
MemberStatus int `json:"member_status"` // Current user's member status
|
||||
IsClosed int `json:"is_closed"`
|
||||
City BaseObject `json:"city"`
|
||||
Country BaseCountry `json:"country"`
|
||||
AdminLevel int `json:"admin_level,omitempty"`
|
||||
Deactivated string `json:"deactivated,omitempty"` // Information whether community is banned
|
||||
FinishDate int `json:"finish_date,omitempty"` // Finish date in Unixtime format
|
||||
Photo100 string `json:"photo_100,omitempty"` // URL of square photo of the community with 100 pixels in width
|
||||
Photo200 string `json:"photo_200,omitempty"` // URL of square photo of the community with 200 pixels in width
|
||||
Photo50 string `json:"photo_50,omitempty"` // URL of square photo of the community with 50 pixels in width
|
||||
StartDate int `json:"start_date,omitempty"` // Start date in Unixtime format
|
||||
Market GroupsMarketInfo `json:"market,omitempty"`
|
||||
MemberStatus int `json:"member_status,omitempty"` // Current user's member status
|
||||
City BaseObject `json:"city,omitempty"`
|
||||
Country BaseCountry `json:"country,omitempty"`
|
||||
|
||||
// Information whether current user is administrator.
|
||||
IsAdmin BaseBoolInt `json:"is_admin"`
|
||||
|
||||
// Information whether current user is advertiser.
|
||||
IsAdvertiser BaseBoolInt `json:"is_advertiser"`
|
||||
IsAdvertiser BaseBoolInt `json:"is_advertiser,omitempty"`
|
||||
|
||||
// Information whether current user is member.
|
||||
IsMember BaseBoolInt `json:"is_member"`
|
||||
IsMember BaseBoolInt `json:"is_member,omitempty"`
|
||||
|
||||
// Information whether community is in faves.
|
||||
IsFavorite BaseBoolInt `json:"is_favorite"`
|
||||
IsFavorite BaseBoolInt `json:"is_favorite,omitempty"`
|
||||
|
||||
// Information whether community is adult.
|
||||
IsAdult BaseBoolInt `json:"is_adult"`
|
||||
IsAdult BaseBoolInt `json:"is_adult,omitempty"`
|
||||
|
||||
// Information whether current user is subscribed.
|
||||
IsSubscribed BaseBoolInt `json:"is_subscribed"`
|
||||
IsSubscribed BaseBoolInt `json:"is_subscribed,omitempty"`
|
||||
|
||||
// Information whether current user can post on community's wall.
|
||||
CanPost BaseBoolInt `json:"can_post"`
|
||||
CanPost BaseBoolInt `json:"can_post,omitempty"`
|
||||
|
||||
// Information whether current user can see all posts on community's wall.
|
||||
CanSeeAllPosts BaseBoolInt `json:"can_see_all_posts"`
|
||||
CanSeeAllPosts BaseBoolInt `json:"can_see_all_posts,omitempty"`
|
||||
|
||||
// Information whether current user can create topic.
|
||||
CanCreateTopic BaseBoolInt `json:"can_create_topic"`
|
||||
CanCreateTopic BaseBoolInt `json:"can_create_topic,omitempty"`
|
||||
|
||||
// Information whether current user can upload video.
|
||||
CanUploadVideo BaseBoolInt `json:"can_upload_video"`
|
||||
CanUploadVideo BaseBoolInt `json:"can_upload_video,omitempty"`
|
||||
|
||||
// Information whether current user can upload doc.
|
||||
CanUploadDoc BaseBoolInt `json:"can_upload_doc"`
|
||||
CanUploadDoc BaseBoolInt `json:"can_upload_doc,omitempty"`
|
||||
|
||||
// Information whether community has photo.
|
||||
HasPhoto BaseBoolInt `json:"has_photo"`
|
||||
HasPhoto BaseBoolInt `json:"has_photo,omitempty"`
|
||||
|
||||
// Information whether current user can send a message to community.
|
||||
CanMessage BaseBoolInt `json:"can_message"`
|
||||
CanMessage BaseBoolInt `json:"can_message,omitempty"`
|
||||
|
||||
// Information whether community can send a message to current user.
|
||||
IsMessagesBlocked BaseBoolInt `json:"is_messages_blocked"`
|
||||
IsMessagesBlocked BaseBoolInt `json:"is_messages_blocked,omitempty"`
|
||||
|
||||
// Information whether community can send notifications by phone number to current user.
|
||||
CanSendNotify BaseBoolInt `json:"can_send_notify"`
|
||||
CanSendNotify BaseBoolInt `json:"can_send_notify,omitempty"`
|
||||
|
||||
// Information whether current user is subscribed to podcasts.
|
||||
IsSubscribedPodcasts BaseBoolInt `json:"is_subscribed_podcasts"`
|
||||
IsSubscribedPodcasts BaseBoolInt `json:"is_subscribed_podcasts,omitempty"`
|
||||
|
||||
// Owner in whitelist or not.
|
||||
CanSubscribePodcasts BaseBoolInt `json:"can_subscribe_podcasts"`
|
||||
CanSubscribePodcasts BaseBoolInt `json:"can_subscribe_podcasts,omitempty"`
|
||||
|
||||
// Can subscribe to wall.
|
||||
CanSubscribePosts BaseBoolInt `json:"can_subscribe_posts"`
|
||||
CanSubscribePosts BaseBoolInt `json:"can_subscribe_posts,omitempty"`
|
||||
|
||||
// Information whether community has market app.
|
||||
HasMarketApp BaseBoolInt `json:"has_market_app"`
|
||||
IsHiddenFromFeed BaseBoolInt `json:"is_hidden_from_feed"`
|
||||
IsMarketCartEnabled BaseBoolInt `json:"is_market_cart_enabled"`
|
||||
Verified BaseBoolInt `json:"verified"` // Information whether community is verified
|
||||
HasMarketApp BaseBoolInt `json:"has_market_app,omitempty"`
|
||||
IsHiddenFromFeed BaseBoolInt `json:"is_hidden_from_feed,omitempty"`
|
||||
IsMarketCartEnabled BaseBoolInt `json:"is_market_cart_enabled,omitempty"`
|
||||
Verified BaseBoolInt `json:"verified,omitempty"` // Information whether community is verified
|
||||
|
||||
// Information whether the community has a fire pictogram.
|
||||
Trending BaseBoolInt `json:"trending"`
|
||||
Description string `json:"description"` // Community description
|
||||
WikiPage string `json:"wiki_page"` // Community's main wiki page title
|
||||
MembersCount int `json:"members_count"` // Community members number
|
||||
Counters GroupsCountersGroup `json:"counters"`
|
||||
Cover GroupsCover `json:"cover"`
|
||||
Trending BaseBoolInt `json:"trending,omitempty"`
|
||||
Description string `json:"description,omitempty"` // Community description
|
||||
WikiPage string `json:"wiki_page,omitempty"` // Community's main wiki page title
|
||||
MembersCount int `json:"members_count,omitempty"` // Community members number
|
||||
Counters GroupsCountersGroup `json:"counters,omitempty"`
|
||||
Cover GroupsCover `json:"cover,omitempty"`
|
||||
|
||||
// Type of group, start date of event or category of public page.
|
||||
Activity string `json:"activity"`
|
||||
FixedPost int `json:"fixed_post"` // Fixed post ID
|
||||
Status string `json:"status"` // Community status
|
||||
MainAlbumID int `json:"main_album_id"` // Community's main photo album ID
|
||||
Links []GroupsLinksItem `json:"links"`
|
||||
Contacts []GroupsContactsItem `json:"contacts"`
|
||||
Site string `json:"site"` // Community's website
|
||||
MainSection int `json:"main_section"`
|
||||
OnlineStatus GroupsOnlineStatus `json:"online_status"` // Status of replies in community messages
|
||||
AgeLimits int `json:"age_limits"` // Information whether age limit
|
||||
BanInfo GroupsGroupBanInfo `json:"ban_info"` // User ban info
|
||||
Addresses GroupsAddressesInfo `json:"addresses"` // Info about addresses in Groups
|
||||
LiveCovers GroupsLiveCovers `json:"live_covers"`
|
||||
CropPhoto UsersCropPhoto `json:"crop_photo"`
|
||||
Wall int `json:"wall"`
|
||||
ActionButton GroupsActionButton `json:"action_button"`
|
||||
TrackCode string `json:"track_code"`
|
||||
PublicDateLabel string `json:"public_date_label"`
|
||||
AuthorID int `json:"author_id"`
|
||||
Phone string `json:"phone"`
|
||||
Activity string `json:"activity,omitempty"`
|
||||
FixedPost int `json:"fixed_post,omitempty"` // Fixed post ID
|
||||
Status string `json:"status,omitempty"` // Community status
|
||||
MainAlbumID int `json:"main_album_id,omitempty"` // Community's main photo album ID
|
||||
Links []GroupsLinksItem `json:"links,omitempty"`
|
||||
Contacts []GroupsContactsItem `json:"contacts,omitempty"`
|
||||
Site string `json:"site,omitempty"` // Community's website
|
||||
MainSection int `json:"main_section,omitempty"`
|
||||
OnlineStatus GroupsOnlineStatus `json:"online_status,omitempty"` // Status of replies in community messages
|
||||
AgeLimits int `json:"age_limits,omitempty"` // Information whether age limit
|
||||
BanInfo GroupsGroupBanInfo `json:"ban_info,omitempty"` // User ban info
|
||||
Addresses GroupsAddressesInfo `json:"addresses,omitempty"` // Info about addresses in Groups
|
||||
LiveCovers GroupsLiveCovers `json:"live_covers,omitempty"`
|
||||
CropPhoto UsersCropPhoto `json:"crop_photo,omitempty"`
|
||||
Wall int `json:"wall,omitempty"`
|
||||
ActionButton GroupsActionButton `json:"action_button,omitempty"`
|
||||
TrackCode string `json:"track_code,omitempty"`
|
||||
PublicDateLabel string `json:"public_date_label,omitempty"`
|
||||
AuthorID int `json:"author_id,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
Like GroupsGroupLike `json:"like"`
|
||||
}
|
||||
|
||||
// ToMention return mention.
|
||||
@@ -223,6 +228,18 @@ func (group GroupsGroup) ToMention() string {
|
||||
return fmt.Sprintf("[club%d|%s]", group.ID, group.Name)
|
||||
}
|
||||
|
||||
// GroupsGroupLike struct.
|
||||
type GroupsGroupLike struct {
|
||||
IsLiked BaseBoolInt `json:"is_liked"`
|
||||
Friends GroupsGroupLikeFriends `json:"friends"`
|
||||
}
|
||||
|
||||
// GroupsGroupLikeFriends struct.
|
||||
type GroupsGroupLikeFriends struct {
|
||||
Count int `json:"count"`
|
||||
Preview []int `json:"preview"`
|
||||
}
|
||||
|
||||
// GroupsLiveCovers struct.
|
||||
type GroupsLiveCovers struct {
|
||||
IsEnabled BaseBoolInt `json:"is_enabled"`
|
||||
@@ -275,16 +292,70 @@ type GroupsContactsItem struct {
|
||||
|
||||
// GroupsCountersGroup struct.
|
||||
type GroupsCountersGroup struct {
|
||||
Addresses int `json:"addresses"` // Addresses number
|
||||
Albums int `json:"albums"` // Photo albums number
|
||||
Articles int `json:"articles"` // Articles number
|
||||
Audios int `json:"audios"` // Audios number
|
||||
Docs int `json:"docs"` // Docs number
|
||||
Market int `json:"market"` // Market items number
|
||||
Photos int `json:"photos"` // Photos number
|
||||
Topics int `json:"topics"` // Topics number
|
||||
Videos int `json:"videos"` // Videos number
|
||||
Narratives int `json:"narratives"` // Narratives number
|
||||
Addresses int `json:"addresses"` // Addresses number
|
||||
Albums int `json:"albums"` // Photo albums number
|
||||
Articles int `json:"articles"` // Articles number
|
||||
Audios int `json:"audios"` // Audios number
|
||||
Docs int `json:"docs"` // Docs number
|
||||
Market int `json:"market"` // Market items number
|
||||
Photos int `json:"photos"` // Photos number
|
||||
Topics int `json:"topics"` // Topics number
|
||||
Videos int `json:"videos"` // Videos number
|
||||
Narratives int `json:"narratives"` // Narratives number
|
||||
Clips int `json:"clips"` // Clips number
|
||||
ClipsFollowers int `json:"clips_followers"` // Clips followers number
|
||||
}
|
||||
|
||||
// UnmarshalJSON GroupsCountersGroup.
|
||||
//
|
||||
// BUG(VK): GroupsCountersGroup return [].
|
||||
func (personal *GroupsCountersGroup) UnmarshalJSON(data []byte) error {
|
||||
if bytes.Equal(data, []byte("[]")) {
|
||||
return nil
|
||||
}
|
||||
|
||||
type renamedGroupsCountersGroup GroupsCountersGroup
|
||||
|
||||
var r renamedGroupsCountersGroup
|
||||
|
||||
err := json.Unmarshal(data, &r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*personal = GroupsCountersGroup(r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeMsgpack GroupsCountersGroup.
|
||||
//
|
||||
// BUG(VK): GroupsCountersGroup return [].
|
||||
func (personal *GroupsCountersGroup) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
data, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Equal(data, []byte{msgpcode.FixedArrayLow}) {
|
||||
return nil
|
||||
}
|
||||
|
||||
type renamedGroupsCountersGroup GroupsCountersGroup
|
||||
|
||||
var r renamedGroupsCountersGroup
|
||||
|
||||
d := msgpack.NewDecoder(bytes.NewReader(data))
|
||||
d.SetCustomStructTag("json")
|
||||
|
||||
err = d.Decode(&r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*personal = GroupsCountersGroup(r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GroupsCover struct.
|
||||
@@ -479,6 +550,70 @@ type GroupsGroupSettings struct {
|
||||
SecondarySection int `json:"secondary_section"`
|
||||
ActionButton GroupsActionButton `json:"action_button"`
|
||||
Phone string `json:"phone"`
|
||||
|
||||
RecognizePhoto int `json:"recognize_photo"`
|
||||
|
||||
MarketServices GroupsMarketServices `json:"market_services"`
|
||||
Narratives int `json:"narratives"`
|
||||
Clips int `json:"clips"`
|
||||
Textlives int `json:"textlives"`
|
||||
Youla GroupsYoula `json:"youla"`
|
||||
}
|
||||
|
||||
// GroupsMarketServices struct.
|
||||
type GroupsMarketServices struct {
|
||||
Enabled BaseBoolInt `json:"enabled"`
|
||||
CanMessage BaseBoolInt `json:"can_message"`
|
||||
CommentsEnabled BaseBoolInt `json:"comments_enabled"`
|
||||
ContactID int `json:"contact_id"`
|
||||
Currency MarketCurrency `json:"currency"`
|
||||
ViewType GroupsSelectedItems `json:"view_type"`
|
||||
BlockName GroupsSelectedItems `json:"block_name"`
|
||||
ButtonLabel GroupsSelectedItems `json:"button_label"`
|
||||
}
|
||||
|
||||
// GroupsSelectedItems struct.
|
||||
type GroupsSelectedItems struct {
|
||||
SelectedItemID int64 `json:"selected_item_id"`
|
||||
Items []BaseObjectWithName `json:"items"`
|
||||
}
|
||||
|
||||
// GroupsYoula struct.
|
||||
type GroupsYoula struct {
|
||||
CategoryTree GroupsYoulaCategory `json:"category_tree"`
|
||||
GroupSettings GroupsYoulaSettings `json:"group_settings"`
|
||||
}
|
||||
|
||||
// GroupsYoulaCategory struct.
|
||||
type GroupsYoulaCategory struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Subcategories []GroupsYoulaSubcategory `json:"subcategories"`
|
||||
}
|
||||
|
||||
// GroupsYoulaSubcategory struct.
|
||||
type GroupsYoulaSubcategory struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
ParentID int `json:"parent_id"`
|
||||
Subcategories []GroupsYoulaSubcategory `json:"subcategories"`
|
||||
}
|
||||
|
||||
// GroupsYoulaSettings struct.
|
||||
type GroupsYoulaSettings struct {
|
||||
IsActive BaseBoolInt `json:"is_active"`
|
||||
IsModerated BaseBoolInt `json:"is_moderated"`
|
||||
ShowModerationSetting BaseBoolInt `json:"show_moderation_setting"`
|
||||
ModerationStatus int `json:"moderation_status"`
|
||||
DeclineReason string `json:"decline_reason"`
|
||||
GroupMode int `json:"group_mode"`
|
||||
SelectedCategoryIDS []int `json:"selected_category_ids"`
|
||||
Lat float64 `json:"lat"`
|
||||
Long float64 `json:"long"`
|
||||
Radius float64 `json:"radius"`
|
||||
RadiusArea string `json:"radius_area"`
|
||||
Address string `json:"address"`
|
||||
Radiuses []float64 `json:"radiuses"`
|
||||
}
|
||||
|
||||
// GroupsSectionsList struct.
|
||||
@@ -532,6 +667,53 @@ func (g *GroupsSectionsList) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeMsgpack need for decode dynamic array (Example: [1, "Фотографии"]) to struct.
|
||||
func (g *GroupsSectionsList) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
data, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var alias []interface{}
|
||||
|
||||
err = msgpack.Unmarshal(data, &alias)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(alias) != 2 {
|
||||
return &json.UnmarshalTypeError{
|
||||
Value: string(data),
|
||||
Type: reflect.TypeOf((*GroupsSectionsList)(nil)),
|
||||
}
|
||||
}
|
||||
|
||||
id, ok := alias[0].(int8)
|
||||
if !ok {
|
||||
return &json.UnmarshalTypeError{
|
||||
Value: string(data),
|
||||
Type: reflect.TypeOf((*GroupsSectionsList)(nil)),
|
||||
Struct: "GroupsSectionsList",
|
||||
Field: "ID",
|
||||
}
|
||||
}
|
||||
|
||||
name, ok := alias[1].(string)
|
||||
if !ok {
|
||||
return &json.UnmarshalTypeError{
|
||||
Value: string(data),
|
||||
Type: reflect.TypeOf((*GroupsSectionsList)(nil)),
|
||||
Struct: "GroupsSectionsList",
|
||||
Field: "Name",
|
||||
}
|
||||
}
|
||||
|
||||
g.ID = int(id)
|
||||
g.Name = name
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GroupsActionType for action_button in groups.
|
||||
type GroupsActionType string
|
||||
|
||||
@@ -685,7 +867,10 @@ type GroupsLongPollServer struct {
|
||||
Ts string `json:"ts"` // Number of the last event
|
||||
}
|
||||
|
||||
// TODO: func (g GroupsLongPollServer) GetURL() string {
|
||||
// GetURL return link.
|
||||
func (lp GroupsLongPollServer) GetURL(wait int) string {
|
||||
return fmt.Sprintf("%s?act=a_check&key=%s&ts=%s&wait=%d", lp.Server, lp.Key, lp.Ts, wait)
|
||||
}
|
||||
|
||||
// GroupsLongPollSettings struct.
|
||||
type GroupsLongPollSettings struct {
|
||||
@@ -714,12 +899,14 @@ type GroupsMarketInfo struct {
|
||||
Enabled BaseBoolInt `json:"enabled"` // Information whether the market is enabled
|
||||
CommentsEnabled BaseBoolInt `json:"comments_enabled,omitempty"`
|
||||
CanMessage BaseBoolInt `json:"can_message,omitempty"`
|
||||
IsHsEnabled BaseBoolInt `json:"is_hs_enabled,omitempty"`
|
||||
MainAlbumID int `json:"main_album_id,omitempty"` // Main market album ID
|
||||
PriceMax string `json:"price_max,omitempty"` // Maximum price
|
||||
PriceMin string `json:"price_min,omitempty"` // Minimum price
|
||||
Wiki PagesWikipageFull `json:"wiki,omitempty"`
|
||||
CityIDs []int `json:"city_ids"`
|
||||
CountryIDs []int `json:"country_ids,omitempty"`
|
||||
MinOrderPrice MarketPrice `json:"min_order_price,omitempty"`
|
||||
}
|
||||
|
||||
// GroupsGroupRole Role type.
|
||||
|
||||
65
vendor/github.com/SevereCloud/vksdk/v2/object/market.go
generated
vendored
65
vendor/github.com/SevereCloud/vksdk/v2/object/market.go
generated
vendored
@@ -4,6 +4,9 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
// Information whether the MarketMarketItem is available.
|
||||
@@ -28,6 +31,8 @@ type MarketMarketAlbum struct {
|
||||
Photo PhotosPhoto `json:"photo"`
|
||||
Title string `json:"title"` // Market album title
|
||||
UpdatedTime int `json:"updated_time"` // Date when album has been updated last time in Unixtime
|
||||
IsMain BaseBoolInt `json:"is_main"`
|
||||
IsHidden BaseBoolInt `json:"is_hidden"`
|
||||
}
|
||||
|
||||
// ToAttachment return attachment format.
|
||||
@@ -98,6 +103,36 @@ func (market *MarketMarketItem) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeMsgpack MarketMarketItem.
|
||||
//
|
||||
// BUG(VK): https://github.com/SevereCloud/vksdk/issues/147
|
||||
func (market *MarketMarketItem) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
data, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Equal(data, []byte{msgpcode.False}) {
|
||||
return nil
|
||||
}
|
||||
|
||||
type renamedMarketMarketItem MarketMarketItem
|
||||
|
||||
var r renamedMarketMarketItem
|
||||
|
||||
d := msgpack.NewDecoder(bytes.NewReader(data))
|
||||
d.SetCustomStructTag("json")
|
||||
|
||||
err = d.Decode(&r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*market = MarketMarketItem(r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarketMarketItemProperty struct.
|
||||
type MarketMarketItemProperty struct {
|
||||
VariantID int `json:"variant_id"`
|
||||
@@ -149,6 +184,36 @@ func (m *MarketPrice) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeMsgpack MarketPrice.
|
||||
//
|
||||
// BUG(VK): unavailable product, in fave.get return [].
|
||||
func (m *MarketPrice) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
data, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Equal(data, []byte{msgpcode.FixedArrayLow}) {
|
||||
return nil
|
||||
}
|
||||
|
||||
type renamedMarketPrice MarketPrice
|
||||
|
||||
var r renamedMarketPrice
|
||||
|
||||
d := msgpack.NewDecoder(bytes.NewReader(data))
|
||||
d.SetCustomStructTag("json")
|
||||
|
||||
err = d.Decode(&r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*m = MarketPrice(r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarketSection struct.
|
||||
type MarketSection struct {
|
||||
ID int `json:"id"` // Section ID
|
||||
|
||||
52
vendor/github.com/SevereCloud/vksdk/v2/object/marusia.go
generated
vendored
Normal file
52
vendor/github.com/SevereCloud/vksdk/v2/object/marusia.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package object // import "github.com/SevereCloud/vksdk/v2/object"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// MarusiaPicture struct.
|
||||
type MarusiaPicture struct {
|
||||
ID int `json:"id"`
|
||||
OwnerID int `json:"owner_id"`
|
||||
}
|
||||
|
||||
// MarusiaPictureUploadResponse struct.
|
||||
type MarusiaPictureUploadResponse struct {
|
||||
Hash string `json:"hash"` // Uploading hash
|
||||
Photo json.RawMessage `json:"photo"` // Uploaded photo data
|
||||
Server int `json:"server"` // Upload server number
|
||||
AID int `json:"aid"`
|
||||
MessageCode int `json:"message_code"`
|
||||
}
|
||||
|
||||
// MarusiaAudio struct.
|
||||
type MarusiaAudio struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
OwnerID int `json:"owner_id"`
|
||||
}
|
||||
|
||||
// MarusiaAudioUploadResponse struct.
|
||||
type MarusiaAudioUploadResponse struct {
|
||||
Sha string `json:"sha"`
|
||||
Secret string `json:"secret"`
|
||||
Meta MarusiaAudioMeta `json:"meta"`
|
||||
Hash string `json:"hash"`
|
||||
Server string `json:"server"`
|
||||
UserID int `json:"user_id"`
|
||||
RequestID string `json:"request_id"`
|
||||
}
|
||||
|
||||
// MarusiaAudioMeta struct.
|
||||
type MarusiaAudioMeta struct {
|
||||
Album string `json:"album"`
|
||||
Artist string `json:"artist"`
|
||||
Bitrate string `json:"bitrate"`
|
||||
Duration string `json:"duration"`
|
||||
Genre string `json:"genre"`
|
||||
Kad string `json:"kad"`
|
||||
Md5 string `json:"md5"`
|
||||
Md5DataSize string `json:"md5_data_size"`
|
||||
Samplerate string `json:"samplerate"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
53
vendor/github.com/SevereCloud/vksdk/v2/object/messages.go
generated
vendored
53
vendor/github.com/SevereCloud/vksdk/v2/object/messages.go
generated
vendored
@@ -79,6 +79,7 @@ type MessagesMessage struct {
|
||||
UpdateTime int `json:"update_time"` // Date when the message has been updated in Unixtime
|
||||
MembersCount int `json:"members_count"` // Members number
|
||||
ExpireTTL int `json:"expire_ttl"`
|
||||
MessageTag string `json:"message_tag"` // for https://notify.mail.ru/
|
||||
}
|
||||
|
||||
// MessagesBasePayload struct.
|
||||
@@ -375,17 +376,18 @@ type MessagesTemplateElement struct {
|
||||
|
||||
// MessagesTemplateElementCarousel struct.
|
||||
type MessagesTemplateElementCarousel struct {
|
||||
Title string `json:"title"`
|
||||
Action MessagesTemplateElementCarouselAction `json:"action"`
|
||||
Description string `json:"description"`
|
||||
Photo PhotosPhoto `json:"photo"`
|
||||
Buttons []MessagesKeyboardButton `json:"buttons"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Action MessagesTemplateElementCarouselAction `json:"action,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Photo *PhotosPhoto `json:"photo,omitempty"` // Only read
|
||||
PhotoID string `json:"photo_id,omitempty"` // Only for send
|
||||
Buttons []MessagesKeyboardButton `json:"buttons,omitempty"`
|
||||
}
|
||||
|
||||
// MessagesTemplateElementCarouselAction struct.
|
||||
type MessagesTemplateElementCarouselAction struct {
|
||||
Type string `json:"type"`
|
||||
Link string `json:"link"`
|
||||
Link string `json:"link,omitempty"`
|
||||
}
|
||||
|
||||
// MessageContentSourceMessage ...
|
||||
@@ -443,6 +445,7 @@ type MessagesChat struct {
|
||||
AdminID int `json:"admin_id"` // Chat creator ID
|
||||
ID int `json:"id"` // Chat ID
|
||||
IsDefaultPhoto BaseBoolInt `json:"is_default_photo"`
|
||||
IsGroupChannel BaseBoolInt `json:"is_group_channel"`
|
||||
Photo100 string `json:"photo_100"` // URL of the preview image with 100 px in width
|
||||
Photo200 string `json:"photo_200"` // URL of the preview image with 200 px in width
|
||||
Photo50 string `json:"photo_50"` // URL of the preview image with 50 px in width
|
||||
@@ -473,20 +476,24 @@ type MessagesChatPushSettings struct {
|
||||
|
||||
// MessagesChatSettingsPhoto struct.
|
||||
type MessagesChatSettingsPhoto struct {
|
||||
Photo100 string `json:"photo_100"`
|
||||
Photo200 string `json:"photo_200"`
|
||||
Photo50 string `json:"photo_50"`
|
||||
IsDefaultPhoto BaseBoolInt `json:"is_default_photo"`
|
||||
Photo100 string `json:"photo_100"`
|
||||
Photo200 string `json:"photo_200"`
|
||||
Photo50 string `json:"photo_50"`
|
||||
IsDefaultPhoto BaseBoolInt `json:"is_default_photo"`
|
||||
IsDefaultCallPhoto bool `json:"is_default_call_photo"`
|
||||
}
|
||||
|
||||
// MessagesConversation struct.
|
||||
type MessagesConversation struct {
|
||||
CanWrite MessagesConversationCanWrite `json:"can_write"`
|
||||
ChatSettings MessagesConversationChatSettings `json:"chat_settings"`
|
||||
InRead int `json:"in_read"` // Last message user have read
|
||||
LastMessageID int `json:"last_message_id"` // ID of the last message in conversation
|
||||
Mentions []int `json:"mentions"` // IDs of messages with mentions
|
||||
MessageRequest string `json:"message_request"`
|
||||
CanWrite MessagesConversationCanWrite `json:"can_write"`
|
||||
ChatSettings MessagesConversationChatSettings `json:"chat_settings"`
|
||||
InRead int `json:"in_read"` // Last message user have read
|
||||
LastMessageID int `json:"last_message_id"` // ID of the last message in conversation
|
||||
Mentions []int `json:"mentions"` // IDs of messages with mentions
|
||||
MessageRequest string `json:"message_request"`
|
||||
LastConversationMessageID int `json:"last_conversation_message_id"`
|
||||
InReadCMID int `json:"in_read_cmid"`
|
||||
OutReadCMID int `json:"out_read_cmid"`
|
||||
|
||||
// Last outcoming message have been read by the opponent.
|
||||
OutRead int `json:"out_read"`
|
||||
@@ -495,6 +502,10 @@ type MessagesConversation struct {
|
||||
Important BaseBoolInt `json:"important"`
|
||||
Unanswered BaseBoolInt `json:"unanswered"`
|
||||
IsMarkedUnread BaseBoolInt `json:"is_marked_unread"`
|
||||
CanSendMoney BaseBoolInt `json:"can_send_money"`
|
||||
CanReceiveMoney BaseBoolInt `json:"can_receive_money"`
|
||||
IsNew BaseBoolInt `json:"is_new"`
|
||||
IsArchived BaseBoolInt `json:"is_archived"`
|
||||
UnreadCount int `json:"unread_count"` // Unread messages number
|
||||
CurrentKeyboard MessagesKeyboard `json:"current_keyboard"`
|
||||
SortID struct {
|
||||
@@ -530,6 +541,7 @@ type MessagesConversationChatSettings struct {
|
||||
CanCall BaseBoolInt `json:"can_call"`
|
||||
CanUseMassMentions BaseBoolInt `json:"can_use_mass_mentions"`
|
||||
CanChangeServiceType BaseBoolInt `json:"can_change_service_type"`
|
||||
CanChangeStyle BaseBoolInt `json:"can_change_style"`
|
||||
} `json:"acl"`
|
||||
IsGroupChannel BaseBoolInt `json:"is_group_channel"`
|
||||
IsDisappearing BaseBoolInt `json:"is_disappearing"`
|
||||
@@ -559,6 +571,7 @@ type MessagesChatPermissions struct {
|
||||
SeeInviteLink MessagesChatPermission `json:"see_invite_link"`
|
||||
Call MessagesChatPermission `json:"call"`
|
||||
ChangeAdmins MessagesChatPermission `json:"change_admins"`
|
||||
ChangeStyle MessagesChatPermission `json:"change_style"`
|
||||
}
|
||||
|
||||
// MessagesConversationPeer struct.
|
||||
@@ -570,9 +583,11 @@ type MessagesConversationPeer struct {
|
||||
|
||||
// MessagesConversationPushSettings struct.
|
||||
type MessagesConversationPushSettings struct {
|
||||
DisabledUntil int `json:"disabled_until"`
|
||||
DisabledForever BaseBoolInt `json:"disabled_forever"`
|
||||
NoSound BaseBoolInt `json:"no_sound"`
|
||||
DisabledUntil int `json:"disabled_until"`
|
||||
DisabledForever BaseBoolInt `json:"disabled_forever"`
|
||||
NoSound BaseBoolInt `json:"no_sound"`
|
||||
DisabledMentions BaseBoolInt `json:"disabled_mentions"`
|
||||
DisabledMassMentions BaseBoolInt `json:"disabled_mass_mentions"`
|
||||
}
|
||||
|
||||
// MessagesConversationWithMessage struct.
|
||||
|
||||
6
vendor/github.com/SevereCloud/vksdk/v2/object/notifications.go
generated
vendored
6
vendor/github.com/SevereCloud/vksdk/v2/object/notifications.go
generated
vendored
@@ -1,7 +1,5 @@
|
||||
package object // import "github.com/SevereCloud/vksdk/v2/object"
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// NotificationsFeedback struct.
|
||||
type NotificationsFeedback struct {
|
||||
Attachments []WallWallpostAttachment `json:"attachments"`
|
||||
@@ -16,8 +14,8 @@ type NotificationsFeedback struct {
|
||||
// NotificationsNotification struct.
|
||||
type NotificationsNotification struct {
|
||||
Date int `json:"date"` // Date when the event has been occurred
|
||||
Feedback json.RawMessage `json:"feedback"`
|
||||
Parent json.RawMessage `json:"parent"`
|
||||
Feedback RawMessage `json:"feedback"`
|
||||
Parent RawMessage `json:"parent"`
|
||||
Reply NotificationsReply `json:"reply"`
|
||||
Type string `json:"type"` // Notification type
|
||||
}
|
||||
|
||||
71
vendor/github.com/SevereCloud/vksdk/v2/object/object.go
generated
vendored
71
vendor/github.com/SevereCloud/vksdk/v2/object/object.go
generated
vendored
@@ -9,6 +9,8 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
// Attachment interface.
|
||||
@@ -42,6 +44,44 @@ func (b *BaseBoolInt) UnmarshalJSON(data []byte) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeMsgpack func.
|
||||
func (b *BaseBoolInt) DecodeMsgpack(dec *msgpack.Decoder) (err error) {
|
||||
data, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
valueInt int
|
||||
valueBool bool
|
||||
)
|
||||
|
||||
switch {
|
||||
case msgpack.Unmarshal(data, &valueBool) == nil:
|
||||
*b = BaseBoolInt(valueBool)
|
||||
case msgpack.Unmarshal(data, &valueInt) == nil:
|
||||
if valueInt == 1 {
|
||||
*b = true
|
||||
break
|
||||
}
|
||||
|
||||
if valueInt == 0 {
|
||||
*b = false
|
||||
break
|
||||
}
|
||||
|
||||
fallthrough
|
||||
default:
|
||||
// return msgpack error
|
||||
err = &json.UnmarshalTypeError{
|
||||
Value: string(data),
|
||||
Type: reflect.TypeOf((*BaseBoolInt)(nil)),
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// BaseCountry struct.
|
||||
type BaseCountry struct {
|
||||
ID int `json:"id"`
|
||||
@@ -151,6 +191,33 @@ func (obj *BaseImage) UnmarshalJSON(data []byte) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// DecodeMsgpack is required to support images with `src` field.
|
||||
func (obj *BaseImage) DecodeMsgpack(dec *msgpack.Decoder) (err error) {
|
||||
type renamedBaseImage struct {
|
||||
Height float64 `msgpack:"height"`
|
||||
URL string `msgpack:"url"`
|
||||
Src string `msgpack:"src"`
|
||||
Width float64 `msgpack:"width"`
|
||||
Type string `msgpack:"type"`
|
||||
}
|
||||
|
||||
var renamedObj renamedBaseImage
|
||||
|
||||
err = dec.Decode(&renamedObj)
|
||||
|
||||
obj.Height = renamedObj.Height
|
||||
obj.Width = renamedObj.Width
|
||||
obj.Type = renamedObj.Type
|
||||
|
||||
if renamedObj.Src == "" {
|
||||
obj.URL = renamedObj.URL
|
||||
} else {
|
||||
obj.URL = renamedObj.Src
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// BaseLikes struct.
|
||||
type BaseLikes struct {
|
||||
UserLikes BaseBoolInt `json:"user_likes"` // Information whether current user likes
|
||||
@@ -346,9 +413,11 @@ const (
|
||||
type Privacy struct {
|
||||
Category PrivacyCategory `json:"category,omitempty"`
|
||||
Lists struct {
|
||||
Allowed []int `json:"allowed"`
|
||||
Allowed []int `json:"allowed"`
|
||||
Excluded []int `json:"excluded"`
|
||||
} `json:"lists,omitempty"`
|
||||
Owners struct {
|
||||
Allowed []int `json:"allowed"`
|
||||
Excluded []int `json:"excluded"`
|
||||
} `json:"owners,omitempty"`
|
||||
}
|
||||
|
||||
1
vendor/github.com/SevereCloud/vksdk/v2/object/photos.go
generated
vendored
1
vendor/github.com/SevereCloud/vksdk/v2/object/photos.go
generated
vendored
@@ -239,6 +239,7 @@ type PhotosPhotoFull struct {
|
||||
Photo1280 string `json:"photo_1280"` // URL of image with 1280 px width
|
||||
Photo2560 string `json:"photo_2560"` // URL of image with 2560 px width
|
||||
Sizes []PhotosPhotoSizes `json:"sizes"`
|
||||
OrigPhoto PhotosPhotoSizes `json:"orig_photo"`
|
||||
}
|
||||
|
||||
// ToAttachment return attachment format.
|
||||
|
||||
39
vendor/github.com/SevereCloud/vksdk/v2/object/raw.go
generated
vendored
Normal file
39
vendor/github.com/SevereCloud/vksdk/v2/object/raw.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package object // import "github.com/SevereCloud/vksdk/v2/object"
|
||||
|
||||
import "github.com/vmihailenco/msgpack/v5"
|
||||
|
||||
// RawMessage is a raw encoded JSON or MessagePack value.
|
||||
type RawMessage []byte
|
||||
|
||||
// MarshalJSON returns m as the JSON encoding of m.
|
||||
func (m RawMessage) MarshalJSON() ([]byte, error) {
|
||||
if m == nil {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets *m to a copy of data.
|
||||
func (m *RawMessage) UnmarshalJSON(data []byte) error {
|
||||
*m = append((*m)[0:0], data...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeMsgpack write m as the MessagePack encoding of m.
|
||||
func (m RawMessage) EncodeMsgpack(enc *msgpack.Encoder) error {
|
||||
_, err := enc.Writer().Write(m)
|
||||
return err
|
||||
}
|
||||
|
||||
// DecodeMsgpack sets *m to a copy of data.
|
||||
func (m *RawMessage) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
msg, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*m = RawMessage(msg)
|
||||
|
||||
return nil
|
||||
}
|
||||
37
vendor/github.com/SevereCloud/vksdk/v2/object/stories.go
generated
vendored
37
vendor/github.com/SevereCloud/vksdk/v2/object/stories.go
generated
vendored
@@ -127,6 +127,7 @@ type StoriesStory struct {
|
||||
Seen BaseBoolInt `json:"seen"`
|
||||
IsOwnerPinned BaseBoolInt `json:"is_owner_pinned"`
|
||||
IsOneTime BaseBoolInt `json:"is_one_time"`
|
||||
IsAdvice BaseBoolInt `json:"is_advice,omitempty"`
|
||||
NeedMute BaseBoolInt `json:"need_mute"`
|
||||
MuteReply BaseBoolInt `json:"mute_reply"`
|
||||
CanLike BaseBoolInt `json:"can_like"`
|
||||
@@ -152,6 +153,7 @@ type StoriesStory struct {
|
||||
NarrativesCount int `json:"narratives_count"`
|
||||
FirstNarrativeTitle string `json:"first_narrative_title"`
|
||||
Questions StoriesQuestions `json:"questions"`
|
||||
ReactionSetID string `json:"reaction_set_id"`
|
||||
}
|
||||
|
||||
// StoriesFeedItemType type.
|
||||
@@ -251,8 +253,10 @@ type StoriesClickableSticker struct { // nolint: maligned
|
||||
StickerID int `json:"sticker_id,omitempty"`
|
||||
StickerPackID int `json:"sticker_pack_id,omitempty"`
|
||||
|
||||
// type=place
|
||||
// type=place or geo
|
||||
PlaceID int `json:"place_id,omitempty"`
|
||||
// Title
|
||||
CategoryID int `json:"category_id,omitempty"`
|
||||
|
||||
// type=question
|
||||
Question string `json:"question,omitempty"`
|
||||
@@ -267,8 +271,14 @@ type StoriesClickableSticker struct { // nolint: maligned
|
||||
Hashtag string `json:"hashtag,omitempty"`
|
||||
|
||||
// type=link
|
||||
LinkObject BaseLink `json:"link_object,omitempty"`
|
||||
TooltipText string `json:"tooltip_text,omitempty"`
|
||||
LinkObject BaseLink `json:"link_object,omitempty"`
|
||||
TooltipText string `json:"tooltip_text,omitempty"`
|
||||
TooltipTextKey string `json:"tooltip_text_key,omitempty"`
|
||||
|
||||
// type=time
|
||||
TimestampMs int64 `json:"timestamp_ms,omitempty"`
|
||||
Date string `json:"date,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
|
||||
// type=market_item
|
||||
Subtype string `json:"subtype,omitempty"`
|
||||
@@ -290,10 +300,19 @@ type StoriesClickableSticker struct { // nolint: maligned
|
||||
AudioStartTime int `json:"audio_start_time,omitempty"`
|
||||
|
||||
// type=app
|
||||
App AppsApp `json:"app"`
|
||||
AppContext string `json:"app_context"`
|
||||
HasNewInteractions BaseBoolInt `json:"has_new_interactions"`
|
||||
IsBroadcastNotifyAllowed BaseBoolInt `json:"is_broadcast_notify_allowed"`
|
||||
App AppsApp `json:"app,omitempty"`
|
||||
AppContext string `json:"app_context,omitempty"`
|
||||
HasNewInteractions BaseBoolInt `json:"has_new_interactions,omitempty"`
|
||||
IsBroadcastNotifyAllowed BaseBoolInt `json:"is_broadcast_notify_allowed,omitempty"`
|
||||
|
||||
// type=emoji
|
||||
Emoji string `json:"emoji,omitempty"`
|
||||
|
||||
// type=text
|
||||
Text string `json:"text,omitempty"`
|
||||
BackgroundStyle string `json:"background_style,omitempty"`
|
||||
Alignment string `json:"alignment,omitempty"`
|
||||
SelectionColor string `json:"selection_color,omitempty"`
|
||||
}
|
||||
|
||||
// TODO: сделать несколько структур для кликабельного стикера
|
||||
@@ -313,6 +332,10 @@ const (
|
||||
ClickableStickerPoll = "poll"
|
||||
ClickableStickerMusic = "music"
|
||||
ClickableStickerApp = "app"
|
||||
ClickableStickerTime = "time"
|
||||
ClickableStickerEmoji = "emoji"
|
||||
ClickableStickerGeo = "geo"
|
||||
ClickableStickerText = "text"
|
||||
)
|
||||
|
||||
// Subtype of clickable sticker.
|
||||
|
||||
33
vendor/github.com/SevereCloud/vksdk/v2/object/users.go
generated
vendored
33
vendor/github.com/SevereCloud/vksdk/v2/object/users.go
generated
vendored
@@ -4,6 +4,9 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
// User relationship status.
|
||||
@@ -258,6 +261,36 @@ func (personal *UsersPersonal) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeMsgpack UsersPersonal.
|
||||
//
|
||||
// BUG(VK): UsersPersonal return [].
|
||||
func (personal *UsersPersonal) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
data, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Equal(data, []byte{msgpcode.FixedArrayLow}) {
|
||||
return nil
|
||||
}
|
||||
|
||||
type renamedUsersPersonal UsersPersonal
|
||||
|
||||
var r renamedUsersPersonal
|
||||
|
||||
d := msgpack.NewDecoder(bytes.NewReader(data))
|
||||
d.SetCustomStructTag("json")
|
||||
|
||||
err = d.Decode(&r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*personal = UsersPersonal(r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UsersRelative struct.
|
||||
type UsersRelative struct {
|
||||
BirthDate string `json:"birth_date"` // Date of child birthday (format dd.mm.yyyy)
|
||||
|
||||
60
vendor/github.com/SevereCloud/vksdk/v2/object/utils.go
generated
vendored
60
vendor/github.com/SevereCloud/vksdk/v2/object/utils.go
generated
vendored
@@ -1,5 +1,13 @@
|
||||
package object // import "github.com/SevereCloud/vksdk/v2/object"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"github.com/vmihailenco/msgpack/v5/msgpcode"
|
||||
)
|
||||
|
||||
// UtilsDomainResolvedType object type.
|
||||
const (
|
||||
UtilsDomainResolvedTypeUser = "user"
|
||||
@@ -15,6 +23,58 @@ type UtilsDomainResolved struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON UtilsDomainResolved.
|
||||
//
|
||||
// BUG(VK): UtilsDomainResolved return [].
|
||||
func (link *UtilsDomainResolved) UnmarshalJSON(data []byte) error {
|
||||
if bytes.Equal(data, []byte("[]")) {
|
||||
return nil
|
||||
}
|
||||
|
||||
type renamedUtilsDomainResolved UtilsDomainResolved
|
||||
|
||||
var r renamedUtilsDomainResolved
|
||||
|
||||
err := json.Unmarshal(data, &r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*link = UtilsDomainResolved(r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeMsgpack UtilsDomainResolved.
|
||||
//
|
||||
// BUG(VK): UtilsDomainResolved return [].
|
||||
func (link *UtilsDomainResolved) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||
data, err := dec.DecodeRaw()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Equal(data, []byte{msgpcode.FixedArrayLow}) {
|
||||
return nil
|
||||
}
|
||||
|
||||
type renamedUtilsDomainResolved UtilsDomainResolved
|
||||
|
||||
var r renamedUtilsDomainResolved
|
||||
|
||||
d := msgpack.NewDecoder(bytes.NewReader(data))
|
||||
d.SetCustomStructTag("json")
|
||||
|
||||
err = d.Decode(&r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*link = UtilsDomainResolved(r)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UtilsLastShortenedLink struct.
|
||||
type UtilsLastShortenedLink struct {
|
||||
AccessKey string `json:"access_key"` // Access key for private stats
|
||||
|
||||
71
vendor/github.com/SevereCloud/vksdk/v2/object/video.go
generated
vendored
71
vendor/github.com/SevereCloud/vksdk/v2/object/video.go
generated
vendored
@@ -12,6 +12,9 @@ type VideoVideo struct {
|
||||
// Date when the video has been added in Unixtime.
|
||||
AddingDate int `json:"adding_date"`
|
||||
|
||||
// Date when the video has been released in Unixtime.
|
||||
ReleaseDate int `json:"release_date"`
|
||||
|
||||
// Information whether current user can add the video.
|
||||
CanAdd BaseBoolInt `json:"can_add"`
|
||||
|
||||
@@ -27,12 +30,17 @@ type VideoVideo struct {
|
||||
// Information whether current user can like the video.
|
||||
CanLike BaseBoolInt `json:"can_like"`
|
||||
|
||||
// Information whether current user can download the video.
|
||||
CanDownload BaseBoolInt `json:"can_download"`
|
||||
|
||||
// Information whether current user can repost this video.
|
||||
CanRepost BaseBoolInt `json:"can_repost"`
|
||||
CanSubscribe BaseBoolInt `json:"can_subscribe"`
|
||||
CanAttachLink BaseBoolInt `json:"can_attach_link"`
|
||||
IsFavorite BaseBoolInt `json:"is_favorite"`
|
||||
IsPrivate BaseBoolInt `json:"is_private"`
|
||||
IsExplicit BaseBoolInt `json:"is_explicit"`
|
||||
IsSubscribed BaseBoolInt `json:"is_subscribed"`
|
||||
Added BaseBoolInt `json:"added"`
|
||||
Repeat BaseBoolInt `json:"repeat"` // Information whether the video is repeated
|
||||
ContentRestricted int `json:"content_restricted"`
|
||||
@@ -43,6 +51,7 @@ type VideoVideo struct {
|
||||
Description string `json:"description"` // Video description
|
||||
Duration int `json:"duration"` // Video duration in seconds
|
||||
Files VideoVideoFiles `json:"files"`
|
||||
Trailer VideoVideoFiles `json:"trailer,omitempty"`
|
||||
FirstFrame []VideoVideoImage `json:"first_frame"`
|
||||
Image []VideoVideoImage `json:"image"`
|
||||
Height int `json:"height"` // Video height
|
||||
@@ -56,22 +65,27 @@ type VideoVideo struct {
|
||||
Photo1280 string `json:"photo_1280"` // URL of the preview image with 1280 px in width
|
||||
|
||||
// URL of the page with a player that can be used to play the video in the browser.
|
||||
Player string `json:"player"`
|
||||
Processing int `json:"processing"` // Returns if the video is processing
|
||||
Title string `json:"title"` // Video title
|
||||
Type string `json:"type"`
|
||||
Views int `json:"views"` // Number of views
|
||||
Width int `json:"width"` // Video width
|
||||
Platform string `json:"platform"`
|
||||
LocalViews int `json:"local_views"`
|
||||
Likes BaseLikesInfo `json:"likes"` // Count of likes
|
||||
Reposts BaseRepostsInfo `json:"reposts"` // Count of views
|
||||
TrackCode string `json:"track_code"`
|
||||
PrivacyView Privacy `json:"privacy_view"`
|
||||
PrivacyComment Privacy `json:"privacy_comment"`
|
||||
ActionButton VideoActionButton `json:"action_button"`
|
||||
Restriction VideoRestriction `json:"restriction"`
|
||||
ContentRestrictedMessage string `json:"content_restricted_message"`
|
||||
Player string `json:"player"`
|
||||
Processing int `json:"processing"` // Returns if the video is processing
|
||||
Title string `json:"title"` // Video title
|
||||
Subtitle string `json:"subtitle"` // Video subtitle
|
||||
Type string `json:"type"`
|
||||
Views int `json:"views"` // Number of views
|
||||
Width int `json:"width"` // Video width
|
||||
Platform string `json:"platform"`
|
||||
LocalViews int `json:"local_views"`
|
||||
Likes BaseLikesInfo `json:"likes"` // Count of likes
|
||||
Reposts BaseRepostsInfo `json:"reposts"` // Count of views
|
||||
TrackCode string `json:"track_code"`
|
||||
PrivacyView Privacy `json:"privacy_view"`
|
||||
PrivacyComment Privacy `json:"privacy_comment"`
|
||||
ActionButton VideoActionButton `json:"action_button"`
|
||||
Restriction VideoRestriction `json:"restriction"`
|
||||
ContentRestrictedMessage string `json:"content_restricted_message"`
|
||||
MainArtists []AudioAudioArtist `json:"main_artists"`
|
||||
FeaturedArtists []AudioAudioArtist `json:"featured_artists"`
|
||||
Genres []BaseObjectWithName `json:"genres"`
|
||||
OvID string `json:"ov_id,omitempty"`
|
||||
}
|
||||
|
||||
// ToAttachment return attachment format.
|
||||
@@ -112,16 +126,20 @@ type VideoSnippet struct {
|
||||
|
||||
// VideoVideoFiles struct.
|
||||
type VideoVideoFiles struct {
|
||||
External string `json:"external"` // URL of the external player
|
||||
Mp4_1080 string `json:"mp4_1080"` // URL of the mpeg4 file with 1080p quality
|
||||
Mp4_1440 string `json:"mp4_1440"` // URL of the mpeg4 file with 2k quality
|
||||
Mp4_2160 string `json:"mp4_2160"` // URL of the mpeg4 file with 4k quality
|
||||
Mp4_240 string `json:"mp4_240"` // URL of the mpeg4 file with 240p quality
|
||||
Mp4_360 string `json:"mp4_360"` // URL of the mpeg4 file with 360p quality
|
||||
Mp4_480 string `json:"mp4_480"` // URL of the mpeg4 file with 480p quality
|
||||
Mp4_720 string `json:"mp4_720"` // URL of the mpeg4 file with 720p quality
|
||||
Live string `json:"live"`
|
||||
HLS string `json:"hls"`
|
||||
External string `json:"external,omitempty"` // URL of the external player
|
||||
Mp4_1080 string `json:"mp4_1080,omitempty"` // URL of the mpeg4 file with 1080p quality
|
||||
Mp4_1440 string `json:"mp4_1440,omitempty"` // URL of the mpeg4 file with 2k quality
|
||||
Mp4_2160 string `json:"mp4_2160,omitempty"` // URL of the mpeg4 file with 4k quality
|
||||
Mp4_240 string `json:"mp4_240,omitempty"` // URL of the mpeg4 file with 240p quality
|
||||
Mp4_360 string `json:"mp4_360,omitempty"` // URL of the mpeg4 file with 360p quality
|
||||
Mp4_480 string `json:"mp4_480,omitempty"` // URL of the mpeg4 file with 480p quality
|
||||
Mp4_720 string `json:"mp4_720,omitempty"` // URL of the mpeg4 file with 720p quality
|
||||
Live string `json:"live,omitempty"`
|
||||
HLS string `json:"hls,omitempty"`
|
||||
DashUni string `json:"dash_uni,omitempty"`
|
||||
DashSep string `json:"dash_sep,omitempty"`
|
||||
DashWebm string `json:"dash_webm,omitempty"`
|
||||
FailoverHost string `json:"failover_host,omitempty"`
|
||||
}
|
||||
|
||||
// VideoCatBlock struct.
|
||||
@@ -213,6 +231,7 @@ type VideoVideoFull struct {
|
||||
Description string `json:"description"` // Video description
|
||||
Duration int `json:"duration"` // Video duration in seconds
|
||||
Files VideoVideoFiles `json:"files"`
|
||||
Trailer VideoVideoFiles `json:"trailer"`
|
||||
ID int `json:"id"` // Video ID
|
||||
Likes BaseLikes `json:"likes"`
|
||||
Live int `json:"live"` // Returns if the video is live translation
|
||||
|
||||
23
vendor/github.com/SevereCloud/vksdk/v2/object/wall.go
generated
vendored
23
vendor/github.com/SevereCloud/vksdk/v2/object/wall.go
generated
vendored
@@ -128,7 +128,7 @@ const (
|
||||
WallPostTypeSuggest = "suggest"
|
||||
)
|
||||
|
||||
// WallWallpost struct.
|
||||
// WallWallpost struct.
|
||||
type WallWallpost struct {
|
||||
AccessKey string `json:"access_key"` // Access key to private object
|
||||
ID int `json:"id"` // Post ID
|
||||
@@ -156,14 +156,17 @@ type WallWallpost struct {
|
||||
IsPinned BaseBoolInt `json:"is_pinned"`
|
||||
IsFavorite BaseBoolInt `json:"is_favorite"` // Information whether the post in favorites list
|
||||
IsArchived BaseBoolInt `json:"is_archived"` // Is post archived, only for post owners
|
||||
IsDeleted BaseBoolInt `json:"is_deleted"`
|
||||
MarkedAsAds BaseBoolInt `json:"marked_as_ads"`
|
||||
Edited int `json:"edited"` // Date of editing in Unixtime
|
||||
Copyright WallPostCopyright `json:"copyright"`
|
||||
PostID int `json:"post_id"`
|
||||
ParentsStack []int `json:"parents_stack"`
|
||||
Donut WallWallpostDonut `json:"donut"` // need api v5.125
|
||||
Donut WallWallpostDonut `json:"donut"`
|
||||
ShortTextRate float64 `json:"short_text_rate"`
|
||||
CarouselOffset int `json:"carousel_offset"`
|
||||
Header WallWallpostHeader `json:"header"`
|
||||
Hash string `json:"hash"`
|
||||
}
|
||||
|
||||
// Attachment type.
|
||||
@@ -235,8 +238,10 @@ type WallWallpostToID struct {
|
||||
IsFavorite BaseBoolInt `json:"is_favorite"` // Information whether the post in favorites list
|
||||
MarkedAsAds BaseBoolInt `json:"marked_as_ads"`
|
||||
ParentsStack []int `json:"parents_stack"`
|
||||
Donut WallWallpostDonut `json:"donut"` // need api v5.125
|
||||
Donut WallWallpostDonut `json:"donut"`
|
||||
ShortTextRate float64 `json:"short_text_rate"`
|
||||
Views WallViews `json:"views"` // Count of views
|
||||
Header WallWallpostHeader `json:"header"`
|
||||
}
|
||||
|
||||
// WallWallpostDonut info about VK Donut.
|
||||
@@ -255,3 +260,15 @@ type WallPostCopyright struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// WallWallpostHeader struct.
|
||||
type WallWallpostHeader struct {
|
||||
Type string `json:"type"`
|
||||
CustomDescription WallWallpostHeaderCustomDescription `json:"custom_description"`
|
||||
}
|
||||
|
||||
// WallWallpostHeaderCustomDescription struct.
|
||||
type WallWallpostHeaderCustomDescription struct {
|
||||
SourceID int `json:"source_id"`
|
||||
Date int `json:"date"`
|
||||
}
|
||||
|
||||
3
vendor/github.com/SevereCloud/vksdk/v2/object/widgets.go
generated
vendored
3
vendor/github.com/SevereCloud/vksdk/v2/object/widgets.go
generated
vendored
@@ -45,6 +45,9 @@ type WidgetsWidgetComment struct {
|
||||
Views struct {
|
||||
Count int `json:"count"`
|
||||
} `json:"views"`
|
||||
Donut WallWallpostDonut `json:"donut"`
|
||||
ShortTextRate float64 `json:"short_text_rate"`
|
||||
Header WallWallpostHeader `json:"header"`
|
||||
}
|
||||
|
||||
// WidgetsWidgetLikes struct.
|
||||
|
||||
4
vendor/github.com/d5/tengo/v2/README.md
generated
vendored
4
vendor/github.com/d5/tengo/v2/README.md
generated
vendored
@@ -1,7 +1,3 @@
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/d5/tengolang-share/master/logo_400.png" width="200" height="200">
|
||||
</p>
|
||||
|
||||
# The Tengo Language
|
||||
|
||||
[](https://godoc.org/github.com/d5/tengo/v2)
|
||||
|
||||
70
vendor/github.com/d5/tengo/v2/compiler.go
generated
vendored
70
vendor/github.com/d5/tengo/v2/compiler.go
generated
vendored
@@ -1,9 +1,11 @@
|
||||
package tengo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -45,11 +47,12 @@ type Compiler struct {
|
||||
parent *Compiler
|
||||
modulePath string
|
||||
importDir string
|
||||
importFileExt []string
|
||||
constants []Object
|
||||
symbolTable *SymbolTable
|
||||
scopes []compilationScope
|
||||
scopeIndex int
|
||||
modules *ModuleMap
|
||||
modules ModuleGetter
|
||||
compiledModules map[string]*CompiledFunction
|
||||
allowFileImport bool
|
||||
loops []*loop
|
||||
@@ -63,7 +66,7 @@ func NewCompiler(
|
||||
file *parser.SourceFile,
|
||||
symbolTable *SymbolTable,
|
||||
constants []Object,
|
||||
modules *ModuleMap,
|
||||
modules ModuleGetter,
|
||||
trace io.Writer,
|
||||
) *Compiler {
|
||||
mainScope := compilationScope{
|
||||
@@ -96,6 +99,7 @@ func NewCompiler(
|
||||
trace: trace,
|
||||
modules: modules,
|
||||
compiledModules: make(map[string]*CompiledFunction),
|
||||
importFileExt: []string{SourceFileExtDefault},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,12 +542,8 @@ func (c *Compiler) Compile(node parser.Node) error {
|
||||
}
|
||||
} else if c.allowFileImport {
|
||||
moduleName := node.ModuleName
|
||||
if !strings.HasSuffix(moduleName, ".tengo") {
|
||||
moduleName += ".tengo"
|
||||
}
|
||||
|
||||
modulePath, err := filepath.Abs(
|
||||
filepath.Join(c.importDir, moduleName))
|
||||
modulePath, err := c.getPathModule(moduleName)
|
||||
if err != nil {
|
||||
return c.errorf(node, "module file path error: %s",
|
||||
err.Error())
|
||||
@@ -640,6 +640,39 @@ func (c *Compiler) SetImportDir(dir string) {
|
||||
c.importDir = dir
|
||||
}
|
||||
|
||||
// SetImportFileExt sets the extension name of the source file for loading
|
||||
// local module files.
|
||||
//
|
||||
// Use this method if you want other source file extension than ".tengo".
|
||||
//
|
||||
// // this will search for *.tengo, *.foo, *.bar
|
||||
// err := c.SetImportFileExt(".tengo", ".foo", ".bar")
|
||||
//
|
||||
// This function requires at least one argument, since it will replace the
|
||||
// current list of extension name.
|
||||
func (c *Compiler) SetImportFileExt(exts ...string) error {
|
||||
if len(exts) == 0 {
|
||||
return fmt.Errorf("missing arg: at least one argument is required")
|
||||
}
|
||||
|
||||
for _, ext := range exts {
|
||||
if ext != filepath.Ext(ext) || ext == "" {
|
||||
return fmt.Errorf("invalid file extension: %s", ext)
|
||||
}
|
||||
}
|
||||
|
||||
c.importFileExt = exts // Replace the hole current extension list
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetImportFileExt returns the current list of extension name.
|
||||
// Thease are the complementary suffix of the source file to search and load
|
||||
// local module files.
|
||||
func (c *Compiler) GetImportFileExt() []string {
|
||||
return c.importFileExt
|
||||
}
|
||||
|
||||
func (c *Compiler) compileAssign(
|
||||
node parser.Node,
|
||||
lhs, rhs []parser.Expr,
|
||||
@@ -1098,6 +1131,7 @@ func (c *Compiler) fork(
|
||||
child.parent = c // parent to set to current compiler
|
||||
child.allowFileImport = c.allowFileImport
|
||||
child.importDir = c.importDir
|
||||
child.importFileExt = c.importFileExt
|
||||
if isFile && c.importDir != "" {
|
||||
child.importDir = filepath.Dir(modulePath)
|
||||
}
|
||||
@@ -1287,6 +1321,28 @@ func (c *Compiler) printTrace(a ...interface{}) {
|
||||
_, _ = fmt.Fprintln(c.trace, a...)
|
||||
}
|
||||
|
||||
func (c *Compiler) getPathModule(moduleName string) (pathFile string, err error) {
|
||||
for _, ext := range c.importFileExt {
|
||||
nameFile := moduleName
|
||||
|
||||
if !strings.HasSuffix(nameFile, ext) {
|
||||
nameFile += ext
|
||||
}
|
||||
|
||||
pathFile, err = filepath.Abs(filepath.Join(c.importDir, nameFile))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if file exists
|
||||
if _, err := os.Stat(pathFile); !errors.Is(err, os.ErrNotExist) {
|
||||
return pathFile, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("module '%s' not found at: %s", moduleName, pathFile)
|
||||
}
|
||||
|
||||
func resolveAssignLHS(
|
||||
expr parser.Expr,
|
||||
) (name string, selectors []parser.Expr) {
|
||||
|
||||
5
vendor/github.com/d5/tengo/v2/modules.go
generated
vendored
5
vendor/github.com/d5/tengo/v2/modules.go
generated
vendored
@@ -6,6 +6,11 @@ type Importable interface {
|
||||
Import(moduleName string) (interface{}, error)
|
||||
}
|
||||
|
||||
// ModuleGetter enables implementing dynamic module loading.
|
||||
type ModuleGetter interface {
|
||||
Get(name string) Importable
|
||||
}
|
||||
|
||||
// ModuleMap represents a set of named modules. Use NewModuleMap to create a
|
||||
// new module map.
|
||||
type ModuleMap struct {
|
||||
|
||||
16
vendor/github.com/d5/tengo/v2/script.go
generated
vendored
16
vendor/github.com/d5/tengo/v2/script.go
generated
vendored
@@ -12,7 +12,7 @@ import (
|
||||
// Script can simplify compilation and execution of embedded scripts.
|
||||
type Script struct {
|
||||
variables map[string]*Variable
|
||||
modules *ModuleMap
|
||||
modules ModuleGetter
|
||||
input []byte
|
||||
maxAllocs int64
|
||||
maxConstObjects int
|
||||
@@ -54,7 +54,7 @@ func (s *Script) Remove(name string) bool {
|
||||
}
|
||||
|
||||
// SetImports sets import modules.
|
||||
func (s *Script) SetImports(modules *ModuleMap) {
|
||||
func (s *Script) SetImports(modules ModuleGetter) {
|
||||
s.modules = modules
|
||||
}
|
||||
|
||||
@@ -219,6 +219,18 @@ func (c *Compiled) RunContext(ctx context.Context) (err error) {
|
||||
v := NewVM(c.bytecode, c.globals, c.maxAllocs)
|
||||
ch := make(chan error, 1)
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
switch e := r.(type) {
|
||||
case string:
|
||||
ch <- fmt.Errorf(e)
|
||||
case error:
|
||||
ch <- e
|
||||
default:
|
||||
ch <- fmt.Errorf("unknown panic: %v", e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
ch <- v.Run()
|
||||
}()
|
||||
|
||||
|
||||
3
vendor/github.com/d5/tengo/v2/tengo.go
generated
vendored
3
vendor/github.com/d5/tengo/v2/tengo.go
generated
vendored
@@ -26,6 +26,9 @@ const (
|
||||
|
||||
// MaxFrames is the maximum number of function frames for a VM.
|
||||
MaxFrames = 1024
|
||||
|
||||
// SourceFileExtDefault is the default extension for source files.
|
||||
SourceFileExtDefault = ".tengo"
|
||||
)
|
||||
|
||||
// CallableFunc is a function signature for the callable functions.
|
||||
|
||||
2
vendor/github.com/d5/tengo/v2/vm.go
generated
vendored
2
vendor/github.com/d5/tengo/v2/vm.go
generated
vendored
@@ -293,7 +293,7 @@ func (v *VM) run() {
|
||||
case parser.OpMap:
|
||||
v.ip += 2
|
||||
numElements := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8
|
||||
kv := make(map[string]Object)
|
||||
kv := make(map[string]Object, numElements)
|
||||
for i := v.sp - numElements; i < v.sp; i += 2 {
|
||||
key := v.stack[i]
|
||||
value := v.stack[i+1]
|
||||
|
||||
8
vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml
generated
vendored
8
vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml
generated
vendored
@@ -1,8 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- '1.10'
|
||||
- '1.11'
|
||||
- '1.12'
|
||||
- '1.13'
|
||||
- tip
|
||||
1014
vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
generated
vendored
1014
vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
generated
vendored
File diff suppressed because it is too large
Load Diff
1279
vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
generated
vendored
1279
vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
generated
vendored
File diff suppressed because it is too large
Load Diff
990
vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
generated
vendored
990
vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
generated
vendored
@@ -1,990 +0,0 @@
|
||||
package tgbotapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// APIResponse is a response from the Telegram API with the result
|
||||
// stored raw.
|
||||
type APIResponse struct {
|
||||
Ok bool `json:"ok"`
|
||||
Result json.RawMessage `json:"result"`
|
||||
ErrorCode int `json:"error_code"`
|
||||
Description string `json:"description"`
|
||||
Parameters *ResponseParameters `json:"parameters"`
|
||||
}
|
||||
|
||||
// ResponseParameters are various errors that can be returned in APIResponse.
|
||||
type ResponseParameters struct {
|
||||
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
|
||||
RetryAfter int `json:"retry_after"` // optional
|
||||
}
|
||||
|
||||
// Update is an update response, from GetUpdates.
|
||||
type Update struct {
|
||||
UpdateID int `json:"update_id"`
|
||||
Message *Message `json:"message"`
|
||||
EditedMessage *Message `json:"edited_message"`
|
||||
ChannelPost *Message `json:"channel_post"`
|
||||
EditedChannelPost *Message `json:"edited_channel_post"`
|
||||
InlineQuery *InlineQuery `json:"inline_query"`
|
||||
ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"`
|
||||
CallbackQuery *CallbackQuery `json:"callback_query"`
|
||||
ShippingQuery *ShippingQuery `json:"shipping_query"`
|
||||
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query"`
|
||||
}
|
||||
|
||||
// UpdatesChannel is the channel for getting updates.
|
||||
type UpdatesChannel <-chan Update
|
||||
|
||||
// Clear discards all unprocessed incoming updates.
|
||||
func (ch UpdatesChannel) Clear() {
|
||||
for len(ch) != 0 {
|
||||
<-ch
|
||||
}
|
||||
}
|
||||
|
||||
// User is a user on Telegram.
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"` // optional
|
||||
UserName string `json:"username"` // optional
|
||||
LanguageCode string `json:"language_code"` // optional
|
||||
IsBot bool `json:"is_bot"` // optional
|
||||
}
|
||||
|
||||
// String displays a simple text version of a user.
|
||||
//
|
||||
// It is normally a user's username, but falls back to a first/last
|
||||
// name as available.
|
||||
func (u *User) String() string {
|
||||
if u == nil {
|
||||
return ""
|
||||
}
|
||||
if u.UserName != "" {
|
||||
return u.UserName
|
||||
}
|
||||
|
||||
name := u.FirstName
|
||||
if u.LastName != "" {
|
||||
name += " " + u.LastName
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
// GroupChat is a group chat.
|
||||
type GroupChat struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
// ChatPhoto represents a chat photo.
|
||||
type ChatPhoto struct {
|
||||
SmallFileID string `json:"small_file_id"`
|
||||
BigFileID string `json:"big_file_id"`
|
||||
}
|
||||
|
||||
// Chat contains information about the place a message was sent.
|
||||
type Chat struct {
|
||||
ID int64 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"` // optional
|
||||
UserName string `json:"username"` // optional
|
||||
FirstName string `json:"first_name"` // optional
|
||||
LastName string `json:"last_name"` // optional
|
||||
AllMembersAreAdmins bool `json:"all_members_are_administrators"` // optional
|
||||
Photo *ChatPhoto `json:"photo"`
|
||||
Description string `json:"description,omitempty"` // optional
|
||||
InviteLink string `json:"invite_link,omitempty"` // optional
|
||||
PinnedMessage *Message `json:"pinned_message"` // optional
|
||||
}
|
||||
|
||||
// IsPrivate returns if the Chat is a private conversation.
|
||||
func (c Chat) IsPrivate() bool {
|
||||
return c.Type == "private"
|
||||
}
|
||||
|
||||
// IsGroup returns if the Chat is a group.
|
||||
func (c Chat) IsGroup() bool {
|
||||
return c.Type == "group"
|
||||
}
|
||||
|
||||
// IsSuperGroup returns if the Chat is a supergroup.
|
||||
func (c Chat) IsSuperGroup() bool {
|
||||
return c.Type == "supergroup"
|
||||
}
|
||||
|
||||
// IsChannel returns if the Chat is a channel.
|
||||
func (c Chat) IsChannel() bool {
|
||||
return c.Type == "channel"
|
||||
}
|
||||
|
||||
// ChatConfig returns a ChatConfig struct for chat related methods.
|
||||
func (c Chat) ChatConfig() ChatConfig {
|
||||
return ChatConfig{ChatID: c.ID}
|
||||
}
|
||||
|
||||
// Message is returned by almost every request, and contains data about
|
||||
// almost anything.
|
||||
type Message struct {
|
||||
MessageID int `json:"message_id"`
|
||||
From *User `json:"from"` // optional
|
||||
Date int `json:"date"`
|
||||
Chat *Chat `json:"chat"`
|
||||
ForwardFrom *User `json:"forward_from"` // optional
|
||||
ForwardFromChat *Chat `json:"forward_from_chat"` // optional
|
||||
ForwardFromMessageID int `json:"forward_from_message_id"` // optional
|
||||
ForwardDate int `json:"forward_date"` // optional
|
||||
ReplyToMessage *Message `json:"reply_to_message"` // optional
|
||||
EditDate int `json:"edit_date"` // optional
|
||||
Text string `json:"text"` // optional
|
||||
Entities *[]MessageEntity `json:"entities"` // optional
|
||||
CaptionEntities *[]MessageEntity `json:"caption_entities"` // optional
|
||||
Audio *Audio `json:"audio"` // optional
|
||||
Document *Document `json:"document"` // optional
|
||||
Animation *ChatAnimation `json:"animation"` // optional
|
||||
Game *Game `json:"game"` // optional
|
||||
Photo *[]PhotoSize `json:"photo"` // optional
|
||||
Sticker *Sticker `json:"sticker"` // optional
|
||||
Video *Video `json:"video"` // optional
|
||||
VideoNote *VideoNote `json:"video_note"` // optional
|
||||
Voice *Voice `json:"voice"` // optional
|
||||
Caption string `json:"caption"` // optional
|
||||
Contact *Contact `json:"contact"` // optional
|
||||
Location *Location `json:"location"` // optional
|
||||
Venue *Venue `json:"venue"` // optional
|
||||
NewChatMembers *[]User `json:"new_chat_members"` // optional
|
||||
LeftChatMember *User `json:"left_chat_member"` // optional
|
||||
NewChatTitle string `json:"new_chat_title"` // optional
|
||||
NewChatPhoto *[]PhotoSize `json:"new_chat_photo"` // optional
|
||||
DeleteChatPhoto bool `json:"delete_chat_photo"` // optional
|
||||
GroupChatCreated bool `json:"group_chat_created"` // optional
|
||||
SuperGroupChatCreated bool `json:"supergroup_chat_created"` // optional
|
||||
ChannelChatCreated bool `json:"channel_chat_created"` // optional
|
||||
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
|
||||
MigrateFromChatID int64 `json:"migrate_from_chat_id"` // optional
|
||||
PinnedMessage *Message `json:"pinned_message"` // optional
|
||||
Invoice *Invoice `json:"invoice"` // optional
|
||||
SuccessfulPayment *SuccessfulPayment `json:"successful_payment"` // optional
|
||||
PassportData *PassportData `json:"passport_data,omitempty"` // optional
|
||||
}
|
||||
|
||||
// Time converts the message timestamp into a Time.
|
||||
func (m *Message) Time() time.Time {
|
||||
return time.Unix(int64(m.Date), 0)
|
||||
}
|
||||
|
||||
// IsCommand returns true if message starts with a "bot_command" entity.
|
||||
func (m *Message) IsCommand() bool {
|
||||
if m.Entities == nil || len(*m.Entities) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
entity := (*m.Entities)[0]
|
||||
return entity.Offset == 0 && entity.IsCommand()
|
||||
}
|
||||
|
||||
// Command checks if the message was a command and if it was, returns the
|
||||
// command. If the Message was not a command, it returns an empty string.
|
||||
//
|
||||
// If the command contains the at name syntax, it is removed. Use
|
||||
// CommandWithAt() if you do not want that.
|
||||
func (m *Message) Command() string {
|
||||
command := m.CommandWithAt()
|
||||
|
||||
if i := strings.Index(command, "@"); i != -1 {
|
||||
command = command[:i]
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
// CommandWithAt checks if the message was a command and if it was, returns the
|
||||
// command. If the Message was not a command, it returns an empty string.
|
||||
//
|
||||
// If the command contains the at name syntax, it is not removed. Use Command()
|
||||
// if you want that.
|
||||
func (m *Message) CommandWithAt() string {
|
||||
if !m.IsCommand() {
|
||||
return ""
|
||||
}
|
||||
|
||||
// IsCommand() checks that the message begins with a bot_command entity
|
||||
entity := (*m.Entities)[0]
|
||||
return m.Text[1:entity.Length]
|
||||
}
|
||||
|
||||
// CommandArguments checks if the message was a command and if it was,
|
||||
// returns all text after the command name. If the Message was not a
|
||||
// command, it returns an empty string.
|
||||
//
|
||||
// Note: The first character after the command name is omitted:
|
||||
// - "/foo bar baz" yields "bar baz", not " bar baz"
|
||||
// - "/foo-bar baz" yields "bar baz", too
|
||||
// Even though the latter is not a command conforming to the spec, the API
|
||||
// marks "/foo" as command entity.
|
||||
func (m *Message) CommandArguments() string {
|
||||
if !m.IsCommand() {
|
||||
return ""
|
||||
}
|
||||
|
||||
// IsCommand() checks that the message begins with a bot_command entity
|
||||
entity := (*m.Entities)[0]
|
||||
if len(m.Text) == entity.Length {
|
||||
return "" // The command makes up the whole message
|
||||
}
|
||||
|
||||
return m.Text[entity.Length+1:]
|
||||
}
|
||||
|
||||
// MessageEntity contains information about data in a Message.
|
||||
type MessageEntity struct {
|
||||
Type string `json:"type"`
|
||||
Offset int `json:"offset"`
|
||||
Length int `json:"length"`
|
||||
URL string `json:"url"` // optional
|
||||
User *User `json:"user"` // optional
|
||||
}
|
||||
|
||||
// ParseURL attempts to parse a URL contained within a MessageEntity.
|
||||
func (e MessageEntity) ParseURL() (*url.URL, error) {
|
||||
if e.URL == "" {
|
||||
return nil, errors.New(ErrBadURL)
|
||||
}
|
||||
|
||||
return url.Parse(e.URL)
|
||||
}
|
||||
|
||||
// IsMention returns true if the type of the message entity is "mention" (@username).
|
||||
func (e MessageEntity) IsMention() bool {
|
||||
return e.Type == "mention"
|
||||
}
|
||||
|
||||
// IsHashtag returns true if the type of the message entity is "hashtag".
|
||||
func (e MessageEntity) IsHashtag() bool {
|
||||
return e.Type == "hashtag"
|
||||
}
|
||||
|
||||
// IsCommand returns true if the type of the message entity is "bot_command".
|
||||
func (e MessageEntity) IsCommand() bool {
|
||||
return e.Type == "bot_command"
|
||||
}
|
||||
|
||||
// IsUrl returns true if the type of the message entity is "url".
|
||||
func (e MessageEntity) IsUrl() bool {
|
||||
return e.Type == "url"
|
||||
}
|
||||
|
||||
// IsEmail returns true if the type of the message entity is "email".
|
||||
func (e MessageEntity) IsEmail() bool {
|
||||
return e.Type == "email"
|
||||
}
|
||||
|
||||
// IsBold returns true if the type of the message entity is "bold" (bold text).
|
||||
func (e MessageEntity) IsBold() bool {
|
||||
return e.Type == "bold"
|
||||
}
|
||||
|
||||
// IsItalic returns true if the type of the message entity is "italic" (italic text).
|
||||
func (e MessageEntity) IsItalic() bool {
|
||||
return e.Type == "italic"
|
||||
}
|
||||
|
||||
// IsCode returns true if the type of the message entity is "code" (monowidth string).
|
||||
func (e MessageEntity) IsCode() bool {
|
||||
return e.Type == "code"
|
||||
}
|
||||
|
||||
// IsPre returns true if the type of the message entity is "pre" (monowidth block).
|
||||
func (e MessageEntity) IsPre() bool {
|
||||
return e.Type == "pre"
|
||||
}
|
||||
|
||||
// IsTextLink returns true if the type of the message entity is "text_link" (clickable text URL).
|
||||
func (e MessageEntity) IsTextLink() bool {
|
||||
return e.Type == "text_link"
|
||||
}
|
||||
|
||||
// PhotoSize contains information about photos.
|
||||
type PhotoSize struct {
|
||||
FileID string `json:"file_id"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
FileSize int `json:"file_size"` // optional
|
||||
}
|
||||
|
||||
// Audio contains information about audio.
|
||||
type Audio struct {
|
||||
FileID string `json:"file_id"`
|
||||
Duration int `json:"duration"`
|
||||
Performer string `json:"performer"` // optional
|
||||
Title string `json:"title"` // optional
|
||||
MimeType string `json:"mime_type"` // optional
|
||||
FileSize int `json:"file_size"` // optional
|
||||
}
|
||||
|
||||
// Document contains information about a document.
|
||||
type Document struct {
|
||||
FileID string `json:"file_id"`
|
||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
||||
FileName string `json:"file_name"` // optional
|
||||
MimeType string `json:"mime_type"` // optional
|
||||
FileSize int `json:"file_size"` // optional
|
||||
}
|
||||
|
||||
// Sticker contains information about a sticker.
|
||||
type Sticker struct {
|
||||
FileUniqueID string `json:"file_unique_id"`
|
||||
FileID string `json:"file_id"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
||||
Emoji string `json:"emoji"` // optional
|
||||
FileSize int `json:"file_size"` // optional
|
||||
SetName string `json:"set_name"` // optional
|
||||
IsAnimated bool `json:"is_animated"` // optional
|
||||
}
|
||||
|
||||
type StickerSet struct {
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title"`
|
||||
IsAnimated bool `json:"is_animated"`
|
||||
ContainsMasks bool `json:"contains_masks"`
|
||||
Stickers []Sticker `json:"stickers"`
|
||||
}
|
||||
|
||||
// ChatAnimation contains information about an animation.
|
||||
type ChatAnimation struct {
|
||||
FileID string `json:"file_id"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Duration int `json:"duration"`
|
||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
||||
FileName string `json:"file_name"` // optional
|
||||
MimeType string `json:"mime_type"` // optional
|
||||
FileSize int `json:"file_size"` // optional
|
||||
}
|
||||
|
||||
// Video contains information about a video.
|
||||
type Video struct {
|
||||
FileID string `json:"file_id"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Duration int `json:"duration"`
|
||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
||||
MimeType string `json:"mime_type"` // optional
|
||||
FileSize int `json:"file_size"` // optional
|
||||
}
|
||||
|
||||
// VideoNote contains information about a video.
|
||||
type VideoNote struct {
|
||||
FileID string `json:"file_id"`
|
||||
Length int `json:"length"`
|
||||
Duration int `json:"duration"`
|
||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
||||
FileSize int `json:"file_size"` // optional
|
||||
}
|
||||
|
||||
// Voice contains information about a voice.
|
||||
type Voice struct {
|
||||
FileID string `json:"file_id"`
|
||||
Duration int `json:"duration"`
|
||||
MimeType string `json:"mime_type"` // optional
|
||||
FileSize int `json:"file_size"` // optional
|
||||
}
|
||||
|
||||
// Contact contains information about a contact.
|
||||
//
|
||||
// Note that LastName and UserID may be empty.
|
||||
type Contact struct {
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"` // optional
|
||||
UserID int `json:"user_id"` // optional
|
||||
}
|
||||
|
||||
// Location contains information about a place.
|
||||
type Location struct {
|
||||
Longitude float64 `json:"longitude"`
|
||||
Latitude float64 `json:"latitude"`
|
||||
}
|
||||
|
||||
// Venue contains information about a venue, including its Location.
|
||||
type Venue struct {
|
||||
Location Location `json:"location"`
|
||||
Title string `json:"title"`
|
||||
Address string `json:"address"`
|
||||
FoursquareID string `json:"foursquare_id"` // optional
|
||||
}
|
||||
|
||||
// UserProfilePhotos contains a set of user profile photos.
|
||||
type UserProfilePhotos struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
Photos [][]PhotoSize `json:"photos"`
|
||||
}
|
||||
|
||||
// File contains information about a file to download from Telegram.
|
||||
type File struct {
|
||||
FileID string `json:"file_id"`
|
||||
FileSize int `json:"file_size"` // optional
|
||||
FilePath string `json:"file_path"` // optional
|
||||
}
|
||||
|
||||
// Link returns a full path to the download URL for a File.
|
||||
//
|
||||
// It requires the Bot Token to create the link.
|
||||
func (f *File) Link(token string) string {
|
||||
return fmt.Sprintf(FileEndpoint, token, f.FilePath)
|
||||
}
|
||||
|
||||
// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
|
||||
type ReplyKeyboardMarkup struct {
|
||||
Keyboard [][]KeyboardButton `json:"keyboard"`
|
||||
ResizeKeyboard bool `json:"resize_keyboard"` // optional
|
||||
OneTimeKeyboard bool `json:"one_time_keyboard"` // optional
|
||||
Selective bool `json:"selective"` // optional
|
||||
}
|
||||
|
||||
// KeyboardButton is a button within a custom keyboard.
|
||||
type KeyboardButton struct {
|
||||
Text string `json:"text"`
|
||||
RequestContact bool `json:"request_contact"`
|
||||
RequestLocation bool `json:"request_location"`
|
||||
}
|
||||
|
||||
// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
|
||||
type ReplyKeyboardHide struct {
|
||||
HideKeyboard bool `json:"hide_keyboard"`
|
||||
Selective bool `json:"selective"` // optional
|
||||
}
|
||||
|
||||
// ReplyKeyboardRemove allows the Bot to hide a custom keyboard.
|
||||
type ReplyKeyboardRemove struct {
|
||||
RemoveKeyboard bool `json:"remove_keyboard"`
|
||||
Selective bool `json:"selective"`
|
||||
}
|
||||
|
||||
// InlineKeyboardMarkup is a custom keyboard presented for an inline bot.
|
||||
type InlineKeyboardMarkup struct {
|
||||
InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"`
|
||||
}
|
||||
|
||||
// InlineKeyboardButton is a button within a custom keyboard for
|
||||
// inline query responses.
|
||||
//
|
||||
// Note that some values are references as even an empty string
|
||||
// will change behavior.
|
||||
//
|
||||
// CallbackGame, if set, MUST be first button in first row.
|
||||
type InlineKeyboardButton struct {
|
||||
Text string `json:"text"`
|
||||
URL *string `json:"url,omitempty"` // optional
|
||||
CallbackData *string `json:"callback_data,omitempty"` // optional
|
||||
SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
|
||||
SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat,omitempty"` // optional
|
||||
CallbackGame *CallbackGame `json:"callback_game,omitempty"` // optional
|
||||
Pay bool `json:"pay,omitempty"` // optional
|
||||
}
|
||||
|
||||
// CallbackQuery is data sent when a keyboard button with callback data
|
||||
// is clicked.
|
||||
type CallbackQuery struct {
|
||||
ID string `json:"id"`
|
||||
From *User `json:"from"`
|
||||
Message *Message `json:"message"` // optional
|
||||
InlineMessageID string `json:"inline_message_id"` // optional
|
||||
ChatInstance string `json:"chat_instance"`
|
||||
Data string `json:"data"` // optional
|
||||
GameShortName string `json:"game_short_name"` // optional
|
||||
}
|
||||
|
||||
// ForceReply allows the Bot to have users directly reply to it without
|
||||
// additional interaction.
|
||||
type ForceReply struct {
|
||||
ForceReply bool `json:"force_reply"`
|
||||
Selective bool `json:"selective"` // optional
|
||||
}
|
||||
|
||||
// ChatMember is information about a member in a chat.
|
||||
type ChatMember struct {
|
||||
User *User `json:"user"`
|
||||
Status string `json:"status"`
|
||||
UntilDate int64 `json:"until_date,omitempty"` // optional
|
||||
CanBeEdited bool `json:"can_be_edited,omitempty"` // optional
|
||||
CanChangeInfo bool `json:"can_change_info,omitempty"` // optional
|
||||
CanPostMessages bool `json:"can_post_messages,omitempty"` // optional
|
||||
CanEditMessages bool `json:"can_edit_messages,omitempty"` // optional
|
||||
CanDeleteMessages bool `json:"can_delete_messages,omitempty"` // optional
|
||||
CanInviteUsers bool `json:"can_invite_users,omitempty"` // optional
|
||||
CanRestrictMembers bool `json:"can_restrict_members,omitempty"` // optional
|
||||
CanPinMessages bool `json:"can_pin_messages,omitempty"` // optional
|
||||
CanPromoteMembers bool `json:"can_promote_members,omitempty"` // optional
|
||||
CanSendMessages bool `json:"can_send_messages,omitempty"` // optional
|
||||
CanSendMediaMessages bool `json:"can_send_media_messages,omitempty"` // optional
|
||||
CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` // optional
|
||||
CanAddWebPagePreviews bool `json:"can_add_web_page_previews,omitempty"` // optional
|
||||
}
|
||||
|
||||
// IsCreator returns if the ChatMember was the creator of the chat.
|
||||
func (chat ChatMember) IsCreator() bool { return chat.Status == "creator" }
|
||||
|
||||
// IsAdministrator returns if the ChatMember is a chat administrator.
|
||||
func (chat ChatMember) IsAdministrator() bool { return chat.Status == "administrator" }
|
||||
|
||||
// IsMember returns if the ChatMember is a current member of the chat.
|
||||
func (chat ChatMember) IsMember() bool { return chat.Status == "member" }
|
||||
|
||||
// HasLeft returns if the ChatMember left the chat.
|
||||
func (chat ChatMember) HasLeft() bool { return chat.Status == "left" }
|
||||
|
||||
// WasKicked returns if the ChatMember was kicked from the chat.
|
||||
func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" }
|
||||
|
||||
// Game is a game within Telegram.
|
||||
type Game struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Photo []PhotoSize `json:"photo"`
|
||||
Text string `json:"text"`
|
||||
TextEntities []MessageEntity `json:"text_entities"`
|
||||
Animation Animation `json:"animation"`
|
||||
}
|
||||
|
||||
// Animation is a GIF animation demonstrating the game.
|
||||
type Animation struct {
|
||||
FileID string `json:"file_id"`
|
||||
Thumb PhotoSize `json:"thumb"`
|
||||
FileName string `json:"file_name"`
|
||||
MimeType string `json:"mime_type"`
|
||||
FileSize int `json:"file_size"`
|
||||
}
|
||||
|
||||
// GameHighScore is a user's score and position on the leaderboard.
|
||||
type GameHighScore struct {
|
||||
Position int `json:"position"`
|
||||
User User `json:"user"`
|
||||
Score int `json:"score"`
|
||||
}
|
||||
|
||||
// CallbackGame is for starting a game in an inline keyboard button.
|
||||
type CallbackGame struct{}
|
||||
|
||||
// WebhookInfo is information about a currently set webhook.
|
||||
type WebhookInfo struct {
|
||||
URL string `json:"url"`
|
||||
HasCustomCertificate bool `json:"has_custom_certificate"`
|
||||
PendingUpdateCount int `json:"pending_update_count"`
|
||||
LastErrorDate int `json:"last_error_date"` // optional
|
||||
LastErrorMessage string `json:"last_error_message"` // optional
|
||||
}
|
||||
|
||||
// IsSet returns true if a webhook is currently set.
|
||||
func (info WebhookInfo) IsSet() bool {
|
||||
return info.URL != ""
|
||||
}
|
||||
|
||||
// InputMediaPhoto contains a photo for displaying as part of a media group.
|
||||
type InputMediaPhoto struct {
|
||||
Type string `json:"type"`
|
||||
Media string `json:"media"`
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
}
|
||||
|
||||
// InputMediaVideo contains a video for displaying as part of a media group.
|
||||
type InputMediaVideo struct {
|
||||
Type string `json:"type"`
|
||||
Media string `json:"media"`
|
||||
// thumb intentionally missing as it is not currently compatible
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Duration int `json:"duration"`
|
||||
SupportsStreaming bool `json:"supports_streaming"`
|
||||
}
|
||||
|
||||
// InlineQuery is a Query from Telegram for an inline request.
|
||||
type InlineQuery struct {
|
||||
ID string `json:"id"`
|
||||
From *User `json:"from"`
|
||||
Location *Location `json:"location"` // optional
|
||||
Query string `json:"query"`
|
||||
Offset string `json:"offset"`
|
||||
}
|
||||
|
||||
// InlineQueryResultArticle is an inline query response article.
|
||||
type InlineQueryResultArticle struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
Title string `json:"title"` // required
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"` // required
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
URL string `json:"url"`
|
||||
HideURL bool `json:"hide_url"`
|
||||
Description string `json:"description"`
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
ThumbWidth int `json:"thumb_width"`
|
||||
ThumbHeight int `json:"thumb_height"`
|
||||
}
|
||||
|
||||
// InlineQueryResultPhoto is an inline query response photo.
|
||||
type InlineQueryResultPhoto struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
URL string `json:"photo_url"` // required
|
||||
MimeType string `json:"mime_type"`
|
||||
Width int `json:"photo_width"`
|
||||
Height int `json:"photo_height"`
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultCachedPhoto is an inline query response with cached photo.
|
||||
type InlineQueryResultCachedPhoto struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
PhotoID string `json:"photo_file_id"` // required
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultGIF is an inline query response GIF.
|
||||
type InlineQueryResultGIF struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
URL string `json:"gif_url"` // required
|
||||
ThumbURL string `json:"thumb_url"` // required
|
||||
Width int `json:"gif_width,omitempty"`
|
||||
Height int `json:"gif_height,omitempty"`
|
||||
Duration int `json:"gif_duration,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultCachedGIF is an inline query response with cached gif.
|
||||
type InlineQueryResultCachedGIF struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
GifID string `json:"gif_file_id"` // required
|
||||
Title string `json:"title"`
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF.
|
||||
type InlineQueryResultMPEG4GIF struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
URL string `json:"mpeg4_url"` // required
|
||||
Width int `json:"mpeg4_width"`
|
||||
Height int `json:"mpeg4_height"`
|
||||
Duration int `json:"mpeg4_duration"`
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
Title string `json:"title"`
|
||||
Caption string `json:"caption"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultCachedMpeg4Gif is an inline query response with cached
|
||||
// H.264/MPEG-4 AVC video without sound gif.
|
||||
type InlineQueryResultCachedMpeg4Gif struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
MGifID string `json:"mpeg4_file_id"` // required
|
||||
Title string `json:"title"`
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultVideo is an inline query response video.
|
||||
type InlineQueryResultVideo struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
URL string `json:"video_url"` // required
|
||||
MimeType string `json:"mime_type"` // required
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
Title string `json:"title"`
|
||||
Caption string `json:"caption"`
|
||||
Width int `json:"video_width"`
|
||||
Height int `json:"video_height"`
|
||||
Duration int `json:"video_duration"`
|
||||
Description string `json:"description"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultCachedVideo is an inline query response with cached video.
|
||||
type InlineQueryResultCachedVideo struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
VideoID string `json:"video_file_id"` // required
|
||||
Title string `json:"title"` // required
|
||||
Description string `json:"description"`
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultAudio is an inline query response audio.
|
||||
type InlineQueryResultAudio struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
URL string `json:"audio_url"` // required
|
||||
Title string `json:"title"` // required
|
||||
Caption string `json:"caption"`
|
||||
Performer string `json:"performer"`
|
||||
Duration int `json:"audio_duration"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultCachedAudio is an inline query response with cached audio.
|
||||
type InlineQueryResultCachedAudio struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
AudioID string `json:"audio_file_id"` // required
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultVoice is an inline query response voice.
|
||||
type InlineQueryResultVoice struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
URL string `json:"voice_url"` // required
|
||||
Title string `json:"title"` // required
|
||||
Caption string `json:"caption"`
|
||||
Duration int `json:"voice_duration"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultCachedVoice is an inline query response with cached voice.
|
||||
type InlineQueryResultCachedVoice struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
VoiceID string `json:"voice_file_id"` // required
|
||||
Title string `json:"title"` // required
|
||||
Caption string `json:"caption"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultDocument is an inline query response document.
|
||||
type InlineQueryResultDocument struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
Title string `json:"title"` // required
|
||||
Caption string `json:"caption"`
|
||||
URL string `json:"document_url"` // required
|
||||
MimeType string `json:"mime_type"` // required
|
||||
Description string `json:"description"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
ThumbWidth int `json:"thumb_width"`
|
||||
ThumbHeight int `json:"thumb_height"`
|
||||
}
|
||||
|
||||
// InlineQueryResultCachedDocument is an inline query response with cached document.
|
||||
type InlineQueryResultCachedDocument struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
DocumentID string `json:"document_file_id"` // required
|
||||
Title string `json:"title"` // required
|
||||
Caption string `json:"caption"`
|
||||
Description string `json:"description"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
// InlineQueryResultLocation is an inline query response location.
|
||||
type InlineQueryResultLocation struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
Latitude float64 `json:"latitude"` // required
|
||||
Longitude float64 `json:"longitude"` // required
|
||||
Title string `json:"title"` // required
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
ThumbWidth int `json:"thumb_width"`
|
||||
ThumbHeight int `json:"thumb_height"`
|
||||
}
|
||||
|
||||
// InlineQueryResultVenue is an inline query response venue.
|
||||
type InlineQueryResultVenue struct {
|
||||
Type string `json:"type"` // required
|
||||
ID string `json:"id"` // required
|
||||
Latitude float64 `json:"latitude"` // required
|
||||
Longitude float64 `json:"longitude"` // required
|
||||
Title string `json:"title"` // required
|
||||
Address string `json:"address"` // required
|
||||
FoursquareID string `json:"foursquare_id"`
|
||||
FoursquareType string `json:"foursquare_type"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
ThumbWidth int `json:"thumb_width"`
|
||||
ThumbHeight int `json:"thumb_height"`
|
||||
}
|
||||
|
||||
// InlineQueryResultGame is an inline query response game.
|
||||
type InlineQueryResultGame struct {
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id"`
|
||||
GameShortName string `json:"game_short_name"`
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
}
|
||||
|
||||
// ChosenInlineResult is an inline query result chosen by a User
|
||||
type ChosenInlineResult struct {
|
||||
ResultID string `json:"result_id"`
|
||||
From *User `json:"from"`
|
||||
Location *Location `json:"location"`
|
||||
InlineMessageID string `json:"inline_message_id"`
|
||||
Query string `json:"query"`
|
||||
}
|
||||
|
||||
// InputTextMessageContent contains text for displaying
|
||||
// as an inline query result.
|
||||
type InputTextMessageContent struct {
|
||||
Text string `json:"message_text"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
DisableWebPagePreview bool `json:"disable_web_page_preview"`
|
||||
}
|
||||
|
||||
// InputLocationMessageContent contains a location for displaying
|
||||
// as an inline query result.
|
||||
type InputLocationMessageContent struct {
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
}
|
||||
|
||||
// InputVenueMessageContent contains a venue for displaying
|
||||
// as an inline query result.
|
||||
type InputVenueMessageContent struct {
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
Title string `json:"title"`
|
||||
Address string `json:"address"`
|
||||
FoursquareID string `json:"foursquare_id"`
|
||||
}
|
||||
|
||||
// InputContactMessageContent contains a contact for displaying
|
||||
// as an inline query result.
|
||||
type InputContactMessageContent struct {
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
}
|
||||
|
||||
// Invoice contains basic information about an invoice.
|
||||
type Invoice struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
StartParameter string `json:"start_parameter"`
|
||||
Currency string `json:"currency"`
|
||||
TotalAmount int `json:"total_amount"`
|
||||
}
|
||||
|
||||
// LabeledPrice represents a portion of the price for goods or services.
|
||||
type LabeledPrice struct {
|
||||
Label string `json:"label"`
|
||||
Amount int `json:"amount"`
|
||||
}
|
||||
|
||||
// ShippingAddress represents a shipping address.
|
||||
type ShippingAddress struct {
|
||||
CountryCode string `json:"country_code"`
|
||||
State string `json:"state"`
|
||||
City string `json:"city"`
|
||||
StreetLine1 string `json:"street_line1"`
|
||||
StreetLine2 string `json:"street_line2"`
|
||||
PostCode string `json:"post_code"`
|
||||
}
|
||||
|
||||
// OrderInfo represents information about an order.
|
||||
type OrderInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
PhoneNumber string `json:"phone_number,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"`
|
||||
}
|
||||
|
||||
// ShippingOption represents one shipping option.
|
||||
type ShippingOption struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Prices *[]LabeledPrice `json:"prices"`
|
||||
}
|
||||
|
||||
// SuccessfulPayment contains basic information about a successful payment.
|
||||
type SuccessfulPayment struct {
|
||||
Currency string `json:"currency"`
|
||||
TotalAmount int `json:"total_amount"`
|
||||
InvoicePayload string `json:"invoice_payload"`
|
||||
ShippingOptionID string `json:"shipping_option_id,omitempty"`
|
||||
OrderInfo *OrderInfo `json:"order_info,omitempty"`
|
||||
TelegramPaymentChargeID string `json:"telegram_payment_charge_id"`
|
||||
ProviderPaymentChargeID string `json:"provider_payment_charge_id"`
|
||||
}
|
||||
|
||||
// ShippingQuery contains information about an incoming shipping query.
|
||||
type ShippingQuery struct {
|
||||
ID string `json:"id"`
|
||||
From *User `json:"from"`
|
||||
InvoicePayload string `json:"invoice_payload"`
|
||||
ShippingAddress *ShippingAddress `json:"shipping_address"`
|
||||
}
|
||||
|
||||
// PreCheckoutQuery contains information about an incoming pre-checkout query.
|
||||
type PreCheckoutQuery struct {
|
||||
ID string `json:"id"`
|
||||
From *User `json:"from"`
|
||||
Currency string `json:"currency"`
|
||||
TotalAmount int `json:"total_amount"`
|
||||
InvoicePayload string `json:"invoice_payload"`
|
||||
ShippingOptionID string `json:"shipping_option_id,omitempty"`
|
||||
OrderInfo *OrderInfo `json:"order_info,omitempty"`
|
||||
}
|
||||
|
||||
// Error is an error containing extra information returned by the Telegram API.
|
||||
type Error struct {
|
||||
Code int
|
||||
Message string
|
||||
ResponseParameters
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
.idea/
|
||||
coverage.out
|
||||
tmp/
|
||||
book/
|
||||
@@ -1,12 +1,14 @@
|
||||
# Golang bindings for the Telegram Bot API
|
||||
|
||||
[](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api)
|
||||
[](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api)
|
||||
[](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5)
|
||||
[](https://github.com/go-telegram-bot-api/telegram-bot-api/actions/workflows/test.yml)
|
||||
|
||||
All methods are fairly self explanatory, and reading the [godoc](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) page should
|
||||
All methods are fairly self-explanatory, and reading the [godoc](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) page should
|
||||
explain everything. If something isn't clear, open an issue or submit
|
||||
a pull request.
|
||||
|
||||
There are more tutorials and high-level information on the website, [go-telegram-bot-api.dev](https://go-telegram-bot-api.dev).
|
||||
|
||||
The scope of this project is just to provide a wrapper around the API
|
||||
without any additional features. There are other projects for creating
|
||||
something with plugins and command handlers without having to design
|
||||
@@ -18,7 +20,7 @@ you want to ask questions or discuss development.
|
||||
## Example
|
||||
|
||||
First, ensure the library is installed and up to date by running
|
||||
`go get -u github.com/go-telegram-bot-api/telegram-bot-api`.
|
||||
`go get -u github.com/go-telegram-bot-api/telegram-bot-api/v5`.
|
||||
|
||||
This is a very simple bot that just displays any gotten updates,
|
||||
then replies it to that chat.
|
||||
@@ -29,7 +31,7 @@ package main
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -45,28 +47,21 @@ func main() {
|
||||
u := tgbotapi.NewUpdate(0)
|
||||
u.Timeout = 60
|
||||
|
||||
updates, err := bot.GetUpdatesChan(u)
|
||||
updates := bot.GetUpdatesChan(u)
|
||||
|
||||
for update := range updates {
|
||||
if update.Message == nil { // ignore any non-Message Updates
|
||||
continue
|
||||
if update.Message != nil { // If we got a message
|
||||
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
|
||||
msg.ReplyToMessageID = update.Message.MessageID
|
||||
|
||||
bot.Send(msg)
|
||||
}
|
||||
|
||||
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
|
||||
|
||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
|
||||
msg.ReplyToMessageID = update.Message.MessageID
|
||||
|
||||
bot.Send(msg)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There are more examples on the [wiki](https://github.com/go-telegram-bot-api/telegram-bot-api/wiki)
|
||||
with detailed information on how to do many different kinds of things.
|
||||
It's a great place to get started on using keyboards, commands, or other
|
||||
kinds of reply markup.
|
||||
|
||||
If you need to use webhooks (if you wish to run on Google App Engine),
|
||||
you may use a slightly different method.
|
||||
|
||||
@@ -77,7 +72,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -90,17 +85,22 @@ func main() {
|
||||
|
||||
log.Printf("Authorized on account %s", bot.Self.UserName)
|
||||
|
||||
_, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem"))
|
||||
wh, _ := tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem")
|
||||
|
||||
_, err = bot.SetWebhook(wh)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
info, err := bot.GetWebhookInfo()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if info.LastErrorDate != 0 {
|
||||
log.Printf("Telegram callback failed: %s", info.LastErrorMessage)
|
||||
}
|
||||
|
||||
updates := bot.ListenForWebhook("/" + bot.Token)
|
||||
go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil)
|
||||
|
||||
@@ -110,7 +110,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
If you need, you may generate a self signed certficate, as this requires
|
||||
If you need, you may generate a self-signed certificate, as this requires
|
||||
HTTPS / TLS. The above example tells Telegram that this is your
|
||||
certificate and that it should be trusted, even though it is not
|
||||
properly signed.
|
||||
9
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml
generated
vendored
Normal file
9
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
[book]
|
||||
authors = ["Syfaro"]
|
||||
language = "en"
|
||||
multilingual = false
|
||||
src = "docs"
|
||||
title = "Go Telegram Bot API"
|
||||
|
||||
[output.html]
|
||||
git-repository-url = "https://github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
726
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go
generated
vendored
Normal file
726
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go
generated
vendored
Normal file
@@ -0,0 +1,726 @@
|
||||
// Package tgbotapi has functions and types used for interacting with
|
||||
// the Telegram Bot API.
|
||||
package tgbotapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// HTTPClient is the type needed for the bot to perform HTTP requests.
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
// BotAPI allows you to interact with the Telegram Bot API.
|
||||
type BotAPI struct {
|
||||
Token string `json:"token"`
|
||||
Debug bool `json:"debug"`
|
||||
Buffer int `json:"buffer"`
|
||||
|
||||
Self User `json:"-"`
|
||||
Client HTTPClient `json:"-"`
|
||||
shutdownChannel chan interface{}
|
||||
|
||||
apiEndpoint string
|
||||
}
|
||||
|
||||
// NewBotAPI creates a new BotAPI instance.
|
||||
//
|
||||
// It requires a token, provided by @BotFather on Telegram.
|
||||
func NewBotAPI(token string) (*BotAPI, error) {
|
||||
return NewBotAPIWithClient(token, APIEndpoint, &http.Client{})
|
||||
}
|
||||
|
||||
// NewBotAPIWithAPIEndpoint creates a new BotAPI instance
|
||||
// and allows you to pass API endpoint.
|
||||
//
|
||||
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||
func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) {
|
||||
return NewBotAPIWithClient(token, apiEndpoint, &http.Client{})
|
||||
}
|
||||
|
||||
// NewBotAPIWithClient creates a new BotAPI instance
|
||||
// and allows you to pass a http.Client.
|
||||
//
|
||||
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||
func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) {
|
||||
bot := &BotAPI{
|
||||
Token: token,
|
||||
Client: client,
|
||||
Buffer: 100,
|
||||
shutdownChannel: make(chan interface{}),
|
||||
|
||||
apiEndpoint: apiEndpoint,
|
||||
}
|
||||
|
||||
self, err := bot.GetMe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bot.Self = self
|
||||
|
||||
return bot, nil
|
||||
}
|
||||
|
||||
// SetAPIEndpoint changes the Telegram Bot API endpoint used by the instance.
|
||||
func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) {
|
||||
bot.apiEndpoint = apiEndpoint
|
||||
}
|
||||
|
||||
func buildParams(in Params) url.Values {
|
||||
if in == nil {
|
||||
return url.Values{}
|
||||
}
|
||||
|
||||
out := url.Values{}
|
||||
|
||||
for key, value := range in {
|
||||
out.Set(key, value)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// MakeRequest makes a request to a specific endpoint with our token.
|
||||
func (bot *BotAPI) MakeRequest(endpoint string, params Params) (*APIResponse, error) {
|
||||
if bot.Debug {
|
||||
log.Printf("Endpoint: %s, params: %v\n", endpoint, params)
|
||||
}
|
||||
|
||||
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
|
||||
|
||||
values := buildParams(params)
|
||||
|
||||
req, err := http.NewRequest("POST", method, strings.NewReader(values.Encode()))
|
||||
if err != nil {
|
||||
return &APIResponse{}, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
resp, err := bot.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var apiResp APIResponse
|
||||
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
||||
if err != nil {
|
||||
return &apiResp, err
|
||||
}
|
||||
|
||||
if bot.Debug {
|
||||
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
|
||||
}
|
||||
|
||||
if !apiResp.Ok {
|
||||
var parameters ResponseParameters
|
||||
|
||||
if apiResp.Parameters != nil {
|
||||
parameters = *apiResp.Parameters
|
||||
}
|
||||
|
||||
return &apiResp, &Error{
|
||||
Code: apiResp.ErrorCode,
|
||||
Message: apiResp.Description,
|
||||
ResponseParameters: parameters,
|
||||
}
|
||||
}
|
||||
|
||||
return &apiResp, nil
|
||||
}
|
||||
|
||||
// decodeAPIResponse decode response and return slice of bytes if debug enabled.
|
||||
// If debug disabled, just decode http.Response.Body stream to APIResponse struct
|
||||
// for efficient memory usage
|
||||
func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse) ([]byte, error) {
|
||||
if !bot.Debug {
|
||||
dec := json.NewDecoder(responseBody)
|
||||
err := dec.Decode(resp)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if debug, read response body
|
||||
data, err := ioutil.ReadAll(responseBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UploadFiles makes a request to the API with files.
|
||||
func (bot *BotAPI) UploadFiles(endpoint string, params Params, files []RequestFile) (*APIResponse, error) {
|
||||
r, w := io.Pipe()
|
||||
m := multipart.NewWriter(w)
|
||||
|
||||
// This code modified from the very helpful @HirbodBehnam
|
||||
// https://github.com/go-telegram-bot-api/telegram-bot-api/issues/354#issuecomment-663856473
|
||||
go func() {
|
||||
defer w.Close()
|
||||
defer m.Close()
|
||||
|
||||
for field, value := range params {
|
||||
if err := m.WriteField(field, value); err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if file.Data.NeedsUpload() {
|
||||
name, reader, err := file.Data.UploadData()
|
||||
if err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
part, err := m.CreateFormFile(file.Name, name)
|
||||
if err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := io.Copy(part, reader); err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if closer, ok := reader.(io.ReadCloser); ok {
|
||||
if err = closer.Close(); err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value := file.Data.SendData()
|
||||
|
||||
if err := m.WriteField(file.Name, value); err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if bot.Debug {
|
||||
log.Printf("Endpoint: %s, params: %v, with %d files\n", endpoint, params, len(files))
|
||||
}
|
||||
|
||||
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
|
||||
|
||||
req, err := http.NewRequest("POST", method, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", m.FormDataContentType())
|
||||
|
||||
resp, err := bot.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var apiResp APIResponse
|
||||
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
||||
if err != nil {
|
||||
return &apiResp, err
|
||||
}
|
||||
|
||||
if bot.Debug {
|
||||
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
|
||||
}
|
||||
|
||||
if !apiResp.Ok {
|
||||
var parameters ResponseParameters
|
||||
|
||||
if apiResp.Parameters != nil {
|
||||
parameters = *apiResp.Parameters
|
||||
}
|
||||
|
||||
return &apiResp, &Error{
|
||||
Message: apiResp.Description,
|
||||
ResponseParameters: parameters,
|
||||
}
|
||||
}
|
||||
|
||||
return &apiResp, nil
|
||||
}
|
||||
|
||||
// GetFileDirectURL returns direct URL to file
|
||||
//
|
||||
// It requires the FileID.
|
||||
func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) {
|
||||
file, err := bot.GetFile(FileConfig{fileID})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return file.Link(bot.Token), nil
|
||||
}
|
||||
|
||||
// GetMe fetches the currently authenticated bot.
|
||||
//
|
||||
// This method is called upon creation to validate the token,
|
||||
// and so you may get this data from BotAPI.Self without the need for
|
||||
// another request.
|
||||
func (bot *BotAPI) GetMe() (User, error) {
|
||||
resp, err := bot.MakeRequest("getMe", nil)
|
||||
if err != nil {
|
||||
return User{}, err
|
||||
}
|
||||
|
||||
var user User
|
||||
err = json.Unmarshal(resp.Result, &user)
|
||||
|
||||
return user, err
|
||||
}
|
||||
|
||||
// IsMessageToMe returns true if message directed to this bot.
|
||||
//
|
||||
// It requires the Message.
|
||||
func (bot *BotAPI) IsMessageToMe(message Message) bool {
|
||||
return strings.Contains(message.Text, "@"+bot.Self.UserName)
|
||||
}
|
||||
|
||||
func hasFilesNeedingUpload(files []RequestFile) bool {
|
||||
for _, file := range files {
|
||||
if file.Data.NeedsUpload() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Request sends a Chattable to Telegram, and returns the APIResponse.
|
||||
func (bot *BotAPI) Request(c Chattable) (*APIResponse, error) {
|
||||
params, err := c.params()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t, ok := c.(Fileable); ok {
|
||||
files := t.files()
|
||||
|
||||
// If we have files that need to be uploaded, we should delegate the
|
||||
// request to UploadFile.
|
||||
if hasFilesNeedingUpload(files) {
|
||||
return bot.UploadFiles(t.method(), params, files)
|
||||
}
|
||||
|
||||
// However, if there are no files to be uploaded, there's likely things
|
||||
// that need to be turned into params instead.
|
||||
for _, file := range files {
|
||||
params[file.Name] = file.Data.SendData()
|
||||
}
|
||||
}
|
||||
|
||||
return bot.MakeRequest(c.method(), params)
|
||||
}
|
||||
|
||||
// Send will send a Chattable item to Telegram and provides the
|
||||
// returned Message.
|
||||
func (bot *BotAPI) Send(c Chattable) (Message, error) {
|
||||
resp, err := bot.Request(c)
|
||||
if err != nil {
|
||||
return Message{}, err
|
||||
}
|
||||
|
||||
var message Message
|
||||
err = json.Unmarshal(resp.Result, &message)
|
||||
|
||||
return message, err
|
||||
}
|
||||
|
||||
// SendMediaGroup sends a media group and returns the resulting messages.
|
||||
func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var messages []Message
|
||||
err = json.Unmarshal(resp.Result, &messages)
|
||||
|
||||
return messages, err
|
||||
}
|
||||
|
||||
// GetUserProfilePhotos gets a user's profile photos.
|
||||
//
|
||||
// It requires UserID.
|
||||
// Offset and Limit are optional.
|
||||
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return UserProfilePhotos{}, err
|
||||
}
|
||||
|
||||
var profilePhotos UserProfilePhotos
|
||||
err = json.Unmarshal(resp.Result, &profilePhotos)
|
||||
|
||||
return profilePhotos, err
|
||||
}
|
||||
|
||||
// GetFile returns a File which can download a file from Telegram.
|
||||
//
|
||||
// Requires FileID.
|
||||
func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return File{}, err
|
||||
}
|
||||
|
||||
var file File
|
||||
err = json.Unmarshal(resp.Result, &file)
|
||||
|
||||
return file, err
|
||||
}
|
||||
|
||||
// GetUpdates fetches updates.
|
||||
// If a WebHook is set, this will not return any data!
|
||||
//
|
||||
// Offset, Limit, Timeout, and AllowedUpdates are optional.
|
||||
// To avoid stale items, set Offset to one higher than the previous item.
|
||||
// Set Timeout to a large number to reduce requests, so you can get updates
|
||||
// instantly instead of having to wait between requests.
|
||||
func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return []Update{}, err
|
||||
}
|
||||
|
||||
var updates []Update
|
||||
err = json.Unmarshal(resp.Result, &updates)
|
||||
|
||||
return updates, err
|
||||
}
|
||||
|
||||
// GetWebhookInfo allows you to fetch information about a webhook and if
|
||||
// one currently is set, along with pending update count and error messages.
|
||||
func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) {
|
||||
resp, err := bot.MakeRequest("getWebhookInfo", nil)
|
||||
if err != nil {
|
||||
return WebhookInfo{}, err
|
||||
}
|
||||
|
||||
var info WebhookInfo
|
||||
err = json.Unmarshal(resp.Result, &info)
|
||||
|
||||
return info, err
|
||||
}
|
||||
|
||||
// GetUpdatesChan starts and returns a channel for getting updates.
|
||||
func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel {
|
||||
ch := make(chan Update, bot.Buffer)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-bot.shutdownChannel:
|
||||
close(ch)
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
updates, err := bot.GetUpdates(config)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
log.Println("Failed to get updates, retrying in 3 seconds...")
|
||||
time.Sleep(time.Second * 3)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
for _, update := range updates {
|
||||
if update.UpdateID >= config.Offset {
|
||||
config.Offset = update.UpdateID + 1
|
||||
ch <- update
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// StopReceivingUpdates stops the go routine which receives updates
|
||||
func (bot *BotAPI) StopReceivingUpdates() {
|
||||
if bot.Debug {
|
||||
log.Println("Stopping the update receiver routine...")
|
||||
}
|
||||
close(bot.shutdownChannel)
|
||||
}
|
||||
|
||||
// ListenForWebhook registers a http handler for a webhook.
|
||||
func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
|
||||
ch := make(chan Update, bot.Buffer)
|
||||
|
||||
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
|
||||
update, err := bot.HandleUpdate(r)
|
||||
if err != nil {
|
||||
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write(errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
ch <- *update
|
||||
})
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// ListenForWebhookRespReqFormat registers a http handler for a single incoming webhook.
|
||||
func (bot *BotAPI) ListenForWebhookRespReqFormat(w http.ResponseWriter, r *http.Request) UpdatesChannel {
|
||||
ch := make(chan Update, bot.Buffer)
|
||||
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
update, err := bot.HandleUpdate(r)
|
||||
if err != nil {
|
||||
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write(errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
ch <- *update
|
||||
close(ch)
|
||||
}(w, r)
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// HandleUpdate parses and returns update received via webhook
|
||||
func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) {
|
||||
if r.Method != http.MethodPost {
|
||||
err := errors.New("wrong HTTP method required POST")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var update Update
|
||||
err := json.NewDecoder(r.Body).Decode(&update)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &update, nil
|
||||
}
|
||||
|
||||
// WriteToHTTPResponse writes the request to the HTTP ResponseWriter.
|
||||
//
|
||||
// It doesn't support uploading files.
|
||||
//
|
||||
// See https://core.telegram.org/bots/api#making-requests-when-getting-updates
|
||||
// for details.
|
||||
func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error {
|
||||
params, err := c.params()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t, ok := c.(Fileable); ok {
|
||||
if hasFilesNeedingUpload(t.files()) {
|
||||
return errors.New("unable to use http response to upload files")
|
||||
}
|
||||
}
|
||||
|
||||
values := buildParams(params)
|
||||
values.Set("method", c.method())
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
_, err = w.Write([]byte(values.Encode()))
|
||||
return err
|
||||
}
|
||||
|
||||
// GetChat gets information about a chat.
|
||||
func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return Chat{}, err
|
||||
}
|
||||
|
||||
var chat Chat
|
||||
err = json.Unmarshal(resp.Result, &chat)
|
||||
|
||||
return chat, err
|
||||
}
|
||||
|
||||
// GetChatAdministrators gets a list of administrators in the chat.
|
||||
//
|
||||
// If none have been appointed, only the creator will be returned.
|
||||
// Bots are not shown, even if they are an administrator.
|
||||
func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return []ChatMember{}, err
|
||||
}
|
||||
|
||||
var members []ChatMember
|
||||
err = json.Unmarshal(resp.Result, &members)
|
||||
|
||||
return members, err
|
||||
}
|
||||
|
||||
// GetChatMembersCount gets the number of users in a chat.
|
||||
func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
var count int
|
||||
err = json.Unmarshal(resp.Result, &count)
|
||||
|
||||
return count, err
|
||||
}
|
||||
|
||||
// GetChatMember gets a specific chat member.
|
||||
func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return ChatMember{}, err
|
||||
}
|
||||
|
||||
var member ChatMember
|
||||
err = json.Unmarshal(resp.Result, &member)
|
||||
|
||||
return member, err
|
||||
}
|
||||
|
||||
// GetGameHighScores allows you to get the high scores for a game.
|
||||
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return []GameHighScore{}, err
|
||||
}
|
||||
|
||||
var highScores []GameHighScore
|
||||
err = json.Unmarshal(resp.Result, &highScores)
|
||||
|
||||
return highScores, err
|
||||
}
|
||||
|
||||
// GetInviteLink get InviteLink for a chat
|
||||
func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var inviteLink string
|
||||
err = json.Unmarshal(resp.Result, &inviteLink)
|
||||
|
||||
return inviteLink, err
|
||||
}
|
||||
|
||||
// GetStickerSet returns a StickerSet.
|
||||
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return StickerSet{}, err
|
||||
}
|
||||
|
||||
var stickers StickerSet
|
||||
err = json.Unmarshal(resp.Result, &stickers)
|
||||
|
||||
return stickers, err
|
||||
}
|
||||
|
||||
// StopPoll stops a poll and returns the result.
|
||||
func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return Poll{}, err
|
||||
}
|
||||
|
||||
var poll Poll
|
||||
err = json.Unmarshal(resp.Result, &poll)
|
||||
|
||||
return poll, err
|
||||
}
|
||||
|
||||
// GetMyCommands gets the currently registered commands.
|
||||
func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) {
|
||||
return bot.GetMyCommandsWithConfig(GetMyCommandsConfig{})
|
||||
}
|
||||
|
||||
// GetMyCommandsWithConfig gets the currently registered commands with a config.
|
||||
func (bot *BotAPI) GetMyCommandsWithConfig(config GetMyCommandsConfig) ([]BotCommand, error) {
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var commands []BotCommand
|
||||
err = json.Unmarshal(resp.Result, &commands)
|
||||
|
||||
return commands, err
|
||||
}
|
||||
|
||||
// CopyMessage copy messages of any kind. The method is analogous to the method
|
||||
// forwardMessage, but the copied message doesn't have a link to the original
|
||||
// message. Returns the MessageID of the sent message on success.
|
||||
func (bot *BotAPI) CopyMessage(config CopyMessageConfig) (MessageID, error) {
|
||||
params, err := config.params()
|
||||
if err != nil {
|
||||
return MessageID{}, err
|
||||
}
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
if err != nil {
|
||||
return MessageID{}, err
|
||||
}
|
||||
|
||||
var messageID MessageID
|
||||
err = json.Unmarshal(resp.Result, &messageID)
|
||||
|
||||
return messageID, err
|
||||
}
|
||||
|
||||
// EscapeText takes an input text and escape Telegram markup symbols.
|
||||
// In this way we can send a text without being afraid of having to escape the characters manually.
|
||||
// Note that you don't have to include the formatting style in the input text, or it will be escaped too.
|
||||
// If there is an error, an empty string will be returned.
|
||||
//
|
||||
// parseMode is the text formatting mode (ModeMarkdown, ModeMarkdownV2 or ModeHTML)
|
||||
// text is the input string that will be escaped
|
||||
func EscapeText(parseMode string, text string) string {
|
||||
var replacer *strings.Replacer
|
||||
|
||||
if parseMode == ModeHTML {
|
||||
replacer = strings.NewReplacer("<", "<", ">", ">", "&", "&")
|
||||
} else if parseMode == ModeMarkdown {
|
||||
replacer = strings.NewReplacer("_", "\\_", "*", "\\*", "`", "\\`", "[", "\\[")
|
||||
} else if parseMode == ModeMarkdownV2 {
|
||||
replacer = strings.NewReplacer(
|
||||
"_", "\\_", "*", "\\*", "[", "\\[", "]", "\\]", "(",
|
||||
"\\(", ")", "\\)", "~", "\\~", "`", "\\`", ">", "\\>",
|
||||
"#", "\\#", "+", "\\+", "-", "\\-", "=", "\\=", "|",
|
||||
"\\|", "{", "\\{", "}", "\\}", ".", "\\.", "!", "\\!",
|
||||
)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
|
||||
return replacer.Replace(text)
|
||||
}
|
||||
2468
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go
generated
vendored
Normal file
2468
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -52,241 +52,117 @@ func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// NewPhotoUpload creates a new photo uploader.
|
||||
// NewCopyMessage creates a new copy message.
|
||||
//
|
||||
// chatID is where to send it, fromChatID is the source chat,
|
||||
// and messageID is the ID of the original message.
|
||||
func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig {
|
||||
return CopyMessageConfig{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FromChatID: fromChatID,
|
||||
MessageID: messageID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPhoto creates a new sendPhoto request.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
//
|
||||
// Note that you must send animated GIFs as a document.
|
||||
func NewPhotoUpload(chatID int64, file interface{}) PhotoConfig {
|
||||
func NewPhoto(chatID int64, file RequestFileData) PhotoConfig {
|
||||
return PhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewPhotoShare shares an existing photo.
|
||||
// You may use this to reshare an existing photo without reuploading it.
|
||||
// NewPhotoToChannel creates a new photo uploader to send a photo to a channel.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the file
|
||||
// already uploaded.
|
||||
func NewPhotoShare(chatID int64, fileID string) PhotoConfig {
|
||||
// Note that you must send animated GIFs as a document.
|
||||
func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig {
|
||||
return PhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
BaseChat: BaseChat{
|
||||
ChannelUsername: username,
|
||||
},
|
||||
File: file,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAudioUpload creates a new audio uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewAudioUpload(chatID int64, file interface{}) AudioConfig {
|
||||
// NewAudio creates a new sendAudio request.
|
||||
func NewAudio(chatID int64, file RequestFileData) AudioConfig {
|
||||
return AudioConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAudioShare shares an existing audio file.
|
||||
// You may use this to reshare an existing audio file without
|
||||
// reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the audio
|
||||
// already uploaded.
|
||||
func NewAudioShare(chatID int64, fileID string) AudioConfig {
|
||||
return AudioConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDocumentUpload creates a new document uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewDocumentUpload(chatID int64, file interface{}) DocumentConfig {
|
||||
// NewDocument creates a new sendDocument request.
|
||||
func NewDocument(chatID int64, file RequestFileData) DocumentConfig {
|
||||
return DocumentConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDocumentShare shares an existing document.
|
||||
// You may use this to reshare an existing document without
|
||||
// reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the document
|
||||
// already uploaded.
|
||||
func NewDocumentShare(chatID int64, fileID string) DocumentConfig {
|
||||
return DocumentConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStickerUpload creates a new sticker uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewStickerUpload(chatID int64, file interface{}) StickerConfig {
|
||||
// NewSticker creates a new sendSticker request.
|
||||
func NewSticker(chatID int64, file RequestFileData) StickerConfig {
|
||||
return StickerConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStickerShare shares an existing sticker.
|
||||
// You may use this to reshare an existing sticker without
|
||||
// reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the sticker
|
||||
// already uploaded.
|
||||
func NewStickerShare(chatID int64, fileID string) StickerConfig {
|
||||
return StickerConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoUpload creates a new video uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewVideoUpload(chatID int64, file interface{}) VideoConfig {
|
||||
// NewVideo creates a new sendVideo request.
|
||||
func NewVideo(chatID int64, file RequestFileData) VideoConfig {
|
||||
return VideoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoShare shares an existing video.
|
||||
// You may use this to reshare an existing video without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the video
|
||||
// already uploaded.
|
||||
func NewVideoShare(chatID int64, fileID string) VideoConfig {
|
||||
return VideoConfig{
|
||||
// NewAnimation creates a new sendAnimation request.
|
||||
func NewAnimation(chatID int64, file RequestFileData) AnimationConfig {
|
||||
return AnimationConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAnimationUpload creates a new animation uploader.
|
||||
// NewVideoNote creates a new sendVideoNote request.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewAnimationUpload(chatID int64, file interface{}) AnimationConfig {
|
||||
return AnimationConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAnimationShare shares an existing animation.
|
||||
// You may use this to reshare an existing animation without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the animation
|
||||
// already uploaded.
|
||||
func NewAnimationShare(chatID int64, fileID string) AnimationConfig {
|
||||
return AnimationConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoNoteUpload creates a new video note uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewVideoNoteUpload(chatID int64, length int, file interface{}) VideoNoteConfig {
|
||||
func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfig {
|
||||
return VideoNoteConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
},
|
||||
Length: length,
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoNoteShare shares an existing video.
|
||||
// You may use this to reshare an existing video without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the video
|
||||
// already uploaded.
|
||||
func NewVideoNoteShare(chatID int64, length int, fileID string) VideoNoteConfig {
|
||||
return VideoNoteConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
Length: length,
|
||||
}
|
||||
}
|
||||
|
||||
// NewVoiceUpload creates a new voice uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewVoiceUpload(chatID int64, file interface{}) VoiceConfig {
|
||||
// NewVoice creates a new sendVoice request.
|
||||
func NewVoice(chatID int64, file RequestFileData) VoiceConfig {
|
||||
return VoiceConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVoiceShare shares an existing voice.
|
||||
// You may use this to reshare an existing voice without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the video
|
||||
// already uploaded.
|
||||
func NewVoiceShare(chatID int64, fileID string) VoiceConfig {
|
||||
return VoiceConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -295,26 +171,58 @@ func NewVoiceShare(chatID int64, fileID string) VoiceConfig {
|
||||
// two to ten InputMediaPhoto or InputMediaVideo.
|
||||
func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig {
|
||||
return MediaGroupConfig{
|
||||
BaseChat: BaseChat{
|
||||
ChatID: chatID,
|
||||
},
|
||||
InputMedia: files,
|
||||
ChatID: chatID,
|
||||
Media: files,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInputMediaPhoto creates a new InputMediaPhoto.
|
||||
func NewInputMediaPhoto(media string) InputMediaPhoto {
|
||||
func NewInputMediaPhoto(media RequestFileData) InputMediaPhoto {
|
||||
return InputMediaPhoto{
|
||||
Type: "photo",
|
||||
Media: media,
|
||||
BaseInputMedia{
|
||||
Type: "photo",
|
||||
Media: media,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewInputMediaVideo creates a new InputMediaVideo.
|
||||
func NewInputMediaVideo(media string) InputMediaVideo {
|
||||
func NewInputMediaVideo(media RequestFileData) InputMediaVideo {
|
||||
return InputMediaVideo{
|
||||
Type: "video",
|
||||
Media: media,
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "video",
|
||||
Media: media,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewInputMediaAnimation creates a new InputMediaAnimation.
|
||||
func NewInputMediaAnimation(media RequestFileData) InputMediaAnimation {
|
||||
return InputMediaAnimation{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "animation",
|
||||
Media: media,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewInputMediaAudio creates a new InputMediaAudio.
|
||||
func NewInputMediaAudio(media RequestFileData) InputMediaAudio {
|
||||
return InputMediaAudio{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "audio",
|
||||
Media: media,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewInputMediaDocument creates a new InputMediaDocument.
|
||||
func NewInputMediaDocument(media RequestFileData) InputMediaDocument {
|
||||
return InputMediaDocument{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "document",
|
||||
Media: media,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +277,7 @@ func NewChatAction(chatID int64, action string) ChatActionConfig {
|
||||
// NewUserProfilePhotos gets user profile photos.
|
||||
//
|
||||
// userID is the ID of the user you wish to get profile photos from.
|
||||
func NewUserProfilePhotos(userID int) UserProfilePhotosConfig {
|
||||
func NewUserProfilePhotos(userID int64) UserProfilePhotosConfig {
|
||||
return UserProfilePhotosConfig{
|
||||
UserID: userID,
|
||||
Offset: 0,
|
||||
@@ -392,25 +300,33 @@ func NewUpdate(offset int) UpdateConfig {
|
||||
// NewWebhook creates a new webhook.
|
||||
//
|
||||
// link is the url parsable link you wish to get the updates.
|
||||
func NewWebhook(link string) WebhookConfig {
|
||||
u, _ := url.Parse(link)
|
||||
func NewWebhook(link string) (WebhookConfig, error) {
|
||||
u, err := url.Parse(link)
|
||||
|
||||
if err != nil {
|
||||
return WebhookConfig{}, err
|
||||
}
|
||||
|
||||
return WebhookConfig{
|
||||
URL: u,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewWebhookWithCert creates a new webhook with a certificate.
|
||||
//
|
||||
// link is the url you wish to get webhooks,
|
||||
// file contains a string to a file, FileReader, or FileBytes.
|
||||
func NewWebhookWithCert(link string, file interface{}) WebhookConfig {
|
||||
u, _ := url.Parse(link)
|
||||
func NewWebhookWithCert(link string, file RequestFileData) (WebhookConfig, error) {
|
||||
u, err := url.Parse(link)
|
||||
|
||||
if err != nil {
|
||||
return WebhookConfig{}, err
|
||||
}
|
||||
|
||||
return WebhookConfig{
|
||||
URL: u,
|
||||
Certificate: file,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewInlineQueryResultArticle creates a new inline query article.
|
||||
@@ -438,6 +354,19 @@ func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQu
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultArticleMarkdownV2 creates a new inline query article with MarkdownV2 parsing.
|
||||
func NewInlineQueryResultArticleMarkdownV2(id, title, messageText string) InlineQueryResultArticle {
|
||||
return InlineQueryResultArticle{
|
||||
Type: "article",
|
||||
ID: id,
|
||||
Title: title,
|
||||
InputMessageContent: InputTextMessageContent{
|
||||
Text: messageText,
|
||||
ParseMode: "MarkdownV2",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
|
||||
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
|
||||
return InlineQueryResultArticle{
|
||||
@@ -465,7 +394,7 @@ func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF
|
||||
return InlineQueryResultCachedGIF{
|
||||
Type: "gif",
|
||||
ID: id,
|
||||
GifID: gifID,
|
||||
GIFID: gifID,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,12 +407,12 @@ func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedPhoto create a new inline query with cached photo.
|
||||
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GifID string) InlineQueryResultCachedMpeg4Gif {
|
||||
return InlineQueryResultCachedMpeg4Gif{
|
||||
Type: "mpeg4_gif",
|
||||
ID: id,
|
||||
MGifID: MPEG4GifID,
|
||||
// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF.
|
||||
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF {
|
||||
return InlineQueryResultCachedMPEG4GIF{
|
||||
Type: "mpeg4_gif",
|
||||
ID: id,
|
||||
MPEG4FileID: MPEG4GIFID,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,6 +463,16 @@ func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResul
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedSticker create a new inline query with cached sticker.
|
||||
func NewInlineQueryResultCachedSticker(id, stickerID, title string) InlineQueryResultCachedSticker {
|
||||
return InlineQueryResultCachedSticker{
|
||||
Type: "sticker",
|
||||
ID: id,
|
||||
StickerID: stickerID,
|
||||
Title: title,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultAudio creates a new inline query audio.
|
||||
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
||||
return InlineQueryResultAudio{
|
||||
@@ -628,6 +567,18 @@ func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTex
|
||||
}
|
||||
}
|
||||
|
||||
// NewEditMessageTextAndMarkup allows you to edit the text and replymarkup of a message.
|
||||
func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig {
|
||||
return EditMessageTextConfig{
|
||||
BaseEdit: BaseEdit{
|
||||
ChatID: chatID,
|
||||
MessageID: messageID,
|
||||
ReplyMarkup: &replyMarkup,
|
||||
},
|
||||
Text: text,
|
||||
}
|
||||
}
|
||||
|
||||
// NewEditMessageCaption allows you to edit the caption of a message.
|
||||
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
|
||||
return EditMessageCaptionConfig{
|
||||
@@ -651,17 +602,6 @@ func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKe
|
||||
}
|
||||
}
|
||||
|
||||
// NewHideKeyboard hides the keyboard, with the option for being selective
|
||||
// or hiding for everyone.
|
||||
func NewHideKeyboard(selective bool) ReplyKeyboardHide {
|
||||
log.Println("NewHideKeyboard is deprecated, please use NewRemoveKeyboard")
|
||||
|
||||
return ReplyKeyboardHide{
|
||||
HideKeyboard: true,
|
||||
Selective: selective,
|
||||
}
|
||||
}
|
||||
|
||||
// NewRemoveKeyboard hides the keyboard, with the option for being selective
|
||||
// or hiding for everyone.
|
||||
func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove {
|
||||
@@ -717,6 +657,13 @@ func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
|
||||
}
|
||||
}
|
||||
|
||||
// NewOneTimeReplyKeyboard creates a new one time keyboard.
|
||||
func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
|
||||
markup := NewReplyKeyboard(rows...)
|
||||
markup.OneTimeKeyboard = true
|
||||
return markup
|
||||
}
|
||||
|
||||
// NewInlineKeyboardButtonData creates an inline keyboard button with text
|
||||
// and data for a callback.
|
||||
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
||||
@@ -726,6 +673,15 @@ func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineKeyboardButtonLoginURL creates an inline keyboard button with text
|
||||
// which goes to a LoginURL.
|
||||
func NewInlineKeyboardButtonLoginURL(text string, loginURL LoginURL) InlineKeyboardButton {
|
||||
return InlineKeyboardButton{
|
||||
Text: text,
|
||||
LoginURL: &loginURL,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineKeyboardButtonURL creates an inline keyboard button with text
|
||||
// which goes to a URL.
|
||||
func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton {
|
||||
@@ -784,7 +740,7 @@ func NewCallbackWithAlert(id, text string) CallbackConfig {
|
||||
}
|
||||
|
||||
// NewInvoice creates a new Invoice request to the user.
|
||||
func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices *[]LabeledPrice) InvoiceConfig {
|
||||
func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices []LabeledPrice) InvoiceConfig {
|
||||
return InvoiceConfig{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
Title: title,
|
||||
@@ -796,33 +752,176 @@ func NewInvoice(chatID int64, title, description, payload, providerToken, startP
|
||||
Prices: prices}
|
||||
}
|
||||
|
||||
// NewSetChatPhotoUpload creates a new chat photo uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
//
|
||||
// Note that you must send animated GIFs as a document.
|
||||
func NewSetChatPhotoUpload(chatID int64, file interface{}) SetChatPhotoConfig {
|
||||
// NewChatTitle allows you to update the title of a chat.
|
||||
func NewChatTitle(chatID int64, title string) SetChatTitleConfig {
|
||||
return SetChatTitleConfig{
|
||||
ChatID: chatID,
|
||||
Title: title,
|
||||
}
|
||||
}
|
||||
|
||||
// NewChatDescription allows you to update the description of a chat.
|
||||
func NewChatDescription(chatID int64, description string) SetChatDescriptionConfig {
|
||||
return SetChatDescriptionConfig{
|
||||
ChatID: chatID,
|
||||
Description: description,
|
||||
}
|
||||
}
|
||||
|
||||
// NewChatPhoto allows you to update the photo for a chat.
|
||||
func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig {
|
||||
return SetChatPhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
BaseChat: BaseChat{
|
||||
ChatID: chatID,
|
||||
},
|
||||
File: photo,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewSetChatPhotoShare shares an existing photo.
|
||||
// You may use this to reshare an existing photo without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the file
|
||||
// already uploaded.
|
||||
func NewSetChatPhotoShare(chatID int64, fileID string) SetChatPhotoConfig {
|
||||
return SetChatPhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
// NewDeleteChatPhoto allows you to delete the photo for a chat.
|
||||
func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig {
|
||||
return DeleteChatPhotoConfig{
|
||||
ChatID: chatID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPoll allows you to create a new poll.
|
||||
func NewPoll(chatID int64, question string, options ...string) SendPollConfig {
|
||||
return SendPollConfig{
|
||||
BaseChat: BaseChat{
|
||||
ChatID: chatID,
|
||||
},
|
||||
Question: question,
|
||||
Options: options,
|
||||
IsAnonymous: true, // This is Telegram's default.
|
||||
}
|
||||
}
|
||||
|
||||
// NewStopPoll allows you to stop a poll.
|
||||
func NewStopPoll(chatID int64, messageID int) StopPollConfig {
|
||||
return StopPollConfig{
|
||||
BaseEdit{
|
||||
ChatID: chatID,
|
||||
MessageID: messageID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDice allows you to send a random dice roll.
|
||||
func NewDice(chatID int64) DiceConfig {
|
||||
return DiceConfig{
|
||||
BaseChat: BaseChat{
|
||||
ChatID: chatID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDiceWithEmoji allows you to send a random roll of one of many types.
|
||||
//
|
||||
// Emoji may be 🎲 (1-6), 🎯 (1-6), or 🏀 (1-5).
|
||||
func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig {
|
||||
return DiceConfig{
|
||||
BaseChat: BaseChat{
|
||||
ChatID: chatID,
|
||||
},
|
||||
Emoji: emoji,
|
||||
}
|
||||
}
|
||||
|
||||
// NewBotCommandScopeDefault represents the default scope of bot commands.
|
||||
func NewBotCommandScopeDefault() BotCommandScope {
|
||||
return BotCommandScope{Type: "default"}
|
||||
}
|
||||
|
||||
// NewBotCommandScopeAllPrivateChats represents the scope of bot commands,
|
||||
// covering all private chats.
|
||||
func NewBotCommandScopeAllPrivateChats() BotCommandScope {
|
||||
return BotCommandScope{Type: "all_private_chats"}
|
||||
}
|
||||
|
||||
// NewBotCommandScopeAllGroupChats represents the scope of bot commands,
|
||||
// covering all group and supergroup chats.
|
||||
func NewBotCommandScopeAllGroupChats() BotCommandScope {
|
||||
return BotCommandScope{Type: "all_group_chats"}
|
||||
}
|
||||
|
||||
// NewBotCommandScopeAllChatAdministrators represents the scope of bot commands,
|
||||
// covering all group and supergroup chat administrators.
|
||||
func NewBotCommandScopeAllChatAdministrators() BotCommandScope {
|
||||
return BotCommandScope{Type: "all_chat_administrators"}
|
||||
}
|
||||
|
||||
// NewBotCommandScopeChat represents the scope of bot commands, covering a
|
||||
// specific chat.
|
||||
func NewBotCommandScopeChat(chatID int64) BotCommandScope {
|
||||
return BotCommandScope{
|
||||
Type: "chat",
|
||||
ChatID: chatID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewBotCommandScopeChatAdministrators represents the scope of bot commands,
|
||||
// covering all administrators of a specific group or supergroup chat.
|
||||
func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope {
|
||||
return BotCommandScope{
|
||||
Type: "chat_administrators",
|
||||
ChatID: chatID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewBotCommandScopeChatMember represents the scope of bot commands, covering a
|
||||
// specific member of a group or supergroup chat.
|
||||
func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope {
|
||||
return BotCommandScope{
|
||||
Type: "chat_member",
|
||||
ChatID: chatID,
|
||||
UserID: userID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetMyCommandsWithScope allows you to set the registered commands for a
|
||||
// given scope.
|
||||
func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig {
|
||||
return GetMyCommandsConfig{Scope: &scope}
|
||||
}
|
||||
|
||||
// NewGetMyCommandsWithScopeAndLanguage allows you to set the registered
|
||||
// commands for a given scope and language code.
|
||||
func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig {
|
||||
return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
|
||||
}
|
||||
|
||||
// NewSetMyCommands allows you to set the registered commands.
|
||||
func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig {
|
||||
return SetMyCommandsConfig{Commands: commands}
|
||||
}
|
||||
|
||||
// NewSetMyCommandsWithScope allows you to set the registered commands for a given scope.
|
||||
func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig {
|
||||
return SetMyCommandsConfig{Commands: commands, Scope: &scope}
|
||||
}
|
||||
|
||||
// NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope
|
||||
// and language code.
|
||||
func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig {
|
||||
return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode}
|
||||
}
|
||||
|
||||
// NewDeleteMyCommands allows you to delete the registered commands.
|
||||
func NewDeleteMyCommands() DeleteMyCommandsConfig {
|
||||
return DeleteMyCommandsConfig{}
|
||||
}
|
||||
|
||||
// NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given
|
||||
// scope.
|
||||
func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig {
|
||||
return DeleteMyCommandsConfig{Scope: &scope}
|
||||
}
|
||||
|
||||
// NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given
|
||||
// scope and language code.
|
||||
func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig {
|
||||
return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode}
|
||||
}
|
||||
97
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go
generated
vendored
Normal file
97
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
package tgbotapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Params represents a set of parameters that gets passed to a request.
|
||||
type Params map[string]string
|
||||
|
||||
// AddNonEmpty adds a value if it not an empty string.
|
||||
func (p Params) AddNonEmpty(key, value string) {
|
||||
if value != "" {
|
||||
p[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// AddNonZero adds a value if it is not zero.
|
||||
func (p Params) AddNonZero(key string, value int) {
|
||||
if value != 0 {
|
||||
p[key] = strconv.Itoa(value)
|
||||
}
|
||||
}
|
||||
|
||||
// AddNonZero64 is the same as AddNonZero except uses an int64.
|
||||
func (p Params) AddNonZero64(key string, value int64) {
|
||||
if value != 0 {
|
||||
p[key] = strconv.FormatInt(value, 10)
|
||||
}
|
||||
}
|
||||
|
||||
// AddBool adds a value of a bool if it is true.
|
||||
func (p Params) AddBool(key string, value bool) {
|
||||
if value {
|
||||
p[key] = strconv.FormatBool(value)
|
||||
}
|
||||
}
|
||||
|
||||
// AddNonZeroFloat adds a floating point value that is not zero.
|
||||
func (p Params) AddNonZeroFloat(key string, value float64) {
|
||||
if value != 0 {
|
||||
p[key] = strconv.FormatFloat(value, 'f', 6, 64)
|
||||
}
|
||||
}
|
||||
|
||||
// AddInterface adds an interface if it is not nil and can be JSON marshalled.
|
||||
func (p Params) AddInterface(key string, value interface{}) error {
|
||||
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
b, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p[key] = string(b)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddFirstValid attempts to add the first item that is not a default value.
|
||||
//
|
||||
// For example, AddFirstValid(0, "", "test") would add "test".
|
||||
func (p Params) AddFirstValid(key string, args ...interface{}) error {
|
||||
for _, arg := range args {
|
||||
switch v := arg.(type) {
|
||||
case int:
|
||||
if v != 0 {
|
||||
p[key] = strconv.Itoa(v)
|
||||
return nil
|
||||
}
|
||||
case int64:
|
||||
if v != 0 {
|
||||
p[key] = strconv.FormatInt(v, 10)
|
||||
return nil
|
||||
}
|
||||
case string:
|
||||
if v != "" {
|
||||
p[key] = v
|
||||
return nil
|
||||
}
|
||||
case nil:
|
||||
default:
|
||||
b, err := json.Marshal(arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p[key] = string(b)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -54,13 +54,15 @@ type (
|
||||
Credentials *EncryptedCredentials `json:"credentials"`
|
||||
}
|
||||
|
||||
// PassportFile represents a file uploaded to Telegram Passport. Currently all
|
||||
// PassportFile represents a file uploaded to Telegram Passport. Currently, all
|
||||
// Telegram Passport files are in JPEG format when decrypted and don't exceed
|
||||
// 10MB.
|
||||
PassportFile struct {
|
||||
// Unique identifier for this file
|
||||
FileID string `json:"file_id"`
|
||||
|
||||
FileUniqueID string `json:"file_unique_id"`
|
||||
|
||||
// File size
|
||||
FileSize int `json:"file_size"`
|
||||
|
||||
@@ -212,7 +214,7 @@ type (
|
||||
// PassportElementErrorFile represents an issue with a document scan. The
|
||||
// error is considered resolved when the file with the document scan changes.
|
||||
PassportElementErrorFile struct {
|
||||
// Error source, must be file
|
||||
// Error source, must be a file
|
||||
Source string `json:"source"`
|
||||
|
||||
// The section of the user's Telegram Passport which has the issue, one
|
||||
3225
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go
generated
vendored
Normal file
3225
vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/types.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user