Update vendor
This commit is contained in:
291
vendor/github.com/matterbridge/matterclient/channels.go
generated
vendored
Normal file
291
vendor/github.com/matterbridge/matterclient/channels.go
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
package matterclient
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
// GetChannels returns all channels we're members off
|
||||
func (m *Client) GetChannels() []*model.Channel {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
var channels []*model.Channel
|
||||
// our primary team channels first
|
||||
channels = append(channels, m.Team.Channels...)
|
||||
|
||||
for _, t := range m.OtherTeams {
|
||||
if t.ID != m.Team.ID {
|
||||
channels = append(channels, t.Channels...)
|
||||
}
|
||||
}
|
||||
|
||||
return channels
|
||||
}
|
||||
|
||||
func (m *Client) GetChannelHeader(channelID string) string {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
for _, t := range m.OtherTeams {
|
||||
for _, channel := range append(t.Channels, t.MoreChannels...) {
|
||||
if channel.Id == channelID {
|
||||
return channel.Header
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func getNormalisedName(channel *model.Channel) string {
|
||||
if channel.Type == model.ChannelTypeGroup {
|
||||
res := strings.ReplaceAll(channel.DisplayName, ", ", "-")
|
||||
res = strings.ReplaceAll(res, " ", "_")
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
return channel.Name
|
||||
}
|
||||
|
||||
func (m *Client) GetChannelID(name string, teamID string) string {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
if teamID != "" {
|
||||
return m.getChannelIDTeam(name, teamID)
|
||||
}
|
||||
|
||||
for _, t := range m.OtherTeams {
|
||||
for _, channel := range append(t.Channels, t.MoreChannels...) {
|
||||
if getNormalisedName(channel) == name {
|
||||
return channel.Id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Client) getChannelIDTeam(name string, teamID string) string {
|
||||
for _, t := range m.OtherTeams {
|
||||
if t.ID == teamID {
|
||||
for _, channel := range append(t.Channels, t.MoreChannels...) {
|
||||
if getNormalisedName(channel) == name {
|
||||
return channel.Id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Client) GetChannelName(channelID string) string {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
for _, t := range m.OtherTeams {
|
||||
if t == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, channel := range append(t.Channels, t.MoreChannels...) {
|
||||
if channel.Id == channelID {
|
||||
return getNormalisedName(channel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Client) GetChannelTeamID(id string) string {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
for _, t := range append(m.OtherTeams, m.Team) {
|
||||
for _, channel := range append(t.Channels, t.MoreChannels...) {
|
||||
if channel.Id == id {
|
||||
return channel.TeamId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Client) GetLastViewedAt(channelID string) int64 {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
for {
|
||||
res, resp, err := m.Client.GetChannelMember(channelID, m.User.Id, "")
|
||||
if err == nil {
|
||||
return res.LastViewedAt
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("GetChannelMember", resp); err != nil {
|
||||
return model.GetMillis()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetMoreChannels returns existing channels where we're not a member off.
|
||||
func (m *Client) GetMoreChannels() []*model.Channel {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
var channels []*model.Channel
|
||||
for _, t := range m.OtherTeams {
|
||||
channels = append(channels, t.MoreChannels...)
|
||||
}
|
||||
|
||||
return channels
|
||||
}
|
||||
|
||||
// GetTeamFromChannel returns teamId belonging to channel (DM channels have no teamId).
|
||||
func (m *Client) GetTeamFromChannel(channelID string) string {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
var channels []*model.Channel
|
||||
|
||||
for _, t := range m.OtherTeams {
|
||||
channels = append(channels, t.Channels...)
|
||||
|
||||
if t.MoreChannels != nil {
|
||||
channels = append(channels, t.MoreChannels...)
|
||||
}
|
||||
|
||||
for _, c := range channels {
|
||||
if c.Id == channelID {
|
||||
if c.Type == model.ChannelTypeGroup {
|
||||
return "G"
|
||||
}
|
||||
|
||||
return t.ID
|
||||
}
|
||||
}
|
||||
|
||||
channels = nil
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Client) JoinChannel(channelID string) error {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
for _, c := range m.Team.Channels {
|
||||
if c.Id == channelID {
|
||||
m.logger.Debug("Not joining ", channelID, " already joined.")
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
m.logger.Debug("Joining ", channelID)
|
||||
|
||||
_, _, err := m.Client.AddChannelMember(channelID, m.User.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) UpdateChannelsTeam(teamID string) error {
|
||||
var (
|
||||
mmchannels []*model.Channel
|
||||
resp *model.Response
|
||||
err error
|
||||
)
|
||||
|
||||
for {
|
||||
mmchannels, resp, err = m.Client.GetChannelsForTeamForUser(teamID, m.User.Id, false, "")
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if err = m.HandleRatelimit("GetChannelsForTeamForUser", resp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for idx, t := range m.OtherTeams {
|
||||
if t.ID == teamID {
|
||||
m.Lock()
|
||||
m.OtherTeams[idx].Channels = mmchannels
|
||||
m.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
mmchannels, resp, err = m.Client.GetPublicChannelsForTeam(teamID, 0, 5000, "")
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("GetPublicChannelsForTeam", resp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for idx, t := range m.OtherTeams {
|
||||
if t.ID == teamID {
|
||||
m.Lock()
|
||||
m.OtherTeams[idx].MoreChannels = mmchannels
|
||||
m.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) UpdateChannels() error {
|
||||
if err := m.UpdateChannelsTeam(m.Team.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, t := range m.OtherTeams {
|
||||
if err := m.UpdateChannelsTeam(t.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) UpdateChannelHeader(channelID string, header string) {
|
||||
channel := &model.Channel{Id: channelID, Header: header}
|
||||
|
||||
m.logger.Debugf("updating channelheader %#v, %#v", channelID, header)
|
||||
|
||||
_, _, err := m.Client.UpdateChannel(channel)
|
||||
if err != nil {
|
||||
m.logger.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Client) UpdateLastViewed(channelID string) error {
|
||||
m.logger.Debugf("posting lastview %#v", channelID)
|
||||
|
||||
view := &model.ChannelView{ChannelId: channelID}
|
||||
|
||||
for {
|
||||
_, resp, err := m.Client.ViewChannel(m.User.Id, view)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("ViewChannel", resp); err != nil {
|
||||
m.logger.Errorf("ChannelView update for %s failed: %s", channelID, err)
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
14
vendor/github.com/matterbridge/matterclient/go.mod
generated
vendored
Normal file
14
vendor/github.com/matterbridge/matterclient/go.mod
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
module github.com/matterbridge/matterclient
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/jpillora/backoff v1.0.0
|
||||
github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba
|
||||
github.com/mattermost/mattermost-server/v6 v6.0.0
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
|
||||
)
|
||||
1404
vendor/github.com/matterbridge/matterclient/go.sum
generated
vendored
Normal file
1404
vendor/github.com/matterbridge/matterclient/go.sum
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
743
vendor/github.com/matterbridge/matterclient/matterclient.go
generated
vendored
Normal file
743
vendor/github.com/matterbridge/matterclient/matterclient.go
generated
vendored
Normal file
@@ -0,0 +1,743 @@
|
||||
package matterclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/jpillora/backoff"
|
||||
prefixed "github.com/matterbridge/logrus-prefixed-formatter"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Credentials struct {
|
||||
Login string
|
||||
Team string
|
||||
Pass string
|
||||
Token string
|
||||
CookieToken bool
|
||||
Server string
|
||||
NoTLS bool
|
||||
SkipTLSVerify bool
|
||||
SkipVersionCheck bool
|
||||
MFAToken string
|
||||
}
|
||||
|
||||
type Team struct {
|
||||
Team *model.Team
|
||||
ID string
|
||||
Channels []*model.Channel
|
||||
MoreChannels []*model.Channel
|
||||
Users map[string]*model.User
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Raw *model.WebSocketEvent
|
||||
Post *model.Post
|
||||
Team string
|
||||
Channel string
|
||||
Username string
|
||||
Text string
|
||||
Type string
|
||||
UserID string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
sync.RWMutex
|
||||
*Credentials
|
||||
|
||||
Team *Team
|
||||
OtherTeams []*Team
|
||||
Client *model.Client4
|
||||
User *model.User
|
||||
Users map[string]*model.User
|
||||
MessageChan chan *Message
|
||||
WsClient *model.WebSocketClient
|
||||
AntiIdle bool
|
||||
AntiIdleChan string
|
||||
AntiIdleIntvl int
|
||||
WsQuit bool
|
||||
WsConnected bool
|
||||
OnWsConnect func()
|
||||
reconnectBusy bool
|
||||
|
||||
logger *logrus.Entry
|
||||
rootLogger *logrus.Logger
|
||||
lruCache *lru.Cache
|
||||
aliveChan chan bool
|
||||
loginCancel context.CancelFunc
|
||||
lastPong time.Time
|
||||
}
|
||||
|
||||
func New(login string, pass string, team string, server string, mfatoken string) *Client {
|
||||
rootLogger := logrus.New()
|
||||
rootLogger.SetFormatter(&prefixed.TextFormatter{
|
||||
PrefixPadding: 13,
|
||||
DisableColors: true,
|
||||
FullTimestamp: true,
|
||||
})
|
||||
|
||||
cred := &Credentials{
|
||||
Login: login,
|
||||
Pass: pass,
|
||||
Team: team,
|
||||
Server: server,
|
||||
MFAToken: mfatoken,
|
||||
}
|
||||
|
||||
cache, _ := lru.New(500)
|
||||
|
||||
return &Client{
|
||||
Credentials: cred,
|
||||
MessageChan: make(chan *Message, 100),
|
||||
Users: make(map[string]*model.User),
|
||||
rootLogger: rootLogger,
|
||||
lruCache: cache,
|
||||
logger: rootLogger.WithFields(logrus.Fields{"prefix": "matterclient"}),
|
||||
aliveChan: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
// Login tries to connect the client with the loging details with which it was initialized.
|
||||
func (m *Client) Login() error {
|
||||
// check if this is a first connect or a reconnection
|
||||
firstConnection := true
|
||||
if m.WsConnected {
|
||||
firstConnection = false
|
||||
}
|
||||
|
||||
m.WsConnected = false
|
||||
if m.WsQuit {
|
||||
return nil
|
||||
}
|
||||
|
||||
b := &backoff.Backoff{
|
||||
Min: time.Second,
|
||||
Max: 5 * time.Minute,
|
||||
Jitter: true,
|
||||
}
|
||||
|
||||
// do initialization setup
|
||||
if err := m.initClient(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.doLogin(firstConnection, b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.initUser(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.Team == nil {
|
||||
validTeamNames := make([]string, len(m.OtherTeams))
|
||||
for i, t := range m.OtherTeams {
|
||||
validTeamNames[i] = t.Team.Name
|
||||
}
|
||||
|
||||
return fmt.Errorf("Team '%s' not found in %v", m.Credentials.Team, validTeamNames)
|
||||
}
|
||||
|
||||
// connect websocket
|
||||
m.wsConnect()
|
||||
|
||||
ctx, loginCancel := context.WithCancel(context.Background())
|
||||
m.loginCancel = loginCancel
|
||||
|
||||
m.logger.Debug("starting wsreceiver")
|
||||
|
||||
go m.WsReceiver(ctx)
|
||||
|
||||
if m.OnWsConnect != nil {
|
||||
m.logger.Debug("executing OnWsConnect()")
|
||||
|
||||
go m.OnWsConnect()
|
||||
}
|
||||
|
||||
go m.checkConnection(ctx)
|
||||
|
||||
if m.AntiIdle {
|
||||
if m.AntiIdleChan == "" {
|
||||
// do anti idle on town-square, every installation should have this channel
|
||||
m.AntiIdleChan = "town-square"
|
||||
}
|
||||
|
||||
channels := m.GetChannels()
|
||||
for _, channel := range channels {
|
||||
if channel.Name == m.AntiIdleChan {
|
||||
go m.antiIdle(ctx, channel.Id, m.AntiIdleIntvl)
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) Reconnect() {
|
||||
if m.reconnectBusy {
|
||||
return
|
||||
}
|
||||
|
||||
m.reconnectBusy = true
|
||||
|
||||
m.logger.Info("reconnect: logout")
|
||||
m.reconnectLogout()
|
||||
|
||||
for {
|
||||
m.logger.Info("reconnect: login")
|
||||
|
||||
err := m.Login()
|
||||
if err != nil {
|
||||
m.logger.Errorf("reconnect: login failed: %s, retrying in 10 seconds", err)
|
||||
time.Sleep(time.Second * 10)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
m.logger.Info("reconnect successful")
|
||||
|
||||
m.reconnectBusy = false
|
||||
}
|
||||
|
||||
func (m *Client) initClient(b *backoff.Backoff) error {
|
||||
uriScheme := "https://"
|
||||
if m.NoTLS {
|
||||
uriScheme = "http://"
|
||||
}
|
||||
// login to mattermost
|
||||
m.Client = model.NewAPIv4Client(uriScheme + m.Credentials.Server)
|
||||
m.Client.HTTPClient.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: m.SkipTLSVerify, //nolint:gosec
|
||||
},
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}
|
||||
m.Client.HTTPClient.Timeout = time.Second * 10
|
||||
|
||||
// handle MMAUTHTOKEN and personal token
|
||||
if err := m.handleLoginToken(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if server alive, retry until
|
||||
if err := m.serverAlive(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) handleLoginToken() error {
|
||||
switch {
|
||||
case strings.Contains(m.Credentials.Pass, model.SessionCookieToken):
|
||||
token := strings.Split(m.Credentials.Pass, model.SessionCookieToken+"=")
|
||||
if len(token) != 2 {
|
||||
return errors.New("incorrect MMAUTHTOKEN. valid input is MMAUTHTOKEN=yourtoken")
|
||||
}
|
||||
|
||||
m.Credentials.Token = token[1]
|
||||
m.Credentials.CookieToken = true
|
||||
case strings.Contains(m.Credentials.Pass, "token="):
|
||||
token := strings.Split(m.Credentials.Pass, "token=")
|
||||
if len(token) != 2 {
|
||||
return errors.New("incorrect personal token. valid input is token=yourtoken")
|
||||
}
|
||||
|
||||
m.Credentials.Token = token[1]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) serverAlive(b *backoff.Backoff) error {
|
||||
defer b.Reset()
|
||||
|
||||
for {
|
||||
d := b.Duration()
|
||||
// bogus call to get the serverversion
|
||||
resp, err := m.Client.Logout()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.ServerVersion == "" {
|
||||
m.logger.Debugf("Server not up yet, reconnecting in %s", d)
|
||||
time.Sleep(d)
|
||||
} else {
|
||||
m.logger.Infof("Found version %s", resp.ServerVersion)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initialize user and teams
|
||||
// nolint:funlen
|
||||
func (m *Client) initUser() error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
// we only load all team data on initial login.
|
||||
// all other updates are for channels from our (primary) team only.
|
||||
teams, _, err := m.Client.GetTeamsForUser(m.User.Id, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, team := range teams {
|
||||
idx := 0
|
||||
max := 200
|
||||
usermap := make(map[string]*model.User)
|
||||
|
||||
mmusers, _, err := m.Client.GetUsersInTeam(team.Id, idx, max, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for len(mmusers) > 0 {
|
||||
for _, user := range mmusers {
|
||||
usermap[user.Id] = user
|
||||
}
|
||||
|
||||
mmusers, _, err = m.Client.GetUsersInTeam(team.Id, idx, max, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
idx++
|
||||
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
}
|
||||
|
||||
m.logger.Infof("found %d users in team %s", len(usermap), team.Name)
|
||||
|
||||
t := &Team{
|
||||
Team: team,
|
||||
Users: usermap,
|
||||
ID: team.Id,
|
||||
}
|
||||
|
||||
mmchannels, _, err := m.Client.GetChannelsForTeamForUser(team.Id, m.User.Id, false, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Channels = mmchannels
|
||||
|
||||
mmchannels, _, err = m.Client.GetPublicChannelsForTeam(team.Id, 0, 5000, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.MoreChannels = mmchannels
|
||||
m.OtherTeams = append(m.OtherTeams, t)
|
||||
|
||||
if team.Name == m.Credentials.Team {
|
||||
m.Team = t
|
||||
m.logger.Debugf("initUser(): found our team %s (id: %s)", team.Name, team.Id)
|
||||
}
|
||||
// add all users
|
||||
for k, v := range t.Users {
|
||||
m.Users[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) doLogin(firstConnection bool, b *backoff.Backoff) error {
|
||||
var (
|
||||
logmsg = "trying login"
|
||||
err error
|
||||
user *model.User
|
||||
)
|
||||
|
||||
for {
|
||||
m.logger.Debugf("%s %s %s %s", logmsg, m.Credentials.Team, m.Credentials.Login, m.Credentials.Server)
|
||||
|
||||
switch {
|
||||
case m.Credentials.Token != "":
|
||||
user, _, err = m.doLoginToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case m.Credentials.MFAToken != "":
|
||||
user, _, err = m.Client.LoginWithMFA(m.Credentials.Login, m.Credentials.Pass, m.Credentials.MFAToken)
|
||||
default:
|
||||
user, _, err = m.Client.Login(m.Credentials.Login, m.Credentials.Pass)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
d := b.Duration()
|
||||
|
||||
m.logger.Debug(err)
|
||||
|
||||
if firstConnection {
|
||||
return err
|
||||
}
|
||||
|
||||
m.logger.Debugf("LOGIN: %s, reconnecting in %s", err, d)
|
||||
|
||||
time.Sleep(d)
|
||||
|
||||
logmsg = "retrying login"
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
m.User = user
|
||||
|
||||
break
|
||||
}
|
||||
// reset timer
|
||||
b.Reset()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) doLoginToken() (*model.User, *model.Response, error) {
|
||||
var (
|
||||
resp *model.Response
|
||||
logmsg = "trying login"
|
||||
user *model.User
|
||||
err error
|
||||
)
|
||||
|
||||
m.Client.AuthType = model.HeaderBearer
|
||||
m.Client.AuthToken = m.Credentials.Token
|
||||
|
||||
if m.Credentials.CookieToken {
|
||||
m.logger.Debugf(logmsg + " with cookie (MMAUTH) token")
|
||||
m.Client.HTTPClient.Jar = m.createCookieJar(m.Credentials.Token)
|
||||
} else {
|
||||
m.logger.Debugf(logmsg + " with personal token")
|
||||
}
|
||||
|
||||
user, resp, err = m.Client.GetMe("")
|
||||
if err != nil {
|
||||
return user, resp, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
m.logger.Errorf("LOGIN TOKEN: %s is invalid", m.Credentials.Pass)
|
||||
|
||||
return user, resp, errors.New("invalid token")
|
||||
}
|
||||
|
||||
return user, resp, nil
|
||||
}
|
||||
|
||||
func (m *Client) createCookieJar(token string) *cookiejar.Jar {
|
||||
var cookies []*http.Cookie
|
||||
|
||||
jar, _ := cookiejar.New(nil)
|
||||
|
||||
firstCookie := &http.Cookie{
|
||||
Name: "MMAUTHTOKEN",
|
||||
Value: token,
|
||||
Path: "/",
|
||||
Domain: m.Credentials.Server,
|
||||
}
|
||||
|
||||
cookies = append(cookies, firstCookie)
|
||||
cookieURL, _ := url.Parse("https://" + m.Credentials.Server)
|
||||
|
||||
jar.SetCookies(cookieURL, cookies)
|
||||
|
||||
return jar
|
||||
}
|
||||
|
||||
func (m *Client) wsConnect() {
|
||||
b := &backoff.Backoff{
|
||||
Min: time.Second,
|
||||
Max: 5 * time.Minute,
|
||||
Jitter: true,
|
||||
}
|
||||
|
||||
m.WsConnected = false
|
||||
wsScheme := "wss://"
|
||||
|
||||
if m.NoTLS {
|
||||
wsScheme = "ws://"
|
||||
}
|
||||
|
||||
// setup websocket connection
|
||||
wsurl := wsScheme + m.Credentials.Server
|
||||
// + model.API_URL_SUFFIX_V4
|
||||
// + "/websocket"
|
||||
header := http.Header{}
|
||||
header.Set(model.HeaderAuth, "BEARER "+m.Client.AuthToken)
|
||||
|
||||
m.logger.Debugf("WsClient: making connection: %s", wsurl)
|
||||
|
||||
for {
|
||||
wsDialer := &websocket.Dialer{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: m.SkipTLSVerify, //nolint:gosec
|
||||
},
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
m.WsClient, err = model.NewWebSocketClientWithDialer(wsDialer, wsurl, m.Client.AuthToken)
|
||||
if err != nil {
|
||||
d := b.Duration()
|
||||
|
||||
m.logger.Debugf("WSS: %s, reconnecting in %s", err, d)
|
||||
|
||||
time.Sleep(d)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
m.WsClient.Listen()
|
||||
|
||||
m.lastPong = time.Now()
|
||||
|
||||
m.logger.Debug("WsClient: connected")
|
||||
|
||||
// only start to parse WS messages when login is completely done
|
||||
m.WsConnected = true
|
||||
}
|
||||
|
||||
func (m *Client) doCheckAlive() error {
|
||||
if _, _, err := m.Client.GetMe(""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.reconnectBusy {
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.WsClient.ListenError == nil {
|
||||
m.WsClient.SendMessage("ping", nil)
|
||||
} else {
|
||||
m.logger.Errorf("got a listen error: %#v", m.WsClient.ListenError)
|
||||
|
||||
return m.WsClient.ListenError
|
||||
}
|
||||
|
||||
if time.Since(m.lastPong) > 90*time.Second {
|
||||
return errors.New("no pong received in 90 seconds")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) checkAlive(ctx context.Context) {
|
||||
ticker := time.NewTicker(time.Second * 45)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
m.logger.Debugf("checkAlive: ctx.Done() triggered")
|
||||
|
||||
return
|
||||
case <-ticker.C:
|
||||
// check if session still is valid
|
||||
err := m.doCheckAlive()
|
||||
if err != nil {
|
||||
m.logger.Errorf("connection not alive: %s", err)
|
||||
m.aliveChan <- false
|
||||
}
|
||||
|
||||
m.aliveChan <- true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Client) checkConnection(ctx context.Context) {
|
||||
go m.checkAlive(ctx)
|
||||
|
||||
for {
|
||||
select {
|
||||
case alive := <-m.aliveChan:
|
||||
if !alive {
|
||||
time.Sleep(time.Second * 10)
|
||||
|
||||
if m.doCheckAlive() != nil {
|
||||
m.Reconnect()
|
||||
}
|
||||
}
|
||||
case <-ctx.Done():
|
||||
m.logger.Debug("checkConnection: ctx.Done() triggered, exiting")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WsReceiver implements the core loop that manages the connection to the chat server. In
|
||||
// case of a disconnect it will try to reconnect. A call to this method is blocking until
|
||||
// the 'WsQuite' field of the MMClient object is set to 'true'.
|
||||
func (m *Client) WsReceiver(ctx context.Context) {
|
||||
m.logger.Debug("starting WsReceiver")
|
||||
|
||||
ticker := time.NewTicker(time.Second * 10)
|
||||
|
||||
for {
|
||||
select {
|
||||
case event := <-m.WsClient.EventChannel:
|
||||
if event == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !event.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
m.logger.Debugf("WsReceiver event: %#v", event)
|
||||
|
||||
msg := &Message{
|
||||
Raw: event,
|
||||
Team: m.Credentials.Team,
|
||||
}
|
||||
|
||||
m.parseMessage(msg)
|
||||
|
||||
m.MessageChan <- msg
|
||||
case response := <-m.WsClient.ResponseChannel:
|
||||
if response == nil || !response.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
m.logger.Debugf("WsReceiver response: %#v", response)
|
||||
|
||||
if text, ok := response.Data["text"].(string); ok {
|
||||
if text == "pong" {
|
||||
m.lastPong = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
m.parseResponse(response)
|
||||
case <-m.WsClient.PingTimeoutChannel:
|
||||
m.logger.Error("got a ping timeout")
|
||||
m.Reconnect()
|
||||
|
||||
return
|
||||
case <-ticker.C:
|
||||
if m.WsClient.ListenError != nil {
|
||||
m.logger.Errorf("%#v", m.WsClient.ListenError)
|
||||
m.Reconnect()
|
||||
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
m.logger.Debugf("wsReceiver: ctx.Done() triggered")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logout disconnects the client from the chat server.
|
||||
func (m *Client) reconnectLogout() error {
|
||||
err := m.Logout()
|
||||
m.WsQuit = false
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Logout disconnects the client from the chat server.
|
||||
func (m *Client) Logout() error {
|
||||
m.logger.Debug("logout running loginCancel to exit goroutines")
|
||||
m.loginCancel()
|
||||
|
||||
m.logger.Debugf("logout as %s (team: %s) on %s", m.Credentials.Login, m.Credentials.Team, m.Credentials.Server)
|
||||
m.WsQuit = true
|
||||
// close the websocket
|
||||
m.logger.Debug("closing websocket")
|
||||
m.WsClient.Close()
|
||||
|
||||
if strings.Contains(m.Credentials.Pass, model.SessionCookieToken) {
|
||||
m.logger.Debug("Not invalidating session in logout, credential is a token")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// actually log out
|
||||
m.logger.Debug("running m.Client.Logout")
|
||||
|
||||
if _, err := m.Client.Logout(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.logger.Debug("exiting Logout()")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetLogLevel tries to parse the specified level and if successful sets
|
||||
// the log level accordingly. Accepted levels are: 'debug', 'info', 'warn',
|
||||
// 'error', 'fatal' and 'panic'.
|
||||
func (m *Client) SetLogLevel(level string) {
|
||||
l, err := logrus.ParseLevel(level)
|
||||
if err != nil {
|
||||
m.logger.Warnf("Failed to parse specified log-level '%s': %#v", level, err)
|
||||
} else {
|
||||
m.rootLogger.SetLevel(l)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Client) HandleRatelimit(name string, resp *model.Response) error {
|
||||
if resp.StatusCode != 429 {
|
||||
return fmt.Errorf("StatusCode error: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
waitTime, err := strconv.Atoi(resp.Header.Get("X-RateLimit-Reset"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.logger.Warnf("Ratelimited on %s for %d", name, waitTime)
|
||||
|
||||
time.Sleep(time.Duration(waitTime) * time.Second)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) antiIdle(ctx context.Context, channelID string, interval int) {
|
||||
if interval == 0 {
|
||||
interval = 60
|
||||
}
|
||||
|
||||
m.logger.Debugf("starting antiIdle for %s every %d secs", channelID, interval)
|
||||
ticker := time.NewTicker(time.Second * time.Duration(interval))
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
m.logger.Debugf("antiIlde: ctx.Done() triggered, exiting for %s", channelID)
|
||||
|
||||
return
|
||||
case <-ticker.C:
|
||||
m.logger.Tracef("antiIdle %s", channelID)
|
||||
|
||||
m.UpdateLastViewed(channelID)
|
||||
}
|
||||
}
|
||||
}
|
||||
280
vendor/github.com/matterbridge/matterclient/messages.go
generated
vendored
Normal file
280
vendor/github.com/matterbridge/matterclient/messages.go
generated
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
package matterclient
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
func (m *Client) parseResponse(rmsg *model.WebSocketResponse) {
|
||||
m.logger.Debugf("getting response: %#v", rmsg)
|
||||
}
|
||||
|
||||
func (m *Client) DeleteMessage(postID string) error {
|
||||
_, err := m.Client.DeletePost(postID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) EditMessage(postID string, text string) (string, error) {
|
||||
post := &model.Post{Message: text, Id: postID}
|
||||
|
||||
res, _, err := m.Client.UpdatePost(postID, post)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return res.Id, nil
|
||||
}
|
||||
|
||||
func (m *Client) GetFileLinks(filenames []string) []string {
|
||||
uriScheme := "https://"
|
||||
if m.NoTLS {
|
||||
uriScheme = "http://"
|
||||
}
|
||||
|
||||
var output []string
|
||||
|
||||
for _, f := range filenames {
|
||||
res, _, err := m.Client.GetFileLink(f)
|
||||
if err != nil {
|
||||
// public links is probably disabled, create the link ourselves
|
||||
output = append(output, uriScheme+m.Credentials.Server+model.APIURLSuffix+"/files/"+f)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
output = append(output, res)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func (m *Client) GetPosts(channelID string, limit int) *model.PostList {
|
||||
for {
|
||||
res, resp, err := m.Client.GetPostsForChannel(channelID, 0, limit, "", true)
|
||||
if err == nil {
|
||||
return res
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("GetPostsForChannel", resp); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Client) GetPostsSince(channelID string, time int64) *model.PostList {
|
||||
for {
|
||||
res, resp, err := m.Client.GetPostsSince(channelID, time, true)
|
||||
if err == nil {
|
||||
return res
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("GetPostsSince", resp); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Client) GetPublicLink(filename string) string {
|
||||
res, _, err := m.Client.GetFileLink(filename)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (m *Client) GetPublicLinks(filenames []string) []string {
|
||||
var output []string
|
||||
|
||||
for _, f := range filenames {
|
||||
res, _, err := m.Client.GetFileLink(f)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
output = append(output, res)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func (m *Client) PostMessage(channelID string, text string, rootID string) (string, error) {
|
||||
post := &model.Post{
|
||||
ChannelId: channelID,
|
||||
Message: text,
|
||||
RootId: rootID,
|
||||
}
|
||||
|
||||
for {
|
||||
res, resp, err := m.Client.CreatePost(post)
|
||||
if err == nil {
|
||||
return res.Id, nil
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("CreatePost", resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Client) PostMessageWithFiles(channelID string, text string, rootID string, fileIds []string) (string, error) {
|
||||
post := &model.Post{
|
||||
ChannelId: channelID,
|
||||
Message: text,
|
||||
RootId: rootID,
|
||||
FileIds: fileIds,
|
||||
}
|
||||
|
||||
for {
|
||||
res, resp, err := m.Client.CreatePost(post)
|
||||
if err == nil {
|
||||
return res.Id, nil
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("CreatePost", resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Client) SearchPosts(query string) *model.PostList {
|
||||
res, _, err := m.Client.SearchPosts(m.Team.ID, query, false)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// SendDirectMessage sends a direct message to specified user
|
||||
func (m *Client) SendDirectMessage(toUserID string, msg string, rootID string) error {
|
||||
return m.SendDirectMessageProps(toUserID, msg, rootID, nil)
|
||||
}
|
||||
|
||||
func (m *Client) SendDirectMessageProps(toUserID string, msg string, rootID string, props map[string]interface{}) error {
|
||||
m.logger.Debugf("SendDirectMessage to %s, msg %s", toUserID, msg)
|
||||
|
||||
for {
|
||||
// create DM channel (only happens on first message)
|
||||
_, resp, err := m.Client.CreateDirectChannel(m.User.Id, toUserID)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("CreateDirectChannel", resp); err != nil {
|
||||
m.logger.Debugf("SendDirectMessage to %#v failed: %s", toUserID, err)
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
channelName := model.GetDMNameFromIds(toUserID, m.User.Id)
|
||||
|
||||
// update our channels
|
||||
if err := m.UpdateChannels(); err != nil {
|
||||
m.logger.Errorf("failed to update channels: %#v", err)
|
||||
}
|
||||
|
||||
// build & send the message
|
||||
msg = strings.ReplaceAll(msg, "\r", "")
|
||||
post := &model.Post{
|
||||
ChannelId: m.GetChannelID(channelName, m.Team.ID),
|
||||
Message: msg,
|
||||
RootId: rootID,
|
||||
}
|
||||
|
||||
post.SetProps(props)
|
||||
|
||||
for {
|
||||
_, resp, err := m.Client.CreatePost(post)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("CreatePost", resp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Client) UploadFile(data []byte, channelID string, filename string) (string, error) {
|
||||
f, _, err := m.Client.UploadFile(data, channelID, filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return f.FileInfos[0].Id, nil
|
||||
}
|
||||
|
||||
func (m *Client) parseActionPost(rmsg *Message) {
|
||||
// add post to cache, if it already exists don't relay this again.
|
||||
// this should fix reposts
|
||||
if ok, _ := m.lruCache.ContainsOrAdd(digestString(rmsg.Raw.GetData()["post"].(string)), true); ok {
|
||||
m.logger.Debugf("message %#v in cache, not processing again", rmsg.Raw.GetData()["post"].(string))
|
||||
rmsg.Text = ""
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var data model.Post
|
||||
if err := json.NewDecoder(strings.NewReader(rmsg.Raw.GetData()["post"].(string))).Decode(&data); err != nil {
|
||||
return
|
||||
}
|
||||
// we don't have the user, refresh the userlist
|
||||
if m.GetUser(data.UserId) == nil {
|
||||
m.logger.Infof("User '%v' is not known, ignoring message '%#v'",
|
||||
data.UserId, data)
|
||||
return
|
||||
}
|
||||
|
||||
rmsg.Username = m.GetUserName(data.UserId)
|
||||
rmsg.Channel = m.GetChannelName(data.ChannelId)
|
||||
rmsg.UserID = data.UserId
|
||||
rmsg.Type = data.Type
|
||||
teamid, _ := rmsg.Raw.GetData()["team_id"].(string)
|
||||
// edit messsages have no team_id for some reason
|
||||
if teamid == "" {
|
||||
// we can find the team_id from the channelid
|
||||
teamid = m.GetChannelTeamID(data.ChannelId)
|
||||
rmsg.Raw.GetData()["team_id"] = teamid
|
||||
}
|
||||
|
||||
if teamid != "" {
|
||||
rmsg.Team = m.GetTeamName(teamid)
|
||||
}
|
||||
// direct message
|
||||
if rmsg.Raw.GetData()["channel_type"] == "D" {
|
||||
rmsg.Channel = m.GetUser(data.UserId).Username
|
||||
}
|
||||
|
||||
rmsg.Text = data.Message
|
||||
rmsg.Post = &data
|
||||
}
|
||||
|
||||
func (m *Client) parseMessage(rmsg *Message) {
|
||||
switch rmsg.Raw.EventType() {
|
||||
case model.WebsocketEventPosted, model.WebsocketEventPostEdited, model.WebsocketEventPostDeleted:
|
||||
m.parseActionPost(rmsg)
|
||||
case "user_updated":
|
||||
user := rmsg.Raw.GetData()["user"].(map[string]interface{})
|
||||
if _, ok := user["id"].(string); ok {
|
||||
m.UpdateUser(user["id"].(string))
|
||||
}
|
||||
case "group_added":
|
||||
if err := m.UpdateChannels(); err != nil {
|
||||
m.logger.Errorf("failed to update channels: %#v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func digestString(s string) string {
|
||||
return fmt.Sprintf("%x", md5.Sum([]byte(s))) //nolint:gosec
|
||||
}
|
||||
212
vendor/github.com/matterbridge/matterclient/users.go
generated
vendored
Normal file
212
vendor/github.com/matterbridge/matterclient/users.go
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
package matterclient
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
func (m *Client) GetNickName(userID string) string {
|
||||
if user := m.GetUser(userID); user != nil {
|
||||
return user.Nickname
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Client) GetStatus(userID string) string {
|
||||
res, _, err := m.Client.GetUserStatus(userID, "")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if res.Status == model.StatusAway {
|
||||
return "away"
|
||||
}
|
||||
|
||||
if res.Status == model.StatusOnline {
|
||||
return "online"
|
||||
}
|
||||
|
||||
return "offline"
|
||||
}
|
||||
|
||||
func (m *Client) GetStatuses() map[string]string {
|
||||
var ids []string
|
||||
|
||||
statuses := make(map[string]string)
|
||||
|
||||
for id := range m.Users {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
res, _, err := m.Client.GetUsersStatusesByIds(ids)
|
||||
if err != nil {
|
||||
return statuses
|
||||
}
|
||||
|
||||
for _, status := range res {
|
||||
statuses[status.UserId] = "offline"
|
||||
if status.Status == model.StatusAway {
|
||||
statuses[status.UserId] = "away"
|
||||
}
|
||||
|
||||
if status.Status == model.StatusOnline {
|
||||
statuses[status.UserId] = "online"
|
||||
}
|
||||
}
|
||||
|
||||
return statuses
|
||||
}
|
||||
|
||||
func (m *Client) GetTeamID() string {
|
||||
return m.Team.ID
|
||||
}
|
||||
|
||||
// GetTeamName returns the name of the specified teamId
|
||||
func (m *Client) GetTeamName(teamID string) string {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
for _, t := range m.OtherTeams {
|
||||
if t.ID == teamID {
|
||||
return t.Team.Name
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Client) GetUser(userID string) *model.User {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
_, ok := m.Users[userID]
|
||||
if !ok {
|
||||
res, _, err := m.Client.GetUser(userID, "")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
m.Users[userID] = res
|
||||
}
|
||||
|
||||
return m.Users[userID]
|
||||
}
|
||||
|
||||
func (m *Client) GetUserName(userID string) string {
|
||||
if user := m.GetUser(userID); user != nil {
|
||||
return user.Username
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Client) GetUsers() map[string]*model.User {
|
||||
users := make(map[string]*model.User)
|
||||
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
for k, v := range m.Users {
|
||||
users[k] = v
|
||||
}
|
||||
|
||||
return users
|
||||
}
|
||||
|
||||
func (m *Client) UpdateUsers() error {
|
||||
idx := 0
|
||||
max := 200
|
||||
|
||||
var (
|
||||
mmusers []*model.User
|
||||
resp *model.Response
|
||||
err error
|
||||
)
|
||||
|
||||
for {
|
||||
mmusers, resp, err = m.Client.GetUsers(idx, max, "")
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if err = m.HandleRatelimit("GetUsers", resp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for len(mmusers) > 0 {
|
||||
m.Lock()
|
||||
|
||||
for _, user := range mmusers {
|
||||
m.Users[user.Id] = user
|
||||
}
|
||||
|
||||
m.Unlock()
|
||||
|
||||
for {
|
||||
mmusers, resp, err = m.Client.GetUsers(idx, max, "")
|
||||
if err == nil {
|
||||
idx++
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if err := m.HandleRatelimit("GetUsers", resp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) UpdateUserNick(nick string) error {
|
||||
user := m.User
|
||||
user.Nickname = nick
|
||||
|
||||
_, _, err := m.Client.UpdateUser(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) UsernamesInChannel(channelID string) []string {
|
||||
res, _, err := m.Client.GetChannelMembers(channelID, 0, 50000, "")
|
||||
if err != nil {
|
||||
m.logger.Errorf("UsernamesInChannel(%s) failed: %s", channelID, err)
|
||||
|
||||
return []string{}
|
||||
}
|
||||
|
||||
allusers := m.GetUsers()
|
||||
result := []string{}
|
||||
|
||||
for _, member := range res {
|
||||
result = append(result, allusers[member.UserId].Nickname)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *Client) UpdateStatus(userID string, status string) error {
|
||||
_, _, err := m.Client.UpdateUserStatus(userID, &model.Status{Status: status})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Client) UpdateUser(userID string) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
res, _, err := m.Client.GetUser(userID, "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
m.Users[userID] = res
|
||||
}
|
||||
Reference in New Issue
Block a user