mirror of
https://github.com/paymog/slack-cli.git
synced 2026-09-18 23:43:49 +08:00
cdcd9fe4d9
The edge API's GetConversationsContext runs 3 concurrent goroutines (ClientUserBoot, IMList, SearchChannels), then calls ClientCounts and ConversationsGenericInfo for MPIM discovery. Previously, ANY failure in the pipeline discarded ALL successfully fetched channels: - A goroutine error discarded results from other goroutines - ClientCounts failing (e.g. team_is_restricted) discarded everything - ConversationsGenericInfo failing discarded everything Now errors are non-fatal: channels from successful sources are kept. Only if all primary sources fail (0 channels collected) is the error propagated. MPIM discovery failures are always non-fatal since MPIMs are supplementary to the main channel/IM/DM data.
139 lines
3.4 KiB
Go
139 lines
3.4 KiB
Go
package edge
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
|
|
"github.com/rusq/slack"
|
|
)
|
|
|
|
var ErrParameterMissing = errors.New("required parameter missing")
|
|
|
|
// High level functions that wrap low level calls to webclient API to return
|
|
// the data in the format close to the Slack API.
|
|
|
|
func (cl *Client) GetConversationsContext(ctx context.Context, _ *slack.GetConversationsParameters) (channels []slack.Channel, _ string, err error) {
|
|
type result struct {
|
|
Channels []slack.Channel
|
|
Err error
|
|
}
|
|
|
|
var resultC = make(chan result, 2)
|
|
var pipeline = []func(){
|
|
func() {
|
|
// getting client.userBoot information
|
|
ub, err := cl.ClientUserBoot(ctx)
|
|
if err != nil {
|
|
resultC <- result{Err: err}
|
|
return
|
|
}
|
|
var ch = make([]slack.Channel, 0, len(ub.Channels))
|
|
for _, c := range ub.Channels {
|
|
ch = append(ch, c.SlackChannel())
|
|
}
|
|
resultC <- result{Channels: ch, Err: err}
|
|
},
|
|
func() {
|
|
// collecting the IMs.
|
|
ims, err := cl.IMList(ctx)
|
|
var ch = make([]slack.Channel, 0, len(ims))
|
|
for _, c := range ims {
|
|
ch = append(ch, c.SlackChannel())
|
|
}
|
|
resultC <- result{Channels: ch, Err: err}
|
|
},
|
|
func() {
|
|
// collecting the channels.
|
|
ch, err := cl.SearchChannels(ctx, "")
|
|
resultC <- result{Channels: ch, Err: err}
|
|
},
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(len(pipeline))
|
|
for _, f := range pipeline {
|
|
go func(f func()) {
|
|
defer wg.Done()
|
|
f()
|
|
}(f)
|
|
}
|
|
go func() {
|
|
wg.Wait()
|
|
close(resultC)
|
|
}()
|
|
|
|
// Collect results from all goroutines. Individual failures are non-fatal:
|
|
// we keep channels from sources that succeeded. Only if every source fails
|
|
// (nothing collected) do we propagate the last error.
|
|
var seenChannels = make(map[string]struct{})
|
|
var lastErr error
|
|
for r := range resultC {
|
|
if r.Err != nil {
|
|
lastErr = r.Err
|
|
continue
|
|
}
|
|
for _, c := range r.Channels {
|
|
if _, seen := seenChannels[c.ID]; !seen {
|
|
seenChannels[c.ID] = struct{}{}
|
|
channels = append(channels, c)
|
|
}
|
|
}
|
|
}
|
|
if len(channels) == 0 && lastErr != nil {
|
|
return nil, "", lastErr
|
|
}
|
|
|
|
// ClientCounts returns MPIM IDs that we haven't seen in the user boot
|
|
// response. This is supplementary — failures here don't discard the
|
|
// channels we already collected.
|
|
cr, err := cl.ClientCounts(ctx)
|
|
if err != nil {
|
|
return channels, "", nil
|
|
}
|
|
|
|
// determine which mpims are already in the list, and which need to be
|
|
// fetched
|
|
var fetchIDs = make([]string, 0, len(cr.MPIMs))
|
|
for _, c := range cr.MPIMs {
|
|
if _, seen := seenChannels[c.ID]; !seen {
|
|
fetchIDs = append(fetchIDs, c.ID)
|
|
}
|
|
}
|
|
|
|
// getting the info on any MPIMs that we haven't seen yet.
|
|
mpims, err := cl.ConversationsGenericInfo(ctx, fetchIDs...)
|
|
if err != nil {
|
|
return channels, "", nil
|
|
}
|
|
channels = append(channels, mpims...)
|
|
return channels, "", nil
|
|
}
|
|
|
|
func (cl *Client) GetUsersInConversationContext(ctx context.Context, p *slack.GetUsersInConversationParameters) (ids []string, _ string, err error) {
|
|
if p.ChannelID == "" {
|
|
return nil, "", ErrParameterMissing
|
|
}
|
|
uu, err := cl.UsersList(ctx, p.ChannelID)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
for _, u := range uu {
|
|
ids = append(ids, u.ID)
|
|
}
|
|
return ids, "", nil
|
|
}
|
|
|
|
var ErrNotFound = errors.New("not found")
|
|
|
|
func (cl *Client) GetConversationInfoContext(ctx context.Context, input *slack.GetConversationInfoInput) (*slack.Channel, error) {
|
|
cc, err := cl.ConversationsGenericInfo(ctx, input.ChannelID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(cc) == 0 {
|
|
return nil, ErrNotFound
|
|
}
|
|
return &cc[0], nil
|
|
}
|