Add support new version of Slack applocation
- Added support of Event API in socketMode - Fix files upload for new applications
This commit is contained in:
@@ -9,6 +9,9 @@ import (
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/42wim/matterbridge/bridge/helper"
|
||||
"github.com/slack-go/slack"
|
||||
"github.com/slack-go/slack/socketmode"
|
||||
"github.com/slack-go/slack/slackevents"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// ErrEventIgnored is for events that should be ignored
|
||||
@@ -19,6 +22,9 @@ func (b *Bslack) handleSlack() {
|
||||
if b.GetString(incomingWebhookConfig) != "" && b.GetString(tokenConfig) == "" {
|
||||
b.Log.Debugf("Choosing webhooks based receiving")
|
||||
go b.handleMatterHook(messages)
|
||||
} else if b.GetString(appTokenConfig) != "" && b.GetString(tokenConfig) != "" {
|
||||
b.Log.Debugf("Choosing socket mode based receiving")
|
||||
go b.handleSlackClientSocketMode(messages)
|
||||
} else {
|
||||
b.Log.Debugf("Choosing token based receiving")
|
||||
go b.handleSlackClient(messages)
|
||||
@@ -47,6 +53,135 @@ func (b *Bslack) handleSlack() {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bslack) handleSlackClientSocketMode(messages chan *config.Message) {
|
||||
|
||||
for evt := range b.smc.Events {
|
||||
switch evt.Type {
|
||||
case socketmode.EventTypeConnecting:
|
||||
b.Log.Debug("Connecting to Slack with Socket Mode...")
|
||||
case socketmode.EventTypeConnectionError:
|
||||
b.Log.Debug("Connection failed. Retrying later...")
|
||||
case socketmode.EventTypeConnected:
|
||||
b.Log.Debug("Connected to Slack with Socket Mode.")
|
||||
if info, err := b.rtm.AuthTest(); err == nil {
|
||||
b.si = &slack.Info {
|
||||
User: &slack.UserDetails{
|
||||
ID: info.UserID,
|
||||
Name: info.User,
|
||||
},
|
||||
Team: &slack.Team{
|
||||
ID: info.TeamID,
|
||||
Name: info.Team,
|
||||
},
|
||||
}
|
||||
b.channels.populateChannels(true)
|
||||
b.users.populateUsers(true)
|
||||
} else {
|
||||
b.Log.Fatalf("Get user info error %+v", err)
|
||||
}
|
||||
case socketmode.EventTypeEventsAPI:
|
||||
eventsAPIEvent, ok := evt.Data.(slackevents.EventsAPIEvent)
|
||||
if !ok {
|
||||
b.Log.Printf("Ignored %+v\n", evt)
|
||||
continue
|
||||
}
|
||||
|
||||
b.smc.Ack(*evt.Request)
|
||||
|
||||
switch eventsAPIEvent.Type {
|
||||
case slackevents.CallbackEvent:
|
||||
innerEvent := eventsAPIEvent.InnerEvent
|
||||
// b.Log.Debugf("Event received %+v", innerEvent)
|
||||
switch ev := innerEvent.Data.(type) {
|
||||
case *slackevents.MessageEvent:
|
||||
// Workaround for handler compability
|
||||
evString, _ := json.Marshal(ev)
|
||||
b.Log.Debugf("Message event: %s", evString)
|
||||
slackEvent := &slack.MessageEvent{}
|
||||
if err := json.Unmarshal(evString, &slackEvent); err != nil {
|
||||
b.Log.Errorf("Skipped message: %#v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if b.skipMessageEvent(slackEvent) {
|
||||
b.Log.Debugf("Skipped message: %#v", slackEvent)
|
||||
continue
|
||||
}
|
||||
rmsg, err := b.handleMessageEvent(slackEvent)
|
||||
if err != nil {
|
||||
b.Log.Errorf("%#v", err)
|
||||
continue
|
||||
}
|
||||
messages <- rmsg
|
||||
case *slackevents.FileDeletedEvent:
|
||||
slackEvent := &slack.FileDeletedEvent{
|
||||
Type: ev.Type,
|
||||
EventTimestamp: ev.EventTimestamp,
|
||||
FileID: ev.FileID,
|
||||
}
|
||||
rmsg, err := b.handleFileDeletedEvent(slackEvent)
|
||||
if err != nil {
|
||||
b.Log.Printf("%#v", err)
|
||||
continue
|
||||
}
|
||||
messages <- rmsg
|
||||
case *slackevents.MemberJoinedChannelEvent:
|
||||
b.users.populateUser(ev.User)
|
||||
case *slackevents.UserProfileChangedEvent:
|
||||
b.users.invalidateUser(ev.User.ID)
|
||||
|
||||
// TODO not implemented
|
||||
// case *slack.ChannelJoinedEvent:
|
||||
// // When we join a channel we update the full list of users as
|
||||
// // well as the information for the channel that we joined as this
|
||||
// // should now tell that we are a member of it.
|
||||
// b.channels.registerChannel(ev.Channel)
|
||||
|
||||
case *slackevents.AppMentionEvent:
|
||||
default:
|
||||
b.Log.Debugf("Unhandled incoming event: %T", ev)
|
||||
}
|
||||
default:
|
||||
b.Log.Printf("Unsupported Events API event received: %+v", eventsAPIEvent.Type)
|
||||
}
|
||||
case socketmode.EventTypeInteractive:
|
||||
callback, ok := evt.Data.(slack.InteractionCallback)
|
||||
if !ok {
|
||||
b.Log.Printf("Ignored %+v\n", evt)
|
||||
continue
|
||||
}
|
||||
|
||||
b.Log.Debugf("Interaction skipped: %+v\n", callback)
|
||||
|
||||
var payload interface{}
|
||||
|
||||
switch callback.Type {
|
||||
case slack.InteractionTypeBlockActions:
|
||||
case slack.InteractionTypeShortcut:
|
||||
case slack.InteractionTypeViewSubmission:
|
||||
case slack.InteractionTypeDialogSubmission:
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
b.smc.Ack(*evt.Request, payload)
|
||||
case socketmode.EventTypeSlashCommand:
|
||||
cmd, ok := evt.Data.(slack.SlashCommand)
|
||||
if !ok {
|
||||
b.Log.Printf("Ignored %+v\n", evt)
|
||||
} else {
|
||||
b.Log.Debugf("Slash command skipped: %+v", cmd)
|
||||
}
|
||||
var payload interface{}
|
||||
b.smc.Ack(*evt.Request, payload)
|
||||
case "hello":
|
||||
continue
|
||||
default:
|
||||
b.Log.Errorf("Unexpected event type received: %s\n", evt.Type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bslack) handleSlackClient(messages chan *config.Message) {
|
||||
for msg := range b.rtm.IncomingEvents {
|
||||
if msg.Type != sUserTyping && msg.Type != sHello && msg.Type != sLatencyReport {
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/rs/xid"
|
||||
"github.com/slack-go/slack"
|
||||
"github.com/slack-go/slack/socketmode"
|
||||
)
|
||||
|
||||
type Bslack struct {
|
||||
@@ -24,6 +25,7 @@ type Bslack struct {
|
||||
mh *matterhook.Client
|
||||
sc *slack.Client
|
||||
rtm *slack.RTM
|
||||
smc *socketmode.Client
|
||||
si *slack.Info
|
||||
|
||||
cache *lru.Cache
|
||||
@@ -57,6 +59,7 @@ const (
|
||||
cfileDownloadChannel = "file_download_channel"
|
||||
|
||||
tokenConfig = "Token"
|
||||
appTokenConfig = "AppToken"
|
||||
incomingWebhookConfig = "WebhookBindAddress"
|
||||
outgoingWebhookConfig = "WebhookURL"
|
||||
skipTLSConfig = "SkipTLSVerify"
|
||||
@@ -109,14 +112,26 @@ func (b *Bslack) Connect() error {
|
||||
if token := b.GetString(tokenConfig); token != "" {
|
||||
b.Log.Info("Connecting using token")
|
||||
|
||||
b.sc = slack.New(token, slack.OptionDebug(b.GetBool("Debug")))
|
||||
appToken := b.GetString(appTokenConfig)
|
||||
b.sc = slack.New(token, slack.OptionDebug(b.GetBool("Debug")), slack.OptionAppLevelToken(appToken))
|
||||
|
||||
b.channels = newChannelManager(b.Log, b.sc)
|
||||
b.users = newUserManager(b.Log, b.sc)
|
||||
|
||||
b.rtm = b.sc.NewRTM()
|
||||
go b.rtm.ManageConnection()
|
||||
|
||||
if appToken != "" {
|
||||
b.smc = socketmode.New(
|
||||
b.sc,
|
||||
socketmode.OptionDebug(b.GetBool("Debug")),
|
||||
)
|
||||
} else {
|
||||
go b.rtm.ManageConnection()
|
||||
}
|
||||
go b.handleSlack()
|
||||
if b.smc != nil {
|
||||
go b.smc.Run()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -457,35 +472,60 @@ func (b *Bslack) uploadFile(msg *config.Message, channelID string) (string, erro
|
||||
// Because the result of the UploadFile is slower than the MessageEvent from slack
|
||||
// we can't match on the file ID yet, so we have to match on the filename too.
|
||||
ts := time.Now()
|
||||
b.Log.Debugf("Adding file %s to cache at %s with timestamp", fi.Name, ts.String())
|
||||
fSize := int(fi.Size)
|
||||
if fSize == 0 {
|
||||
fSize = len(*fi.Data)
|
||||
}
|
||||
b.Log.Debugf("Adding file %s to cache at %s with timestamp, size %d", fi.Name, ts.String(), fSize)
|
||||
b.cache.Add("filename"+fi.Name, ts)
|
||||
initialComment := fmt.Sprintf("File from %s", msg.Username)
|
||||
if fi.Comment != "" {
|
||||
initialComment += fmt.Sprintf(" with comment: %s", fi.Comment)
|
||||
}
|
||||
res, err := b.sc.UploadFile(slack.FileUploadParameters{
|
||||
Reader: bytes.NewReader(*fi.Data),
|
||||
Filename: fi.Name,
|
||||
Channels: []string{channelID},
|
||||
InitialComment: initialComment,
|
||||
ThreadTimestamp: msg.ParentID,
|
||||
})
|
||||
if err != nil {
|
||||
b.Log.Errorf("uploadfile %#v", err)
|
||||
return "", err
|
||||
}
|
||||
if res.ID != "" {
|
||||
b.Log.Debugf("Adding file ID %s to cache with timestamp %s", res.ID, ts.String())
|
||||
b.cache.Add("file"+res.ID, ts)
|
||||
|
||||
// search for message id by uploaded file in private/public channels, get thread timestamp from uploaded file
|
||||
if v, ok := res.Shares.Private[channelID]; ok && len(v) > 0 {
|
||||
messageID = v[0].Ts
|
||||
if b.smc != nil {
|
||||
res, err := b.sc.UploadFileV2(slack.UploadFileV2Parameters{
|
||||
Reader: bytes.NewReader(*fi.Data),
|
||||
Filename: fi.Name,
|
||||
FileSize: fSize,
|
||||
Channel: channelID,
|
||||
InitialComment: initialComment,
|
||||
ThreadTimestamp: msg.ParentID,
|
||||
})
|
||||
if err != nil {
|
||||
b.Log.Errorf("uploadfile %#v", err)
|
||||
return "", err
|
||||
}
|
||||
if v, ok := res.Shares.Public[channelID]; ok && len(v) > 0 {
|
||||
messageID = v[0].Ts
|
||||
if res.ID != "" {
|
||||
b.Log.Debugf("Adding file ID %s to cache with timestamp %s", res.ID, ts.String())
|
||||
b.cache.Add("file"+res.ID, ts)
|
||||
messageID = res.ID // TODO
|
||||
}
|
||||
} else { // Deprecated version
|
||||
res, err := b.sc.UploadFile(slack.FileUploadParameters{
|
||||
Reader: bytes.NewReader(*fi.Data),
|
||||
Filename: fi.Name,
|
||||
Channels: []string{channelID},
|
||||
InitialComment: initialComment,
|
||||
ThreadTimestamp: msg.ParentID,
|
||||
})
|
||||
if err != nil {
|
||||
b.Log.Errorf("uploadfile %#v", err)
|
||||
return "", err
|
||||
}
|
||||
if res.ID != "" {
|
||||
b.Log.Debugf("Adding file ID %s to cache with timestamp %s", res.ID, ts.String())
|
||||
b.cache.Add("file"+res.ID, ts)
|
||||
// search for message id by uploaded file in private/public channels, get thread timestamp from uploaded file
|
||||
if v, ok := res.Shares.Private[channelID]; ok && len(v) > 0 {
|
||||
messageID = v[0].Ts
|
||||
}
|
||||
if v, ok := res.Shares.Public[channelID]; ok && len(v) > 0 {
|
||||
messageID = v[0].Ts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return messageID, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user