mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-06-27 20:29:24 +00:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
248d88c849 | |||
d19535fa21 | |||
49204cafcc | |||
812db2d267 | |||
14490bea9f | |||
0352970051 | |||
ed01820722 | |||
90a61f15cc | |||
86cd7f1ba6 | |||
d6ee55e35f | |||
aef64eec32 | |||
c4193d5ccd | |||
0c94186818 | |||
9039720013 | |||
a3470f8aec | |||
01badde21d | |||
a37b232dd9 | |||
579ee48385 | |||
dd985d1dad | |||
d2caea70a2 | |||
21143cf5ee |
@ -36,7 +36,7 @@ Has a REST API.
|
|||||||
|
|
||||||
# Requirements
|
# Requirements
|
||||||
Accounts to one of the supported bridges
|
Accounts to one of the supported bridges
|
||||||
* [Mattermost](https://github.com/mattermost/platform/) 3.8.x - 3.10.x, 4.0.x - 4.1.x
|
* [Mattermost](https://github.com/mattermost/platform/) 3.8.x - 3.10.x, 4.0.x - 4.2.x
|
||||||
* [IRC](http://www.mirc.com/servers.html)
|
* [IRC](http://www.mirc.com/servers.html)
|
||||||
* [XMPP](https://jabber.org)
|
* [XMPP](https://jabber.org)
|
||||||
* [Gitter](https://gitter.im)
|
* [Gitter](https://gitter.im)
|
||||||
@ -53,7 +53,7 @@ See https://github.com/42wim/matterbridge/wiki
|
|||||||
|
|
||||||
# Installing
|
# Installing
|
||||||
## Binaries
|
## Binaries
|
||||||
* Latest stable release [v1.1.0](https://github.com/42wim/matterbridge/releases/latest)
|
* Latest stable release [v1.2.0](https://github.com/42wim/matterbridge/releases/latest)
|
||||||
* Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)
|
* Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
@ -69,6 +69,10 @@ func (b *Api) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
func (b *Api) Send(msg config.Message) (string, error) {
|
func (b *Api) Send(msg config.Message) (string, error) {
|
||||||
b.Lock()
|
b.Lock()
|
||||||
defer b.Unlock()
|
defer b.Unlock()
|
||||||
|
// ignore delete messages
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
b.Messages.Enqueue(&msg)
|
b.Messages.Enqueue(&msg)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ const (
|
|||||||
EVENT_FAILURE = "failure"
|
EVENT_FAILURE = "failure"
|
||||||
EVENT_REJOIN_CHANNELS = "rejoin_channels"
|
EVENT_REJOIN_CHANNELS = "rejoin_channels"
|
||||||
EVENT_USER_ACTION = "user_action"
|
EVENT_USER_ACTION = "user_action"
|
||||||
|
EVENT_MSG_DELETE = "msg_delete"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
|
@ -66,6 +66,7 @@ func (b *bdiscord) Connect() error {
|
|||||||
b.c.AddHandler(b.messageCreate)
|
b.c.AddHandler(b.messageCreate)
|
||||||
b.c.AddHandler(b.memberUpdate)
|
b.c.AddHandler(b.memberUpdate)
|
||||||
b.c.AddHandler(b.messageUpdate)
|
b.c.AddHandler(b.messageUpdate)
|
||||||
|
b.c.AddHandler(b.messageDelete)
|
||||||
err = b.c.Open()
|
err = b.c.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
flog.Debugf("%#v", err)
|
flog.Debugf("%#v", err)
|
||||||
@ -129,6 +130,13 @@ func (b *bdiscord) Send(msg config.Message) (string, error) {
|
|||||||
|
|
||||||
if wID == "" {
|
if wID == "" {
|
||||||
flog.Debugf("Broadcasting using token (API)")
|
flog.Debugf("Broadcasting using token (API)")
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
if msg.ID == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
err := b.c.ChannelMessageDelete(channelID, msg.ID)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
if msg.ID != "" {
|
if msg.ID != "" {
|
||||||
_, err := b.c.ChannelMessageEdit(channelID, msg.ID, msg.Username+msg.Text)
|
_, err := b.c.ChannelMessageEdit(channelID, msg.ID, msg.Username+msg.Text)
|
||||||
return msg.ID, err
|
return msg.ID, err
|
||||||
@ -152,6 +160,17 @@ func (b *bdiscord) Send(msg config.Message) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) {
|
||||||
|
rmsg := config.Message{Account: b.Account, ID: m.ID, Event: config.EVENT_MSG_DELETE, Text: config.EVENT_MSG_DELETE}
|
||||||
|
rmsg.Channel = b.getChannelName(m.ChannelID)
|
||||||
|
if b.UseChannelID {
|
||||||
|
rmsg.Channel = "ID:" + m.ChannelID
|
||||||
|
}
|
||||||
|
flog.Debugf("Sending message from %s to gateway", b.Account)
|
||||||
|
flog.Debugf("Message is %#v", rmsg)
|
||||||
|
b.Remote <- rmsg
|
||||||
|
}
|
||||||
|
|
||||||
func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
|
func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
|
||||||
if b.Config.EditDisable {
|
if b.Config.EditDisable {
|
||||||
return
|
return
|
||||||
@ -223,6 +242,7 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
|
|||||||
|
|
||||||
rmsg.Text = text
|
rmsg.Text = text
|
||||||
flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.Account)
|
flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.Account)
|
||||||
|
flog.Debugf("Message is %#v", rmsg)
|
||||||
b.Remote <- rmsg
|
b.Remote <- rmsg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ func (b *Bgitter) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
rmsg.Event = config.EVENT_USER_ACTION
|
rmsg.Event = config.EVENT_USER_ACTION
|
||||||
rmsg.Text = strings.Replace(rmsg.Text, "@"+ev.Message.From.Username+" ", "", -1)
|
rmsg.Text = strings.Replace(rmsg.Text, "@"+ev.Message.From.Username+" ", "", -1)
|
||||||
}
|
}
|
||||||
|
flog.Debugf("Message is %#v", rmsg)
|
||||||
b.Remote <- rmsg
|
b.Remote <- rmsg
|
||||||
}
|
}
|
||||||
case *gitter.GitterConnectionClosed:
|
case *gitter.GitterConnectionClosed:
|
||||||
@ -105,6 +106,17 @@ func (b *Bgitter) Send(msg config.Message) (string, error) {
|
|||||||
flog.Errorf("Could not find roomID for %v", msg.Channel)
|
flog.Errorf("Could not find roomID for %v", msg.Channel)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
if msg.ID == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
// gitter has no delete message api
|
||||||
|
_, err := b.c.UpdateMessage(roomID, msg.ID, "")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
if msg.ID != "" {
|
if msg.ID != "" {
|
||||||
flog.Debugf("updating message with id %s", msg.ID)
|
flog.Debugf("updating message with id %s", msg.ID)
|
||||||
_, err := b.c.UpdateMessage(roomID, msg.ID, msg.Username+msg.Text)
|
_, err := b.c.UpdateMessage(roomID, msg.ID, msg.Username+msg.Text)
|
||||||
|
@ -129,6 +129,10 @@ func (b *Birc) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Birc) Send(msg config.Message) (string, error) {
|
func (b *Birc) Send(msg config.Message) (string, error) {
|
||||||
|
// ignore delete messages
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
flog.Debugf("Receiving %#v", msg)
|
flog.Debugf("Receiving %#v", msg)
|
||||||
if strings.HasPrefix(msg.Text, "!") {
|
if strings.HasPrefix(msg.Text, "!") {
|
||||||
b.Command(&msg)
|
b.Command(&msg)
|
||||||
|
@ -76,6 +76,10 @@ func (b *Bmatrix) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
|
|
||||||
func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||||
flog.Debugf("Receiving %#v", msg)
|
flog.Debugf("Receiving %#v", msg)
|
||||||
|
// ignore delete messages
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
channel := b.getRoomID(msg.Channel)
|
channel := b.getRoomID(msg.Channel)
|
||||||
flog.Debugf("Sending to channel %s", channel)
|
flog.Debugf("Sending to channel %s", channel)
|
||||||
if msg.Event == config.EVENT_USER_ACTION {
|
if msg.Event == config.EVENT_USER_ACTION {
|
||||||
|
@ -25,6 +25,7 @@ type MMMessage struct {
|
|||||||
Username string
|
Username string
|
||||||
UserID string
|
UserID string
|
||||||
ID string
|
ID string
|
||||||
|
Event string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bmattermost struct {
|
type Bmattermost struct {
|
||||||
@ -168,6 +169,12 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) {
|
|||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
if msg.ID == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return msg.ID, b.mc.DeleteMessage(msg.ID)
|
||||||
|
}
|
||||||
if msg.ID != "" {
|
if msg.ID != "" {
|
||||||
return b.mc.EditMessage(msg.ID, message)
|
return b.mc.EditMessage(msg.ID, message)
|
||||||
}
|
}
|
||||||
@ -188,13 +195,14 @@ func (b *Bmattermost) handleMatter() {
|
|||||||
go b.handleMatterClient(mchan)
|
go b.handleMatterClient(mchan)
|
||||||
}
|
}
|
||||||
for message := range mchan {
|
for message := range mchan {
|
||||||
rmsg := config.Message{Username: message.Username, Channel: message.Channel, Account: b.Account, UserID: message.UserID, ID: message.ID}
|
rmsg := config.Message{Username: message.Username, Channel: message.Channel, Account: b.Account, UserID: message.UserID, ID: message.ID, Event: message.Event}
|
||||||
text, ok := b.replaceAction(message.Text)
|
text, ok := b.replaceAction(message.Text)
|
||||||
if ok {
|
if ok {
|
||||||
rmsg.Event = config.EVENT_USER_ACTION
|
rmsg.Event = config.EVENT_USER_ACTION
|
||||||
}
|
}
|
||||||
rmsg.Text = text
|
rmsg.Text = text
|
||||||
flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
|
flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
|
||||||
|
flog.Debugf("Message is %#v", rmsg)
|
||||||
b.Remote <- rmsg
|
b.Remote <- rmsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,7 +222,7 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
|
|||||||
}
|
}
|
||||||
// do not post our own messages back to irc
|
// do not post our own messages back to irc
|
||||||
// only listen to message from our team
|
// only listen to message from our team
|
||||||
if (message.Raw.Event == "posted" || message.Raw.Event == "post_edited") &&
|
if (message.Raw.Event == "posted" || message.Raw.Event == "post_edited" || message.Raw.Event == "post_deleted") &&
|
||||||
b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId {
|
b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId {
|
||||||
// if the message has reactions don't repost it (for now, until we can correlate reaction with message)
|
// if the message has reactions don't repost it (for now, until we can correlate reaction with message)
|
||||||
if message.Post.HasReactions {
|
if message.Post.HasReactions {
|
||||||
@ -230,6 +238,9 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
|
|||||||
if message.Raw.Event == "post_edited" && !b.Config.EditDisable {
|
if message.Raw.Event == "post_edited" && !b.Config.EditDisable {
|
||||||
m.Text = message.Text + b.Config.EditSuffix
|
m.Text = message.Text + b.Config.EditSuffix
|
||||||
}
|
}
|
||||||
|
if message.Raw.Event == "post_deleted" {
|
||||||
|
m.Event = config.EVENT_MSG_DELETE
|
||||||
|
}
|
||||||
if len(message.Post.FileIds) > 0 {
|
if len(message.Post.FileIds) > 0 {
|
||||||
for _, link := range b.mc.GetFileLinks(message.Post.FileIds) {
|
for _, link := range b.mc.GetFileLinks(message.Post.FileIds) {
|
||||||
m.Text = m.Text + "\n" + link
|
m.Text = m.Text + "\n" + link
|
||||||
|
@ -58,6 +58,10 @@ func (b *Brocketchat) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Brocketchat) Send(msg config.Message) (string, error) {
|
func (b *Brocketchat) Send(msg config.Message) (string, error) {
|
||||||
|
// ignore delete messages
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
flog.Debugf("Receiving %#v", msg)
|
flog.Debugf("Receiving %#v", msg)
|
||||||
matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL}
|
matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL}
|
||||||
matterMessage.Channel = msg.Channel
|
matterMessage.Channel = msg.Channel
|
||||||
|
@ -166,6 +166,16 @@ func (b *Bslack) Send(msg config.Message) (string, error) {
|
|||||||
// replace mentions
|
// replace mentions
|
||||||
np.LinkNames = 1
|
np.LinkNames = 1
|
||||||
|
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
// some protocols echo deletes, but with empty ID
|
||||||
|
if msg.ID == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
// we get a "slack <ID>", split it
|
||||||
|
ts := strings.Fields(msg.ID)
|
||||||
|
b.sc.DeleteMessage(schannel.ID, ts[1])
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
// if we have no ID it means we're creating a new message, not updating an existing one
|
// if we have no ID it means we're creating a new message, not updating an existing one
|
||||||
if msg.ID != "" {
|
if msg.ID != "" {
|
||||||
ts := strings.Fields(msg.ID)
|
ts := strings.Fields(msg.ID)
|
||||||
@ -231,91 +241,90 @@ func (b *Bslack) handleSlack() {
|
|||||||
if b.Config.WebhookURL == "" && b.Config.WebhookBindAddress == "" && message.Username == b.si.User.Name {
|
if b.Config.WebhookURL == "" && b.Config.WebhookBindAddress == "" && message.Username == b.si.User.Name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if message.Text == "" || message.Username == "" {
|
if (message.Text == "" || message.Username == "") && message.Raw.SubType != "message_deleted" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
texts := strings.Split(message.Text, "\n")
|
text := message.Text
|
||||||
for _, text := range texts {
|
text = b.replaceURL(text)
|
||||||
text = b.replaceURL(text)
|
text = html.UnescapeString(text)
|
||||||
text = html.UnescapeString(text)
|
flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
|
||||||
flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
|
msg := config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID, ID: "slack " + message.Raw.Timestamp}
|
||||||
msg := config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID, ID: "slack " + message.Raw.Timestamp}
|
if message.Raw.SubType == "me_message" {
|
||||||
if message.Raw.SubType == "me_message" {
|
msg.Event = config.EVENT_USER_ACTION
|
||||||
msg.Event = config.EVENT_USER_ACTION
|
|
||||||
}
|
|
||||||
if message.Raw.SubType == "channel_leave" || message.Raw.SubType == "channel_join" {
|
|
||||||
msg.Username = "system"
|
|
||||||
msg.Event = config.EVENT_JOIN_LEAVE
|
|
||||||
}
|
|
||||||
// edited messages have a submessage, use this timestamp
|
|
||||||
if message.Raw.SubMessage != nil {
|
|
||||||
msg.ID = "slack " + message.Raw.SubMessage.Timestamp
|
|
||||||
}
|
|
||||||
b.Remote <- msg
|
|
||||||
}
|
}
|
||||||
|
if message.Raw.SubType == "channel_leave" || message.Raw.SubType == "channel_join" {
|
||||||
|
msg.Username = "system"
|
||||||
|
msg.Event = config.EVENT_JOIN_LEAVE
|
||||||
|
}
|
||||||
|
// edited messages have a submessage, use this timestamp
|
||||||
|
if message.Raw.SubMessage != nil {
|
||||||
|
msg.ID = "slack " + message.Raw.SubMessage.Timestamp
|
||||||
|
}
|
||||||
|
if message.Raw.SubType == "message_deleted" {
|
||||||
|
msg.Text = config.EVENT_MSG_DELETE
|
||||||
|
msg.Event = config.EVENT_MSG_DELETE
|
||||||
|
msg.ID = "slack " + message.Raw.DeletedTimestamp
|
||||||
|
}
|
||||||
|
flog.Debugf("Message is %#v", msg)
|
||||||
|
b.Remote <- msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
|
func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
|
||||||
count := 0
|
|
||||||
for msg := range b.rtm.IncomingEvents {
|
for msg := range b.rtm.IncomingEvents {
|
||||||
switch ev := msg.Data.(type) {
|
switch ev := msg.Data.(type) {
|
||||||
case *slack.MessageEvent:
|
case *slack.MessageEvent:
|
||||||
// ignore first message
|
flog.Debugf("Receiving from slackclient %#v", ev)
|
||||||
if count > 0 {
|
if len(ev.Attachments) > 0 {
|
||||||
flog.Debugf("Receiving from slackclient %#v", ev)
|
// skip messages we made ourselves
|
||||||
if len(ev.Attachments) > 0 {
|
if ev.Attachments[0].CallbackID == "matterbridge" {
|
||||||
// skip messages we made ourselves
|
continue
|
||||||
if ev.Attachments[0].CallbackID == "matterbridge" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !b.Config.EditDisable && ev.SubMessage != nil && ev.SubMessage.ThreadTimestamp != ev.SubMessage.Timestamp {
|
}
|
||||||
flog.Debugf("SubMessage %#v", ev.SubMessage)
|
if !b.Config.EditDisable && ev.SubMessage != nil && ev.SubMessage.ThreadTimestamp != ev.SubMessage.Timestamp {
|
||||||
ev.User = ev.SubMessage.User
|
flog.Debugf("SubMessage %#v", ev.SubMessage)
|
||||||
ev.Text = ev.SubMessage.Text + b.Config.EditSuffix
|
ev.User = ev.SubMessage.User
|
||||||
}
|
ev.Text = ev.SubMessage.Text + b.Config.EditSuffix
|
||||||
// use our own func because rtm.GetChannelInfo doesn't work for private channels
|
}
|
||||||
channel, err := b.getChannelByID(ev.Channel)
|
// use our own func because rtm.GetChannelInfo doesn't work for private channels
|
||||||
|
channel, err := b.getChannelByID(ev.Channel)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m := &MMMessage{}
|
||||||
|
if ev.BotID == "" && ev.SubType != "message_deleted" {
|
||||||
|
user, err := b.rtm.GetUserInfo(ev.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
m := &MMMessage{}
|
m.UserID = user.ID
|
||||||
if ev.BotID == "" {
|
m.Username = user.Name
|
||||||
user, err := b.rtm.GetUserInfo(ev.User)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
m.UserID = user.ID
|
|
||||||
m.Username = user.Name
|
|
||||||
}
|
|
||||||
m.Channel = channel.Name
|
|
||||||
m.Text = ev.Text
|
|
||||||
if m.Text == "" {
|
|
||||||
for _, attach := range ev.Attachments {
|
|
||||||
if attach.Text != "" {
|
|
||||||
m.Text = attach.Text
|
|
||||||
} else {
|
|
||||||
m.Text = attach.Fallback
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.Raw = ev
|
|
||||||
m.Text = b.replaceMention(m.Text)
|
|
||||||
// when using webhookURL we can't check if it's our webhook or not for now
|
|
||||||
if ev.BotID != "" && b.Config.WebhookURL == "" {
|
|
||||||
bot, err := b.rtm.GetBotInfo(ev.BotID)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if bot.Name != "" {
|
|
||||||
m.Username = bot.Name
|
|
||||||
m.UserID = bot.ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mchan <- m
|
|
||||||
}
|
}
|
||||||
count++
|
m.Channel = channel.Name
|
||||||
|
m.Text = ev.Text
|
||||||
|
if m.Text == "" {
|
||||||
|
for _, attach := range ev.Attachments {
|
||||||
|
if attach.Text != "" {
|
||||||
|
m.Text = attach.Text
|
||||||
|
} else {
|
||||||
|
m.Text = attach.Fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.Raw = ev
|
||||||
|
m.Text = b.replaceMention(m.Text)
|
||||||
|
// when using webhookURL we can't check if it's our webhook or not for now
|
||||||
|
if ev.BotID != "" && b.Config.WebhookURL == "" {
|
||||||
|
bot, err := b.rtm.GetBotInfo(ev.BotID)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if bot.Name != "" {
|
||||||
|
m.Username = bot.Name
|
||||||
|
m.UserID = bot.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mchan <- m
|
||||||
case *slack.OutgoingErrorEvent:
|
case *slack.OutgoingErrorEvent:
|
||||||
flog.Debugf("%#v", ev.Error())
|
flog.Debugf("%#v", ev.Error())
|
||||||
case *slack.ChannelJoinedEvent:
|
case *slack.ChannelJoinedEvent:
|
||||||
|
@ -70,6 +70,10 @@ func (b *Bsteam) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bsteam) Send(msg config.Message) (string, error) {
|
func (b *Bsteam) Send(msg config.Message) (string, error) {
|
||||||
|
// ignore delete messages
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
id, err := steamid.NewId(msg.Channel)
|
id, err := steamid.NewId(msg.Channel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -68,6 +68,18 @@ func (b *Btelegram) Send(msg config.Message) (string, error) {
|
|||||||
msg.Text = makeHTML(msg.Text)
|
msg.Text = makeHTML(msg.Text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
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})
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
// edit the message if we have a msg ID
|
// edit the message if we have a msg ID
|
||||||
if msg.ID != "" {
|
if msg.ID != "" {
|
||||||
msgid, err := strconv.Atoi(msg.ID)
|
msgid, err := strconv.Atoi(msg.ID)
|
||||||
|
@ -80,6 +80,10 @@ func (b *Bxmpp) JoinChannel(channel config.ChannelInfo) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bxmpp) Send(msg config.Message) (string, error) {
|
func (b *Bxmpp) Send(msg config.Message) (string, error) {
|
||||||
|
// ignore delete messages
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
flog.Debugf("Receiving %#v", msg)
|
flog.Debugf("Receiving %#v", msg)
|
||||||
b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Config.Muc, Text: msg.Username + msg.Text})
|
b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Config.Muc, Text: msg.Username + msg.Text})
|
||||||
return "", nil
|
return "", nil
|
||||||
|
27
changelog.md
27
changelog.md
@ -1,3 +1,30 @@
|
|||||||
|
# v1.2.0
|
||||||
|
## Breaking changes
|
||||||
|
* If you're running a discord bridge, update to this release before 16 october otherwise
|
||||||
|
it will stop working. (see https://discordapp.com/developers/docs/reference)
|
||||||
|
|
||||||
|
## New features
|
||||||
|
* general: Add delete support. (actually delete the messages on bridges that support it)
|
||||||
|
(mattermost,discord,gitter,slack,telegram)
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
* Do not break messages on newline (slack). Closes #258
|
||||||
|
* Update telegram library
|
||||||
|
* Update discord library (supports v6 API now). Old API is deprecated on 16 October
|
||||||
|
|
||||||
|
# v1.1.2
|
||||||
|
## New features
|
||||||
|
* general: also build darwin binaries
|
||||||
|
* mattermost: add support for mattermost 4.2.x
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
* mattermost: Send images when text is empty regression. (mattermost). Closes #254
|
||||||
|
* slack: also send the first messsage after connect. #252
|
||||||
|
|
||||||
|
# v1.1.1
|
||||||
|
## Bugfix
|
||||||
|
* mattermost: fix public links
|
||||||
|
|
||||||
# v1.1.0
|
# v1.1.0
|
||||||
## New features
|
## New features
|
||||||
* general: Add better editing support. (actually edit the messages on bridges that support it)
|
* general: Add better editing support. (actually edit the messages on bridges that support it)
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
go version |grep go1.9 || exit
|
go version |grep go1.9 || exit
|
||||||
VERSION=$(git describe --tags)
|
VERSION=$(git describe --tags)
|
||||||
mkdir ci/binaries
|
mkdir ci/binaries
|
||||||
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-win64.exe
|
GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-windows-amd64.exe
|
||||||
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-linux64
|
GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-linux-amd64
|
||||||
GOOS=linux GOARCH=arm go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-linux-arm
|
GOOS=linux GOARCH=arm go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-linux-arm
|
||||||
|
GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-darwin-amd64
|
||||||
cd ci
|
cd ci
|
||||||
cat > deploy.json <<EOF
|
cat > deploy.json <<EOF
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
version = "1.1.0"
|
version = "1.2.0"
|
||||||
githash string
|
githash string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -383,7 +383,6 @@ WebhookURL="https://hooks.slack.com/services/yourhook"
|
|||||||
#AND DEDICATED BOT USER WHEN POSSIBLE!
|
#AND DEDICATED BOT USER WHEN POSSIBLE!
|
||||||
#Address to listen on for outgoing webhook requests from slack
|
#Address to listen on for outgoing webhook requests from slack
|
||||||
#See account settings - integrations - outgoing webhooks on slack
|
#See account settings - integrations - outgoing webhooks on slack
|
||||||
#This setting will not be used when useAPI is eanbled
|
|
||||||
#webhooks
|
#webhooks
|
||||||
#OPTIONAL
|
#OPTIONAL
|
||||||
WebhookBindAddress="0.0.0.0:9999"
|
WebhookBindAddress="0.0.0.0:9999"
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
[mattermost]
|
[mattermost]
|
||||||
[mattermost.work]
|
[mattermost.work]
|
||||||
useAPI=true
|
|
||||||
#do not prefix it wit http:// or https://
|
#do not prefix it wit http:// or https://
|
||||||
Server="yourmattermostserver.domain"
|
Server="yourmattermostserver.domain"
|
||||||
Team="yourteam"
|
Team="yourteam"
|
||||||
|
@ -277,6 +277,13 @@ func (m *MMClient) WsReceiver() {
|
|||||||
// check if we didn't empty the message
|
// check if we didn't empty the message
|
||||||
if msg.Text != "" {
|
if msg.Text != "" {
|
||||||
m.MessageChan <- msg
|
m.MessageChan <- msg
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// if we have file attached but the message is empty, also send it
|
||||||
|
if msg.Post != nil {
|
||||||
|
if msg.Text != "" || len(msg.Post.FileIds) > 0 {
|
||||||
|
m.MessageChan <- msg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -292,7 +299,7 @@ func (m *MMClient) WsReceiver() {
|
|||||||
|
|
||||||
func (m *MMClient) parseMessage(rmsg *Message) {
|
func (m *MMClient) parseMessage(rmsg *Message) {
|
||||||
switch rmsg.Raw.Event {
|
switch rmsg.Raw.Event {
|
||||||
case model.WEBSOCKET_EVENT_POSTED, model.WEBSOCKET_EVENT_POST_EDITED:
|
case model.WEBSOCKET_EVENT_POSTED, model.WEBSOCKET_EVENT_POST_EDITED, model.WEBSOCKET_EVENT_POST_DELETED:
|
||||||
m.parseActionPost(rmsg)
|
m.parseActionPost(rmsg)
|
||||||
/*
|
/*
|
||||||
case model.ACTION_USER_REMOVED:
|
case model.ACTION_USER_REMOVED:
|
||||||
@ -469,6 +476,14 @@ func (m *MMClient) EditMessage(postId string, text string) (string, error) {
|
|||||||
return res.Id, nil
|
return res.Id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MMClient) DeleteMessage(postId string) error {
|
||||||
|
_, resp := m.Client.DeletePost(postId)
|
||||||
|
if resp.Error != nil {
|
||||||
|
return resp.Error
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MMClient) JoinChannel(channelId string) error {
|
func (m *MMClient) JoinChannel(channelId string) error {
|
||||||
m.RLock()
|
m.RLock()
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
@ -511,8 +526,8 @@ func (m *MMClient) GetPosts(channelId string, limit int) *model.PostList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *MMClient) GetPublicLink(filename string) string {
|
func (m *MMClient) GetPublicLink(filename string) string {
|
||||||
res, err := m.Client.GetFileLink(filename)
|
res, resp := m.Client.GetFileLink(filename)
|
||||||
if err != nil {
|
if resp.Error != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
@ -521,8 +536,8 @@ func (m *MMClient) GetPublicLink(filename string) string {
|
|||||||
func (m *MMClient) GetPublicLinks(filenames []string) []string {
|
func (m *MMClient) GetPublicLinks(filenames []string) []string {
|
||||||
var output []string
|
var output []string
|
||||||
for _, f := range filenames {
|
for _, f := range filenames {
|
||||||
res, err := m.Client.GetFileLink(f)
|
res, resp := m.Client.GetFileLink(f)
|
||||||
if err != nil {
|
if resp.Error != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
output = append(output, res)
|
output = append(output, res)
|
||||||
@ -538,8 +553,8 @@ func (m *MMClient) GetFileLinks(filenames []string) []string {
|
|||||||
|
|
||||||
var output []string
|
var output []string
|
||||||
for _, f := range filenames {
|
for _, f := range filenames {
|
||||||
res, err := m.Client.GetFileLink(f)
|
res, resp := m.Client.GetFileLink(f)
|
||||||
if err != nil {
|
if resp.Error != nil {
|
||||||
// public links is probably disabled, create the link ourselves
|
// public links is probably disabled, create the link ourselves
|
||||||
output = append(output, uriScheme+m.Credentials.Server+model.API_URL_SUFFIX_V3+"/files/"+f+"/get")
|
output = append(output, uriScheme+m.Credentials.Server+model.API_URL_SUFFIX_V3+"/files/"+f+"/get")
|
||||||
continue
|
continue
|
||||||
@ -567,6 +582,16 @@ func (m *MMClient) UpdateLastViewed(channelId string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MMClient) UpdateUserNick(nick string) error {
|
||||||
|
user := m.User
|
||||||
|
user.Nickname = nick
|
||||||
|
_, resp := m.Client.UpdateUser(user)
|
||||||
|
if resp.Error != nil {
|
||||||
|
return resp.Error
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MMClient) UsernamesInChannel(channelId string) []string {
|
func (m *MMClient) UsernamesInChannel(channelId string) []string {
|
||||||
res, resp := m.Client.GetChannelMembers(channelId, 0, 50000, "")
|
res, resp := m.Client.GetChannelMembers(channelId, 0, 50000, "")
|
||||||
if resp.Error != nil {
|
if resp.Error != nil {
|
||||||
@ -600,9 +625,9 @@ func (m *MMClient) createCookieJar(token string) *cookiejar.Jar {
|
|||||||
func (m *MMClient) SendDirectMessage(toUserId string, msg string) {
|
func (m *MMClient) SendDirectMessage(toUserId string, msg string) {
|
||||||
m.log.Debugf("SendDirectMessage to %s, msg %s", toUserId, msg)
|
m.log.Debugf("SendDirectMessage to %s, msg %s", toUserId, msg)
|
||||||
// create DM channel (only happens on first message)
|
// create DM channel (only happens on first message)
|
||||||
_, err := m.Client.CreateDirectChannel(m.User.Id, toUserId)
|
_, resp := m.Client.CreateDirectChannel(m.User.Id, toUserId)
|
||||||
if err != nil {
|
if resp.Error != nil {
|
||||||
m.log.Debugf("SendDirectMessage to %#v failed: %s", toUserId, err)
|
m.log.Debugf("SendDirectMessage to %#v failed: %s", toUserId, resp.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
channelName := model.GetDMNameFromIds(toUserId, m.User.Id)
|
channelName := model.GetDMNameFromIds(toUserId, m.User.Id)
|
||||||
@ -854,7 +879,8 @@ func supportedVersion(version string) bool {
|
|||||||
strings.HasPrefix(version, "3.9.0") ||
|
strings.HasPrefix(version, "3.9.0") ||
|
||||||
strings.HasPrefix(version, "3.10.0") ||
|
strings.HasPrefix(version, "3.10.0") ||
|
||||||
strings.HasPrefix(version, "4.0") ||
|
strings.HasPrefix(version, "4.0") ||
|
||||||
strings.HasPrefix(version, "4.1") {
|
strings.HasPrefix(version, "4.1") ||
|
||||||
|
strings.HasPrefix(version, "4.2") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
3
vendor/github.com/bwmarrin/discordgo/discord.go
generated
vendored
3
vendor/github.com/bwmarrin/discordgo/discord.go
generated
vendored
@ -21,7 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
|
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
|
||||||
const VERSION = "0.16.0"
|
const VERSION = "0.17.0"
|
||||||
|
|
||||||
// ErrMFA will be risen by New when the user has 2FA.
|
// ErrMFA will be risen by New when the user has 2FA.
|
||||||
var ErrMFA = errors.New("account has 2FA enabled")
|
var ErrMFA = errors.New("account has 2FA enabled")
|
||||||
@ -59,6 +59,7 @@ func New(args ...interface{}) (s *Session, err error) {
|
|||||||
MaxRestRetries: 3,
|
MaxRestRetries: 3,
|
||||||
Client: &http.Client{Timeout: (20 * time.Second)},
|
Client: &http.Client{Timeout: (20 * time.Second)},
|
||||||
sequence: new(int64),
|
sequence: new(int64),
|
||||||
|
LastHeartbeatAck: time.Now().UTC(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no arguments are passed return the empty Session interface.
|
// If no arguments are passed return the empty Session interface.
|
||||||
|
42
vendor/github.com/bwmarrin/discordgo/endpoints.go
generated
vendored
42
vendor/github.com/bwmarrin/discordgo/endpoints.go
generated
vendored
@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
package discordgo
|
package discordgo
|
||||||
|
|
||||||
|
// APIVersion is the Discord API version used for the REST and Websocket API.
|
||||||
|
var APIVersion = "6"
|
||||||
|
|
||||||
// Known Discord API Endpoints.
|
// Known Discord API Endpoints.
|
||||||
var (
|
var (
|
||||||
EndpointStatus = "https://status.discordapp.com/api/v2/"
|
EndpointStatus = "https://status.discordapp.com/api/v2/"
|
||||||
@ -18,13 +21,14 @@ var (
|
|||||||
EndpointSmActive = EndpointSm + "active.json"
|
EndpointSmActive = EndpointSm + "active.json"
|
||||||
EndpointSmUpcoming = EndpointSm + "upcoming.json"
|
EndpointSmUpcoming = EndpointSm + "upcoming.json"
|
||||||
|
|
||||||
EndpointDiscord = "https://discordapp.com/"
|
EndpointDiscord = "https://discordapp.com/"
|
||||||
EndpointAPI = EndpointDiscord + "api/"
|
EndpointAPI = EndpointDiscord + "api/v" + APIVersion + "/"
|
||||||
EndpointGuilds = EndpointAPI + "guilds/"
|
EndpointGuilds = EndpointAPI + "guilds/"
|
||||||
EndpointChannels = EndpointAPI + "channels/"
|
EndpointChannels = EndpointAPI + "channels/"
|
||||||
EndpointUsers = EndpointAPI + "users/"
|
EndpointUsers = EndpointAPI + "users/"
|
||||||
EndpointGateway = EndpointAPI + "gateway"
|
EndpointGateway = EndpointAPI + "gateway"
|
||||||
EndpointWebhooks = EndpointAPI + "webhooks/"
|
EndpointGatewayBot = EndpointGateway + "/bot"
|
||||||
|
EndpointWebhooks = EndpointAPI + "webhooks/"
|
||||||
|
|
||||||
EndpointCDN = "https://cdn.discordapp.com/"
|
EndpointCDN = "https://cdn.discordapp.com/"
|
||||||
EndpointCDNAttachments = EndpointCDN + "attachments/"
|
EndpointCDNAttachments = EndpointCDN + "attachments/"
|
||||||
@ -54,16 +58,17 @@ var (
|
|||||||
EndpointReport = EndpointAPI + "report"
|
EndpointReport = EndpointAPI + "report"
|
||||||
EndpointIntegrations = EndpointAPI + "integrations"
|
EndpointIntegrations = EndpointAPI + "integrations"
|
||||||
|
|
||||||
EndpointUser = func(uID string) string { return EndpointUsers + uID }
|
EndpointUser = func(uID string) string { return EndpointUsers + uID }
|
||||||
EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
|
EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
|
||||||
EndpointUserSettings = func(uID string) string { return EndpointUsers + uID + "/settings" }
|
EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" }
|
||||||
EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
|
EndpointUserSettings = func(uID string) string { return EndpointUsers + uID + "/settings" }
|
||||||
EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
|
EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
|
||||||
EndpointUserGuildSettings = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID + "/settings" }
|
EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
|
||||||
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
|
EndpointUserGuildSettings = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID + "/settings" }
|
||||||
EndpointUserDevices = func(uID string) string { return EndpointUsers + uID + "/devices" }
|
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
|
||||||
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
|
EndpointUserDevices = func(uID string) string { return EndpointUsers + uID + "/devices" }
|
||||||
EndpointUserNotes = func(uID string) string { return EndpointUsers + "@me/notes/" + uID }
|
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
|
||||||
|
EndpointUserNotes = func(uID string) string { return EndpointUsers + "@me/notes/" + uID }
|
||||||
|
|
||||||
EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
|
EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
|
||||||
EndpointGuildInivtes = func(gID string) string { return EndpointGuilds + gID + "/invites" }
|
EndpointGuildInivtes = func(gID string) string { return EndpointGuilds + gID + "/invites" }
|
||||||
@ -103,6 +108,9 @@ var (
|
|||||||
EndpointWebhook = func(wID string) string { return EndpointWebhooks + wID }
|
EndpointWebhook = func(wID string) string { return EndpointWebhooks + wID }
|
||||||
EndpointWebhookToken = func(wID, token string) string { return EndpointWebhooks + wID + "/" + token }
|
EndpointWebhookToken = func(wID, token string) string { return EndpointWebhooks + wID + "/" + token }
|
||||||
|
|
||||||
|
EndpointMessageReactionsAll = func(cID, mID string) string {
|
||||||
|
return EndpointChannelMessage(cID, mID) + "/reactions"
|
||||||
|
}
|
||||||
EndpointMessageReactions = func(cID, mID, eID string) string {
|
EndpointMessageReactions = func(cID, mID, eID string) string {
|
||||||
return EndpointChannelMessage(cID, mID) + "/reactions/" + eID
|
return EndpointChannelMessage(cID, mID) + "/reactions/" + eID
|
||||||
}
|
}
|
||||||
|
14
vendor/github.com/bwmarrin/discordgo/event.go
generated
vendored
14
vendor/github.com/bwmarrin/discordgo/event.go
generated
vendored
@ -156,12 +156,20 @@ func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance
|
|||||||
// Handles calling permanent and once handlers for an event type.
|
// Handles calling permanent and once handlers for an event type.
|
||||||
func (s *Session) handle(t string, i interface{}) {
|
func (s *Session) handle(t string, i interface{}) {
|
||||||
for _, eh := range s.handlers[t] {
|
for _, eh := range s.handlers[t] {
|
||||||
go eh.eventHandler.Handle(s, i)
|
if s.SyncEvents {
|
||||||
|
eh.eventHandler.Handle(s, i)
|
||||||
|
} else {
|
||||||
|
go eh.eventHandler.Handle(s, i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.onceHandlers[t]) > 0 {
|
if len(s.onceHandlers[t]) > 0 {
|
||||||
for _, eh := range s.onceHandlers[t] {
|
for _, eh := range s.onceHandlers[t] {
|
||||||
go eh.eventHandler.Handle(s, i)
|
if s.SyncEvents {
|
||||||
|
eh.eventHandler.Handle(s, i)
|
||||||
|
} else {
|
||||||
|
go eh.eventHandler.Handle(s, i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.onceHandlers[t] = nil
|
s.onceHandlers[t] = nil
|
||||||
}
|
}
|
||||||
@ -216,7 +224,7 @@ func (s *Session) onInterface(i interface{}) {
|
|||||||
case *VoiceStateUpdate:
|
case *VoiceStateUpdate:
|
||||||
go s.onVoiceStateUpdate(t)
|
go s.onVoiceStateUpdate(t)
|
||||||
}
|
}
|
||||||
err := s.State.onInterface(s, i)
|
err := s.State.OnInterface(s, i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log(LogDebug, "error dispatching internal event, %s", err)
|
s.log(LogDebug, "error dispatching internal event, %s", err)
|
||||||
}
|
}
|
||||||
|
94
vendor/github.com/bwmarrin/discordgo/message.go
generated
vendored
94
vendor/github.com/bwmarrin/discordgo/message.go
generated
vendored
@ -10,9 +10,24 @@
|
|||||||
package discordgo
|
package discordgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MessageType is the type of Message
|
||||||
|
type MessageType int
|
||||||
|
|
||||||
|
// Block contains the valid known MessageType values
|
||||||
|
const (
|
||||||
|
MessageTypeDefault MessageType = iota
|
||||||
|
MessageTypeRecipientAdd
|
||||||
|
MessageTypeRecipientRemove
|
||||||
|
MessageTypeCall
|
||||||
|
MessageTypeChannelNameChange
|
||||||
|
MessageTypeChannelIconChange
|
||||||
|
MessageTypeChannelPinnedMessage
|
||||||
|
MessageTypeGuildMemberJoin
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Message stores all data related to a specific Discord message.
|
// A Message stores all data related to a specific Discord message.
|
||||||
@ -30,12 +45,14 @@ type Message struct {
|
|||||||
Embeds []*MessageEmbed `json:"embeds"`
|
Embeds []*MessageEmbed `json:"embeds"`
|
||||||
Mentions []*User `json:"mentions"`
|
Mentions []*User `json:"mentions"`
|
||||||
Reactions []*MessageReactions `json:"reactions"`
|
Reactions []*MessageReactions `json:"reactions"`
|
||||||
|
Type MessageType `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// File stores info about files you e.g. send in messages.
|
// File stores info about files you e.g. send in messages.
|
||||||
type File struct {
|
type File struct {
|
||||||
Name string
|
Name string
|
||||||
Reader io.Reader
|
ContentType string
|
||||||
|
Reader io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
|
// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
|
||||||
@ -43,7 +60,10 @@ type MessageSend struct {
|
|||||||
Content string `json:"content,omitempty"`
|
Content string `json:"content,omitempty"`
|
||||||
Embed *MessageEmbed `json:"embed,omitempty"`
|
Embed *MessageEmbed `json:"embed,omitempty"`
|
||||||
Tts bool `json:"tts"`
|
Tts bool `json:"tts"`
|
||||||
File *File `json:"file"`
|
Files []*File `json:"-"`
|
||||||
|
|
||||||
|
// TODO: Remove this when compatibility is not required.
|
||||||
|
File *File `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
|
// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
|
||||||
@ -168,13 +188,65 @@ type MessageReactions struct {
|
|||||||
|
|
||||||
// ContentWithMentionsReplaced will replace all @<id> mentions with the
|
// ContentWithMentionsReplaced will replace all @<id> mentions with the
|
||||||
// username of the mention.
|
// username of the mention.
|
||||||
func (m *Message) ContentWithMentionsReplaced() string {
|
func (m *Message) ContentWithMentionsReplaced() (content string) {
|
||||||
if m.Mentions == nil {
|
content = m.Content
|
||||||
return m.Content
|
|
||||||
}
|
|
||||||
content := m.Content
|
|
||||||
for _, user := range m.Mentions {
|
for _, user := range m.Mentions {
|
||||||
content = regexp.MustCompile(fmt.Sprintf("<@!?(%s)>", user.ID)).ReplaceAllString(content, "@"+user.Username)
|
content = strings.NewReplacer(
|
||||||
|
"<@"+user.ID+">", "@"+user.Username,
|
||||||
|
"<@!"+user.ID+">", "@"+user.Username,
|
||||||
|
).Replace(content)
|
||||||
}
|
}
|
||||||
return content
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var patternChannels = regexp.MustCompile("<#[^>]*>")
|
||||||
|
|
||||||
|
// ContentWithMoreMentionsReplaced will replace all @<id> mentions with the
|
||||||
|
// username of the mention, but also role IDs and more.
|
||||||
|
func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) {
|
||||||
|
content = m.Content
|
||||||
|
|
||||||
|
if !s.StateEnabled {
|
||||||
|
content = m.ContentWithMentionsReplaced()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := s.State.Channel(m.ChannelID)
|
||||||
|
if err != nil {
|
||||||
|
content = m.ContentWithMentionsReplaced()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range m.Mentions {
|
||||||
|
nick := user.Username
|
||||||
|
|
||||||
|
member, err := s.State.Member(channel.GuildID, user.ID)
|
||||||
|
if err == nil && member.Nick != "" {
|
||||||
|
nick = member.Nick
|
||||||
|
}
|
||||||
|
|
||||||
|
content = strings.NewReplacer(
|
||||||
|
"<@"+user.ID+">", "@"+user.Username,
|
||||||
|
"<@!"+user.ID+">", "@"+nick,
|
||||||
|
).Replace(content)
|
||||||
|
}
|
||||||
|
for _, roleID := range m.MentionRoles {
|
||||||
|
role, err := s.State.Role(channel.GuildID, roleID)
|
||||||
|
if err != nil || !role.Mentionable {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
content = strings.Replace(content, "<&"+role.ID+">", "@"+role.Name, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string {
|
||||||
|
channel, err := s.State.Channel(mention[2 : len(mention)-1])
|
||||||
|
if err != nil || channel.Type == ChannelTypeGuildVoice {
|
||||||
|
return mention
|
||||||
|
}
|
||||||
|
|
||||||
|
return "#" + channel.Name
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
47
vendor/github.com/bwmarrin/discordgo/ratelimit.go
generated
vendored
47
vendor/github.com/bwmarrin/discordgo/ratelimit.go
generated
vendored
@ -3,17 +3,26 @@ package discordgo
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// customRateLimit holds information for defining a custom rate limit
|
||||||
|
type customRateLimit struct {
|
||||||
|
suffix string
|
||||||
|
requests int
|
||||||
|
reset time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
// RateLimiter holds all ratelimit buckets
|
// RateLimiter holds all ratelimit buckets
|
||||||
type RateLimiter struct {
|
type RateLimiter struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
global *int64
|
global *int64
|
||||||
buckets map[string]*Bucket
|
buckets map[string]*Bucket
|
||||||
globalRateLimit time.Duration
|
globalRateLimit time.Duration
|
||||||
|
customRateLimits []*customRateLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRatelimiter returns a new RateLimiter
|
// NewRatelimiter returns a new RateLimiter
|
||||||
@ -22,6 +31,13 @@ func NewRatelimiter() *RateLimiter {
|
|||||||
return &RateLimiter{
|
return &RateLimiter{
|
||||||
buckets: make(map[string]*Bucket),
|
buckets: make(map[string]*Bucket),
|
||||||
global: new(int64),
|
global: new(int64),
|
||||||
|
customRateLimits: []*customRateLimit{
|
||||||
|
&customRateLimit{
|
||||||
|
suffix: "//reactions//",
|
||||||
|
requests: 1,
|
||||||
|
reset: 200 * time.Millisecond,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +56,14 @@ func (r *RateLimiter) getBucket(key string) *Bucket {
|
|||||||
global: r.global,
|
global: r.global,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if there is a custom ratelimit set for this bucket ID.
|
||||||
|
for _, rl := range r.customRateLimits {
|
||||||
|
if strings.HasSuffix(b.Key, rl.suffix) {
|
||||||
|
b.customRateLimit = rl
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
r.buckets[key] = b
|
r.buckets[key] = b
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
@ -76,13 +100,28 @@ type Bucket struct {
|
|||||||
limit int
|
limit int
|
||||||
reset time.Time
|
reset time.Time
|
||||||
global *int64
|
global *int64
|
||||||
|
|
||||||
|
lastReset time.Time
|
||||||
|
customRateLimit *customRateLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release unlocks the bucket and reads the headers to update the buckets ratelimit info
|
// Release unlocks the bucket and reads the headers to update the buckets ratelimit info
|
||||||
// and locks up the whole thing in case if there's a global ratelimit.
|
// and locks up the whole thing in case if there's a global ratelimit.
|
||||||
func (b *Bucket) Release(headers http.Header) error {
|
func (b *Bucket) Release(headers http.Header) error {
|
||||||
|
|
||||||
defer b.Unlock()
|
defer b.Unlock()
|
||||||
|
|
||||||
|
// Check if the bucket uses a custom ratelimiter
|
||||||
|
if rl := b.customRateLimit; rl != nil {
|
||||||
|
if time.Now().Sub(b.lastReset) >= rl.reset {
|
||||||
|
b.remaining = rl.requests - 1
|
||||||
|
b.lastReset = time.Now()
|
||||||
|
}
|
||||||
|
if b.remaining < 1 {
|
||||||
|
b.reset = time.Now().Add(rl.reset)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if headers == nil {
|
if headers == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
138
vendor/github.com/bwmarrin/discordgo/restapi.go
generated
vendored
138
vendor/github.com/bwmarrin/discordgo/restapi.go
generated
vendored
@ -23,6 +23,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -309,8 +310,8 @@ func (s *Session) UserUpdate(email, password, username, avatar, newPassword stri
|
|||||||
// If left blank, avatar will be set to null/blank
|
// If left blank, avatar will be set to null/blank
|
||||||
|
|
||||||
data := struct {
|
data := struct {
|
||||||
Email string `json:"email"`
|
Email string `json:"email,omitempty"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password,omitempty"`
|
||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
Avatar string `json:"avatar,omitempty"`
|
Avatar string `json:"avatar,omitempty"`
|
||||||
NewPassword string `json:"new_password,omitempty"`
|
NewPassword string `json:"new_password,omitempty"`
|
||||||
@ -763,7 +764,21 @@ func (s *Session) GuildMember(guildID, userID string) (st *Member, err error) {
|
|||||||
// userID : The ID of a User
|
// userID : The ID of a User
|
||||||
func (s *Session) GuildMemberDelete(guildID, userID string) (err error) {
|
func (s *Session) GuildMemberDelete(guildID, userID string) (err error) {
|
||||||
|
|
||||||
_, err = s.RequestWithBucketID("DELETE", EndpointGuildMember(guildID, userID), nil, EndpointGuildMember(guildID, ""))
|
return s.GuildMemberDeleteWithReason(guildID, userID, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GuildMemberDeleteWithReason removes the given user from the given guild.
|
||||||
|
// guildID : The ID of a Guild.
|
||||||
|
// userID : The ID of a User
|
||||||
|
// reason : The reason for the kick
|
||||||
|
func (s *Session) GuildMemberDeleteWithReason(guildID, userID, reason string) (err error) {
|
||||||
|
|
||||||
|
uri := EndpointGuildMember(guildID, userID)
|
||||||
|
if reason != "" {
|
||||||
|
uri += "?reason=" + url.QueryEscape(reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.RequestWithBucketID("DELETE", uri, nil, EndpointGuildMember(guildID, ""))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1316,6 +1331,8 @@ func (s *Session) ChannelMessageSend(channelID string, content string) (*Message
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||||
|
|
||||||
// ChannelMessageSendComplex sends a message to the given channel.
|
// ChannelMessageSendComplex sends a message to the given channel.
|
||||||
// channelID : The ID of a Channel.
|
// channelID : The ID of a Channel.
|
||||||
// data : The message struct to send.
|
// data : The message struct to send.
|
||||||
@ -1326,48 +1343,62 @@ func (s *Session) ChannelMessageSendComplex(channelID string, data *MessageSend)
|
|||||||
|
|
||||||
endpoint := EndpointChannelMessages(channelID)
|
endpoint := EndpointChannelMessages(channelID)
|
||||||
|
|
||||||
var response []byte
|
// TODO: Remove this when compatibility is not required.
|
||||||
|
files := data.Files
|
||||||
if data.File != nil {
|
if data.File != nil {
|
||||||
|
if files == nil {
|
||||||
|
files = []*File{data.File}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("cannot specify both File and Files")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var response []byte
|
||||||
|
if len(files) > 0 {
|
||||||
body := &bytes.Buffer{}
|
body := &bytes.Buffer{}
|
||||||
bodywriter := multipart.NewWriter(body)
|
bodywriter := multipart.NewWriter(body)
|
||||||
|
|
||||||
// What's a better way of doing this? Reflect? Generator? I'm open to suggestions
|
var payload []byte
|
||||||
|
payload, err = json.Marshal(data)
|
||||||
if data.Content != "" {
|
|
||||||
if err = bodywriter.WriteField("content", data.Content); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.Embed != nil {
|
|
||||||
var embed []byte
|
|
||||||
embed, err = json.Marshal(data.Embed)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = bodywriter.WriteField("embed", string(embed))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.Tts {
|
|
||||||
if err = bodywriter.WriteField("tts", "true"); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var writer io.Writer
|
|
||||||
writer, err = bodywriter.CreateFormFile("file", data.File.Name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = io.Copy(writer, data.File.Reader)
|
var p io.Writer
|
||||||
|
|
||||||
|
h := make(textproto.MIMEHeader)
|
||||||
|
h.Set("Content-Disposition", `form-data; name="payload_json"`)
|
||||||
|
h.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
p, err = bodywriter.CreatePart(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, err = p.Write(payload); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, file := range files {
|
||||||
|
h := make(textproto.MIMEHeader)
|
||||||
|
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file%d"; filename="%s"`, i, quoteEscaper.Replace(file.Name)))
|
||||||
|
contentType := file.ContentType
|
||||||
|
if contentType == "" {
|
||||||
|
contentType = "application/octet-stream"
|
||||||
|
}
|
||||||
|
h.Set("Content-Type", contentType)
|
||||||
|
|
||||||
|
p, err = bodywriter.CreatePart(h)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = io.Copy(p, file.Reader); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = bodywriter.Close()
|
err = bodywriter.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -1685,6 +1716,28 @@ func (s *Session) Gateway() (gateway string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GatewayBot returns the websocket Gateway address and the recommended number of shards
|
||||||
|
func (s *Session) GatewayBot() (st *GatewayBotResponse, err error) {
|
||||||
|
|
||||||
|
response, err := s.RequestWithBucketID("GET", EndpointGatewayBot, nil, EndpointGatewayBot)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = unmarshal(response, &st)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the gateway always has a trailing slash.
|
||||||
|
// MacOS will fail to connect if we add query params without a trailing slash on the base domain.
|
||||||
|
if !strings.HasSuffix(st.URL, "/") {
|
||||||
|
st.URL += "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Functions specific to Webhooks
|
// Functions specific to Webhooks
|
||||||
|
|
||||||
// WebhookCreate returns a new Webhook.
|
// WebhookCreate returns a new Webhook.
|
||||||
@ -1810,14 +1863,9 @@ func (s *Session) WebhookEditWithToken(webhookID, token, name, avatar string) (s
|
|||||||
|
|
||||||
// WebhookDelete deletes a webhook for a given ID
|
// WebhookDelete deletes a webhook for a given ID
|
||||||
// webhookID: The ID of a webhook.
|
// webhookID: The ID of a webhook.
|
||||||
func (s *Session) WebhookDelete(webhookID string) (st *Webhook, err error) {
|
func (s *Session) WebhookDelete(webhookID string) (err error) {
|
||||||
|
|
||||||
body, err := s.RequestWithBucketID("DELETE", EndpointWebhook(webhookID), nil, EndpointWebhooks)
|
_, err = s.RequestWithBucketID("DELETE", EndpointWebhook(webhookID), nil, EndpointWebhooks)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = unmarshal(body, &st)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1875,6 +1923,16 @@ func (s *Session) MessageReactionRemove(channelID, messageID, emojiID, userID st
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MessageReactionsRemoveAll deletes all reactions from a message
|
||||||
|
// channelID : The channel ID
|
||||||
|
// messageID : The message ID.
|
||||||
|
func (s *Session) MessageReactionsRemoveAll(channelID, messageID string) error {
|
||||||
|
|
||||||
|
_, err := s.RequestWithBucketID("DELETE", EndpointMessageReactionsAll(channelID, messageID), nil, EndpointMessageReactionsAll(channelID, messageID))
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// MessageReactions gets all the users reactions for a specific emoji.
|
// MessageReactions gets all the users reactions for a specific emoji.
|
||||||
// channelID : The channel ID.
|
// channelID : The channel ID.
|
||||||
// messageID : The message ID.
|
// messageID : The message ID.
|
||||||
|
72
vendor/github.com/bwmarrin/discordgo/state.go
generated
vendored
72
vendor/github.com/bwmarrin/discordgo/state.go
generated
vendored
@ -42,6 +42,7 @@ type State struct {
|
|||||||
|
|
||||||
guildMap map[string]*Guild
|
guildMap map[string]*Guild
|
||||||
channelMap map[string]*Channel
|
channelMap map[string]*Channel
|
||||||
|
memberMap map[string]map[string]*Member
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewState creates an empty state.
|
// NewState creates an empty state.
|
||||||
@ -59,9 +60,18 @@ func NewState() *State {
|
|||||||
TrackPresences: true,
|
TrackPresences: true,
|
||||||
guildMap: make(map[string]*Guild),
|
guildMap: make(map[string]*Guild),
|
||||||
channelMap: make(map[string]*Channel),
|
channelMap: make(map[string]*Channel),
|
||||||
|
memberMap: make(map[string]map[string]*Member),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *State) createMemberMap(guild *Guild) {
|
||||||
|
members := make(map[string]*Member)
|
||||||
|
for _, m := range guild.Members {
|
||||||
|
members[m.User.ID] = m
|
||||||
|
}
|
||||||
|
s.memberMap[guild.ID] = members
|
||||||
|
}
|
||||||
|
|
||||||
// GuildAdd adds a guild to the current world state, or
|
// GuildAdd adds a guild to the current world state, or
|
||||||
// updates it if it already exists.
|
// updates it if it already exists.
|
||||||
func (s *State) GuildAdd(guild *Guild) error {
|
func (s *State) GuildAdd(guild *Guild) error {
|
||||||
@ -77,6 +87,14 @@ func (s *State) GuildAdd(guild *Guild) error {
|
|||||||
s.channelMap[c.ID] = c
|
s.channelMap[c.ID] = c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this guild contains a new member slice, we must regenerate the member map so the pointers stay valid
|
||||||
|
if guild.Members != nil {
|
||||||
|
s.createMemberMap(guild)
|
||||||
|
} else if _, ok := s.memberMap[guild.ID]; !ok {
|
||||||
|
// Even if we have no new member slice, we still initialize the member map for this guild if it doesn't exist
|
||||||
|
s.memberMap[guild.ID] = make(map[string]*Member)
|
||||||
|
}
|
||||||
|
|
||||||
if g, ok := s.guildMap[guild.ID]; ok {
|
if g, ok := s.guildMap[guild.ID]; ok {
|
||||||
// We are about to replace `g` in the state with `guild`, but first we need to
|
// We are about to replace `g` in the state with `guild`, but first we need to
|
||||||
// make sure we preserve any fields that the `guild` doesn't contain from `g`.
|
// make sure we preserve any fields that the `guild` doesn't contain from `g`.
|
||||||
@ -271,14 +289,19 @@ func (s *State) MemberAdd(member *Member) error {
|
|||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
for i, m := range guild.Members {
|
members, ok := s.memberMap[member.GuildID]
|
||||||
if m.User.ID == member.User.ID {
|
if !ok {
|
||||||
guild.Members[i] = member
|
return ErrStateNotFound
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
m, ok := members[member.User.ID]
|
||||||
|
if !ok {
|
||||||
|
members[member.User.ID] = member
|
||||||
|
guild.Members = append(guild.Members, member)
|
||||||
|
} else {
|
||||||
|
*m = *member // Update the actual data, which will also update the member pointer in the slice
|
||||||
}
|
}
|
||||||
|
|
||||||
guild.Members = append(guild.Members, member)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,6 +319,17 @@ func (s *State) MemberRemove(member *Member) error {
|
|||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
|
members, ok := s.memberMap[member.GuildID]
|
||||||
|
if !ok {
|
||||||
|
return ErrStateNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = members[member.User.ID]
|
||||||
|
if !ok {
|
||||||
|
return ErrStateNotFound
|
||||||
|
}
|
||||||
|
delete(members, member.User.ID)
|
||||||
|
|
||||||
for i, m := range guild.Members {
|
for i, m := range guild.Members {
|
||||||
if m.User.ID == member.User.ID {
|
if m.User.ID == member.User.ID {
|
||||||
guild.Members = append(guild.Members[:i], guild.Members[i+1:]...)
|
guild.Members = append(guild.Members[:i], guild.Members[i+1:]...)
|
||||||
@ -312,18 +346,17 @@ func (s *State) Member(guildID, userID string) (*Member, error) {
|
|||||||
return nil, ErrNilState
|
return nil, ErrNilState
|
||||||
}
|
}
|
||||||
|
|
||||||
guild, err := s.Guild(guildID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.RLock()
|
s.RLock()
|
||||||
defer s.RUnlock()
|
defer s.RUnlock()
|
||||||
|
|
||||||
for _, m := range guild.Members {
|
members, ok := s.memberMap[guildID]
|
||||||
if m.User.ID == userID {
|
if !ok {
|
||||||
return m, nil
|
return nil, ErrStateNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m, ok := members[userID]
|
||||||
|
if ok {
|
||||||
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ErrStateNotFound
|
return nil, ErrStateNotFound
|
||||||
@ -427,7 +460,7 @@ func (s *State) ChannelAdd(channel *Channel) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if channel.IsPrivate {
|
if channel.Type == ChannelTypeDM || channel.Type == ChannelTypeGroupDM {
|
||||||
s.PrivateChannels = append(s.PrivateChannels, channel)
|
s.PrivateChannels = append(s.PrivateChannels, channel)
|
||||||
} else {
|
} else {
|
||||||
guild, ok := s.guildMap[channel.GuildID]
|
guild, ok := s.guildMap[channel.GuildID]
|
||||||
@ -454,7 +487,7 @@ func (s *State) ChannelRemove(channel *Channel) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if channel.IsPrivate {
|
if channel.Type == ChannelTypeDM || channel.Type == ChannelTypeGroupDM {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
@ -735,6 +768,7 @@ func (s *State) onReady(se *Session, r *Ready) (err error) {
|
|||||||
|
|
||||||
for _, g := range s.Guilds {
|
for _, g := range s.Guilds {
|
||||||
s.guildMap[g.ID] = g
|
s.guildMap[g.ID] = g
|
||||||
|
s.createMemberMap(g)
|
||||||
|
|
||||||
for _, c := range g.Channels {
|
for _, c := range g.Channels {
|
||||||
s.channelMap[c.ID] = c
|
s.channelMap[c.ID] = c
|
||||||
@ -748,8 +782,8 @@ func (s *State) onReady(se *Session, r *Ready) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// onInterface handles all events related to states.
|
// OnInterface handles all events related to states.
|
||||||
func (s *State) onInterface(se *Session, i interface{}) (err error) {
|
func (s *State) OnInterface(se *Session, i interface{}) (err error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return ErrNilState
|
return ErrNilState
|
||||||
}
|
}
|
||||||
|
87
vendor/github.com/bwmarrin/discordgo/structs.go
generated
vendored
87
vendor/github.com/bwmarrin/discordgo/structs.go
generated
vendored
@ -50,6 +50,10 @@ type Session struct {
|
|||||||
// active guilds and the members of the guilds.
|
// active guilds and the members of the guilds.
|
||||||
StateEnabled bool
|
StateEnabled bool
|
||||||
|
|
||||||
|
// Whether or not to call event handlers synchronously.
|
||||||
|
// e.g false = launch event handlers in their own goroutines.
|
||||||
|
SyncEvents bool
|
||||||
|
|
||||||
// Exposed but should not be modified by User.
|
// Exposed but should not be modified by User.
|
||||||
|
|
||||||
// Whether the Data Websocket is ready
|
// Whether the Data Websocket is ready
|
||||||
@ -78,6 +82,9 @@ type Session struct {
|
|||||||
// The http client used for REST requests
|
// The http client used for REST requests
|
||||||
Client *http.Client
|
Client *http.Client
|
||||||
|
|
||||||
|
// Stores the last HeartbeatAck that was recieved (in UTC)
|
||||||
|
LastHeartbeatAck time.Time
|
||||||
|
|
||||||
// Event handlers
|
// Event handlers
|
||||||
handlersMu sync.RWMutex
|
handlersMu sync.RWMutex
|
||||||
handlers map[string][]*eventHandlerInstance
|
handlers map[string][]*eventHandlerInstance
|
||||||
@ -141,18 +148,30 @@ type Invite struct {
|
|||||||
Temporary bool `json:"temporary"`
|
Temporary bool `json:"temporary"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChannelType is the type of a Channel
|
||||||
|
type ChannelType int
|
||||||
|
|
||||||
|
// Block contains known ChannelType values
|
||||||
|
const (
|
||||||
|
ChannelTypeGuildText ChannelType = iota
|
||||||
|
ChannelTypeDM
|
||||||
|
ChannelTypeGuildVoice
|
||||||
|
ChannelTypeGroupDM
|
||||||
|
ChannelTypeGuildCategory
|
||||||
|
)
|
||||||
|
|
||||||
// A Channel holds all data related to an individual Discord channel.
|
// A Channel holds all data related to an individual Discord channel.
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
GuildID string `json:"guild_id"`
|
GuildID string `json:"guild_id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Topic string `json:"topic"`
|
Topic string `json:"topic"`
|
||||||
Type string `json:"type"`
|
Type ChannelType `json:"type"`
|
||||||
LastMessageID string `json:"last_message_id"`
|
LastMessageID string `json:"last_message_id"`
|
||||||
|
NSFW bool `json:"nsfw"`
|
||||||
Position int `json:"position"`
|
Position int `json:"position"`
|
||||||
Bitrate int `json:"bitrate"`
|
Bitrate int `json:"bitrate"`
|
||||||
IsPrivate bool `json:"is_private"`
|
Recipients []*User `json:"recipient"`
|
||||||
Recipient *User `json:"recipient"`
|
|
||||||
Messages []*Message `json:"-"`
|
Messages []*Message `json:"-"`
|
||||||
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites"`
|
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites"`
|
||||||
}
|
}
|
||||||
@ -292,13 +311,14 @@ type Presence struct {
|
|||||||
Game *Game `json:"game"`
|
Game *Game `json:"game"`
|
||||||
Nick string `json:"nick"`
|
Nick string `json:"nick"`
|
||||||
Roles []string `json:"roles"`
|
Roles []string `json:"roles"`
|
||||||
|
Since *int `json:"since"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Game struct holds the name of the "playing .." game for a user
|
// A Game struct holds the name of the "playing .." game for a user
|
||||||
type Game struct {
|
type Game struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Type int `json:"type"`
|
Type int `json:"type"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals json to Game struct
|
// UnmarshalJSON unmarshals json to Game struct
|
||||||
@ -509,6 +529,12 @@ type MessageReaction struct {
|
|||||||
ChannelID string `json:"channel_id"`
|
ChannelID string `json:"channel_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GatewayBotResponse stores the data for the gateway/bot response
|
||||||
|
type GatewayBotResponse struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
Shards int `json:"shards"`
|
||||||
|
}
|
||||||
|
|
||||||
// Constants for the different bit offsets of text channel permissions
|
// Constants for the different bit offsets of text channel permissions
|
||||||
const (
|
const (
|
||||||
PermissionReadMessages = 1 << (iota + 10)
|
PermissionReadMessages = 1 << (iota + 10)
|
||||||
@ -579,3 +605,56 @@ const (
|
|||||||
PermissionManageServer |
|
PermissionManageServer |
|
||||||
PermissionAdministrator
|
PermissionAdministrator
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Block contains Discord JSON Error Response codes
|
||||||
|
const (
|
||||||
|
ErrCodeUnknownAccount = 10001
|
||||||
|
ErrCodeUnknownApplication = 10002
|
||||||
|
ErrCodeUnknownChannel = 10003
|
||||||
|
ErrCodeUnknownGuild = 10004
|
||||||
|
ErrCodeUnknownIntegration = 10005
|
||||||
|
ErrCodeUnknownInvite = 10006
|
||||||
|
ErrCodeUnknownMember = 10007
|
||||||
|
ErrCodeUnknownMessage = 10008
|
||||||
|
ErrCodeUnknownOverwrite = 10009
|
||||||
|
ErrCodeUnknownProvider = 10010
|
||||||
|
ErrCodeUnknownRole = 10011
|
||||||
|
ErrCodeUnknownToken = 10012
|
||||||
|
ErrCodeUnknownUser = 10013
|
||||||
|
ErrCodeUnknownEmoji = 10014
|
||||||
|
|
||||||
|
ErrCodeBotsCannotUseEndpoint = 20001
|
||||||
|
ErrCodeOnlyBotsCanUseEndpoint = 20002
|
||||||
|
|
||||||
|
ErrCodeMaximumGuildsReached = 30001
|
||||||
|
ErrCodeMaximumFriendsReached = 30002
|
||||||
|
ErrCodeMaximumPinsReached = 30003
|
||||||
|
ErrCodeMaximumGuildRolesReached = 30005
|
||||||
|
ErrCodeTooManyReactions = 30010
|
||||||
|
|
||||||
|
ErrCodeUnauthorized = 40001
|
||||||
|
|
||||||
|
ErrCodeMissingAccess = 50001
|
||||||
|
ErrCodeInvalidAccountType = 50002
|
||||||
|
ErrCodeCannotExecuteActionOnDMChannel = 50003
|
||||||
|
ErrCodeEmbedCisabled = 50004
|
||||||
|
ErrCodeCannotEditFromAnotherUser = 50005
|
||||||
|
ErrCodeCannotSendEmptyMessage = 50006
|
||||||
|
ErrCodeCannotSendMessagesToThisUser = 50007
|
||||||
|
ErrCodeCannotSendMessagesInVoiceChannel = 50008
|
||||||
|
ErrCodeChannelVerificationLevelTooHigh = 50009
|
||||||
|
ErrCodeOAuth2ApplicationDoesNotHaveBot = 50010
|
||||||
|
ErrCodeOAuth2ApplicationLimitReached = 50011
|
||||||
|
ErrCodeInvalidOAuthState = 50012
|
||||||
|
ErrCodeMissingPermissions = 50013
|
||||||
|
ErrCodeInvalidAuthenticationToken = 50014
|
||||||
|
ErrCodeNoteTooLong = 50015
|
||||||
|
ErrCodeTooFewOrTooManyMessagesToDelete = 50016
|
||||||
|
ErrCodeCanOnlyPinMessageToOriginatingChannel = 50019
|
||||||
|
ErrCodeCannotExecuteActionOnSystemMessage = 50021
|
||||||
|
ErrCodeMessageProvidedTooOldForBulkDelete = 50034
|
||||||
|
ErrCodeInvalidFormBody = 50035
|
||||||
|
ErrCodeInviteAcceptedToGuildApplicationsBotNotIn = 50036
|
||||||
|
|
||||||
|
ErrCodeReactionBlocked = 90001
|
||||||
|
)
|
||||||
|
18
vendor/github.com/bwmarrin/discordgo/user.go
generated
vendored
18
vendor/github.com/bwmarrin/discordgo/user.go
generated
vendored
@ -1,6 +1,9 @@
|
|||||||
package discordgo
|
package discordgo
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// A User stores all data for an individual Discord user.
|
// A User stores all data for an individual Discord user.
|
||||||
type User struct {
|
type User struct {
|
||||||
@ -24,3 +27,16 @@ func (u *User) String() string {
|
|||||||
func (u *User) Mention() string {
|
func (u *User) Mention() string {
|
||||||
return fmt.Sprintf("<@%s>", u.ID)
|
return fmt.Sprintf("<@%s>", u.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AvatarURL returns a URL to the user's avatar.
|
||||||
|
// size: The size of the user's avatar as a power of two
|
||||||
|
func (u *User) AvatarURL(size string) string {
|
||||||
|
var URL string
|
||||||
|
if strings.HasPrefix(u.Avatar, "a_") {
|
||||||
|
URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
|
||||||
|
} else {
|
||||||
|
URL = EndpointUserAvatar(u.ID, u.Avatar)
|
||||||
|
}
|
||||||
|
|
||||||
|
return URL + "?size=" + size
|
||||||
|
}
|
||||||
|
13
vendor/github.com/bwmarrin/discordgo/voice.go
generated
vendored
13
vendor/github.com/bwmarrin/discordgo/voice.go
generated
vendored
@ -796,7 +796,7 @@ func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For now, skip anything except audio.
|
// For now, skip anything except audio.
|
||||||
if rlen < 12 || recvbuf[0] != 0x80 {
|
if rlen < 12 || (recvbuf[0] != 0x80 && recvbuf[0] != 0x90) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -810,8 +810,17 @@ func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct
|
|||||||
copy(nonce[:], recvbuf[0:12])
|
copy(nonce[:], recvbuf[0:12])
|
||||||
p.Opus, _ = secretbox.Open(nil, recvbuf[12:rlen], &nonce, &v.op4.SecretKey)
|
p.Opus, _ = secretbox.Open(nil, recvbuf[12:rlen], &nonce, &v.op4.SecretKey)
|
||||||
|
|
||||||
|
if len(p.Opus) > 8 && recvbuf[0] == 0x90 {
|
||||||
|
// Extension bit is set, first 8 bytes is the extended header
|
||||||
|
p.Opus = p.Opus[8:]
|
||||||
|
}
|
||||||
|
|
||||||
if c != nil {
|
if c != nil {
|
||||||
c <- &p
|
select {
|
||||||
|
case c <- &p:
|
||||||
|
case <-close:
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
58
vendor/github.com/bwmarrin/discordgo/wsapi.go
generated
vendored
58
vendor/github.com/bwmarrin/discordgo/wsapi.go
generated
vendored
@ -15,7 +15,6 @@ import (
|
|||||||
"compress/zlib"
|
"compress/zlib"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -87,7 +86,7 @@ func (s *Session) Open() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the version and encoding to the URL
|
// Add the version and encoding to the URL
|
||||||
s.gateway = fmt.Sprintf("%s?v=5&encoding=json", s.gateway)
|
s.gateway = s.gateway + "?v=" + APIVersion + "&encoding=json"
|
||||||
}
|
}
|
||||||
|
|
||||||
header := http.Header{}
|
header := http.Header{}
|
||||||
@ -131,6 +130,7 @@ func (s *Session) Open() (err error) {
|
|||||||
// lock.
|
// lock.
|
||||||
s.listening = make(chan interface{})
|
s.listening = make(chan interface{})
|
||||||
go s.listen(s.wsConn, s.listening)
|
go s.listen(s.wsConn, s.listening)
|
||||||
|
s.LastHeartbeatAck = time.Now().UTC()
|
||||||
|
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
|
|
||||||
@ -199,10 +199,13 @@ type helloOp struct {
|
|||||||
Trace []string `json:"_trace"`
|
Trace []string `json:"_trace"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FailedHeartbeatAcks is the Number of heartbeat intervals to wait until forcing a connection restart.
|
||||||
|
const FailedHeartbeatAcks time.Duration = 5 * time.Millisecond
|
||||||
|
|
||||||
// heartbeat sends regular heartbeats to Discord so it knows the client
|
// heartbeat sends regular heartbeats to Discord so it knows the client
|
||||||
// is still connected. If you do not send these heartbeats Discord will
|
// is still connected. If you do not send these heartbeats Discord will
|
||||||
// disconnect the websocket connection after a few seconds.
|
// disconnect the websocket connection after a few seconds.
|
||||||
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {
|
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, heartbeatIntervalMsec time.Duration) {
|
||||||
|
|
||||||
s.log(LogInformational, "called")
|
s.log(LogInformational, "called")
|
||||||
|
|
||||||
@ -211,20 +214,26 @@ func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}
|
|||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
ticker := time.NewTicker(i * time.Millisecond)
|
ticker := time.NewTicker(heartbeatIntervalMsec * time.Millisecond)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
s.RLock()
|
||||||
|
last := s.LastHeartbeatAck
|
||||||
|
s.RUnlock()
|
||||||
sequence := atomic.LoadInt64(s.sequence)
|
sequence := atomic.LoadInt64(s.sequence)
|
||||||
s.log(LogInformational, "sending gateway websocket heartbeat seq %d", sequence)
|
s.log(LogInformational, "sending gateway websocket heartbeat seq %d", sequence)
|
||||||
s.wsMutex.Lock()
|
s.wsMutex.Lock()
|
||||||
err = wsConn.WriteJSON(heartbeatOp{1, sequence})
|
err = wsConn.WriteJSON(heartbeatOp{1, sequence})
|
||||||
s.wsMutex.Unlock()
|
s.wsMutex.Unlock()
|
||||||
if err != nil {
|
if err != nil || time.Now().UTC().Sub(last) > (heartbeatIntervalMsec*FailedHeartbeatAcks) {
|
||||||
s.log(LogError, "error sending heartbeat to gateway %s, %s", s.gateway, err)
|
if err != nil {
|
||||||
s.Lock()
|
s.log(LogError, "error sending heartbeat to gateway %s, %s", s.gateway, err)
|
||||||
s.DataReady = false
|
} else {
|
||||||
s.Unlock()
|
s.log(LogError, "haven't gotten a heartbeat ACK in %v, triggering a reconnection", time.Now().UTC().Sub(last))
|
||||||
|
}
|
||||||
|
s.Close()
|
||||||
|
s.reconnect()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.Lock()
|
s.Lock()
|
||||||
@ -241,8 +250,10 @@ func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}
|
|||||||
}
|
}
|
||||||
|
|
||||||
type updateStatusData struct {
|
type updateStatusData struct {
|
||||||
IdleSince *int `json:"idle_since"`
|
IdleSince *int `json:"since"`
|
||||||
Game *Game `json:"game"`
|
Game *Game `json:"game"`
|
||||||
|
AFK bool `json:"afk"`
|
||||||
|
Status string `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateStatusOp struct {
|
type updateStatusOp struct {
|
||||||
@ -265,7 +276,10 @@ func (s *Session) UpdateStreamingStatus(idle int, game string, url string) (err
|
|||||||
return ErrWSNotFound
|
return ErrWSNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
var usd updateStatusData
|
usd := updateStatusData{
|
||||||
|
Status: "online",
|
||||||
|
}
|
||||||
|
|
||||||
if idle > 0 {
|
if idle > 0 {
|
||||||
usd.IdleSince = &idle
|
usd.IdleSince = &idle
|
||||||
}
|
}
|
||||||
@ -398,7 +412,10 @@ func (s *Session) onEvent(messageType int, message []byte) {
|
|||||||
// Reconnect
|
// Reconnect
|
||||||
// Must immediately disconnect from gateway and reconnect to new gateway.
|
// Must immediately disconnect from gateway and reconnect to new gateway.
|
||||||
if e.Operation == 7 {
|
if e.Operation == 7 {
|
||||||
// TODO
|
s.log(LogInformational, "Closing and reconnecting in response to Op7")
|
||||||
|
s.Close()
|
||||||
|
s.reconnect()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid Session
|
// Invalid Session
|
||||||
@ -426,6 +443,14 @@ func (s *Session) onEvent(messageType int, message []byte) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if e.Operation == 11 {
|
||||||
|
s.Lock()
|
||||||
|
s.LastHeartbeatAck = time.Now().UTC()
|
||||||
|
s.Unlock()
|
||||||
|
s.log(LogInformational, "got heartbeat ACK")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Do not try to Dispatch a non-Dispatch Message
|
// Do not try to Dispatch a non-Dispatch Message
|
||||||
if e.Operation != 0 {
|
if e.Operation != 0 {
|
||||||
// But we probably should be doing something with them.
|
// But we probably should be doing something with them.
|
||||||
@ -688,6 +713,13 @@ func (s *Session) reconnect() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Certain race conditions can call reconnect() twice. If this happens, we
|
||||||
|
// just break out of the reconnect loop
|
||||||
|
if err == ErrWSAlreadyOpen {
|
||||||
|
s.log(LogInformational, "Websocket already exists, no need to reconnect")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.log(LogError, "error reconnecting to gateway, %s", err)
|
s.log(LogError, "error reconnecting to gateway, %s", err)
|
||||||
|
|
||||||
<-time.After(wait * time.Second)
|
<-time.After(wait * time.Second)
|
||||||
|
197
vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
generated
vendored
197
vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
generated
vendored
@ -191,7 +191,11 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna
|
|||||||
}
|
}
|
||||||
|
|
||||||
var apiResp APIResponse
|
var apiResp APIResponse
|
||||||
json.Unmarshal(bytes, &apiResp)
|
|
||||||
|
err = json.Unmarshal(bytes, &apiResp)
|
||||||
|
if err != nil {
|
||||||
|
return APIResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
if !apiResp.Ok {
|
if !apiResp.Ok {
|
||||||
return APIResponse{}, errors.New(apiResp.Description)
|
return APIResponse{}, errors.New(apiResp.Description)
|
||||||
@ -438,14 +442,7 @@ func (bot *BotAPI) SetWebhook(config WebhookConfig) (APIResponse, error) {
|
|||||||
return APIResponse{}, err
|
return APIResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var apiResp APIResponse
|
return resp, nil
|
||||||
json.Unmarshal(resp.Result, &apiResp)
|
|
||||||
|
|
||||||
if bot.Debug {
|
|
||||||
log.Printf("setWebhook resp: %+v\n", apiResp)
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiResp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookInfo allows you to fetch information about a webhook and if
|
// GetWebhookInfo allows you to fetch information about a webhook and if
|
||||||
@ -550,7 +547,7 @@ func (bot *BotAPI) AnswerCallbackQuery(config CallbackConfig) (APIResponse, erro
|
|||||||
// KickChatMember kicks a user from a chat. Note that this only will work
|
// KickChatMember kicks a user from a chat. Note that this only will work
|
||||||
// in supergroups, and requires the bot to be an admin. Also note they
|
// in supergroups, and requires the bot to be an admin. Also note they
|
||||||
// will be unable to rejoin until they are unbanned.
|
// will be unable to rejoin until they are unbanned.
|
||||||
func (bot *BotAPI) KickChatMember(config ChatMemberConfig) (APIResponse, error) {
|
func (bot *BotAPI) KickChatMember(config KickChatMemberConfig) (APIResponse, error) {
|
||||||
v := url.Values{}
|
v := url.Values{}
|
||||||
|
|
||||||
if config.SuperGroupUsername == "" {
|
if config.SuperGroupUsername == "" {
|
||||||
@ -560,6 +557,10 @@ func (bot *BotAPI) KickChatMember(config ChatMemberConfig) (APIResponse, error)
|
|||||||
}
|
}
|
||||||
v.Add("user_id", strconv.Itoa(config.UserID))
|
v.Add("user_id", strconv.Itoa(config.UserID))
|
||||||
|
|
||||||
|
if config.UntilDate != 0 {
|
||||||
|
v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
|
||||||
|
}
|
||||||
|
|
||||||
bot.debugLog("kickChatMember", v, nil)
|
bot.debugLog("kickChatMember", v, nil)
|
||||||
|
|
||||||
return bot.MakeRequest("kickChatMember", v)
|
return bot.MakeRequest("kickChatMember", v)
|
||||||
@ -677,14 +678,16 @@ func (bot *BotAPI) GetChatMember(config ChatConfigWithUser) (ChatMember, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnbanChatMember unbans a user from a chat. Note that this only will work
|
// UnbanChatMember unbans a user from a chat. Note that this only will work
|
||||||
// in supergroups, and requires the bot to be an admin.
|
// in supergroups and channels, and requires the bot to be an admin.
|
||||||
func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) {
|
func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) {
|
||||||
v := url.Values{}
|
v := url.Values{}
|
||||||
|
|
||||||
if config.SuperGroupUsername == "" {
|
if config.SuperGroupUsername != "" {
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
v.Add("chat_id", config.SuperGroupUsername)
|
||||||
|
} else if config.ChannelUsername != "" {
|
||||||
|
v.Add("chat_id", config.ChannelUsername)
|
||||||
|
} else {
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
}
|
}
|
||||||
v.Add("user_id", strconv.Itoa(config.UserID))
|
v.Add("user_id", strconv.Itoa(config.UserID))
|
||||||
|
|
||||||
@ -693,6 +696,82 @@ func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error)
|
|||||||
return bot.MakeRequest("unbanChatMember", v)
|
return bot.MakeRequest("unbanChatMember", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RestrictChatMember to restrict a user in a supergroup. The bot must be an
|
||||||
|
//administrator in the supergroup for this to work and must have the
|
||||||
|
//appropriate admin rights. Pass True for all boolean parameters to lift
|
||||||
|
//restrictions from a user. Returns True on success.
|
||||||
|
func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
if config.SuperGroupUsername != "" {
|
||||||
|
v.Add("chat_id", config.SuperGroupUsername)
|
||||||
|
} else if config.ChannelUsername != "" {
|
||||||
|
v.Add("chat_id", config.ChannelUsername)
|
||||||
|
} else {
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
}
|
||||||
|
v.Add("user_id", strconv.Itoa(config.UserID))
|
||||||
|
|
||||||
|
if &config.CanSendMessages != nil {
|
||||||
|
v.Add("can_send_messages", strconv.FormatBool(*config.CanSendMessages))
|
||||||
|
}
|
||||||
|
if &config.CanSendMediaMessages != nil {
|
||||||
|
v.Add("can_send_media_messages", strconv.FormatBool(*config.CanSendMediaMessages))
|
||||||
|
}
|
||||||
|
if &config.CanSendOtherMessages != nil {
|
||||||
|
v.Add("can_send_other_messages", strconv.FormatBool(*config.CanSendOtherMessages))
|
||||||
|
}
|
||||||
|
if &config.CanAddWebPagePreviews != nil {
|
||||||
|
v.Add("can_add_web_page_previews", strconv.FormatBool(*config.CanAddWebPagePreviews))
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.debugLog("restrictChatMember", v, nil)
|
||||||
|
|
||||||
|
return bot.MakeRequest("restrictChatMember", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bot *BotAPI) PromoteChatMember(config PromoteChatMemberConfig) (APIResponse, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
if config.SuperGroupUsername != "" {
|
||||||
|
v.Add("chat_id", config.SuperGroupUsername)
|
||||||
|
} else if config.ChannelUsername != "" {
|
||||||
|
v.Add("chat_id", config.ChannelUsername)
|
||||||
|
} else {
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
}
|
||||||
|
v.Add("user_id", strconv.Itoa(config.UserID))
|
||||||
|
|
||||||
|
if &config.CanChangeInfo != nil {
|
||||||
|
v.Add("can_change_info", strconv.FormatBool(*config.CanChangeInfo))
|
||||||
|
}
|
||||||
|
if &config.CanPostMessages != nil {
|
||||||
|
v.Add("can_post_messages", strconv.FormatBool(*config.CanPostMessages))
|
||||||
|
}
|
||||||
|
if &config.CanEditMessages != nil {
|
||||||
|
v.Add("can_edit_messages", strconv.FormatBool(*config.CanEditMessages))
|
||||||
|
}
|
||||||
|
if &config.CanDeleteMessages != nil {
|
||||||
|
v.Add("can_delete_messages", strconv.FormatBool(*config.CanDeleteMessages))
|
||||||
|
}
|
||||||
|
if &config.CanInviteUsers != nil {
|
||||||
|
v.Add("can_invite_users", strconv.FormatBool(*config.CanInviteUsers))
|
||||||
|
}
|
||||||
|
if &config.CanRestrictMembers != nil {
|
||||||
|
v.Add("can_restrict_members", strconv.FormatBool(*config.CanRestrictMembers))
|
||||||
|
}
|
||||||
|
if &config.CanPinMessages != nil {
|
||||||
|
v.Add("can_pin_messages", strconv.FormatBool(*config.CanPinMessages))
|
||||||
|
}
|
||||||
|
if &config.CanPromoteMembers != nil {
|
||||||
|
v.Add("can_promote_members", strconv.FormatBool(*config.CanPromoteMembers))
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.debugLog("promoteChatMember", v, nil)
|
||||||
|
|
||||||
|
return bot.MakeRequest("promoteChatMember", v)
|
||||||
|
}
|
||||||
|
|
||||||
// GetGameHighScores allows you to get the high scores for a game.
|
// GetGameHighScores allows you to get the high scores for a game.
|
||||||
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
||||||
v, _ := config.values()
|
v, _ := config.values()
|
||||||
@ -707,3 +786,93 @@ func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHigh
|
|||||||
|
|
||||||
return highScores, err
|
return highScores, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnswerShippingQuery allows you to reply to Update with shipping_query parameter.
|
||||||
|
func (bot *BotAPI) AnswerShippingQuery(config ShippingConfig) (APIResponse, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
v.Add("shipping_query_id", config.ShippingQueryID)
|
||||||
|
v.Add("ok", strconv.FormatBool(config.OK))
|
||||||
|
if config.OK == true {
|
||||||
|
data, err := json.Marshal(config.ShippingOptions)
|
||||||
|
if err != nil {
|
||||||
|
return APIResponse{}, err
|
||||||
|
}
|
||||||
|
v.Add("shipping_options", string(data))
|
||||||
|
} else {
|
||||||
|
v.Add("error_message", config.ErrorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.debugLog("answerShippingQuery", v, nil)
|
||||||
|
|
||||||
|
return bot.MakeRequest("answerShippingQuery", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnswerPreCheckoutQuery allows you to reply to Update with pre_checkout_query.
|
||||||
|
func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
v.Add("pre_checkout_query_id", config.PreCheckoutQueryID)
|
||||||
|
v.Add("ok", strconv.FormatBool(config.OK))
|
||||||
|
if config.OK != true {
|
||||||
|
v.Add("error", config.ErrorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.debugLog("answerPreCheckoutQuery", v, nil)
|
||||||
|
|
||||||
|
return bot.MakeRequest("answerPreCheckoutQuery", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMessage deletes a message in a chat
|
||||||
|
func (bot *BotAPI) DeleteMessage(config DeleteMessageConfig) (APIResponse, error) {
|
||||||
|
v, err := config.values()
|
||||||
|
if err != nil {
|
||||||
|
return APIResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.debugLog(config.method(), v, nil)
|
||||||
|
|
||||||
|
return bot.MakeRequest(config.method(), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInviteLink get InviteLink for a chat
|
||||||
|
func (bot *BotAPI) GetInviteLink(config ChatConfig) (string, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
if config.SuperGroupUsername == "" {
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
} else {
|
||||||
|
v.Add("chat_id", config.SuperGroupUsername)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := bot.MakeRequest("exportChatInviteLink", v)
|
||||||
|
|
||||||
|
var inviteLink string
|
||||||
|
err = json.Unmarshal(resp.Result, &inviteLink)
|
||||||
|
|
||||||
|
return inviteLink, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pin message in supergroup
|
||||||
|
func (bot *BotAPI) PinChatMessage(config PinChatMessageConfig) (APIResponse, error) {
|
||||||
|
v, err := config.values()
|
||||||
|
if err != nil {
|
||||||
|
return APIResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.debugLog(config.method(), v, nil)
|
||||||
|
|
||||||
|
return bot.MakeRequest(config.method(), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unpin message in supergroup
|
||||||
|
func (bot *BotAPI) UnpinChatMessage(config UnpinChatMessageConfig) (APIResponse, error) {
|
||||||
|
v, err := config.values()
|
||||||
|
if err != nil {
|
||||||
|
return APIResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bot.debugLog(config.method(), v, nil)
|
||||||
|
|
||||||
|
return bot.MakeRequest(config.method(), v)
|
||||||
|
}
|
243
vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
generated
vendored
243
vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
generated
vendored
@ -349,6 +349,7 @@ func (config AudioConfig) method() string {
|
|||||||
// DocumentConfig contains information about a SendDocument request.
|
// DocumentConfig contains information about a SendDocument request.
|
||||||
type DocumentConfig struct {
|
type DocumentConfig struct {
|
||||||
BaseFile
|
BaseFile
|
||||||
|
Caption string
|
||||||
}
|
}
|
||||||
|
|
||||||
// values returns a url.Values representation of DocumentConfig.
|
// values returns a url.Values representation of DocumentConfig.
|
||||||
@ -359,6 +360,9 @@ func (config DocumentConfig) values() (url.Values, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
v.Add(config.name(), config.FileID)
|
v.Add(config.name(), config.FileID)
|
||||||
|
if config.Caption != "" {
|
||||||
|
v.Add("caption", config.Caption)
|
||||||
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
@ -367,6 +371,10 @@ func (config DocumentConfig) values() (url.Values, error) {
|
|||||||
func (config DocumentConfig) params() (map[string]string, error) {
|
func (config DocumentConfig) params() (map[string]string, error) {
|
||||||
params, _ := config.BaseFile.params()
|
params, _ := config.BaseFile.params()
|
||||||
|
|
||||||
|
if config.Caption != "" {
|
||||||
|
params["caption"] = config.Caption
|
||||||
|
}
|
||||||
|
|
||||||
return params, nil
|
return params, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,6 +451,10 @@ func (config VideoConfig) values() (url.Values, error) {
|
|||||||
func (config VideoConfig) params() (map[string]string, error) {
|
func (config VideoConfig) params() (map[string]string, error) {
|
||||||
params, _ := config.BaseFile.params()
|
params, _ := config.BaseFile.params()
|
||||||
|
|
||||||
|
if config.Caption != "" {
|
||||||
|
params["caption"] = config.Caption
|
||||||
|
}
|
||||||
|
|
||||||
return params, nil
|
return params, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,6 +468,57 @@ func (config VideoConfig) method() string {
|
|||||||
return "sendVideo"
|
return "sendVideo"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VideoNoteConfig contains information about a SendVideoNote request.
|
||||||
|
type VideoNoteConfig struct {
|
||||||
|
BaseFile
|
||||||
|
Duration int
|
||||||
|
Length int
|
||||||
|
}
|
||||||
|
|
||||||
|
// values returns a url.Values representation of VideoNoteConfig.
|
||||||
|
func (config VideoNoteConfig) values() (url.Values, error) {
|
||||||
|
v, err := config.BaseChat.values()
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Add(config.name(), config.FileID)
|
||||||
|
if config.Duration != 0 {
|
||||||
|
v.Add("duration", strconv.Itoa(config.Duration))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Telegram API seems to have a bug, if no length is provided or it is 0, it will send an error response
|
||||||
|
if config.Length != 0 {
|
||||||
|
v.Add("length", strconv.Itoa(config.Length))
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// params returns a map[string]string representation of VideoNoteConfig.
|
||||||
|
func (config VideoNoteConfig) params() (map[string]string, error) {
|
||||||
|
params, _ := config.BaseFile.params()
|
||||||
|
|
||||||
|
if config.Length != 0 {
|
||||||
|
params["length"] = strconv.Itoa(config.Length)
|
||||||
|
}
|
||||||
|
if config.Duration != 0 {
|
||||||
|
params["duration"] = strconv.Itoa(config.Duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return params, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// name returns the field name for the VideoNote.
|
||||||
|
func (config VideoNoteConfig) name() string {
|
||||||
|
return "video_note"
|
||||||
|
}
|
||||||
|
|
||||||
|
// method returns Telegram API method name for sending VideoNote.
|
||||||
|
func (config VideoNoteConfig) method() string {
|
||||||
|
return "sendVideoNote"
|
||||||
|
}
|
||||||
|
|
||||||
// VoiceConfig contains information about a SendVoice request.
|
// VoiceConfig contains information about a SendVoice request.
|
||||||
type VoiceConfig struct {
|
type VoiceConfig struct {
|
||||||
BaseFile
|
BaseFile
|
||||||
@ -474,6 +537,9 @@ func (config VoiceConfig) values() (url.Values, error) {
|
|||||||
if config.Duration != 0 {
|
if config.Duration != 0 {
|
||||||
v.Add("duration", strconv.Itoa(config.Duration))
|
v.Add("duration", strconv.Itoa(config.Duration))
|
||||||
}
|
}
|
||||||
|
if config.Caption != "" {
|
||||||
|
v.Add("caption", config.Caption)
|
||||||
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
@ -485,6 +551,9 @@ func (config VoiceConfig) params() (map[string]string, error) {
|
|||||||
if config.Duration != 0 {
|
if config.Duration != 0 {
|
||||||
params["duration"] = strconv.Itoa(config.Duration)
|
params["duration"] = strconv.Itoa(config.Duration)
|
||||||
}
|
}
|
||||||
|
if config.Caption != "" {
|
||||||
|
params["caption"] = config.Caption
|
||||||
|
}
|
||||||
|
|
||||||
return params, nil
|
return params, nil
|
||||||
}
|
}
|
||||||
@ -814,9 +883,39 @@ type CallbackConfig struct {
|
|||||||
type ChatMemberConfig struct {
|
type ChatMemberConfig struct {
|
||||||
ChatID int64
|
ChatID int64
|
||||||
SuperGroupUsername string
|
SuperGroupUsername string
|
||||||
|
ChannelUsername string
|
||||||
UserID int
|
UserID int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KickChatMemberConfig contains extra fields to kick user
|
||||||
|
type KickChatMemberConfig struct {
|
||||||
|
ChatMemberConfig
|
||||||
|
UntilDate int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestrictChatMemberConfig contains fields to restrict members of chat
|
||||||
|
type RestrictChatMemberConfig struct {
|
||||||
|
ChatMemberConfig
|
||||||
|
UntilDate int64
|
||||||
|
CanSendMessages *bool
|
||||||
|
CanSendMediaMessages *bool
|
||||||
|
CanSendOtherMessages *bool
|
||||||
|
CanAddWebPagePreviews *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// PromoteChatMemberConfig contains fields to promote members of chat
|
||||||
|
type PromoteChatMemberConfig struct {
|
||||||
|
ChatMemberConfig
|
||||||
|
CanChangeInfo *bool
|
||||||
|
CanPostMessages *bool
|
||||||
|
CanEditMessages *bool
|
||||||
|
CanDeleteMessages *bool
|
||||||
|
CanInviteUsers *bool
|
||||||
|
CanRestrictMembers *bool
|
||||||
|
CanPinMessages *bool
|
||||||
|
CanPromoteMembers *bool
|
||||||
|
}
|
||||||
|
|
||||||
// ChatConfig contains information about getting information on a chat.
|
// ChatConfig contains information about getting information on a chat.
|
||||||
type ChatConfig struct {
|
type ChatConfig struct {
|
||||||
ChatID int64
|
ChatID int64
|
||||||
@ -830,3 +929,147 @@ type ChatConfigWithUser struct {
|
|||||||
SuperGroupUsername string
|
SuperGroupUsername string
|
||||||
UserID int
|
UserID int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvoiceConfig contains information for sendInvoice request.
|
||||||
|
type InvoiceConfig struct {
|
||||||
|
BaseChat
|
||||||
|
Title string // required
|
||||||
|
Description string // required
|
||||||
|
Payload string // required
|
||||||
|
ProviderToken string // required
|
||||||
|
StartParameter string // required
|
||||||
|
Currency string // required
|
||||||
|
Prices *[]LabeledPrice // required
|
||||||
|
PhotoURL string
|
||||||
|
PhotoSize int
|
||||||
|
PhotoWidth int
|
||||||
|
PhotoHeight int
|
||||||
|
NeedName bool
|
||||||
|
NeedPhoneNumber bool
|
||||||
|
NeedEmail bool
|
||||||
|
NeedShippingAddress bool
|
||||||
|
IsFlexible bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config InvoiceConfig) values() (url.Values, error) {
|
||||||
|
v, err := config.BaseChat.values()
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
v.Add("title", config.Title)
|
||||||
|
v.Add("description", config.Description)
|
||||||
|
v.Add("payload", config.Payload)
|
||||||
|
v.Add("provider_token", config.ProviderToken)
|
||||||
|
v.Add("start_parameter", config.StartParameter)
|
||||||
|
v.Add("currency", config.Currency)
|
||||||
|
data, err := json.Marshal(config.Prices)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
v.Add("prices", string(data))
|
||||||
|
if config.PhotoURL != "" {
|
||||||
|
v.Add("photo_url", config.PhotoURL)
|
||||||
|
}
|
||||||
|
if config.PhotoSize != 0 {
|
||||||
|
v.Add("photo_size", strconv.Itoa(config.PhotoSize))
|
||||||
|
}
|
||||||
|
if config.PhotoWidth != 0 {
|
||||||
|
v.Add("photo_width", strconv.Itoa(config.PhotoWidth))
|
||||||
|
}
|
||||||
|
if config.PhotoHeight != 0 {
|
||||||
|
v.Add("photo_height", strconv.Itoa(config.PhotoHeight))
|
||||||
|
}
|
||||||
|
if config.NeedName != false {
|
||||||
|
v.Add("need_name", strconv.FormatBool(config.NeedName))
|
||||||
|
}
|
||||||
|
if config.NeedPhoneNumber != false {
|
||||||
|
v.Add("need_phone_number", strconv.FormatBool(config.NeedPhoneNumber))
|
||||||
|
}
|
||||||
|
if config.NeedEmail != false {
|
||||||
|
v.Add("need_email", strconv.FormatBool(config.NeedEmail))
|
||||||
|
}
|
||||||
|
if config.NeedShippingAddress != false {
|
||||||
|
v.Add("need_shipping_address", strconv.FormatBool(config.NeedShippingAddress))
|
||||||
|
}
|
||||||
|
if config.IsFlexible != false {
|
||||||
|
v.Add("is_flexible", strconv.FormatBool(config.IsFlexible))
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config InvoiceConfig) method() string {
|
||||||
|
return "sendInvoice"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShippingConfig contains information for answerShippingQuery request.
|
||||||
|
type ShippingConfig struct {
|
||||||
|
ShippingQueryID string // required
|
||||||
|
OK bool // required
|
||||||
|
ShippingOptions *[]ShippingOption
|
||||||
|
ErrorMessage string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreCheckoutConfig conatins information for answerPreCheckoutQuery request.
|
||||||
|
type PreCheckoutConfig struct {
|
||||||
|
PreCheckoutQueryID string // required
|
||||||
|
OK bool // required
|
||||||
|
ErrorMessage string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMessageConfig contains information of a message in a chat to delete.
|
||||||
|
type DeleteMessageConfig struct {
|
||||||
|
ChatID int64
|
||||||
|
MessageID int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config DeleteMessageConfig) method() string {
|
||||||
|
return "deleteMessage"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config DeleteMessageConfig) values() (url.Values, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
v.Add("message_id", strconv.Itoa(config.MessageID))
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PinChatMessageConfig contains information of a message in a chat to pin.
|
||||||
|
type PinChatMessageConfig struct {
|
||||||
|
ChatID int64
|
||||||
|
MessageID int
|
||||||
|
DisableNotification bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config PinChatMessageConfig) method() string {
|
||||||
|
return "pinChatMessage"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config PinChatMessageConfig) values() (url.Values, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
v.Add("message_id", strconv.Itoa(config.MessageID))
|
||||||
|
v.Add("disable_notification", strconv.FormatBool(config.DisableNotification))
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnpinChatMessageConfig contains information of chat to unpin.
|
||||||
|
type UnpinChatMessageConfig struct {
|
||||||
|
ChatID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config UnpinChatMessageConfig) method() string {
|
||||||
|
return "unpinChatMessage"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config UnpinChatMessageConfig) values() (url.Values, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
|
||||||
|
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
44
vendor/github.com/go-telegram-bot-api/telegram-bot-api/helpers.go
generated
vendored
44
vendor/github.com/go-telegram-bot-api/telegram-bot-api/helpers.go
generated
vendored
@ -194,6 +194,37 @@ func NewVideoShare(chatID int64, fileID string) VideoConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return VideoNoteConfig{
|
||||||
|
BaseFile: BaseFile{
|
||||||
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
|
File: file,
|
||||||
|
UseExisting: false,
|
||||||
|
},
|
||||||
|
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.
|
// NewVoiceUpload creates a new voice uploader.
|
||||||
//
|
//
|
||||||
// chatID is where to send it, file is a string path to the file,
|
// chatID is where to send it, file is a string path to the file,
|
||||||
@ -609,3 +640,16 @@ func NewCallbackWithAlert(id, text string) CallbackConfig {
|
|||||||
ShowAlert: true,
|
ShowAlert: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInvoice created a new Invoice request to the user.
|
||||||
|
func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices *[]LabeledPrice) InvoiceConfig {
|
||||||
|
return InvoiceConfig{
|
||||||
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
|
Title: title,
|
||||||
|
Description: description,
|
||||||
|
Payload: payload,
|
||||||
|
ProviderToken: providerToken,
|
||||||
|
StartParameter: startParameter,
|
||||||
|
Currency: currency,
|
||||||
|
Prices: prices}
|
||||||
|
}
|
||||||
|
205
vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
generated
vendored
205
vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
generated
vendored
@ -35,6 +35,8 @@ type Update struct {
|
|||||||
InlineQuery *InlineQuery `json:"inline_query"`
|
InlineQuery *InlineQuery `json:"inline_query"`
|
||||||
ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"`
|
ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"`
|
||||||
CallbackQuery *CallbackQuery `json:"callback_query"`
|
CallbackQuery *CallbackQuery `json:"callback_query"`
|
||||||
|
ShippingQuery *ShippingQuery `json:"shipping_query"`
|
||||||
|
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatesChannel is the channel for getting updates.
|
// UpdatesChannel is the channel for getting updates.
|
||||||
@ -49,10 +51,11 @@ func (ch UpdatesChannel) Clear() {
|
|||||||
|
|
||||||
// User is a user on Telegram.
|
// User is a user on Telegram.
|
||||||
type User struct {
|
type User struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
FirstName string `json:"first_name"`
|
FirstName string `json:"first_name"`
|
||||||
LastName string `json:"last_name"` // optional
|
LastName string `json:"last_name"` // optional
|
||||||
UserName string `json:"username"` // optional
|
UserName string `json:"username"` // optional
|
||||||
|
LanguageCode string `json:"language_code"` // optional
|
||||||
}
|
}
|
||||||
|
|
||||||
// String displays a simple text version of a user.
|
// String displays a simple text version of a user.
|
||||||
@ -78,15 +81,24 @@ type GroupChat struct {
|
|||||||
Title string `json:"title"`
|
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.
|
// Chat contains information about the place a message was sent.
|
||||||
type Chat struct {
|
type Chat struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Title string `json:"title"` // optional
|
Title string `json:"title"` // optional
|
||||||
UserName string `json:"username"` // optional
|
UserName string `json:"username"` // optional
|
||||||
FirstName string `json:"first_name"` // optional
|
FirstName string `json:"first_name"` // optional
|
||||||
LastName string `json:"last_name"` // optional
|
LastName string `json:"last_name"` // optional
|
||||||
AllMembersAreAdmins bool `json:"all_members_are_administrators"` // 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPrivate returns if the Chat is a private conversation.
|
// IsPrivate returns if the Chat is a private conversation.
|
||||||
@ -117,40 +129,43 @@ func (c Chat) ChatConfig() ChatConfig {
|
|||||||
// Message is returned by almost every request, and contains data about
|
// Message is returned by almost every request, and contains data about
|
||||||
// almost anything.
|
// almost anything.
|
||||||
type Message struct {
|
type Message struct {
|
||||||
MessageID int `json:"message_id"`
|
MessageID int `json:"message_id"`
|
||||||
From *User `json:"from"` // optional
|
From *User `json:"from"` // optional
|
||||||
Date int `json:"date"`
|
Date int `json:"date"`
|
||||||
Chat *Chat `json:"chat"`
|
Chat *Chat `json:"chat"`
|
||||||
ForwardFrom *User `json:"forward_from"` // optional
|
ForwardFrom *User `json:"forward_from"` // optional
|
||||||
ForwardFromChat *Chat `json:"forward_from_chat"` // optional
|
ForwardFromChat *Chat `json:"forward_from_chat"` // optional
|
||||||
ForwardFromMessageID int `json:"forward_from_message_id"` // optional
|
ForwardFromMessageID int `json:"forward_from_message_id"` // optional
|
||||||
ForwardDate int `json:"forward_date"` // optional
|
ForwardDate int `json:"forward_date"` // optional
|
||||||
ReplyToMessage *Message `json:"reply_to_message"` // optional
|
ReplyToMessage *Message `json:"reply_to_message"` // optional
|
||||||
EditDate int `json:"edit_date"` // optional
|
EditDate int `json:"edit_date"` // optional
|
||||||
Text string `json:"text"` // optional
|
Text string `json:"text"` // optional
|
||||||
Entities *[]MessageEntity `json:"entities"` // optional
|
Entities *[]MessageEntity `json:"entities"` // optional
|
||||||
Audio *Audio `json:"audio"` // optional
|
Audio *Audio `json:"audio"` // optional
|
||||||
Document *Document `json:"document"` // optional
|
Document *Document `json:"document"` // optional
|
||||||
Game *Game `json:"game"` // optional
|
Game *Game `json:"game"` // optional
|
||||||
Photo *[]PhotoSize `json:"photo"` // optional
|
Photo *[]PhotoSize `json:"photo"` // optional
|
||||||
Sticker *Sticker `json:"sticker"` // optional
|
Sticker *Sticker `json:"sticker"` // optional
|
||||||
Video *Video `json:"video"` // optional
|
Video *Video `json:"video"` // optional
|
||||||
Voice *Voice `json:"voice"` // optional
|
VideoNote *VideoNote `json:"video_note"` // optional
|
||||||
Caption string `json:"caption"` // optional
|
Voice *Voice `json:"voice"` // optional
|
||||||
Contact *Contact `json:"contact"` // optional
|
Caption string `json:"caption"` // optional
|
||||||
Location *Location `json:"location"` // optional
|
Contact *Contact `json:"contact"` // optional
|
||||||
Venue *Venue `json:"venue"` // optional
|
Location *Location `json:"location"` // optional
|
||||||
NewChatMember *User `json:"new_chat_member"` // optional
|
Venue *Venue `json:"venue"` // optional
|
||||||
LeftChatMember *User `json:"left_chat_member"` // optional
|
NewChatMembers *[]User `json:"new_chat_members"` // optional
|
||||||
NewChatTitle string `json:"new_chat_title"` // optional
|
LeftChatMember *User `json:"left_chat_member"` // optional
|
||||||
NewChatPhoto *[]PhotoSize `json:"new_chat_photo"` // optional
|
NewChatTitle string `json:"new_chat_title"` // optional
|
||||||
DeleteChatPhoto bool `json:"delete_chat_photo"` // optional
|
NewChatPhoto *[]PhotoSize `json:"new_chat_photo"` // optional
|
||||||
GroupChatCreated bool `json:"group_chat_created"` // optional
|
DeleteChatPhoto bool `json:"delete_chat_photo"` // optional
|
||||||
SuperGroupChatCreated bool `json:"supergroup_chat_created"` // optional
|
GroupChatCreated bool `json:"group_chat_created"` // optional
|
||||||
ChannelChatCreated bool `json:"channel_chat_created"` // optional
|
SuperGroupChatCreated bool `json:"supergroup_chat_created"` // optional
|
||||||
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
|
ChannelChatCreated bool `json:"channel_chat_created"` // optional
|
||||||
MigrateFromChatID int64 `json:"migrate_from_chat_id"` // optional
|
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
|
||||||
PinnedMessage *Message `json:"pinned_message"` // 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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time converts the message timestamp into a Time.
|
// Time converts the message timestamp into a Time.
|
||||||
@ -263,6 +278,15 @@ type Video struct {
|
|||||||
FileSize int `json:"file_size"` // 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.
|
// Voice contains information about a voice.
|
||||||
type Voice struct {
|
type Voice struct {
|
||||||
FileID string `json:"file_id"`
|
FileID string `json:"file_id"`
|
||||||
@ -361,6 +385,7 @@ type InlineKeyboardButton struct {
|
|||||||
SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
|
SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
|
||||||
SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat,omitempty"` // optional
|
SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat,omitempty"` // optional
|
||||||
CallbackGame *CallbackGame `json:"callback_game,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
|
// CallbackQuery is data sent when a keyboard button with callback data
|
||||||
@ -384,8 +409,22 @@ type ForceReply struct {
|
|||||||
|
|
||||||
// ChatMember is information about a member in a chat.
|
// ChatMember is information about a member in a chat.
|
||||||
type ChatMember struct {
|
type ChatMember struct {
|
||||||
User *User `json:"user"`
|
User *User `json:"user"`
|
||||||
Status string `json:"status"`
|
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.
|
// IsCreator returns if the ChatMember was the creator of the chat.
|
||||||
@ -493,6 +532,7 @@ type InlineQueryResultGIF struct {
|
|||||||
URL string `json:"gif_url"` // required
|
URL string `json:"gif_url"` // required
|
||||||
Width int `json:"gif_width"`
|
Width int `json:"gif_width"`
|
||||||
Height int `json:"gif_height"`
|
Height int `json:"gif_height"`
|
||||||
|
Duration int `json:"gif_duration"`
|
||||||
ThumbURL string `json:"thumb_url"`
|
ThumbURL string `json:"thumb_url"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Caption string `json:"caption"`
|
Caption string `json:"caption"`
|
||||||
@ -507,6 +547,7 @@ type InlineQueryResultMPEG4GIF struct {
|
|||||||
URL string `json:"mpeg4_url"` // required
|
URL string `json:"mpeg4_url"` // required
|
||||||
Width int `json:"mpeg4_width"`
|
Width int `json:"mpeg4_width"`
|
||||||
Height int `json:"mpeg4_height"`
|
Height int `json:"mpeg4_height"`
|
||||||
|
Duration int `json:"mpeg4_duration"`
|
||||||
ThumbURL string `json:"thumb_url"`
|
ThumbURL string `json:"thumb_url"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Caption string `json:"caption"`
|
Caption string `json:"caption"`
|
||||||
@ -635,3 +676,73 @@ type InputContactMessageContent struct {
|
|||||||
FirstName string `json:"first_name"`
|
FirstName string `json:"first_name"`
|
||||||
LastName string `json:"last_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"`
|
||||||
|
}
|
||||||
|
2
vendor/github.com/nlopes/slack/websocket_managed_conn.go
generated
vendored
2
vendor/github.com/nlopes/slack/websocket_managed_conn.go
generated
vendored
@ -302,6 +302,8 @@ func (rtm *RTM) handleRawEvent(rawEvent json.RawMessage) {
|
|||||||
rtm.IncomingEvents <- RTMEvent{"hello", &HelloEvent{}}
|
rtm.IncomingEvents <- RTMEvent{"hello", &HelloEvent{}}
|
||||||
case "pong":
|
case "pong":
|
||||||
rtm.handlePong(rawEvent)
|
rtm.handlePong(rawEvent)
|
||||||
|
case "desktop_notification":
|
||||||
|
rtm.Debugln("Received desktop notification, ignoring")
|
||||||
default:
|
default:
|
||||||
rtm.handleEvent(event.Type, rawEvent)
|
rtm.handleEvent(event.Type, rawEvent)
|
||||||
}
|
}
|
||||||
|
6
vendor/manifest
vendored
6
vendor/manifest
vendored
@ -61,7 +61,7 @@
|
|||||||
"importpath": "github.com/bwmarrin/discordgo",
|
"importpath": "github.com/bwmarrin/discordgo",
|
||||||
"repository": "https://github.com/bwmarrin/discordgo",
|
"repository": "https://github.com/bwmarrin/discordgo",
|
||||||
"vcs": "git",
|
"vcs": "git",
|
||||||
"revision": "d420e28024ad527390b43aa7f64e029083e11989",
|
"revision": "2fda7ce223a66a5b70b66987c22c3c94d022ee66",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
@ -136,7 +136,7 @@
|
|||||||
"importpath": "github.com/go-telegram-bot-api/telegram-bot-api",
|
"importpath": "github.com/go-telegram-bot-api/telegram-bot-api",
|
||||||
"repository": "https://github.com/go-telegram-bot-api/telegram-bot-api",
|
"repository": "https://github.com/go-telegram-bot-api/telegram-bot-api",
|
||||||
"vcs": "git",
|
"vcs": "git",
|
||||||
"revision": "89bbb1edff353a7c6d10ef10cfd2675056ad8a58",
|
"revision": "9dda67c714e5e2cba837b28a0172cca2ed54f078",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
@ -429,7 +429,7 @@
|
|||||||
"importpath": "github.com/nlopes/slack",
|
"importpath": "github.com/nlopes/slack",
|
||||||
"repository": "https://github.com/nlopes/slack",
|
"repository": "https://github.com/nlopes/slack",
|
||||||
"vcs": "git",
|
"vcs": "git",
|
||||||
"revision": "ca8436d76f805ec1e682eaae2de3c3a9bc894b0f",
|
"revision": "5cde21b8b96a43fc3435a1f514123d14fd7eabdc",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user