mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-06-28 21:56:19 +00:00
Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
50ac0fdd5d | |||
2dfc1fada8 | |||
979c7dde01 | |||
be898b44c3 | |||
4828c43443 | |||
a5d0197349 | |||
f1ed2ab403 | |||
f8329d8c77 | |||
ecf5669e80 | |||
f825636c4f | |||
ef8fbe1756 | |||
612acfddff | |||
932b80d4f7 | |||
fac5f69ad2 | |||
97c944bb63 | |||
d0c4fe78ee | |||
265457b451 | |||
4a4a29c9f6 | |||
0a91b9e1c9 | |||
f56163295c | |||
d1c87c068b | |||
fa20761110 | |||
e4a0e0a0e9 | |||
d30ae19e2a | |||
5c919e6bff | |||
434393d1c3 | |||
af9aa5d7cb | |||
05eb75442a | |||
3496ed0c7e | |||
1b89604c7a | |||
67a9d133e9 | |||
ed9118b346 |
@ -54,7 +54,7 @@ See https://github.com/42wim/matterbridge/wiki
|
|||||||
|
|
||||||
# Installing
|
# Installing
|
||||||
## Binaries
|
## Binaries
|
||||||
* Latest stable release [v1.5.0](https://github.com/42wim/matterbridge/releases/latest)
|
* Latest stable release [v1.6.3](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
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
@ -8,14 +9,13 @@ import (
|
|||||||
"github.com/zfjagann/golang-ring"
|
"github.com/zfjagann/golang-ring"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Api struct {
|
type Api struct {
|
||||||
Config *config.Protocol
|
|
||||||
Remote chan config.Message
|
|
||||||
Account string
|
|
||||||
Messages ring.Ring
|
Messages ring.Ring
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
*config.BridgeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApiMessage struct {
|
type ApiMessage struct {
|
||||||
@ -33,23 +33,21 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Api {
|
func New(cfg *config.BridgeConfig) *Api {
|
||||||
b := &Api{}
|
b := &Api{BridgeConfig: cfg}
|
||||||
e := echo.New()
|
e := echo.New()
|
||||||
b.Messages = ring.Ring{}
|
b.Messages = ring.Ring{}
|
||||||
b.Messages.SetCapacity(cfg.Buffer)
|
b.Messages.SetCapacity(b.Config.Buffer)
|
||||||
b.Config = &cfg
|
|
||||||
b.Account = account
|
|
||||||
b.Remote = c
|
|
||||||
if b.Config.Token != "" {
|
if b.Config.Token != "" {
|
||||||
e.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
|
e.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
|
||||||
return key == b.Config.Token, nil
|
return key == b.Config.Token, nil
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
e.GET("/api/messages", b.handleMessages)
|
e.GET("/api/messages", b.handleMessages)
|
||||||
|
e.GET("/api/stream", b.handleStream)
|
||||||
e.POST("/api/message", b.handlePostMessage)
|
e.POST("/api/message", b.handlePostMessage)
|
||||||
go func() {
|
go func() {
|
||||||
flog.Fatal(e.Start(cfg.BindAddress))
|
flog.Fatal(e.Start(b.Config.BindAddress))
|
||||||
}()
|
}()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
@ -103,3 +101,24 @@ func (b *Api) handleMessages(c echo.Context) error {
|
|||||||
b.Messages = ring.Ring{}
|
b.Messages = ring.Ring{}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Api) handleStream(c echo.Context) error {
|
||||||
|
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
|
||||||
|
c.Response().WriteHeader(http.StatusOK)
|
||||||
|
closeNotifier := c.Response().CloseNotify()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-closeNotifier:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
msg := b.Messages.Dequeue()
|
||||||
|
if msg != nil {
|
||||||
|
if err := json.NewEncoder(c.Response()).Encode(msg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Response().Flush()
|
||||||
|
}
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/42wim/matterbridge/bridge/mattermost"
|
"github.com/42wim/matterbridge/bridge/mattermost"
|
||||||
"github.com/42wim/matterbridge/bridge/rocketchat"
|
"github.com/42wim/matterbridge/bridge/rocketchat"
|
||||||
"github.com/42wim/matterbridge/bridge/slack"
|
"github.com/42wim/matterbridge/bridge/slack"
|
||||||
|
"github.com/42wim/matterbridge/bridge/sshchat"
|
||||||
"github.com/42wim/matterbridge/bridge/steam"
|
"github.com/42wim/matterbridge/bridge/steam"
|
||||||
"github.com/42wim/matterbridge/bridge/telegram"
|
"github.com/42wim/matterbridge/bridge/telegram"
|
||||||
"github.com/42wim/matterbridge/bridge/xmpp"
|
"github.com/42wim/matterbridge/bridge/xmpp"
|
||||||
@ -45,44 +46,49 @@ func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Brid
|
|||||||
b.Protocol = protocol
|
b.Protocol = protocol
|
||||||
b.Account = bridge.Account
|
b.Account = bridge.Account
|
||||||
b.Joined = make(map[string]bool)
|
b.Joined = make(map[string]bool)
|
||||||
|
bridgeConfig := &config.BridgeConfig{General: &cfg.General, Account: bridge.Account, Remote: c}
|
||||||
|
|
||||||
// override config from environment
|
// override config from environment
|
||||||
config.OverrideCfgFromEnv(cfg, protocol, name)
|
config.OverrideCfgFromEnv(cfg, protocol, name)
|
||||||
switch protocol {
|
switch protocol {
|
||||||
case "mattermost":
|
case "mattermost":
|
||||||
b.Config = cfg.Mattermost[name]
|
bridgeConfig.Config = cfg.Mattermost[name]
|
||||||
b.Bridger = bmattermost.New(cfg.Mattermost[name], bridge.Account, c)
|
b.Bridger = bmattermost.New(bridgeConfig)
|
||||||
case "irc":
|
case "irc":
|
||||||
b.Config = cfg.IRC[name]
|
bridgeConfig.Config = cfg.IRC[name]
|
||||||
b.Bridger = birc.New(cfg.IRC[name], bridge.Account, c)
|
b.Bridger = birc.New(bridgeConfig)
|
||||||
case "gitter":
|
case "gitter":
|
||||||
b.Config = cfg.Gitter[name]
|
bridgeConfig.Config = cfg.Gitter[name]
|
||||||
b.Bridger = bgitter.New(cfg.Gitter[name], bridge.Account, c)
|
b.Bridger = bgitter.New(bridgeConfig)
|
||||||
case "slack":
|
case "slack":
|
||||||
b.Config = cfg.Slack[name]
|
bridgeConfig.Config = cfg.Slack[name]
|
||||||
b.Bridger = bslack.New(cfg.Slack[name], bridge.Account, c)
|
b.Bridger = bslack.New(bridgeConfig)
|
||||||
case "xmpp":
|
case "xmpp":
|
||||||
b.Config = cfg.Xmpp[name]
|
bridgeConfig.Config = cfg.Xmpp[name]
|
||||||
b.Bridger = bxmpp.New(cfg.Xmpp[name], bridge.Account, c)
|
b.Bridger = bxmpp.New(bridgeConfig)
|
||||||
case "discord":
|
case "discord":
|
||||||
b.Config = cfg.Discord[name]
|
bridgeConfig.Config = cfg.Discord[name]
|
||||||
b.Bridger = bdiscord.New(cfg.Discord[name], bridge.Account, c)
|
b.Bridger = bdiscord.New(bridgeConfig)
|
||||||
case "telegram":
|
case "telegram":
|
||||||
b.Config = cfg.Telegram[name]
|
bridgeConfig.Config = cfg.Telegram[name]
|
||||||
b.Bridger = btelegram.New(cfg.Telegram[name], bridge.Account, c)
|
b.Bridger = btelegram.New(bridgeConfig)
|
||||||
case "rocketchat":
|
case "rocketchat":
|
||||||
b.Config = cfg.Rocketchat[name]
|
bridgeConfig.Config = cfg.Rocketchat[name]
|
||||||
b.Bridger = brocketchat.New(cfg.Rocketchat[name], bridge.Account, c)
|
b.Bridger = brocketchat.New(bridgeConfig)
|
||||||
case "matrix":
|
case "matrix":
|
||||||
b.Config = cfg.Matrix[name]
|
bridgeConfig.Config = cfg.Matrix[name]
|
||||||
b.Bridger = bmatrix.New(cfg.Matrix[name], bridge.Account, c)
|
b.Bridger = bmatrix.New(bridgeConfig)
|
||||||
case "steam":
|
case "steam":
|
||||||
b.Config = cfg.Steam[name]
|
bridgeConfig.Config = cfg.Steam[name]
|
||||||
b.Bridger = bsteam.New(cfg.Steam[name], bridge.Account, c)
|
b.Bridger = bsteam.New(bridgeConfig)
|
||||||
|
case "sshchat":
|
||||||
|
bridgeConfig.Config = cfg.Sshchat[name]
|
||||||
|
b.Bridger = bsshchat.New(bridgeConfig)
|
||||||
case "api":
|
case "api":
|
||||||
b.Config = cfg.Api[name]
|
bridgeConfig.Config = cfg.Api[name]
|
||||||
b.Bridger = api.New(cfg.Api[name], bridge.Account, c)
|
b.Bridger = api.New(bridgeConfig)
|
||||||
}
|
}
|
||||||
|
b.Config = bridgeConfig.Config
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ type Protocol struct {
|
|||||||
IgnoreMessages string // all protocols
|
IgnoreMessages string // all protocols
|
||||||
Jid string // xmpp
|
Jid string // xmpp
|
||||||
Login string // mattermost, matrix
|
Login string // mattermost, matrix
|
||||||
|
MediaDownloadSize int // all protocols
|
||||||
MediaServerDownload string
|
MediaServerDownload string
|
||||||
MediaServerUpload string
|
MediaServerUpload string
|
||||||
MessageDelay int // IRC, time in millisecond to wait between messages
|
MessageDelay int // IRC, time in millisecond to wait between messages
|
||||||
@ -80,6 +81,7 @@ type Protocol struct {
|
|||||||
Password string // IRC,mattermost,XMPP,matrix
|
Password string // IRC,mattermost,XMPP,matrix
|
||||||
PrefixMessagesWithNick bool // mattemost, slack
|
PrefixMessagesWithNick bool // mattemost, slack
|
||||||
Protocol string // all protocols
|
Protocol string // all protocols
|
||||||
|
RejoinDelay int // IRC
|
||||||
ReplaceMessages [][]string // all protocols
|
ReplaceMessages [][]string // all protocols
|
||||||
ReplaceNicks [][]string // all protocols
|
ReplaceNicks [][]string // all protocols
|
||||||
RemoteNickFormat string // all protocols
|
RemoteNickFormat string // all protocols
|
||||||
@ -141,11 +143,19 @@ type Config struct {
|
|||||||
Discord map[string]Protocol
|
Discord map[string]Protocol
|
||||||
Telegram map[string]Protocol
|
Telegram map[string]Protocol
|
||||||
Rocketchat map[string]Protocol
|
Rocketchat map[string]Protocol
|
||||||
|
Sshchat map[string]Protocol
|
||||||
General Protocol
|
General Protocol
|
||||||
Gateway []Gateway
|
Gateway []Gateway
|
||||||
SameChannelGateway []SameChannelGateway
|
SameChannelGateway []SameChannelGateway
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BridgeConfig struct {
|
||||||
|
Config Protocol
|
||||||
|
General *Protocol
|
||||||
|
Account string
|
||||||
|
Remote chan Message
|
||||||
|
}
|
||||||
|
|
||||||
func NewConfig(cfgfile string) *Config {
|
func NewConfig(cfgfile string) *Config {
|
||||||
var cfg Config
|
var cfg Config
|
||||||
if _, err := toml.DecodeFile(cfgfile, &cfg); err != nil {
|
if _, err := toml.DecodeFile(cfgfile, &cfg); err != nil {
|
||||||
@ -173,6 +183,9 @@ func NewConfig(cfgfile string) *Config {
|
|||||||
if fail {
|
if fail {
|
||||||
log.Fatalf("Fix your config. Please see changelog for more information")
|
log.Fatalf("Fix your config. Please see changelog for more information")
|
||||||
}
|
}
|
||||||
|
if cfg.General.MediaDownloadSize == 0 {
|
||||||
|
cfg.General.MediaDownloadSize = 1000000
|
||||||
|
}
|
||||||
return &cfg
|
return &cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,9 +12,6 @@ import (
|
|||||||
|
|
||||||
type bdiscord struct {
|
type bdiscord struct {
|
||||||
c *discordgo.Session
|
c *discordgo.Session
|
||||||
Config *config.Protocol
|
|
||||||
Remote chan config.Message
|
|
||||||
Account string
|
|
||||||
Channels []*discordgo.Channel
|
Channels []*discordgo.Channel
|
||||||
Nick string
|
Nick string
|
||||||
UseChannelID bool
|
UseChannelID bool
|
||||||
@ -24,6 +21,7 @@ type bdiscord struct {
|
|||||||
webhookToken string
|
webhookToken string
|
||||||
channelInfoMap map[string]*config.ChannelInfo
|
channelInfoMap map[string]*config.ChannelInfo
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
*config.BridgeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -33,11 +31,8 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *bdiscord {
|
func New(cfg *config.BridgeConfig) *bdiscord {
|
||||||
b := &bdiscord{}
|
b := &bdiscord{BridgeConfig: cfg}
|
||||||
b.Config = &cfg
|
|
||||||
b.Remote = c
|
|
||||||
b.Account = account
|
|
||||||
b.userMemberMap = make(map[string]*discordgo.Member)
|
b.userMemberMap = make(map[string]*discordgo.Member)
|
||||||
b.channelInfoMap = make(map[string]*config.ChannelInfo)
|
b.channelInfoMap = make(map[string]*config.ChannelInfo)
|
||||||
if b.Config.WebhookURL != "" {
|
if b.Config.WebhookURL != "" {
|
||||||
|
@ -9,13 +9,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Bgitter struct {
|
type Bgitter struct {
|
||||||
c *gitter.Gitter
|
c *gitter.Gitter
|
||||||
Config *config.Protocol
|
User *gitter.User
|
||||||
Remote chan config.Message
|
Users []gitter.User
|
||||||
Account string
|
Rooms []gitter.Room
|
||||||
User *gitter.User
|
*config.BridgeConfig
|
||||||
Users []gitter.User
|
|
||||||
Rooms []gitter.Room
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -25,12 +23,8 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Bgitter {
|
func New(cfg *config.BridgeConfig) *Bgitter {
|
||||||
b := &Bgitter{}
|
return &Bgitter{BridgeConfig: cfg}
|
||||||
b.Config = &cfg
|
|
||||||
b.Remote = c
|
|
||||||
b.Account = account
|
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bgitter) Connect() error {
|
func (b *Bgitter) Connect() error {
|
||||||
|
@ -25,12 +25,11 @@ type Birc struct {
|
|||||||
i *girc.Client
|
i *girc.Client
|
||||||
Nick string
|
Nick string
|
||||||
names map[string][]string
|
names map[string][]string
|
||||||
Config *config.Protocol
|
|
||||||
Remote chan config.Message
|
|
||||||
connected chan struct{}
|
connected chan struct{}
|
||||||
Local chan config.Message // local queue for flood control
|
Local chan config.Message // local queue for flood control
|
||||||
Account string
|
|
||||||
FirstConnection bool
|
FirstConnection bool
|
||||||
|
|
||||||
|
*config.BridgeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -40,13 +39,11 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Birc {
|
func New(cfg *config.BridgeConfig) *Birc {
|
||||||
b := &Birc{}
|
b := &Birc{}
|
||||||
b.Config = &cfg
|
b.BridgeConfig = cfg
|
||||||
b.Nick = b.Config.Nick
|
b.Nick = b.Config.Nick
|
||||||
b.Remote = c
|
|
||||||
b.names = make(map[string][]string)
|
b.names = make(map[string][]string)
|
||||||
b.Account = account
|
|
||||||
b.connected = make(chan struct{})
|
b.connected = make(chan struct{})
|
||||||
if b.Config.MessageDelay == 0 {
|
if b.Config.MessageDelay == 0 {
|
||||||
b.Config.MessageDelay = 1300
|
b.Config.MessageDelay = 1300
|
||||||
@ -197,8 +194,9 @@ func (b *Birc) Send(msg config.Message) (string, error) {
|
|||||||
msg.Text = helper.SplitStringLength(msg.Text, b.Config.MessageLength)
|
msg.Text = helper.SplitStringLength(msg.Text, b.Config.MessageLength)
|
||||||
}
|
}
|
||||||
for _, text := range strings.Split(msg.Text, "\n") {
|
for _, text := range strings.Split(msg.Text, "\n") {
|
||||||
|
input := []rune(text)
|
||||||
if len(text) > b.Config.MessageLength {
|
if len(text) > b.Config.MessageLength {
|
||||||
text = text[:b.Config.MessageLength] + " <message clipped>"
|
text = string(input[:b.Config.MessageLength]) + " <message clipped>"
|
||||||
}
|
}
|
||||||
if len(b.Local) < b.Config.MessageQueue {
|
if len(b.Local) < b.Config.MessageQueue {
|
||||||
if len(b.Local) == b.Config.MessageQueue-1 {
|
if len(b.Local) == b.Config.MessageQueue-1 {
|
||||||
@ -269,6 +267,7 @@ func (b *Birc) handleJoinPart(client *girc.Client, event girc.Event) {
|
|||||||
channel := event.Params[0]
|
channel := event.Params[0]
|
||||||
if event.Command == "KICK" {
|
if event.Command == "KICK" {
|
||||||
flog.Infof("Got kicked from %s by %s", channel, event.Source.Name)
|
flog.Infof("Got kicked from %s by %s", channel, event.Source.Name)
|
||||||
|
time.Sleep(time.Duration(b.Config.RejoinDelay) * time.Second)
|
||||||
b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: channel, Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS}
|
b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: channel, Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -324,14 +323,13 @@ func (b *Birc) handlePrivMsg(client *girc.Client, event girc.Event) {
|
|||||||
if event.Source.Name == b.Nick {
|
if event.Source.Name == b.Nick {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rmsg := config.Message{Username: event.Source.Name, Channel: event.Params[0], Account: b.Account, UserID: event.Source.Ident + "@" + event.Source.Host}
|
rmsg := config.Message{Username: event.Source.Name, Channel: strings.ToLower(event.Params[0]), Account: b.Account, UserID: event.Source.Ident + "@" + event.Source.Host}
|
||||||
flog.Debugf("handlePrivMsg() %s %s %#v", event.Source.Name, event.Trailing, event)
|
flog.Debugf("handlePrivMsg() %s %s %#v", event.Source.Name, event.Trailing, event)
|
||||||
msg := ""
|
msg := ""
|
||||||
if event.Command == "CTCP_ACTION" {
|
if event.IsAction() {
|
||||||
// msg = event.Source.Name + " "
|
|
||||||
rmsg.Event = config.EVENT_USER_ACTION
|
rmsg.Event = config.EVENT_USER_ACTION
|
||||||
}
|
}
|
||||||
msg += event.Trailing
|
msg += event.StripAction()
|
||||||
// strip IRC colors
|
// strip IRC colors
|
||||||
re := regexp.MustCompile(`[[:cntrl:]](?:\d{1,2}(?:,\d{1,2})?)?`)
|
re := regexp.MustCompile(`[[:cntrl:]](?:\d{1,2}(?:,\d{1,2})?)?`)
|
||||||
msg = re.ReplaceAllString(msg, "")
|
msg = re.ReplaceAllString(msg, "")
|
||||||
|
@ -15,12 +15,10 @@ import (
|
|||||||
|
|
||||||
type Bmatrix struct {
|
type Bmatrix struct {
|
||||||
mc *matrix.Client
|
mc *matrix.Client
|
||||||
Config *config.Protocol
|
|
||||||
Remote chan config.Message
|
|
||||||
Account string
|
|
||||||
UserID string
|
UserID string
|
||||||
RoomMap map[string]string
|
RoomMap map[string]string
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
*config.BridgeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -30,12 +28,9 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Bmatrix {
|
func New(cfg *config.BridgeConfig) *Bmatrix {
|
||||||
b := &Bmatrix{}
|
b := &Bmatrix{BridgeConfig: cfg}
|
||||||
b.RoomMap = make(map[string]string)
|
b.RoomMap = make(map[string]string)
|
||||||
b.Config = &cfg
|
|
||||||
b.Account = account
|
|
||||||
b.Remote = c
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +101,7 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
|||||||
res, err := b.mc.UploadToContentRepo(content, mtype, int64(len(*fi.Data)))
|
res, err := b.mc.UploadToContentRepo(content, mtype, int64(len(*fi.Data)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
flog.Errorf("file upload failed: %#v", err)
|
flog.Errorf("file upload failed: %#v", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if strings.Contains(mtype, "video") {
|
if strings.Contains(mtype, "video") {
|
||||||
flog.Debugf("sendVideo %s", res.ContentURI)
|
flog.Debugf("sendVideo %s", res.ContentURI)
|
||||||
@ -179,7 +175,7 @@ func (b *Bmatrix) handlematrix() error {
|
|||||||
size := info["size"].(float64)
|
size := info["size"].(float64)
|
||||||
name := ev.Content["body"].(string)
|
name := ev.Content["body"].(string)
|
||||||
flog.Debugf("trying to download %#v with size %#v", name, size)
|
flog.Debugf("trying to download %#v with size %#v", name, size)
|
||||||
if size <= 1000000 {
|
if size <= float64(b.General.MediaDownloadSize) {
|
||||||
data, err := helper.DownloadFile(url)
|
data, err := helper.DownloadFile(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
flog.Errorf("download %s failed %#v", url, err)
|
flog.Errorf("download %s failed %#v", url, err)
|
||||||
|
@ -32,10 +32,8 @@ type MMMessage struct {
|
|||||||
type Bmattermost struct {
|
type Bmattermost struct {
|
||||||
MMhook
|
MMhook
|
||||||
MMapi
|
MMapi
|
||||||
Config *config.Protocol
|
TeamId string
|
||||||
Remote chan config.Message
|
*config.BridgeConfig
|
||||||
TeamId string
|
|
||||||
Account string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -45,11 +43,8 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Bmattermost {
|
func New(cfg *config.BridgeConfig) *Bmattermost {
|
||||||
b := &Bmattermost{}
|
b := &Bmattermost{BridgeConfig: cfg}
|
||||||
b.Config = &cfg
|
|
||||||
b.Remote = c
|
|
||||||
b.Account = account
|
|
||||||
b.mmMap = make(map[string]string)
|
b.mmMap = make(map[string]string)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,7 @@ type MMhook struct {
|
|||||||
|
|
||||||
type Brocketchat struct {
|
type Brocketchat struct {
|
||||||
MMhook
|
MMhook
|
||||||
Config *config.Protocol
|
*config.BridgeConfig
|
||||||
Remote chan config.Message
|
|
||||||
Account string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -26,12 +24,8 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Brocketchat {
|
func New(cfg *config.BridgeConfig) *Brocketchat {
|
||||||
b := &Brocketchat{}
|
return &Brocketchat{BridgeConfig: cfg}
|
||||||
b.Config = &cfg
|
|
||||||
b.Remote = c
|
|
||||||
b.Account = account
|
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Brocketchat) Command(cmd string) string {
|
func (b *Brocketchat) Command(cmd string) string {
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
"github.com/42wim/matterbridge/matterhook"
|
"github.com/42wim/matterbridge/matterhook"
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/matterbridge/slack"
|
"github.com/nlopes/slack"
|
||||||
"html"
|
"html"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -27,14 +27,12 @@ type MMMessage struct {
|
|||||||
type Bslack struct {
|
type Bslack struct {
|
||||||
mh *matterhook.Client
|
mh *matterhook.Client
|
||||||
sc *slack.Client
|
sc *slack.Client
|
||||||
Config *config.Protocol
|
|
||||||
rtm *slack.RTM
|
rtm *slack.RTM
|
||||||
Plus bool
|
Plus bool
|
||||||
Remote chan config.Message
|
|
||||||
Users []slack.User
|
Users []slack.User
|
||||||
Account string
|
|
||||||
si *slack.Info
|
si *slack.Info
|
||||||
channels []slack.Channel
|
channels []slack.Channel
|
||||||
|
*config.BridgeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -44,12 +42,8 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Bslack {
|
func New(cfg *config.BridgeConfig) *Bslack {
|
||||||
b := &Bslack{}
|
return &Bslack{BridgeConfig: cfg}
|
||||||
b.Config = &cfg
|
|
||||||
b.Remote = c
|
|
||||||
b.Account = account
|
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bslack) Command(cmd string) string {
|
func (b *Bslack) Command(cmd string) string {
|
||||||
@ -113,7 +107,7 @@ func (b *Bslack) Disconnect() error {
|
|||||||
|
|
||||||
func (b *Bslack) JoinChannel(channel config.ChannelInfo) error {
|
func (b *Bslack) JoinChannel(channel config.ChannelInfo) error {
|
||||||
// we can only join channels using the API
|
// we can only join channels using the API
|
||||||
if b.Config.WebhookURL == "" && b.Config.WebhookBindAddress == "" {
|
if b.sc != nil {
|
||||||
if strings.HasPrefix(b.Config.Token, "xoxb") {
|
if strings.HasPrefix(b.Config.Token, "xoxb") {
|
||||||
// TODO check if bot has already joined channel
|
// TODO check if bot has already joined channel
|
||||||
return nil
|
return nil
|
||||||
@ -161,7 +155,7 @@ func (b *Bslack) Send(msg config.Message) (string, error) {
|
|||||||
np.AsUser = true
|
np.AsUser = true
|
||||||
}
|
}
|
||||||
np.Username = nick
|
np.Username = nick
|
||||||
np.IconURL = config.GetIconURL(&msg, b.Config)
|
np.IconURL = config.GetIconURL(&msg, &b.Config)
|
||||||
if msg.Avatar != "" {
|
if msg.Avatar != "" {
|
||||||
np.IconURL = msg.Avatar
|
np.IconURL = msg.Avatar
|
||||||
}
|
}
|
||||||
@ -294,7 +288,7 @@ func (b *Bslack) handleSlack() {
|
|||||||
// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra
|
// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra
|
||||||
if message.Raw.File != nil {
|
if message.Raw.File != nil {
|
||||||
// limit to 1MB for now
|
// limit to 1MB for now
|
||||||
if message.Raw.File.Size <= 1000000 {
|
if message.Raw.File.Size <= b.General.MediaDownloadSize {
|
||||||
comment := ""
|
comment := ""
|
||||||
data, err := b.downloadFile(message.Raw.File.URLPrivateDownload)
|
data, err := b.downloadFile(message.Raw.File.URLPrivateDownload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -315,9 +309,11 @@ func (b *Bslack) handleSlack() {
|
|||||||
|
|
||||||
func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
|
func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
|
||||||
for msg := range b.rtm.IncomingEvents {
|
for msg := range b.rtm.IncomingEvents {
|
||||||
|
if msg.Type != "user_typing" && msg.Type != "latency_report" {
|
||||||
|
flog.Debugf("Receiving from slackclient %#v", msg.Data)
|
||||||
|
}
|
||||||
switch ev := msg.Data.(type) {
|
switch ev := msg.Data.(type) {
|
||||||
case *slack.MessageEvent:
|
case *slack.MessageEvent:
|
||||||
flog.Debugf("Receiving from slackclient %#v", ev)
|
|
||||||
if len(ev.Attachments) > 0 {
|
if len(ev.Attachments) > 0 {
|
||||||
// skip messages we made ourselves
|
// skip messages we made ourselves
|
||||||
if ev.Attachments[0].CallbackID == "matterbridge" {
|
if ev.Attachments[0].CallbackID == "matterbridge" {
|
||||||
@ -400,6 +396,8 @@ func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
|
|||||||
}
|
}
|
||||||
case *slack.InvalidAuthEvent:
|
case *slack.InvalidAuthEvent:
|
||||||
flog.Fatalf("Invalid Token %#v", ev)
|
flog.Fatalf("Invalid Token %#v", ev)
|
||||||
|
case *slack.ConnectionErrorEvent:
|
||||||
|
flog.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj)
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
132
bridge/sshchat/sshchat.go
Normal file
132
bridge/sshchat/sshchat.go
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package bsshchat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/shazow/ssh-chat/sshd"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Bsshchat struct {
|
||||||
|
r *bufio.Scanner
|
||||||
|
w io.WriteCloser
|
||||||
|
*config.BridgeConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var flog *log.Entry
|
||||||
|
var protocol = "sshchat"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg *config.BridgeConfig) *Bsshchat {
|
||||||
|
return &Bsshchat{BridgeConfig: cfg}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bsshchat) Connect() error {
|
||||||
|
var err error
|
||||||
|
flog.Infof("Connecting %s", b.Config.Server)
|
||||||
|
go func() {
|
||||||
|
err = sshd.ConnectShell(b.Config.Server, b.Config.Nick, func(r io.Reader, w io.WriteCloser) error {
|
||||||
|
b.r = bufio.NewScanner(r)
|
||||||
|
b.w = w
|
||||||
|
b.r.Scan()
|
||||||
|
w.Write([]byte("/theme mono\r\n"))
|
||||||
|
b.handleSshChat()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
flog.Debugf("%#v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
flog.Info("Connection succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bsshchat) Disconnect() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bsshchat) JoinChannel(channel config.ChannelInfo) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bsshchat) Send(msg config.Message) (string, error) {
|
||||||
|
// ignore delete messages
|
||||||
|
if msg.Event == config.EVENT_MSG_DELETE {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
flog.Debugf("Receiving %#v", msg)
|
||||||
|
if msg.Extra != nil {
|
||||||
|
if len(msg.Extra["file"]) > 0 {
|
||||||
|
for _, f := range msg.Extra["file"] {
|
||||||
|
fi := f.(config.FileInfo)
|
||||||
|
if fi.URL != "" {
|
||||||
|
msg.Text = fi.URL
|
||||||
|
}
|
||||||
|
b.w.Write([]byte(msg.Username + msg.Text))
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.w.Write([]byte(msg.Username + msg.Text + "\r\n"))
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func (b *Bsshchat) sshchatKeepAlive() chan bool {
|
||||||
|
done := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(90 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
flog.Debugf("PING")
|
||||||
|
err := b.xc.PingC2S("", "")
|
||||||
|
if err != nil {
|
||||||
|
flog.Debugf("PING failed %#v", err)
|
||||||
|
}
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return done
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func stripPrompt(s string) string {
|
||||||
|
pos := strings.LastIndex(s, "\033[K")
|
||||||
|
if pos < 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return s[pos+3:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bsshchat) handleSshChat() error {
|
||||||
|
/*
|
||||||
|
done := b.sshchatKeepAlive()
|
||||||
|
defer close(done)
|
||||||
|
*/
|
||||||
|
wait := true
|
||||||
|
for {
|
||||||
|
if b.r.Scan() {
|
||||||
|
res := strings.Split(stripPrompt(b.r.Text()), ":")
|
||||||
|
if res[0] == "-> Set theme" {
|
||||||
|
wait = false
|
||||||
|
log.Debugf("mono found, allowing")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !wait {
|
||||||
|
flog.Debugf("message %#v", res)
|
||||||
|
rmsg := config.Message{Username: res[0], Text: strings.Join(res[1:], ":"), Channel: "sshchat", Account: b.Account, UserID: "nick"}
|
||||||
|
b.Remote <- rmsg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,11 +16,9 @@ import (
|
|||||||
type Bsteam struct {
|
type Bsteam struct {
|
||||||
c *steam.Client
|
c *steam.Client
|
||||||
connected chan struct{}
|
connected chan struct{}
|
||||||
Config *config.Protocol
|
|
||||||
Remote chan config.Message
|
|
||||||
Account string
|
|
||||||
userMap map[steamid.SteamId]string
|
userMap map[steamid.SteamId]string
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
*config.BridgeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -30,11 +28,8 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Bsteam {
|
func New(cfg *config.BridgeConfig) *Bsteam {
|
||||||
b := &Bsteam{}
|
b := &Bsteam{BridgeConfig: cfg}
|
||||||
b.Config = &cfg
|
|
||||||
b.Remote = c
|
|
||||||
b.Account = account
|
|
||||||
b.userMap = make(map[steamid.SteamId]string)
|
b.userMap = make(map[steamid.SteamId]string)
|
||||||
b.connected = make(chan struct{})
|
b.connected = make(chan struct{})
|
||||||
return b
|
return b
|
||||||
|
@ -12,10 +12,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Btelegram struct {
|
type Btelegram struct {
|
||||||
c *tgbotapi.BotAPI
|
c *tgbotapi.BotAPI
|
||||||
Config *config.Protocol
|
*config.BridgeConfig
|
||||||
Remote chan config.Message
|
|
||||||
Account string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -25,12 +23,8 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Btelegram {
|
func New(cfg *config.BridgeConfig) *Btelegram {
|
||||||
b := &Btelegram{}
|
return &Btelegram{BridgeConfig: cfg}
|
||||||
b.Config = &cfg
|
|
||||||
b.Remote = c
|
|
||||||
b.Account = account
|
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Btelegram) Connect() error {
|
func (b *Btelegram) Connect() error {
|
||||||
@ -90,6 +84,9 @@ func (b *Btelegram) Send(msg config.Message) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
m := tgbotapi.NewEditMessageText(chatid, msgid, msg.Username+msg.Text)
|
m := tgbotapi.NewEditMessageText(chatid, msgid, msg.Username+msg.Text)
|
||||||
|
if b.Config.MessageFormat == "HTML" {
|
||||||
|
m.ParseMode = tgbotapi.ModeHTML
|
||||||
|
}
|
||||||
_, err = b.c.Send(m)
|
_, err = b.c.Send(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -179,6 +176,29 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
|
|||||||
if message.Document != nil {
|
if message.Document != nil {
|
||||||
b.handleDownload(message.Document, &fmsg)
|
b.handleDownload(message.Document, &fmsg)
|
||||||
}
|
}
|
||||||
|
if message.Voice != nil {
|
||||||
|
b.handleDownload(message.Voice, &fmsg)
|
||||||
|
}
|
||||||
|
if message.Audio != nil {
|
||||||
|
b.handleDownload(message.Audio, &fmsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if message.ForwardFrom != nil {
|
||||||
|
usernameForward := ""
|
||||||
|
if b.Config.UseFirstName {
|
||||||
|
usernameForward = message.ForwardFrom.FirstName
|
||||||
|
}
|
||||||
|
if usernameForward == "" {
|
||||||
|
usernameForward = message.ForwardFrom.UserName
|
||||||
|
if usernameForward == "" {
|
||||||
|
usernameForward = message.ForwardFrom.FirstName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if usernameForward == "" {
|
||||||
|
usernameForward = "unknown"
|
||||||
|
}
|
||||||
|
text = "Forwarded from " + usernameForward + ": " + text
|
||||||
|
}
|
||||||
|
|
||||||
// quote the previous message
|
// quote the previous message
|
||||||
if message.ReplyToMessage != nil {
|
if message.ReplyToMessage != nil {
|
||||||
@ -224,6 +244,23 @@ func (b *Btelegram) handleDownload(file interface{}, msg *config.Message) {
|
|||||||
text := ""
|
text := ""
|
||||||
fileid := ""
|
fileid := ""
|
||||||
switch v := file.(type) {
|
switch v := file.(type) {
|
||||||
|
case *tgbotapi.Audio:
|
||||||
|
size = v.FileSize
|
||||||
|
url = b.getFileDirectURL(v.FileID)
|
||||||
|
urlPart := strings.Split(url, "/")
|
||||||
|
name = urlPart[len(urlPart)-1]
|
||||||
|
text = " " + url
|
||||||
|
fileid = v.FileID
|
||||||
|
case *tgbotapi.Voice:
|
||||||
|
size = v.FileSize
|
||||||
|
url = b.getFileDirectURL(v.FileID)
|
||||||
|
urlPart := strings.Split(url, "/")
|
||||||
|
name = urlPart[len(urlPart)-1]
|
||||||
|
text = " " + url
|
||||||
|
if !strings.HasSuffix(name, ".ogg") {
|
||||||
|
name = name + ".ogg"
|
||||||
|
}
|
||||||
|
fileid = v.FileID
|
||||||
case *tgbotapi.Sticker:
|
case *tgbotapi.Sticker:
|
||||||
size = v.FileSize
|
size = v.FileSize
|
||||||
url = b.getFileDirectURL(v.FileID)
|
url = b.getFileDirectURL(v.FileID)
|
||||||
@ -262,7 +299,7 @@ func (b *Btelegram) handleDownload(file interface{}, msg *config.Message) {
|
|||||||
// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra
|
// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra
|
||||||
// limit to 1MB for now
|
// limit to 1MB for now
|
||||||
flog.Debugf("trying to download %#v fileid %#v with size %#v", name, fileid, size)
|
flog.Debugf("trying to download %#v fileid %#v with size %#v", name, fileid, size)
|
||||||
if size <= 1000000 {
|
if size <= b.General.MediaDownloadSize {
|
||||||
data, err := helper.DownloadFile(url)
|
data, err := helper.DownloadFile(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
flog.Errorf("download %s failed %#v", url, err)
|
flog.Errorf("download %s failed %#v", url, err)
|
||||||
|
@ -14,9 +14,7 @@ import (
|
|||||||
type Bxmpp struct {
|
type Bxmpp struct {
|
||||||
xc *xmpp.Client
|
xc *xmpp.Client
|
||||||
xmppMap map[string]string
|
xmppMap map[string]string
|
||||||
Config *config.Protocol
|
*config.BridgeConfig
|
||||||
Remote chan config.Message
|
|
||||||
Account string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog *log.Entry
|
var flog *log.Entry
|
||||||
@ -26,12 +24,9 @@ func init() {
|
|||||||
flog = log.WithFields(log.Fields{"module": protocol})
|
flog = log.WithFields(log.Fields{"module": protocol})
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Protocol, account string, c chan config.Message) *Bxmpp {
|
func New(cfg *config.BridgeConfig) *Bxmpp {
|
||||||
b := &Bxmpp{}
|
b := &Bxmpp{BridgeConfig: cfg}
|
||||||
b.xmppMap = make(map[string]string)
|
b.xmppMap = make(map[string]string)
|
||||||
b.Config = &cfg
|
|
||||||
b.Account = account
|
|
||||||
b.Remote = c
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
changelog.md
33
changelog.md
@ -1,3 +1,36 @@
|
|||||||
|
# v1.6.3
|
||||||
|
## Bugfix
|
||||||
|
* slack: Fix connection issues
|
||||||
|
* slack: Add more debug messages
|
||||||
|
* irc: Convert received IRC channel names to lowercase. Fixes #329 (#330)
|
||||||
|
|
||||||
|
# v1.6.2
|
||||||
|
## Bugfix
|
||||||
|
* mattermost: Crashes while connecting to Mattermost (regression). Closes #327
|
||||||
|
|
||||||
|
# v1.6.1
|
||||||
|
## Bugfix
|
||||||
|
* general: Display of nicks not longer working (regression). Closes #323
|
||||||
|
|
||||||
|
# v1.6.0
|
||||||
|
## New features
|
||||||
|
* sshchat: New protocol support added (https://github.com/shazow/ssh-chat)
|
||||||
|
* general: Allow specifying maximum download size of media using MediaDownloadSize (slack,telegram,matrix)
|
||||||
|
* api: Add (simple, one listener) long-polling support (api). Closes #307
|
||||||
|
* telegram: Add support for forwarded messages. Closes #313
|
||||||
|
* telegram: Add support for Audio/Voice files (telegram). Closes #314
|
||||||
|
* irc: Add RejoinDelay option. Delay to rejoin after channel kick (irc). Closes #322
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
* telegram: Also use HTML in edited messages (telegram). Closes #315
|
||||||
|
* matrix: Fix panic (matrix). Closes #316
|
||||||
|
|
||||||
|
# v1.5.1
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
* irc: Fix irc ACTION regression (irc). Closes #306
|
||||||
|
* irc: Split on UTF-8 for MessageSplit (irc). Closes #308
|
||||||
|
|
||||||
# v1.5.0
|
# v1.5.0
|
||||||
## New features
|
## New features
|
||||||
* general: remote mediaserver support. See MediaServerDownload and MediaServerUpload in matterbridge.toml.sample
|
* general: remote mediaserver support. See MediaServerDownload and MediaServerUpload in matterbridge.toml.sample
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
version = "1.5.0"
|
version = "1.6.3"
|
||||||
githash string
|
githash string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -85,6 +85,10 @@ MessageLength=400
|
|||||||
#OPTIONAL (default false)
|
#OPTIONAL (default false)
|
||||||
MessageSplit=false
|
MessageSplit=false
|
||||||
|
|
||||||
|
#Delay in seconds to rejoin a channel when kicked
|
||||||
|
#OPTIONAL (default 0)
|
||||||
|
RejoinDelay=0
|
||||||
|
|
||||||
#Nicks you want to ignore.
|
#Nicks you want to ignore.
|
||||||
#Messages from those users will not be sent to other bridges.
|
#Messages from those users will not be sent to other bridges.
|
||||||
#OPTIONAL
|
#OPTIONAL
|
||||||
@ -1044,6 +1048,15 @@ MediaServerUpload="https://user:pass@yourserver.com/upload"
|
|||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
MediaServerDownload="https://youserver.com/download"
|
MediaServerDownload="https://youserver.com/download"
|
||||||
|
|
||||||
|
#MediaDownloadSize is the maximum size of attachments, videos, images
|
||||||
|
#matterbridge will download and upload this file to bridges that also support uploading files.
|
||||||
|
#eg downloading from slack to upload it to mattermost
|
||||||
|
#
|
||||||
|
#It will only download from bridges that don't have public links available, which are for the moment
|
||||||
|
#slack, telegram and matrix
|
||||||
|
#
|
||||||
|
#Optional (default 1000000 (1 megabyte))
|
||||||
|
MediaDownloadSize=1000000
|
||||||
|
|
||||||
###################################################################
|
###################################################################
|
||||||
#Gateway configuration
|
#Gateway configuration
|
||||||
|
11
vendor/github.com/labstack/echo/context.go
generated
vendored
11
vendor/github.com/labstack/echo/context.go
generated
vendored
@ -494,14 +494,9 @@ func (c *context) Stream(code int, contentType string, r io.Reader) (err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) File(file string) (err error) {
|
func (c *context) File(file string) (err error) {
|
||||||
file, err = url.QueryUnescape(file) // Issue #839
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Open(file)
|
f, err := os.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrNotFound
|
return NotFoundHandler(c)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
@ -510,7 +505,7 @@ func (c *context) File(file string) (err error) {
|
|||||||
file = filepath.Join(file, indexPage)
|
file = filepath.Join(file, indexPage)
|
||||||
f, err = os.Open(file)
|
f, err = os.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrNotFound
|
return NotFoundHandler(c)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
if fi, err = f.Stat(); err != nil {
|
if fi, err = f.Stat(); err != nil {
|
||||||
@ -530,7 +525,7 @@ func (c *context) Inline(file, name string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) contentDisposition(file, name, dispositionType string) (err error) {
|
func (c *context) contentDisposition(file, name, dispositionType string) (err error) {
|
||||||
c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%s", dispositionType, name))
|
c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%q", dispositionType, name))
|
||||||
c.File(file)
|
c.File(file)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
136
vendor/github.com/labstack/echo/echo.go
generated
vendored
136
vendor/github.com/labstack/echo/echo.go
generated
vendored
@ -72,6 +72,7 @@ type (
|
|||||||
TLSServer *http.Server
|
TLSServer *http.Server
|
||||||
Listener net.Listener
|
Listener net.Listener
|
||||||
TLSListener net.Listener
|
TLSListener net.Listener
|
||||||
|
AutoTLSManager autocert.Manager
|
||||||
DisableHTTP2 bool
|
DisableHTTP2 bool
|
||||||
Debug bool
|
Debug bool
|
||||||
HideBanner bool
|
HideBanner bool
|
||||||
@ -79,22 +80,22 @@ type (
|
|||||||
Binder Binder
|
Binder Binder
|
||||||
Validator Validator
|
Validator Validator
|
||||||
Renderer Renderer
|
Renderer Renderer
|
||||||
AutoTLSManager autocert.Manager
|
|
||||||
// Mutex sync.RWMutex
|
// Mutex sync.RWMutex
|
||||||
Logger Logger
|
Logger Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// Route contains a handler and information for matching against requests.
|
// Route contains a handler and information for matching against requests.
|
||||||
Route struct {
|
Route struct {
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Handler string `json:"handler"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPError represents an error that occurred while handling a request.
|
// HTTPError represents an error that occurred while handling a request.
|
||||||
HTTPError struct {
|
HTTPError struct {
|
||||||
Code int
|
Code int
|
||||||
Message interface{}
|
Message interface{}
|
||||||
|
Inner error // Stores the error returned by an external dependency
|
||||||
}
|
}
|
||||||
|
|
||||||
// MiddlewareFunc defines a function to process middleware.
|
// MiddlewareFunc defines a function to process middleware.
|
||||||
@ -121,7 +122,7 @@ type (
|
|||||||
|
|
||||||
// i is the interface for Echo and Group.
|
// i is the interface for Echo and Group.
|
||||||
i interface {
|
i interface {
|
||||||
GET(string, HandlerFunc, ...MiddlewareFunc)
|
GET(string, HandlerFunc, ...MiddlewareFunc) *Route
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -212,7 +213,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = "3.1.0"
|
version = "3.2.5"
|
||||||
website = "https://echo.labstack.com"
|
website = "https://echo.labstack.com"
|
||||||
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
|
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
|
||||||
banner = `
|
banner = `
|
||||||
@ -282,7 +283,7 @@ func New() (e *Echo) {
|
|||||||
e.TLSServer.Handler = e
|
e.TLSServer.Handler = e
|
||||||
e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
|
e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
|
||||||
e.Binder = &DefaultBinder{}
|
e.Binder = &DefaultBinder{}
|
||||||
e.Logger.SetLevel(log.OFF)
|
e.Logger.SetLevel(log.ERROR)
|
||||||
e.stdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
|
e.stdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
|
||||||
e.pool.New = func() interface{} {
|
e.pool.New = func() interface{} {
|
||||||
return e.NewContext(nil, nil)
|
return e.NewContext(nil, nil)
|
||||||
@ -319,6 +320,9 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
|||||||
if he, ok := err.(*HTTPError); ok {
|
if he, ok := err.(*HTTPError); ok {
|
||||||
code = he.Code
|
code = he.Code
|
||||||
msg = he.Message
|
msg = he.Message
|
||||||
|
if he.Inner != nil {
|
||||||
|
msg = fmt.Sprintf("%v, %v", err, he.Inner)
|
||||||
|
}
|
||||||
} else if e.Debug {
|
} else if e.Debug {
|
||||||
msg = err.Error()
|
msg = err.Error()
|
||||||
} else {
|
} else {
|
||||||
@ -328,19 +332,19 @@ func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
|||||||
msg = Map{"message": msg}
|
msg = Map{"message": msg}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.Logger.Error(err)
|
||||||
|
|
||||||
|
// Send response
|
||||||
if !c.Response().Committed {
|
if !c.Response().Committed {
|
||||||
if c.Request().Method == HEAD { // Issue #608
|
if c.Request().Method == HEAD { // Issue #608
|
||||||
if err := c.NoContent(code); err != nil {
|
err = c.NoContent(code)
|
||||||
goto ERROR
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if err := c.JSON(code, msg); err != nil {
|
err = c.JSON(code, msg)
|
||||||
goto ERROR
|
}
|
||||||
}
|
if err != nil {
|
||||||
|
e.Logger.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ERROR:
|
|
||||||
e.Logger.Error(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre adds middleware to the chain which is run before router.
|
// Pre adds middleware to the chain which is run before router.
|
||||||
@ -355,104 +359,114 @@ func (e *Echo) Use(middleware ...MiddlewareFunc) {
|
|||||||
|
|
||||||
// CONNECT registers a new CONNECT route for a path with matching handler in the
|
// CONNECT registers a new CONNECT route for a path with matching handler in the
|
||||||
// router with optional route-level middleware.
|
// router with optional route-level middleware.
|
||||||
func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
e.add(CONNECT, path, h, m...)
|
return e.Add(CONNECT, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE registers a new DELETE route for a path with matching handler in the router
|
// DELETE registers a new DELETE route for a path with matching handler in the router
|
||||||
// with optional route-level middleware.
|
// with optional route-level middleware.
|
||||||
func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
e.add(DELETE, path, h, m...)
|
return e.Add(DELETE, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET registers a new GET route for a path with matching handler in the router
|
// GET registers a new GET route for a path with matching handler in the router
|
||||||
// with optional route-level middleware.
|
// with optional route-level middleware.
|
||||||
func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
e.add(GET, path, h, m...)
|
return e.Add(GET, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HEAD registers a new HEAD route for a path with matching handler in the
|
// HEAD registers a new HEAD route for a path with matching handler in the
|
||||||
// router with optional route-level middleware.
|
// router with optional route-level middleware.
|
||||||
func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
e.add(HEAD, path, h, m...)
|
return e.Add(HEAD, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OPTIONS registers a new OPTIONS route for a path with matching handler in the
|
// OPTIONS registers a new OPTIONS route for a path with matching handler in the
|
||||||
// router with optional route-level middleware.
|
// router with optional route-level middleware.
|
||||||
func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
e.add(OPTIONS, path, h, m...)
|
return e.Add(OPTIONS, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PATCH registers a new PATCH route for a path with matching handler in the
|
// PATCH registers a new PATCH route for a path with matching handler in the
|
||||||
// router with optional route-level middleware.
|
// router with optional route-level middleware.
|
||||||
func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
e.add(PATCH, path, h, m...)
|
return e.Add(PATCH, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST registers a new POST route for a path with matching handler in the
|
// POST registers a new POST route for a path with matching handler in the
|
||||||
// router with optional route-level middleware.
|
// router with optional route-level middleware.
|
||||||
func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
e.add(POST, path, h, m...)
|
return e.Add(POST, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT registers a new PUT route for a path with matching handler in the
|
// PUT registers a new PUT route for a path with matching handler in the
|
||||||
// router with optional route-level middleware.
|
// router with optional route-level middleware.
|
||||||
func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
e.add(PUT, path, h, m...)
|
return e.Add(PUT, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TRACE registers a new TRACE route for a path with matching handler in the
|
// TRACE registers a new TRACE route for a path with matching handler in the
|
||||||
// router with optional route-level middleware.
|
// router with optional route-level middleware.
|
||||||
func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
e.add(TRACE, path, h, m...)
|
return e.Add(TRACE, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any registers a new route for all HTTP methods and path with matching handler
|
// Any registers a new route for all HTTP methods and path with matching handler
|
||||||
// in the router with optional route-level middleware.
|
// in the router with optional route-level middleware.
|
||||||
func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
|
func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
|
||||||
|
routes := make([]*Route, 0)
|
||||||
for _, m := range methods {
|
for _, m := range methods {
|
||||||
e.add(m, path, handler, middleware...)
|
routes = append(routes, e.Add(m, path, handler, middleware...))
|
||||||
}
|
}
|
||||||
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match registers a new route for multiple HTTP methods and path with matching
|
// Match registers a new route for multiple HTTP methods and path with matching
|
||||||
// handler in the router with optional route-level middleware.
|
// handler in the router with optional route-level middleware.
|
||||||
func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
|
func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
|
||||||
|
routes := make([]*Route, 0)
|
||||||
for _, m := range methods {
|
for _, m := range methods {
|
||||||
e.add(m, path, handler, middleware...)
|
routes = append(routes, e.Add(m, path, handler, middleware...))
|
||||||
}
|
}
|
||||||
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static registers a new route with path prefix to serve static files from the
|
// Static registers a new route with path prefix to serve static files from the
|
||||||
// provided root directory.
|
// provided root directory.
|
||||||
func (e *Echo) Static(prefix, root string) {
|
func (e *Echo) Static(prefix, root string) *Route {
|
||||||
if root == "" {
|
if root == "" {
|
||||||
root = "." // For security we want to restrict to CWD.
|
root = "." // For security we want to restrict to CWD.
|
||||||
}
|
}
|
||||||
static(e, prefix, root)
|
return static(e, prefix, root)
|
||||||
}
|
}
|
||||||
|
|
||||||
func static(i i, prefix, root string) {
|
func static(i i, prefix, root string) *Route {
|
||||||
h := func(c Context) error {
|
h := func(c Context) error {
|
||||||
name := filepath.Join(root, path.Clean("/"+c.Param("*"))) // "/"+ for security
|
p, err := PathUnescape(c.Param("*"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
|
||||||
return c.File(name)
|
return c.File(name)
|
||||||
}
|
}
|
||||||
i.GET(prefix, h)
|
i.GET(prefix, h)
|
||||||
if prefix == "/" {
|
if prefix == "/" {
|
||||||
i.GET(prefix+"*", h)
|
return i.GET(prefix+"*", h)
|
||||||
} else {
|
|
||||||
i.GET(prefix+"/*", h)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return i.GET(prefix+"/*", h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// File registers a new route with path to serve a static file.
|
// File registers a new route with path to serve a static file.
|
||||||
func (e *Echo) File(path, file string) {
|
func (e *Echo) File(path, file string) *Route {
|
||||||
e.GET(path, func(c Context) error {
|
return e.GET(path, func(c Context) error {
|
||||||
return c.File(file)
|
return c.File(file)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Echo) add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
|
// Add registers a new route for an HTTP method and path with matching handler
|
||||||
|
// in the router with optional route-level middleware.
|
||||||
|
func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
|
||||||
name := handlerName(handler)
|
name := handlerName(handler)
|
||||||
e.router.Add(method, path, func(c Context) error {
|
e.router.Add(method, path, func(c Context) error {
|
||||||
h := handler
|
h := handler
|
||||||
@ -463,11 +477,12 @@ func (e *Echo) add(method, path string, handler HandlerFunc, middleware ...Middl
|
|||||||
return h(c)
|
return h(c)
|
||||||
})
|
})
|
||||||
r := &Route{
|
r := &Route{
|
||||||
Method: method,
|
Method: method,
|
||||||
Path: path,
|
Path: path,
|
||||||
Handler: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
e.router.routes[method+path] = r
|
e.router.routes[method+path] = r
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group creates a new router group with prefix and optional group-level middleware.
|
// Group creates a new router group with prefix and optional group-level middleware.
|
||||||
@ -479,12 +494,22 @@ func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
|
|||||||
|
|
||||||
// URI generates a URI from handler.
|
// URI generates a URI from handler.
|
||||||
func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
|
func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
|
||||||
|
name := handlerName(handler)
|
||||||
|
return e.Reverse(name, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL is an alias for `URI` function.
|
||||||
|
func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
|
||||||
|
return e.URI(h, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse generates an URL from route name and provided parameters.
|
||||||
|
func (e *Echo) Reverse(name string, params ...interface{}) string {
|
||||||
uri := new(bytes.Buffer)
|
uri := new(bytes.Buffer)
|
||||||
ln := len(params)
|
ln := len(params)
|
||||||
n := 0
|
n := 0
|
||||||
name := handlerName(handler)
|
|
||||||
for _, r := range e.router.routes {
|
for _, r := range e.router.routes {
|
||||||
if r.Handler == name {
|
if r.Name == name {
|
||||||
for i, l := 0, len(r.Path); i < l; i++ {
|
for i, l := 0, len(r.Path); i < l; i++ {
|
||||||
if r.Path[i] == ':' && n < ln {
|
if r.Path[i] == ':' && n < ln {
|
||||||
for ; i < l && r.Path[i] != '/'; i++ {
|
for ; i < l && r.Path[i] != '/'; i++ {
|
||||||
@ -502,11 +527,6 @@ func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
|
|||||||
return uri.String()
|
return uri.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// URL is an alias for `URI` function.
|
|
||||||
func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
|
|
||||||
return e.URI(h, params...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Routes returns the registered routes.
|
// Routes returns the registered routes.
|
||||||
func (e *Echo) Routes() []*Route {
|
func (e *Echo) Routes() []*Route {
|
||||||
routes := []*Route{}
|
routes := []*Route{}
|
||||||
@ -653,7 +673,7 @@ func NewHTTPError(code int, message ...interface{}) *HTTPError {
|
|||||||
|
|
||||||
// Error makes it compatible with `error` interface.
|
// Error makes it compatible with `error` interface.
|
||||||
func (he *HTTPError) Error() string {
|
func (he *HTTPError) Error() string {
|
||||||
return fmt.Sprintf("code=%d, message=%s", he.Code, he.Message)
|
return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
|
// WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
|
||||||
|
47
vendor/github.com/labstack/echo/group.go
generated
vendored
47
vendor/github.com/labstack/echo/group.go
generated
vendored
@ -21,66 +21,66 @@ func (g *Group) Use(middleware ...MiddlewareFunc) {
|
|||||||
// Allow all requests to reach the group as they might get dropped if router
|
// Allow all requests to reach the group as they might get dropped if router
|
||||||
// doesn't find a match, making none of the group middleware process.
|
// doesn't find a match, making none of the group middleware process.
|
||||||
g.echo.Any(path.Clean(g.prefix+"/*"), func(c Context) error {
|
g.echo.Any(path.Clean(g.prefix+"/*"), func(c Context) error {
|
||||||
return ErrNotFound
|
return NotFoundHandler(c)
|
||||||
}, g.middleware...)
|
}, g.middleware...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
|
// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
|
||||||
func (g *Group) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (g *Group) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
g.add(CONNECT, path, h, m...)
|
return g.Add(CONNECT, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE implements `Echo#DELETE()` for sub-routes within the Group.
|
// DELETE implements `Echo#DELETE()` for sub-routes within the Group.
|
||||||
func (g *Group) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (g *Group) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
g.add(DELETE, path, h, m...)
|
return g.Add(DELETE, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET implements `Echo#GET()` for sub-routes within the Group.
|
// GET implements `Echo#GET()` for sub-routes within the Group.
|
||||||
func (g *Group) GET(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (g *Group) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
g.add(GET, path, h, m...)
|
return g.Add(GET, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HEAD implements `Echo#HEAD()` for sub-routes within the Group.
|
// HEAD implements `Echo#HEAD()` for sub-routes within the Group.
|
||||||
func (g *Group) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (g *Group) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
g.add(HEAD, path, h, m...)
|
return g.Add(HEAD, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OPTIONS implements `Echo#OPTIONS()` for sub-routes within the Group.
|
// OPTIONS implements `Echo#OPTIONS()` for sub-routes within the Group.
|
||||||
func (g *Group) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (g *Group) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
g.add(OPTIONS, path, h, m...)
|
return g.Add(OPTIONS, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PATCH implements `Echo#PATCH()` for sub-routes within the Group.
|
// PATCH implements `Echo#PATCH()` for sub-routes within the Group.
|
||||||
func (g *Group) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (g *Group) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
g.add(PATCH, path, h, m...)
|
return g.Add(PATCH, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST implements `Echo#POST()` for sub-routes within the Group.
|
// POST implements `Echo#POST()` for sub-routes within the Group.
|
||||||
func (g *Group) POST(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (g *Group) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
g.add(POST, path, h, m...)
|
return g.Add(POST, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT implements `Echo#PUT()` for sub-routes within the Group.
|
// PUT implements `Echo#PUT()` for sub-routes within the Group.
|
||||||
func (g *Group) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (g *Group) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
g.add(PUT, path, h, m...)
|
return g.Add(PUT, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TRACE implements `Echo#TRACE()` for sub-routes within the Group.
|
// TRACE implements `Echo#TRACE()` for sub-routes within the Group.
|
||||||
func (g *Group) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) {
|
func (g *Group) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||||
g.add(TRACE, path, h, m...)
|
return g.Add(TRACE, path, h, m...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any implements `Echo#Any()` for sub-routes within the Group.
|
// Any implements `Echo#Any()` for sub-routes within the Group.
|
||||||
func (g *Group) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
|
func (g *Group) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
|
||||||
for _, m := range methods {
|
for _, m := range methods {
|
||||||
g.add(m, path, handler, middleware...)
|
g.Add(m, path, handler, middleware...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match implements `Echo#Match()` for sub-routes within the Group.
|
// Match implements `Echo#Match()` for sub-routes within the Group.
|
||||||
func (g *Group) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
|
func (g *Group) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
|
||||||
for _, m := range methods {
|
for _, m := range methods {
|
||||||
g.add(m, path, handler, middleware...)
|
g.Add(m, path, handler, middleware...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,12 +102,13 @@ func (g *Group) File(path, file string) {
|
|||||||
g.echo.File(g.prefix+path, file)
|
g.echo.File(g.prefix+path, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Group) add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) {
|
// Add implements `Echo#Add()` for sub-routes within the Group.
|
||||||
|
func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
|
||||||
// Combine into a new slice to avoid accidentally passing the same slice for
|
// Combine into a new slice to avoid accidentally passing the same slice for
|
||||||
// multiple routes, which would lead to later add() calls overwriting the
|
// multiple routes, which would lead to later add() calls overwriting the
|
||||||
// middleware from earlier calls.
|
// middleware from earlier calls.
|
||||||
m := []MiddlewareFunc{}
|
m := []MiddlewareFunc{}
|
||||||
m = append(m, g.middleware...)
|
m = append(m, g.middleware...)
|
||||||
m = append(m, middleware...)
|
m = append(m, middleware...)
|
||||||
g.echo.add(method, g.prefix+path, handler, m...)
|
return g.echo.Add(method, g.prefix+path, handler, m...)
|
||||||
}
|
}
|
||||||
|
7
vendor/github.com/labstack/echo/middleware/basic_auth.go
generated
vendored
7
vendor/github.com/labstack/echo/middleware/basic_auth.go
generated
vendored
@ -3,6 +3,7 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
)
|
)
|
||||||
@ -27,7 +28,7 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
basic = "Basic"
|
basic = "basic"
|
||||||
defaultRealm = "Restricted"
|
defaultRealm = "Restricted"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ func BasicAuth(fn BasicAuthValidator) echo.MiddlewareFunc {
|
|||||||
func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
|
func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
|
||||||
// Defaults
|
// Defaults
|
||||||
if config.Validator == nil {
|
if config.Validator == nil {
|
||||||
panic("basic-auth middleware requires a validator function")
|
panic("echo: basic-auth middleware requires a validator function")
|
||||||
}
|
}
|
||||||
if config.Skipper == nil {
|
if config.Skipper == nil {
|
||||||
config.Skipper = DefaultBasicAuthConfig.Skipper
|
config.Skipper = DefaultBasicAuthConfig.Skipper
|
||||||
@ -72,7 +73,7 @@ func BasicAuthWithConfig(config BasicAuthConfig) echo.MiddlewareFunc {
|
|||||||
auth := c.Request().Header.Get(echo.HeaderAuthorization)
|
auth := c.Request().Header.Get(echo.HeaderAuthorization)
|
||||||
l := len(basic)
|
l := len(basic)
|
||||||
|
|
||||||
if len(auth) > l+1 && auth[:l] == basic {
|
if len(auth) > l+1 && strings.ToLower(auth[:l]) == basic {
|
||||||
b, err := base64.StdEncoding.DecodeString(auth[l+1:])
|
b, err := base64.StdEncoding.DecodeString(auth[l+1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
112
vendor/github.com/labstack/echo/middleware/body_dump.go
generated
vendored
Normal file
112
vendor/github.com/labstack/echo/middleware/body_dump.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/labstack/echo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// BodyDumpConfig defines the config for BodyDump middleware.
|
||||||
|
BodyDumpConfig struct {
|
||||||
|
// Skipper defines a function to skip middleware.
|
||||||
|
Skipper Skipper
|
||||||
|
|
||||||
|
// Handler receives request and response payload.
|
||||||
|
// Required.
|
||||||
|
Handler BodyDumpHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyDumpHandler receives the request and response payload.
|
||||||
|
BodyDumpHandler func(echo.Context, []byte, []byte)
|
||||||
|
|
||||||
|
bodyDumpResponseWriter struct {
|
||||||
|
io.Writer
|
||||||
|
http.ResponseWriter
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultBodyDumpConfig is the default Gzip middleware config.
|
||||||
|
DefaultBodyDumpConfig = BodyDumpConfig{
|
||||||
|
Skipper: DefaultSkipper,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// BodyDump returns a BodyDump middleware.
|
||||||
|
//
|
||||||
|
// BodyLimit middleware captures the request and response payload and calls the
|
||||||
|
// registered handler.
|
||||||
|
func BodyDump(handler BodyDumpHandler) echo.MiddlewareFunc {
|
||||||
|
c := DefaultBodyDumpConfig
|
||||||
|
c.Handler = handler
|
||||||
|
return BodyDumpWithConfig(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyDumpWithConfig returns a BodyDump middleware with config.
|
||||||
|
// See: `BodyDump()`.
|
||||||
|
func BodyDumpWithConfig(config BodyDumpConfig) echo.MiddlewareFunc {
|
||||||
|
// Defaults
|
||||||
|
if config.Handler == nil {
|
||||||
|
panic("echo: body-dump middleware requires a handler function")
|
||||||
|
}
|
||||||
|
if config.Skipper == nil {
|
||||||
|
config.Skipper = DefaultBodyDumpConfig.Skipper
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) (err error) {
|
||||||
|
if config.Skipper(c) {
|
||||||
|
return next(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request
|
||||||
|
reqBody := []byte{}
|
||||||
|
if c.Request().Body != nil { // Read
|
||||||
|
reqBody, _ = ioutil.ReadAll(c.Request().Body)
|
||||||
|
}
|
||||||
|
c.Request().Body = ioutil.NopCloser(bytes.NewBuffer(reqBody)) // Reset
|
||||||
|
|
||||||
|
// Response
|
||||||
|
resBody := new(bytes.Buffer)
|
||||||
|
mw := io.MultiWriter(c.Response().Writer, resBody)
|
||||||
|
writer := &bodyDumpResponseWriter{Writer: mw, ResponseWriter: c.Response().Writer}
|
||||||
|
c.Response().Writer = writer
|
||||||
|
|
||||||
|
if err = next(c); err != nil {
|
||||||
|
c.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback
|
||||||
|
config.Handler(c, reqBody, resBody.Bytes())
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bodyDumpResponseWriter) WriteHeader(code int) {
|
||||||
|
w.ResponseWriter.WriteHeader(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bodyDumpResponseWriter) Write(b []byte) (int, error) {
|
||||||
|
return w.Writer.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bodyDumpResponseWriter) Flush() {
|
||||||
|
w.ResponseWriter.(http.Flusher).Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bodyDumpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
return w.ResponseWriter.(http.Hijacker).Hijack()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bodyDumpResponseWriter) CloseNotify() <-chan bool {
|
||||||
|
return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||||
|
}
|
4
vendor/github.com/labstack/echo/middleware/body_limit.go
generated
vendored
4
vendor/github.com/labstack/echo/middleware/body_limit.go
generated
vendored
@ -30,7 +30,7 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultBodyLimitConfig is the default Gzip middleware config.
|
// DefaultBodyLimitConfig is the default BodyLimit middleware config.
|
||||||
DefaultBodyLimitConfig = BodyLimitConfig{
|
DefaultBodyLimitConfig = BodyLimitConfig{
|
||||||
Skipper: DefaultSkipper,
|
Skipper: DefaultSkipper,
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ func BodyLimitWithConfig(config BodyLimitConfig) echo.MiddlewareFunc {
|
|||||||
|
|
||||||
limit, err := bytes.Parse(config.Limit)
|
limit, err := bytes.Parse(config.Limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("invalid body-limit=%s", config.Limit))
|
panic(fmt.Errorf("echo: invalid body-limit=%s", config.Limit))
|
||||||
}
|
}
|
||||||
config.limit = limit
|
config.limit = limit
|
||||||
pool := limitedReaderPool(config)
|
pool := limitedReaderPool(config)
|
||||||
|
3
vendor/github.com/labstack/echo/middleware/compress.go
generated
vendored
3
vendor/github.com/labstack/echo/middleware/compress.go
generated
vendored
@ -67,7 +67,7 @@ func GzipWithConfig(config GzipConfig) echo.MiddlewareFunc {
|
|||||||
res := c.Response()
|
res := c.Response()
|
||||||
res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
|
res.Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
|
||||||
if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {
|
if strings.Contains(c.Request().Header.Get(echo.HeaderAcceptEncoding), gzipScheme) {
|
||||||
res.Header().Add(echo.HeaderContentEncoding, gzipScheme) // Issue #806
|
res.Header().Set(echo.HeaderContentEncoding, gzipScheme) // Issue #806
|
||||||
rw := res.Writer
|
rw := res.Writer
|
||||||
w, err := gzip.NewWriterLevel(rw, config.Level)
|
w, err := gzip.NewWriterLevel(rw, config.Level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -98,6 +98,7 @@ func (w *gzipResponseWriter) WriteHeader(code int) {
|
|||||||
if code == http.StatusNoContent { // Issue #489
|
if code == http.StatusNoContent { // Issue #489
|
||||||
w.ResponseWriter.Header().Del(echo.HeaderContentEncoding)
|
w.ResponseWriter.Header().Del(echo.HeaderContentEncoding)
|
||||||
}
|
}
|
||||||
|
w.Header().Del(echo.HeaderContentLength) // Issue #444
|
||||||
w.ResponseWriter.WriteHeader(code)
|
w.ResponseWriter.WriteHeader(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
vendor/github.com/labstack/echo/middleware/jwt.go
generated
vendored
26
vendor/github.com/labstack/echo/middleware/jwt.go
generated
vendored
@ -1,7 +1,6 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -57,6 +56,12 @@ const (
|
|||||||
AlgorithmHS256 = "HS256"
|
AlgorithmHS256 = "HS256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Errors
|
||||||
|
var (
|
||||||
|
ErrJWTMissing = echo.NewHTTPError(http.StatusBadRequest, "Missing or malformed jwt")
|
||||||
|
ErrJWTInvalid = echo.NewHTTPError(http.StatusUnauthorized, "Invalid or expired jwt")
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultJWTConfig is the default JWT auth middleware config.
|
// DefaultJWTConfig is the default JWT auth middleware config.
|
||||||
DefaultJWTConfig = JWTConfig{
|
DefaultJWTConfig = JWTConfig{
|
||||||
@ -77,7 +82,7 @@ var (
|
|||||||
//
|
//
|
||||||
// See: https://jwt.io/introduction
|
// See: https://jwt.io/introduction
|
||||||
// See `JWTConfig.TokenLookup`
|
// See `JWTConfig.TokenLookup`
|
||||||
func JWT(key []byte) echo.MiddlewareFunc {
|
func JWT(key interface{}) echo.MiddlewareFunc {
|
||||||
c := DefaultJWTConfig
|
c := DefaultJWTConfig
|
||||||
c.SigningKey = key
|
c.SigningKey = key
|
||||||
return JWTWithConfig(c)
|
return JWTWithConfig(c)
|
||||||
@ -134,14 +139,15 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
|
|||||||
|
|
||||||
auth, err := extractor(c)
|
auth, err := extractor(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
|
return err
|
||||||
}
|
}
|
||||||
token := new(jwt.Token)
|
token := new(jwt.Token)
|
||||||
// Issue #647, #656
|
// Issue #647, #656
|
||||||
if _, ok := config.Claims.(jwt.MapClaims); ok {
|
if _, ok := config.Claims.(jwt.MapClaims); ok {
|
||||||
token, err = jwt.Parse(auth, config.keyFunc)
|
token, err = jwt.Parse(auth, config.keyFunc)
|
||||||
} else {
|
} else {
|
||||||
claims := reflect.ValueOf(config.Claims).Interface().(jwt.Claims)
|
t := reflect.ValueOf(config.Claims).Type().Elem()
|
||||||
|
claims := reflect.New(t).Interface().(jwt.Claims)
|
||||||
token, err = jwt.ParseWithClaims(auth, claims, config.keyFunc)
|
token, err = jwt.ParseWithClaims(auth, claims, config.keyFunc)
|
||||||
}
|
}
|
||||||
if err == nil && token.Valid {
|
if err == nil && token.Valid {
|
||||||
@ -149,7 +155,11 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
|
|||||||
c.Set(config.ContextKey, token)
|
c.Set(config.ContextKey, token)
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
return echo.ErrUnauthorized
|
return &echo.HTTPError{
|
||||||
|
Code: ErrJWTInvalid.Code,
|
||||||
|
Message: ErrJWTInvalid.Message,
|
||||||
|
Inner: err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,7 +172,7 @@ func jwtFromHeader(header string, authScheme string) jwtExtractor {
|
|||||||
if len(auth) > l+1 && auth[:l] == authScheme {
|
if len(auth) > l+1 && auth[:l] == authScheme {
|
||||||
return auth[l+1:], nil
|
return auth[l+1:], nil
|
||||||
}
|
}
|
||||||
return "", errors.New("Missing or invalid jwt in the request header")
|
return "", ErrJWTMissing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +181,7 @@ func jwtFromQuery(param string) jwtExtractor {
|
|||||||
return func(c echo.Context) (string, error) {
|
return func(c echo.Context) (string, error) {
|
||||||
token := c.QueryParam(param)
|
token := c.QueryParam(param)
|
||||||
if token == "" {
|
if token == "" {
|
||||||
return "", errors.New("Missing jwt in the query string")
|
return "", ErrJWTMissing
|
||||||
}
|
}
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
@ -182,7 +192,7 @@ func jwtFromCookie(name string) jwtExtractor {
|
|||||||
return func(c echo.Context) (string, error) {
|
return func(c echo.Context) (string, error) {
|
||||||
cookie, err := c.Cookie(name)
|
cookie, err := c.Cookie(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New("Missing jwt in the cookie")
|
return "", ErrJWTMissing
|
||||||
}
|
}
|
||||||
return cookie.Value, nil
|
return cookie.Value, nil
|
||||||
}
|
}
|
||||||
|
2
vendor/github.com/labstack/echo/middleware/key_auth.go
generated
vendored
2
vendor/github.com/labstack/echo/middleware/key_auth.go
generated
vendored
@ -72,7 +72,7 @@ func KeyAuthWithConfig(config KeyAuthConfig) echo.MiddlewareFunc {
|
|||||||
config.KeyLookup = DefaultKeyAuthConfig.KeyLookup
|
config.KeyLookup = DefaultKeyAuthConfig.KeyLookup
|
||||||
}
|
}
|
||||||
if config.Validator == nil {
|
if config.Validator == nil {
|
||||||
panic("key-auth middleware requires a validator function")
|
panic("echo: key-auth middleware requires a validator function")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
|
42
vendor/github.com/labstack/echo/middleware/proxy.go
generated
vendored
42
vendor/github.com/labstack/echo/middleware/proxy.go
generated
vendored
@ -1,7 +1,6 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -54,35 +53,38 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultProxyConfig is the default Proxy middleware config.
|
||||||
|
DefaultProxyConfig = ProxyConfig{
|
||||||
|
Skipper: DefaultSkipper,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func proxyHTTP(t *ProxyTarget) http.Handler {
|
func proxyHTTP(t *ProxyTarget) http.Handler {
|
||||||
return httputil.NewSingleHostReverseProxy(t.URL)
|
return httputil.NewSingleHostReverseProxy(t.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
h, ok := w.(http.Hijacker)
|
in, _, err := c.Response().Hijack()
|
||||||
if !ok {
|
|
||||||
c.Error(errors.New("proxy raw, not a hijacker"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
in, _, err := h.Hijack()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(fmt.Errorf("proxy raw, hijack error=%v, url=%s", r.URL, err))
|
c.Error(fmt.Errorf("proxy raw, hijack error=%v, url=%s", t.URL, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer in.Close()
|
defer in.Close()
|
||||||
|
|
||||||
out, err := net.Dial("tcp", t.URL.Host)
|
out, err := net.Dial("tcp", t.URL.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", r.URL, err))
|
he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, dial error=%v, url=%s", t.URL, err))
|
||||||
c.Error(he)
|
c.Error(he)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
|
|
||||||
|
// Write header
|
||||||
err = r.Write(out)
|
err = r.Write(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request copy error=%v, url=%s", r.URL, err))
|
he := echo.NewHTTPError(http.StatusBadGateway, fmt.Sprintf("proxy raw, request header copy error=%v, url=%s", t.URL, err))
|
||||||
c.Error(he)
|
c.Error(he)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -97,7 +99,7 @@ func proxyRaw(t *ProxyTarget, c echo.Context) http.Handler {
|
|||||||
go cp(in, out)
|
go cp(in, out)
|
||||||
err = <-errc
|
err = <-errc
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
c.Logger().Errorf("proxy raw, error=%v, url=%s", r.URL, err)
|
c.Logger().Errorf("proxy raw, copy body error=%v, url=%s", t.URL, err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -118,8 +120,18 @@ func (r *RoundRobinBalancer) Next() *ProxyTarget {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proxy returns an HTTP/WebSocket reverse proxy middleware.
|
// Proxy returns a Proxy middleware.
|
||||||
func Proxy(config ProxyConfig) echo.MiddlewareFunc {
|
//
|
||||||
|
// Proxy middleware forwards the request to upstream server using a configured load balancing technique.
|
||||||
|
func Proxy(balancer ProxyBalancer) echo.MiddlewareFunc {
|
||||||
|
c := DefaultProxyConfig
|
||||||
|
c.Balancer = balancer
|
||||||
|
return ProxyWithConfig(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProxyWithConfig returns a Proxy middleware with config.
|
||||||
|
// See: `Proxy()`
|
||||||
|
func ProxyWithConfig(config ProxyConfig) echo.MiddlewareFunc {
|
||||||
// Defaults
|
// Defaults
|
||||||
if config.Skipper == nil {
|
if config.Skipper == nil {
|
||||||
config.Skipper = DefaultLoggerConfig.Skipper
|
config.Skipper = DefaultLoggerConfig.Skipper
|
||||||
@ -130,6 +142,10 @@ func Proxy(config ProxyConfig) echo.MiddlewareFunc {
|
|||||||
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) (err error) {
|
return func(c echo.Context) (err error) {
|
||||||
|
if config.Skipper(c) {
|
||||||
|
return next(c)
|
||||||
|
}
|
||||||
|
|
||||||
req := c.Request()
|
req := c.Request()
|
||||||
res := c.Response()
|
res := c.Response()
|
||||||
tgt := config.Balancer.Next()
|
tgt := config.Balancer.Next()
|
||||||
|
10
vendor/github.com/labstack/echo/middleware/recover.go
generated
vendored
10
vendor/github.com/labstack/echo/middleware/recover.go
generated
vendored
@ -5,7 +5,6 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
"github.com/labstack/gommon/color"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -64,17 +63,14 @@ func RecoverWithConfig(config RecoverConfig) echo.MiddlewareFunc {
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
var err error
|
err, ok := r.(error)
|
||||||
switch r := r.(type) {
|
if !ok {
|
||||||
case error:
|
|
||||||
err = r
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("%v", r)
|
err = fmt.Errorf("%v", r)
|
||||||
}
|
}
|
||||||
stack := make([]byte, config.StackSize)
|
stack := make([]byte, config.StackSize)
|
||||||
length := runtime.Stack(stack, !config.DisableStackAll)
|
length := runtime.Stack(stack, !config.DisableStackAll)
|
||||||
if !config.DisablePrintStack {
|
if !config.DisablePrintStack {
|
||||||
c.Logger().Printf("[%s] %s %s\n", color.Red("PANIC RECOVER"), err, stack[:length])
|
c.Logger().Printf("[PANIC RECOVER] %v %s\n", err, stack[:length])
|
||||||
}
|
}
|
||||||
c.Error(err)
|
c.Error(err)
|
||||||
}
|
}
|
||||||
|
33
vendor/github.com/labstack/echo/middleware/static.go
generated
vendored
33
vendor/github.com/labstack/echo/middleware/static.go
generated
vendored
@ -2,6 +2,7 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -66,7 +67,7 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) (err error) {
|
||||||
if config.Skipper(c) {
|
if config.Skipper(c) {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
@ -75,17 +76,25 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
|
|||||||
if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
|
if strings.HasSuffix(c.Path(), "*") { // When serving from a group, e.g. `/static*`.
|
||||||
p = c.Param("*")
|
p = c.Param("*")
|
||||||
}
|
}
|
||||||
|
p, err = echo.PathUnescape(p)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security
|
name := filepath.Join(config.Root, path.Clean("/"+p)) // "/"+ for security
|
||||||
|
|
||||||
fi, err := os.Stat(name)
|
fi, err := os.Stat(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
if config.HTML5 && path.Ext(p) == "" {
|
if err = next(c); err != nil {
|
||||||
return c.File(filepath.Join(config.Root, config.Index))
|
if he, ok := err.(*echo.HTTPError); ok {
|
||||||
|
if config.HTML5 && he.Code == http.StatusNotFound {
|
||||||
|
return c.File(filepath.Join(config.Root, config.Index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return next(c)
|
|
||||||
}
|
}
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
@ -99,7 +108,7 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
|
|||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.File(index)
|
return c.File(index)
|
||||||
@ -110,20 +119,20 @@ func StaticWithConfig(config StaticConfig) echo.MiddlewareFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func listDir(name string, res *echo.Response) error {
|
func listDir(name string, res *echo.Response) (err error) {
|
||||||
dir, err := os.Open(name)
|
dir, err := os.Open(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
dirs, err := dir.Readdir(-1)
|
dirs, err := dir.Readdir(-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a directory index
|
// Create a directory index
|
||||||
res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
|
res.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
|
||||||
if _, err = fmt.Fprintf(res, "<pre>\n"); err != nil {
|
if _, err = fmt.Fprintf(res, "<pre>\n"); err != nil {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
for _, d := range dirs {
|
for _, d := range dirs {
|
||||||
name := d.Name()
|
name := d.Name()
|
||||||
@ -133,9 +142,9 @@ func listDir(name string, res *echo.Response) error {
|
|||||||
name += "/"
|
name += "/"
|
||||||
}
|
}
|
||||||
if _, err = fmt.Fprintf(res, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
|
if _, err = fmt.Fprintf(res, "<a href=\"%s\" style=\"color: %s;\">%s</a>\n", name, color, name); err != nil {
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, err = fmt.Fprintf(res, "</pre>\n")
|
_, err = fmt.Fprintf(res, "</pre>\n")
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
19
vendor/github.com/labstack/echo/response.go
generated
vendored
19
vendor/github.com/labstack/echo/response.go
generated
vendored
@ -11,11 +11,12 @@ type (
|
|||||||
// by an HTTP handler to construct an HTTP response.
|
// by an HTTP handler to construct an HTTP response.
|
||||||
// See: https://golang.org/pkg/net/http/#ResponseWriter
|
// See: https://golang.org/pkg/net/http/#ResponseWriter
|
||||||
Response struct {
|
Response struct {
|
||||||
Writer http.ResponseWriter
|
echo *Echo
|
||||||
Status int
|
beforeFuncs []func()
|
||||||
Size int64
|
Writer http.ResponseWriter
|
||||||
Committed bool
|
Status int
|
||||||
echo *Echo
|
Size int64
|
||||||
|
Committed bool
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,6 +35,11 @@ func (r *Response) Header() http.Header {
|
|||||||
return r.Writer.Header()
|
return r.Writer.Header()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Before registers a function which is called just before the response is written.
|
||||||
|
func (r *Response) Before(fn func()) {
|
||||||
|
r.beforeFuncs = append(r.beforeFuncs, fn)
|
||||||
|
}
|
||||||
|
|
||||||
// WriteHeader sends an HTTP response header with status code. If WriteHeader is
|
// WriteHeader sends an HTTP response header with status code. If WriteHeader is
|
||||||
// not called explicitly, the first call to Write will trigger an implicit
|
// not called explicitly, the first call to Write will trigger an implicit
|
||||||
// WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly
|
// WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly
|
||||||
@ -43,6 +49,9 @@ func (r *Response) WriteHeader(code int) {
|
|||||||
r.echo.Logger.Warn("response already committed")
|
r.echo.Logger.Warn("response already committed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
for _, fn := range r.beforeFuncs {
|
||||||
|
fn()
|
||||||
|
}
|
||||||
r.Status = code
|
r.Status = code
|
||||||
r.Writer.WriteHeader(code)
|
r.Writer.WriteHeader(code)
|
||||||
r.Committed = true
|
r.Committed = true
|
||||||
|
2
vendor/github.com/labstack/echo/router.go
generated
vendored
2
vendor/github.com/labstack/echo/router.go
generated
vendored
@ -394,7 +394,7 @@ func (r *Router) Find(method, path string, c Context) {
|
|||||||
if cn = cn.findChildByKind(akind); cn == nil {
|
if cn = cn.findChildByKind(akind); cn == nil {
|
||||||
if nn != nil {
|
if nn != nil {
|
||||||
cn = nn
|
cn = nn
|
||||||
nn = nil // Next
|
nn = cn.parent // Next (Issue #954)
|
||||||
search = ns
|
search = ns
|
||||||
if nk == pkind {
|
if nk == pkind {
|
||||||
goto Param
|
goto Param
|
||||||
|
12
vendor/github.com/labstack/echo/util_go17.go
generated
vendored
Normal file
12
vendor/github.com/labstack/echo/util_go17.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// +build go1.7, !go1.8
|
||||||
|
|
||||||
|
package echo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PathUnescape is wraps `url.QueryUnescape`
|
||||||
|
func PathUnescape(s string) (string, error) {
|
||||||
|
return url.QueryUnescape(s)
|
||||||
|
}
|
10
vendor/github.com/labstack/echo/util_go18.go
generated
vendored
Normal file
10
vendor/github.com/labstack/echo/util_go18.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// +build go1.8
|
||||||
|
|
||||||
|
package echo
|
||||||
|
|
||||||
|
import "net/url"
|
||||||
|
|
||||||
|
// PathUnescape is wraps `url.PathUnescape`
|
||||||
|
func PathUnescape(s string) (string, error) {
|
||||||
|
return url.PathUnescape(s)
|
||||||
|
}
|
20
vendor/github.com/matterbridge/slack/websocket_utils.go
generated
vendored
20
vendor/github.com/matterbridge/slack/websocket_utils.go
generated
vendored
@ -1,20 +0,0 @@
|
|||||||
package slack
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
var portMapping = map[string]string{"ws": "80", "wss": "443"}
|
|
||||||
|
|
||||||
func websocketizeURLPort(orig string) (string, error) {
|
|
||||||
urlObj, err := url.ParseRequestURI(orig)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
_, _, err = net.SplitHostPort(urlObj.Host)
|
|
||||||
if err != nil {
|
|
||||||
return urlObj.Scheme + "://" + urlObj.Host + ":" + portMapping[urlObj.Scheme] + urlObj.Path, nil
|
|
||||||
}
|
|
||||||
return orig, nil
|
|
||||||
}
|
|
@ -25,6 +25,7 @@ type AttachmentAction struct {
|
|||||||
SelectedOptions []AttachmentActionOption `json:"selected_options,omitempty"` // Optional. The first element of this array will be set as the pre-selected option for this menu.
|
SelectedOptions []AttachmentActionOption `json:"selected_options,omitempty"` // Optional. The first element of this array will be set as the pre-selected option for this menu.
|
||||||
OptionGroups []AttachmentActionOptionGroup `json:"option_groups,omitempty"` // Optional.
|
OptionGroups []AttachmentActionOptionGroup `json:"option_groups,omitempty"` // Optional.
|
||||||
Confirm *ConfirmationField `json:"confirm,omitempty"` // Optional.
|
Confirm *ConfirmationField `json:"confirm,omitempty"` // Optional.
|
||||||
|
URL string `json:"url,omitempty"` // Optional.
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttachmentActionOption the individual option to appear in action menu.
|
// AttachmentActionOption the individual option to appear in action menu.
|
||||||
@ -48,6 +49,9 @@ type AttachmentActionCallback struct {
|
|||||||
Channel Channel `json:"channel"`
|
Channel Channel `json:"channel"`
|
||||||
User User `json:"user"`
|
User User `json:"user"`
|
||||||
|
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
|
||||||
OriginalMessage Message `json:"original_message"`
|
OriginalMessage Message `json:"original_message"`
|
||||||
|
|
||||||
ActionTs string `json:"action_ts"`
|
ActionTs string `json:"action_ts"`
|
@ -38,51 +38,51 @@ func channelRequest(ctx context.Context, path string, values url.Values, debug b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ArchiveChannel archives the given channel
|
// ArchiveChannel archives the given channel
|
||||||
func (api *Client) ArchiveChannel(channel string) error {
|
// see https://api.slack.com/methods/channels.archive
|
||||||
return api.ArchiveChannelContext(context.Background(), channel)
|
func (api *Client) ArchiveChannel(channelID string) error {
|
||||||
|
return api.ArchiveChannelContext(context.Background(), channelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArchiveChannelContext archives the given channel with a custom context
|
// ArchiveChannelContext archives the given channel with a custom context
|
||||||
func (api *Client) ArchiveChannelContext(ctx context.Context, channel string) error {
|
// see https://api.slack.com/methods/channels.archive
|
||||||
|
func (api *Client) ArchiveChannelContext(ctx context.Context, channelID string) error {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
}
|
}
|
||||||
_, err := channelRequest(ctx, "channels.archive", values, api.debug)
|
_, err := channelRequest(ctx, "channels.archive", values, api.debug)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnarchiveChannel unarchives the given channel
|
// UnarchiveChannel unarchives the given channel
|
||||||
func (api *Client) UnarchiveChannel(channel string) error {
|
// see https://api.slack.com/methods/channels.unarchive
|
||||||
return api.UnarchiveChannelContext(context.Background(), channel)
|
func (api *Client) UnarchiveChannel(channelID string) error {
|
||||||
|
return api.UnarchiveChannelContext(context.Background(), channelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnarchiveChannelContext unarchives the given channel with a custom context
|
// UnarchiveChannelContext unarchives the given channel with a custom context
|
||||||
func (api *Client) UnarchiveChannelContext(ctx context.Context, channel string) error {
|
// see https://api.slack.com/methods/channels.unarchive
|
||||||
|
func (api *Client) UnarchiveChannelContext(ctx context.Context, channelID string) error {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
}
|
}
|
||||||
_, err := channelRequest(ctx, "channels.unarchive", values, api.debug)
|
_, err := channelRequest(ctx, "channels.unarchive", values, api.debug)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateChannel creates a channel with the given name and returns a *Channel
|
// CreateChannel creates a channel with the given name and returns a *Channel
|
||||||
func (api *Client) CreateChannel(channel string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.create
|
||||||
return api.CreateChannelContext(context.Background(), channel)
|
func (api *Client) CreateChannel(channelName string) (*Channel, error) {
|
||||||
|
return api.CreateChannelContext(context.Background(), channelName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateChannelContext creates a channel with the given name and returns a *Channel with a custom context
|
// CreateChannelContext creates a channel with the given name and returns a *Channel with a custom context
|
||||||
func (api *Client) CreateChannelContext(ctx context.Context, channel string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.create
|
||||||
|
func (api *Client) CreateChannelContext(ctx context.Context, channelName string) (*Channel, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"name": {channel},
|
"name": {channelName},
|
||||||
}
|
}
|
||||||
response, err := channelRequest(ctx, "channels.create", values, api.debug)
|
response, err := channelRequest(ctx, "channels.create", values, api.debug)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -92,15 +92,17 @@ func (api *Client) CreateChannelContext(ctx context.Context, channel string) (*C
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelHistory retrieves the channel history
|
// GetChannelHistory retrieves the channel history
|
||||||
func (api *Client) GetChannelHistory(channel string, params HistoryParameters) (*History, error) {
|
// see https://api.slack.com/methods/channels.history
|
||||||
return api.GetChannelHistoryContext(context.Background(), channel, params)
|
func (api *Client) GetChannelHistory(channelID string, params HistoryParameters) (*History, error) {
|
||||||
|
return api.GetChannelHistoryContext(context.Background(), channelID, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelHistoryContext retrieves the channel history with a custom context
|
// GetChannelHistoryContext retrieves the channel history with a custom context
|
||||||
func (api *Client) GetChannelHistoryContext(ctx context.Context, channel string, params HistoryParameters) (*History, error) {
|
// see https://api.slack.com/methods/channels.history
|
||||||
|
func (api *Client) GetChannelHistoryContext(ctx context.Context, channelID string, params HistoryParameters) (*History, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
}
|
}
|
||||||
if params.Latest != DEFAULT_HISTORY_LATEST {
|
if params.Latest != DEFAULT_HISTORY_LATEST {
|
||||||
values.Add("latest", params.Latest)
|
values.Add("latest", params.Latest)
|
||||||
@ -133,15 +135,17 @@ func (api *Client) GetChannelHistoryContext(ctx context.Context, channel string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelInfo retrieves the given channel
|
// GetChannelInfo retrieves the given channel
|
||||||
func (api *Client) GetChannelInfo(channel string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.info
|
||||||
return api.GetChannelInfoContext(context.Background(), channel)
|
func (api *Client) GetChannelInfo(channelID string) (*Channel, error) {
|
||||||
|
return api.GetChannelInfoContext(context.Background(), channelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelInfoContext retrieves the given channel with a custom context
|
// GetChannelInfoContext retrieves the given channel with a custom context
|
||||||
func (api *Client) GetChannelInfoContext(ctx context.Context, channel string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.info
|
||||||
|
func (api *Client) GetChannelInfoContext(ctx context.Context, channelID string) (*Channel, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
}
|
}
|
||||||
response, err := channelRequest(ctx, "channels.info", values, api.debug)
|
response, err := channelRequest(ctx, "channels.info", values, api.debug)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -151,15 +155,17 @@ func (api *Client) GetChannelInfoContext(ctx context.Context, channel string) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InviteUserToChannel invites a user to a given channel and returns a *Channel
|
// InviteUserToChannel invites a user to a given channel and returns a *Channel
|
||||||
func (api *Client) InviteUserToChannel(channel, user string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.invite
|
||||||
return api.InviteUserToChannelContext(context.Background(), channel, user)
|
func (api *Client) InviteUserToChannel(channelID, user string) (*Channel, error) {
|
||||||
|
return api.InviteUserToChannelContext(context.Background(), channelID, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InviteUserToChannelCustom invites a user to a given channel and returns a *Channel with a custom context
|
// InviteUserToChannelCustom invites a user to a given channel and returns a *Channel with a custom context
|
||||||
func (api *Client) InviteUserToChannelContext(ctx context.Context, channel, user string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.invite
|
||||||
|
func (api *Client) InviteUserToChannelContext(ctx context.Context, channelID, user string) (*Channel, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
"user": {user},
|
"user": {user},
|
||||||
}
|
}
|
||||||
response, err := channelRequest(ctx, "channels.invite", values, api.debug)
|
response, err := channelRequest(ctx, "channels.invite", values, api.debug)
|
||||||
@ -170,15 +176,17 @@ func (api *Client) InviteUserToChannelContext(ctx context.Context, channel, user
|
|||||||
}
|
}
|
||||||
|
|
||||||
// JoinChannel joins the currently authenticated user to a channel
|
// JoinChannel joins the currently authenticated user to a channel
|
||||||
func (api *Client) JoinChannel(channel string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.join
|
||||||
return api.JoinChannelContext(context.Background(), channel)
|
func (api *Client) JoinChannel(channelName string) (*Channel, error) {
|
||||||
|
return api.JoinChannelContext(context.Background(), channelName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinChannelContext joins the currently authenticated user to a channel with a custom context
|
// JoinChannelContext joins the currently authenticated user to a channel with a custom context
|
||||||
func (api *Client) JoinChannelContext(ctx context.Context, channel string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.join
|
||||||
|
func (api *Client) JoinChannelContext(ctx context.Context, channelName string) (*Channel, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"name": {channel},
|
"name": {channelName},
|
||||||
}
|
}
|
||||||
response, err := channelRequest(ctx, "channels.join", values, api.debug)
|
response, err := channelRequest(ctx, "channels.join", values, api.debug)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -188,15 +196,17 @@ func (api *Client) JoinChannelContext(ctx context.Context, channel string) (*Cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LeaveChannel makes the authenticated user leave the given channel
|
// LeaveChannel makes the authenticated user leave the given channel
|
||||||
func (api *Client) LeaveChannel(channel string) (bool, error) {
|
// see https://api.slack.com/methods/channels.leave
|
||||||
return api.LeaveChannelContext(context.Background(), channel)
|
func (api *Client) LeaveChannel(channelID string) (bool, error) {
|
||||||
|
return api.LeaveChannelContext(context.Background(), channelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LeaveChannelContext makes the authenticated user leave the given channel with a custom context
|
// LeaveChannelContext makes the authenticated user leave the given channel with a custom context
|
||||||
func (api *Client) LeaveChannelContext(ctx context.Context, channel string) (bool, error) {
|
// see https://api.slack.com/methods/channels.leave
|
||||||
|
func (api *Client) LeaveChannelContext(ctx context.Context, channelID string) (bool, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
}
|
}
|
||||||
response, err := channelRequest(ctx, "channels.leave", values, api.debug)
|
response, err := channelRequest(ctx, "channels.leave", values, api.debug)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -209,30 +219,31 @@ func (api *Client) LeaveChannelContext(ctx context.Context, channel string) (boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// KickUserFromChannel kicks a user from a given channel
|
// KickUserFromChannel kicks a user from a given channel
|
||||||
func (api *Client) KickUserFromChannel(channel, user string) error {
|
// see https://api.slack.com/methods/channels.kick
|
||||||
return api.KickUserFromChannelContext(context.Background(), channel, user)
|
func (api *Client) KickUserFromChannel(channelID, user string) error {
|
||||||
|
return api.KickUserFromChannelContext(context.Background(), channelID, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KickUserFromChannelContext kicks a user from a given channel with a custom context
|
// KickUserFromChannelContext kicks a user from a given channel with a custom context
|
||||||
func (api *Client) KickUserFromChannelContext(ctx context.Context, channel, user string) error {
|
// see https://api.slack.com/methods/channels.kick
|
||||||
|
func (api *Client) KickUserFromChannelContext(ctx context.Context, channelID, user string) error {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
"user": {user},
|
"user": {user},
|
||||||
}
|
}
|
||||||
_, err := channelRequest(ctx, "channels.kick", values, api.debug)
|
_, err := channelRequest(ctx, "channels.kick", values, api.debug)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChannels retrieves all the channels
|
// GetChannels retrieves all the channels
|
||||||
|
// see https://api.slack.com/methods/channels.list
|
||||||
func (api *Client) GetChannels(excludeArchived bool) ([]Channel, error) {
|
func (api *Client) GetChannels(excludeArchived bool) ([]Channel, error) {
|
||||||
return api.GetChannelsContext(context.Background(), excludeArchived)
|
return api.GetChannelsContext(context.Background(), excludeArchived)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelsContext retrieves all the channels with a custom context
|
// GetChannelsContext retrieves all the channels with a custom context
|
||||||
|
// see https://api.slack.com/methods/channels.list
|
||||||
func (api *Client) GetChannelsContext(ctx context.Context, excludeArchived bool) ([]Channel, error) {
|
func (api *Client) GetChannelsContext(ctx context.Context, excludeArchived bool) ([]Channel, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
@ -252,35 +263,36 @@ func (api *Client) GetChannelsContext(ctx context.Context, excludeArchived bool)
|
|||||||
// timer before making the call. In this way, any further updates needed during the timeout will not generate extra calls
|
// timer before making the call. In this way, any further updates needed during the timeout will not generate extra calls
|
||||||
// (just one per channel). This is useful for when reading scroll-back history, or following a busy live channel. A
|
// (just one per channel). This is useful for when reading scroll-back history, or following a busy live channel. A
|
||||||
// timeout of 5 seconds is a good starting point. Be sure to flush these calls on shutdown/logout.
|
// timeout of 5 seconds is a good starting point. Be sure to flush these calls on shutdown/logout.
|
||||||
func (api *Client) SetChannelReadMark(channel, ts string) error {
|
// see https://api.slack.com/methods/channels.mark
|
||||||
return api.SetChannelReadMarkContext(context.Background(), channel, ts)
|
func (api *Client) SetChannelReadMark(channelID, ts string) error {
|
||||||
|
return api.SetChannelReadMarkContext(context.Background(), channelID, ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetChannelReadMarkContext sets the read mark of a given channel to a specific point with a custom context
|
// SetChannelReadMarkContext sets the read mark of a given channel to a specific point with a custom context
|
||||||
// For more details see SetChannelReadMark documentation
|
// For more details see SetChannelReadMark documentation
|
||||||
func (api *Client) SetChannelReadMarkContext(ctx context.Context, channel, ts string) error {
|
// see https://api.slack.com/methods/channels.mark
|
||||||
|
func (api *Client) SetChannelReadMarkContext(ctx context.Context, channelID, ts string) error {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
"ts": {ts},
|
"ts": {ts},
|
||||||
}
|
}
|
||||||
_, err := channelRequest(ctx, "channels.mark", values, api.debug)
|
_, err := channelRequest(ctx, "channels.mark", values, api.debug)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenameChannel renames a given channel
|
// RenameChannel renames a given channel
|
||||||
func (api *Client) RenameChannel(channel, name string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.rename
|
||||||
return api.RenameChannelContext(context.Background(), channel, name)
|
func (api *Client) RenameChannel(channelID, name string) (*Channel, error) {
|
||||||
|
return api.RenameChannelContext(context.Background(), channelID, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenameChannelContext renames a given channel with a custom context
|
// RenameChannelContext renames a given channel with a custom context
|
||||||
func (api *Client) RenameChannelContext(ctx context.Context, channel, name string) (*Channel, error) {
|
// see https://api.slack.com/methods/channels.rename
|
||||||
|
func (api *Client) RenameChannelContext(ctx context.Context, channelID, name string) (*Channel, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
"name": {name},
|
"name": {name},
|
||||||
}
|
}
|
||||||
// XXX: the created entry in this call returns a string instead of a number
|
// XXX: the created entry in this call returns a string instead of a number
|
||||||
@ -293,15 +305,17 @@ func (api *Client) RenameChannelContext(ctx context.Context, channel, name strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetChannelPurpose sets the channel purpose and returns the purpose that was successfully set
|
// SetChannelPurpose sets the channel purpose and returns the purpose that was successfully set
|
||||||
func (api *Client) SetChannelPurpose(channel, purpose string) (string, error) {
|
// see https://api.slack.com/methods/channels.setPurpose
|
||||||
return api.SetChannelPurposeContext(context.Background(), channel, purpose)
|
func (api *Client) SetChannelPurpose(channelID, purpose string) (string, error) {
|
||||||
|
return api.SetChannelPurposeContext(context.Background(), channelID, purpose)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetChannelPurposeContext sets the channel purpose and returns the purpose that was successfully set with a custom context
|
// SetChannelPurposeContext sets the channel purpose and returns the purpose that was successfully set with a custom context
|
||||||
func (api *Client) SetChannelPurposeContext(ctx context.Context, channel, purpose string) (string, error) {
|
// see https://api.slack.com/methods/channels.setPurpose
|
||||||
|
func (api *Client) SetChannelPurposeContext(ctx context.Context, channelID, purpose string) (string, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
"purpose": {purpose},
|
"purpose": {purpose},
|
||||||
}
|
}
|
||||||
response, err := channelRequest(ctx, "channels.setPurpose", values, api.debug)
|
response, err := channelRequest(ctx, "channels.setPurpose", values, api.debug)
|
||||||
@ -312,15 +326,17 @@ func (api *Client) SetChannelPurposeContext(ctx context.Context, channel, purpos
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetChannelTopic sets the channel topic and returns the topic that was successfully set
|
// SetChannelTopic sets the channel topic and returns the topic that was successfully set
|
||||||
func (api *Client) SetChannelTopic(channel, topic string) (string, error) {
|
// see https://api.slack.com/methods/channels.setTopic
|
||||||
return api.SetChannelTopicContext(context.Background(), channel, topic)
|
func (api *Client) SetChannelTopic(channelID, topic string) (string, error) {
|
||||||
|
return api.SetChannelTopicContext(context.Background(), channelID, topic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetChannelTopicContext sets the channel topic and returns the topic that was successfully set with a custom context
|
// SetChannelTopicContext sets the channel topic and returns the topic that was successfully set with a custom context
|
||||||
func (api *Client) SetChannelTopicContext(ctx context.Context, channel, topic string) (string, error) {
|
// see https://api.slack.com/methods/channels.setTopic
|
||||||
|
func (api *Client) SetChannelTopicContext(ctx context.Context, channelID, topic string) (string, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
"topic": {topic},
|
"topic": {topic},
|
||||||
}
|
}
|
||||||
response, err := channelRequest(ctx, "channels.setTopic", values, api.debug)
|
response, err := channelRequest(ctx, "channels.setTopic", values, api.debug)
|
||||||
@ -331,15 +347,17 @@ func (api *Client) SetChannelTopicContext(ctx context.Context, channel, topic st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelReplies gets an entire thread (a message plus all the messages in reply to it).
|
// GetChannelReplies gets an entire thread (a message plus all the messages in reply to it).
|
||||||
func (api *Client) GetChannelReplies(channel, thread_ts string) ([]Message, error) {
|
// see https://api.slack.com/methods/channels.replies
|
||||||
return api.GetChannelRepliesContext(context.Background(), channel, thread_ts)
|
func (api *Client) GetChannelReplies(channelID, thread_ts string) ([]Message, error) {
|
||||||
|
return api.GetChannelRepliesContext(context.Background(), channelID, thread_ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelRepliesContext gets an entire thread (a message plus all the messages in reply to it) with a custom context
|
// GetChannelRepliesContext gets an entire thread (a message plus all the messages in reply to it) with a custom context
|
||||||
func (api *Client) GetChannelRepliesContext(ctx context.Context, channel, thread_ts string) ([]Message, error) {
|
// see https://api.slack.com/methods/channels.replies
|
||||||
|
func (api *Client) GetChannelRepliesContext(ctx context.Context, channelID, thread_ts string) ([]Message, error) {
|
||||||
values := url.Values{
|
values := url.Values{
|
||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
"channel": {channel},
|
"channel": {channelID},
|
||||||
"thread_ts": {thread_ts},
|
"thread_ts": {thread_ts},
|
||||||
}
|
}
|
||||||
response, err := channelRequest(ctx, "channels.replies", values, api.debug)
|
response, err := channelRequest(ctx, "channels.replies", values, api.debug)
|
62
vendor/github.com/matterbridge/slack/chat.go → vendor/github.com/nlopes/slack/chat.go
generated
vendored
62
vendor/github.com/matterbridge/slack/chat.go → vendor/github.com/nlopes/slack/chat.go
generated
vendored
@ -11,6 +11,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
DEFAULT_MESSAGE_USERNAME = ""
|
DEFAULT_MESSAGE_USERNAME = ""
|
||||||
DEFAULT_MESSAGE_THREAD_TIMESTAMP = ""
|
DEFAULT_MESSAGE_THREAD_TIMESTAMP = ""
|
||||||
|
DEFAULT_MESSAGE_REPLY_BROADCAST = false
|
||||||
DEFAULT_MESSAGE_ASUSER = false
|
DEFAULT_MESSAGE_ASUSER = false
|
||||||
DEFAULT_MESSAGE_PARSE = ""
|
DEFAULT_MESSAGE_PARSE = ""
|
||||||
DEFAULT_MESSAGE_LINK_NAMES = 0
|
DEFAULT_MESSAGE_LINK_NAMES = 0
|
||||||
@ -36,6 +37,7 @@ type PostMessageParameters struct {
|
|||||||
AsUser bool `json:"as_user"`
|
AsUser bool `json:"as_user"`
|
||||||
Parse string `json:"parse"`
|
Parse string `json:"parse"`
|
||||||
ThreadTimestamp string `json:"thread_ts"`
|
ThreadTimestamp string `json:"thread_ts"`
|
||||||
|
ReplyBroadcast bool `json:"reply_broadcast"`
|
||||||
LinkNames int `json:"link_names"`
|
LinkNames int `json:"link_names"`
|
||||||
Attachments []Attachment `json:"attachments"`
|
Attachments []Attachment `json:"attachments"`
|
||||||
UnfurlLinks bool `json:"unfurl_links"`
|
UnfurlLinks bool `json:"unfurl_links"`
|
||||||
@ -44,12 +46,17 @@ type PostMessageParameters struct {
|
|||||||
IconEmoji string `json:"icon_emoji"`
|
IconEmoji string `json:"icon_emoji"`
|
||||||
Markdown bool `json:"mrkdwn,omitempty"`
|
Markdown bool `json:"mrkdwn,omitempty"`
|
||||||
EscapeText bool `json:"escape_text"`
|
EscapeText bool `json:"escape_text"`
|
||||||
|
|
||||||
|
// chat.postEphemeral support
|
||||||
|
Channel string `json:"channel"`
|
||||||
|
User string `json:"user"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPostMessageParameters provides an instance of PostMessageParameters with all the sane default values set
|
// NewPostMessageParameters provides an instance of PostMessageParameters with all the sane default values set
|
||||||
func NewPostMessageParameters() PostMessageParameters {
|
func NewPostMessageParameters() PostMessageParameters {
|
||||||
return PostMessageParameters{
|
return PostMessageParameters{
|
||||||
Username: DEFAULT_MESSAGE_USERNAME,
|
Username: DEFAULT_MESSAGE_USERNAME,
|
||||||
|
User: DEFAULT_MESSAGE_USERNAME,
|
||||||
AsUser: DEFAULT_MESSAGE_ASUSER,
|
AsUser: DEFAULT_MESSAGE_ASUSER,
|
||||||
Parse: DEFAULT_MESSAGE_PARSE,
|
Parse: DEFAULT_MESSAGE_PARSE,
|
||||||
LinkNames: DEFAULT_MESSAGE_LINK_NAMES,
|
LinkNames: DEFAULT_MESSAGE_LINK_NAMES,
|
||||||
@ -102,6 +109,37 @@ func (api *Client) PostMessageContext(ctx context.Context, channel, text string,
|
|||||||
return respChannel, respTimestamp, err
|
return respChannel, respTimestamp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PostEphemeral sends an ephemeral message to a user in a channel.
|
||||||
|
// Message is escaped by default according to https://api.slack.com/docs/formatting
|
||||||
|
// Use http://davestevens.github.io/slack-message-builder/ to help crafting your message.
|
||||||
|
func (api *Client) PostEphemeral(channel, userID string, options ...MsgOption) (string, error) {
|
||||||
|
options = append(options, MsgOptionPostEphemeral())
|
||||||
|
return api.PostEphemeralContext(
|
||||||
|
context.Background(),
|
||||||
|
channel,
|
||||||
|
userID,
|
||||||
|
options...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostEphemeralContext sends an ephemeal message to a user in a channel with a custom context
|
||||||
|
// For more details, see PostEphemeral documentation
|
||||||
|
func (api *Client) PostEphemeralContext(ctx context.Context, channel, userID string, options ...MsgOption) (string, error) {
|
||||||
|
path, values, err := ApplyMsgOptions(api.config.token, channel, options...)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
values.Add("user", userID)
|
||||||
|
|
||||||
|
response, err := chatRequest(ctx, path, values, api.debug)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Timestamp, nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateMessage updates a message in a channel
|
// UpdateMessage updates a message in a channel
|
||||||
func (api *Client) UpdateMessage(channel, timestamp, text string) (string, string, string, error) {
|
func (api *Client) UpdateMessage(channel, timestamp, text string) (string, string, string, error) {
|
||||||
return api.UpdateMessageContext(context.Background(), channel, timestamp, text)
|
return api.UpdateMessageContext(context.Background(), channel, timestamp, text)
|
||||||
@ -171,9 +209,10 @@ func chatRequest(ctx context.Context, path string, values url.Values, debug bool
|
|||||||
type sendMode string
|
type sendMode string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
chatUpdate sendMode = "chat.update"
|
chatUpdate sendMode = "chat.update"
|
||||||
chatPostMessage sendMode = "chat.postMessage"
|
chatPostMessage sendMode = "chat.postMessage"
|
||||||
chatDelete sendMode = "chat.delete"
|
chatDelete sendMode = "chat.delete"
|
||||||
|
chatPostEphemeral sendMode = "chat.postEphemeral"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sendConfig struct {
|
type sendConfig struct {
|
||||||
@ -193,6 +232,15 @@ func MsgOptionPost() MsgOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MsgOptionPostEphemeral posts an ephemeral message
|
||||||
|
func MsgOptionPostEphemeral() MsgOption {
|
||||||
|
return func(config *sendConfig) error {
|
||||||
|
config.mode = chatPostEphemeral
|
||||||
|
config.values.Del("ts")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MsgOptionUpdate updates a message based on the timestamp.
|
// MsgOptionUpdate updates a message based on the timestamp.
|
||||||
func MsgOptionUpdate(timestamp string) MsgOption {
|
func MsgOptionUpdate(timestamp string) MsgOption {
|
||||||
return func(config *sendConfig) error {
|
return func(config *sendConfig) error {
|
||||||
@ -279,6 +327,11 @@ func MsgOptionPostMessageParameters(params PostMessageParameters) MsgOption {
|
|||||||
config.values.Set("username", string(params.Username))
|
config.values.Set("username", string(params.Username))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// chat.postEphemeral support
|
||||||
|
if params.User != DEFAULT_MESSAGE_USERNAME {
|
||||||
|
config.values.Set("user", params.User)
|
||||||
|
}
|
||||||
|
|
||||||
// never generates an error.
|
// never generates an error.
|
||||||
MsgOptionAsUser(params.AsUser)(config)
|
MsgOptionAsUser(params.AsUser)(config)
|
||||||
|
|
||||||
@ -314,6 +367,9 @@ func MsgOptionPostMessageParameters(params PostMessageParameters) MsgOption {
|
|||||||
if params.ThreadTimestamp != DEFAULT_MESSAGE_THREAD_TIMESTAMP {
|
if params.ThreadTimestamp != DEFAULT_MESSAGE_THREAD_TIMESTAMP {
|
||||||
config.values.Set("thread_ts", params.ThreadTimestamp)
|
config.values.Set("thread_ts", params.ThreadTimestamp)
|
||||||
}
|
}
|
||||||
|
if params.ReplyBroadcast != DEFAULT_MESSAGE_REPLY_BROADCAST {
|
||||||
|
config.values.Set("reply_broadcast", "true")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
0
vendor/github.com/matterbridge/slack/dnd.go → vendor/github.com/nlopes/slack/dnd.go
generated
vendored
0
vendor/github.com/matterbridge/slack/dnd.go → vendor/github.com/nlopes/slack/dnd.go
generated
vendored
21
vendor/github.com/nlopes/slack/examples/channels/channels.go
generated
vendored
Normal file
21
vendor/github.com/nlopes/slack/examples/channels/channels.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
api := slack.New("YOUR_TOKEN_HERE")
|
||||||
|
channels, err := api.GetChannels(false)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, channel := range channels {
|
||||||
|
fmt.Println(channel.Name)
|
||||||
|
// channel is of type conversation & groupConversation
|
||||||
|
// see all available methods in `conversation.go`
|
||||||
|
}
|
||||||
|
}
|
30
vendor/github.com/nlopes/slack/examples/files/files.go
generated
vendored
Normal file
30
vendor/github.com/nlopes/slack/examples/files/files.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
api := slack.New("YOUR_TOKEN_HERE")
|
||||||
|
params := slack.FileUploadParameters{
|
||||||
|
Title: "Batman Example",
|
||||||
|
//Filetype: "txt",
|
||||||
|
File: "example.txt",
|
||||||
|
//Content: "Nan Nan Nan Nan Nan Nan Nan Nan Batman",
|
||||||
|
}
|
||||||
|
file, err := api.UploadFile(params)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("Name: %s, URL: %s\n", file.Name, file.URL)
|
||||||
|
|
||||||
|
err = api.DeleteFile(file.ID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("File %s deleted successfully.\n", file.Name)
|
||||||
|
}
|
22
vendor/github.com/nlopes/slack/examples/groups/groups.go
generated
vendored
Normal file
22
vendor/github.com/nlopes/slack/examples/groups/groups.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
api := slack.New("YOUR_TOKEN_HERE")
|
||||||
|
// If you set debugging, it will log all requests to the console
|
||||||
|
// Useful when encountering issues
|
||||||
|
// api.SetDebug(true)
|
||||||
|
groups, err := api.GetGroups(false)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, group := range groups {
|
||||||
|
fmt.Printf("ID: %s, Name: %s\n", group.ID, group.Name)
|
||||||
|
}
|
||||||
|
}
|
21
vendor/github.com/nlopes/slack/examples/ims/ims.go
generated
vendored
Normal file
21
vendor/github.com/nlopes/slack/examples/ims/ims.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
api := slack.New("YOUR_TOKEN_HERE")
|
||||||
|
|
||||||
|
userID := "USER_ID"
|
||||||
|
|
||||||
|
_, _, channelID, err := api.OpenIMChannel(userID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
api.PostMessage(channelID, "Hello World!", slack.PostMessageParameters{})
|
||||||
|
}
|
32
vendor/github.com/nlopes/slack/examples/messages/messages.go
generated
vendored
Normal file
32
vendor/github.com/nlopes/slack/examples/messages/messages.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
api := slack.New("YOUR_TOKEN_HERE")
|
||||||
|
params := slack.PostMessageParameters{}
|
||||||
|
attachment := slack.Attachment{
|
||||||
|
Pretext: "some pretext",
|
||||||
|
Text: "some text",
|
||||||
|
// Uncomment the following part to send a field too
|
||||||
|
/*
|
||||||
|
Fields: []slack.AttachmentField{
|
||||||
|
slack.AttachmentField{
|
||||||
|
Title: "a",
|
||||||
|
Value: "no",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
params.Attachments = []slack.Attachment{attachment}
|
||||||
|
channelID, timestamp, err := api.PostMessage("CHANNEL_ID", "Some text", params)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("Message successfully sent to channel %s at %s", channelID, timestamp)
|
||||||
|
}
|
123
vendor/github.com/nlopes/slack/examples/pins/pins.go
generated
vendored
Normal file
123
vendor/github.com/nlopes/slack/examples/pins/pins.go
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
WARNING: This example is destructive in the sense that it create a channel called testpinning
|
||||||
|
*/
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
apiToken string
|
||||||
|
debug bool
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.StringVar(&apiToken, "token", "YOUR_TOKEN_HERE", "Your Slack API Token")
|
||||||
|
flag.BoolVar(&debug, "debug", false, "Show JSON output")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
api := slack.New(apiToken)
|
||||||
|
if debug {
|
||||||
|
api.SetDebug(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
postAsUserName string
|
||||||
|
postAsUserID string
|
||||||
|
postToChannelID string
|
||||||
|
)
|
||||||
|
|
||||||
|
// Find the user to post as.
|
||||||
|
authTest, err := api.AuthTest()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting channels: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
channelName := "testpinning"
|
||||||
|
|
||||||
|
// Post as the authenticated user.
|
||||||
|
postAsUserName = authTest.User
|
||||||
|
postAsUserID = authTest.UserID
|
||||||
|
|
||||||
|
// Create a temporary channel
|
||||||
|
channel, err := api.CreateChannel(channelName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// If the channel exists, that means we just need to unarchive it
|
||||||
|
if err.Error() == "name_taken" {
|
||||||
|
err = nil
|
||||||
|
channels, err := api.GetChannels(false)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Could not retrieve channels")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, archivedChannel := range channels {
|
||||||
|
if archivedChannel.Name == channelName {
|
||||||
|
if archivedChannel.IsArchived {
|
||||||
|
err = api.UnarchiveChannel(archivedChannel.ID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Could not unarchive %s: %s\n", archivedChannel.ID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
channel = &archivedChannel
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error setting test channel for pinning: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
postToChannelID = channel.ID
|
||||||
|
|
||||||
|
fmt.Printf("Posting as %s (%s) in channel %s\n", postAsUserName, postAsUserID, postToChannelID)
|
||||||
|
|
||||||
|
// Post a message.
|
||||||
|
postParams := slack.PostMessageParameters{}
|
||||||
|
channelID, timestamp, err := api.PostMessage(postToChannelID, "Is this any good?", postParams)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error posting message: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab a reference to the message.
|
||||||
|
msgRef := slack.NewRefToMessage(channelID, timestamp)
|
||||||
|
|
||||||
|
// Add message pin to channel
|
||||||
|
if err := api.AddPin(channelID, msgRef); err != nil {
|
||||||
|
fmt.Printf("Error adding pin: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all of the users pins.
|
||||||
|
listPins, _, err := api.ListPins(channelID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error listing pins: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Printf("All pins by %s...\n", authTest.User)
|
||||||
|
for _, item := range listPins {
|
||||||
|
fmt.Printf(" > Item type: %s\n", item.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the pin.
|
||||||
|
err = api.RemovePin(channelID, msgRef)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error remove pin: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = api.ArchiveChannel(channelID); err != nil {
|
||||||
|
fmt.Printf("Error archiving channel: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
126
vendor/github.com/nlopes/slack/examples/reactions/reactions.go
generated
vendored
Normal file
126
vendor/github.com/nlopes/slack/examples/reactions/reactions.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
apiToken string
|
||||||
|
debug bool
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.StringVar(&apiToken, "token", "YOUR_TOKEN_HERE", "Your Slack API Token")
|
||||||
|
flag.BoolVar(&debug, "debug", false, "Show JSON output")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
api := slack.New(apiToken)
|
||||||
|
if debug {
|
||||||
|
api.SetDebug(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
postAsUserName string
|
||||||
|
postAsUserID string
|
||||||
|
postToUserName string
|
||||||
|
postToUserID string
|
||||||
|
postToChannelID string
|
||||||
|
)
|
||||||
|
|
||||||
|
// Find the user to post as.
|
||||||
|
authTest, err := api.AuthTest()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting channels: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post as the authenticated user.
|
||||||
|
postAsUserName = authTest.User
|
||||||
|
postAsUserID = authTest.UserID
|
||||||
|
|
||||||
|
// Posting to DM with self causes a conversation with slackbot.
|
||||||
|
postToUserName = authTest.User
|
||||||
|
postToUserID = authTest.UserID
|
||||||
|
|
||||||
|
// Find the channel.
|
||||||
|
_, _, chanID, err := api.OpenIMChannel(postToUserID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error opening IM: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
postToChannelID = chanID
|
||||||
|
|
||||||
|
fmt.Printf("Posting as %s (%s) in DM with %s (%s), channel %s\n", postAsUserName, postAsUserID, postToUserName, postToUserID, postToChannelID)
|
||||||
|
|
||||||
|
// Post a message.
|
||||||
|
postParams := slack.PostMessageParameters{}
|
||||||
|
channelID, timestamp, err := api.PostMessage(postToChannelID, "Is this any good?", postParams)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error posting message: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab a reference to the message.
|
||||||
|
msgRef := slack.NewRefToMessage(channelID, timestamp)
|
||||||
|
|
||||||
|
// React with :+1:
|
||||||
|
if err := api.AddReaction("+1", msgRef); err != nil {
|
||||||
|
fmt.Printf("Error adding reaction: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// React with :-1:
|
||||||
|
if err := api.AddReaction("cry", msgRef); err != nil {
|
||||||
|
fmt.Printf("Error adding reaction: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all reactions on the message.
|
||||||
|
msgReactions, err := api.GetReactions(msgRef, slack.NewGetReactionsParameters())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting reactions: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Printf("%d reactions to message...\n", len(msgReactions))
|
||||||
|
for _, r := range msgReactions {
|
||||||
|
fmt.Printf(" %d users say %s\n", r.Count, r.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all of the users reactions.
|
||||||
|
listReactions, _, err := api.ListReactions(slack.NewListReactionsParameters())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error listing reactions: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Printf("All reactions by %s...\n", authTest.User)
|
||||||
|
for _, item := range listReactions {
|
||||||
|
fmt.Printf("%d on a %s...\n", len(item.Reactions), item.Type)
|
||||||
|
for _, r := range item.Reactions {
|
||||||
|
fmt.Printf(" %s (along with %d others)\n", r.Name, r.Count-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the :cry: reaction.
|
||||||
|
err = api.RemoveReaction("cry", msgRef)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error remove reaction: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all reactions on the message.
|
||||||
|
msgReactions, err = api.GetReactions(msgRef, slack.NewGetReactionsParameters())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting reactions: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
fmt.Printf("%d reactions to message after removing cry...\n", len(msgReactions))
|
||||||
|
for _, r := range msgReactions {
|
||||||
|
fmt.Printf(" %d users say %s\n", r.Count, r.Name)
|
||||||
|
}
|
||||||
|
}
|
46
vendor/github.com/nlopes/slack/examples/stars/stars.go
generated
vendored
Normal file
46
vendor/github.com/nlopes/slack/examples/stars/stars.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
apiToken string
|
||||||
|
debug bool
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.StringVar(&apiToken, "token", "YOUR_TOKEN_HERE", "Your Slack API Token")
|
||||||
|
flag.BoolVar(&debug, "debug", false, "Show JSON output")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
api := slack.New(apiToken)
|
||||||
|
if debug {
|
||||||
|
api.SetDebug(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all stars for the usr.
|
||||||
|
params := slack.NewStarsParameters()
|
||||||
|
starredItems, _, err := api.GetStarred(params)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error getting stars: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, s := range starredItems {
|
||||||
|
var desc string
|
||||||
|
switch s.Type {
|
||||||
|
case slack.TYPE_MESSAGE:
|
||||||
|
desc = s.Message.Text
|
||||||
|
case slack.TYPE_FILE:
|
||||||
|
desc = s.File.Name
|
||||||
|
case slack.TYPE_FILE_COMMENT:
|
||||||
|
desc = s.File.Name + " - " + s.Comment.Comment
|
||||||
|
case slack.TYPE_CHANNEL, slack.TYPE_IM, slack.TYPE_GROUP:
|
||||||
|
desc = s.Channel
|
||||||
|
}
|
||||||
|
fmt.Printf("Starred %s: %s\n", s.Type, desc)
|
||||||
|
}
|
||||||
|
}
|
25
vendor/github.com/nlopes/slack/examples/team/team.go
generated
vendored
Normal file
25
vendor/github.com/nlopes/slack/examples/team/team.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
api := slack.New("YOUR_TOKEN_HERE")
|
||||||
|
//Example for single user
|
||||||
|
billingActive, err := api.GetBillableInfo("U023BECGF")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("ID: U023BECGF, BillingActive: %v\n\n\n", billingActive["U023BECGF"])
|
||||||
|
|
||||||
|
//Example for team
|
||||||
|
billingActiveForTeam, _ := api.GetBillableInfoForTeam()
|
||||||
|
for id, value := range billingActiveForTeam {
|
||||||
|
fmt.Printf("ID: %v, BillingActive: %v\n", id, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
17
vendor/github.com/nlopes/slack/examples/users/users.go
generated
vendored
Normal file
17
vendor/github.com/nlopes/slack/examples/users/users.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
api := slack.New("YOUR_TOKEN_HERE")
|
||||||
|
user, err := api.GetUserInfo("U023BECGF")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("ID: %s, Fullname: %s, Email: %s\n", user.ID, user.Profile.RealName, user.Profile.Email)
|
||||||
|
}
|
54
vendor/github.com/nlopes/slack/examples/websocket/websocket.go
generated
vendored
Normal file
54
vendor/github.com/nlopes/slack/examples/websocket/websocket.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/nlopes/slack"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
api := slack.New("YOUR TOKEN HERE")
|
||||||
|
logger := log.New(os.Stdout, "slack-bot: ", log.Lshortfile|log.LstdFlags)
|
||||||
|
slack.SetLogger(logger)
|
||||||
|
api.SetDebug(true)
|
||||||
|
|
||||||
|
rtm := api.NewRTM()
|
||||||
|
go rtm.ManageConnection()
|
||||||
|
|
||||||
|
for msg := range rtm.IncomingEvents {
|
||||||
|
fmt.Print("Event Received: ")
|
||||||
|
switch ev := msg.Data.(type) {
|
||||||
|
case *slack.HelloEvent:
|
||||||
|
// Ignore hello
|
||||||
|
|
||||||
|
case *slack.ConnectedEvent:
|
||||||
|
fmt.Println("Infos:", ev.Info)
|
||||||
|
fmt.Println("Connection counter:", ev.ConnectionCount)
|
||||||
|
// Replace C2147483705 with your Channel ID
|
||||||
|
rtm.SendMessage(rtm.NewOutgoingMessage("Hello world", "C2147483705"))
|
||||||
|
|
||||||
|
case *slack.MessageEvent:
|
||||||
|
fmt.Printf("Message: %v\n", ev)
|
||||||
|
|
||||||
|
case *slack.PresenceChangeEvent:
|
||||||
|
fmt.Printf("Presence Change: %v\n", ev)
|
||||||
|
|
||||||
|
case *slack.LatencyReport:
|
||||||
|
fmt.Printf("Current latency: %v\n", ev.Value)
|
||||||
|
|
||||||
|
case *slack.RTMError:
|
||||||
|
fmt.Printf("Error: %s\n", ev.Error())
|
||||||
|
|
||||||
|
case *slack.InvalidAuthEvent:
|
||||||
|
fmt.Printf("Invalid credentials")
|
||||||
|
return
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
// Ignore other events..
|
||||||
|
// fmt.Printf("Unexpected: %v\n", msg.Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -267,10 +267,7 @@ func (api *Client) DeleteFileContext(ctx context.Context, fileID string) error {
|
|||||||
"file": {fileID},
|
"file": {fileID},
|
||||||
}
|
}
|
||||||
_, err := fileRequest(ctx, "files.delete", values, api.debug)
|
_, err := fileRequest(ctx, "files.delete", values, api.debug)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -208,10 +208,7 @@ func (api *Client) LeaveGroupContext(ctx context.Context, group string) error {
|
|||||||
"channel": {group},
|
"channel": {group},
|
||||||
}
|
}
|
||||||
_, err := groupRequest(ctx, "groups.leave", values, api.debug)
|
_, err := groupRequest(ctx, "groups.leave", values, api.debug)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// KickUserFromGroup kicks a user from a group
|
// KickUserFromGroup kicks a user from a group
|
||||||
@ -227,10 +224,7 @@ func (api *Client) KickUserFromGroupContext(ctx context.Context, group, user str
|
|||||||
"user": {user},
|
"user": {user},
|
||||||
}
|
}
|
||||||
_, err := groupRequest(ctx, "groups.kick", values, api.debug)
|
_, err := groupRequest(ctx, "groups.kick", values, api.debug)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGroups retrieves all groups
|
// GetGroups retrieves all groups
|
||||||
@ -289,10 +283,7 @@ func (api *Client) SetGroupReadMarkContext(ctx context.Context, group, ts string
|
|||||||
"ts": {ts},
|
"ts": {ts},
|
||||||
}
|
}
|
||||||
_, err := groupRequest(ctx, "groups.mark", values, api.debug)
|
_, err := groupRequest(ctx, "groups.mark", values, api.debug)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenGroup opens a private group
|
// OpenGroup opens a private group
|
0
vendor/github.com/matterbridge/slack/im.go → vendor/github.com/nlopes/slack/im.go
generated
vendored
0
vendor/github.com/matterbridge/slack/im.go → vendor/github.com/nlopes/slack/im.go
generated
vendored
@ -3,6 +3,7 @@ package slack
|
|||||||
// OutgoingMessage is used for the realtime API, and seems incomplete.
|
// OutgoingMessage is used for the realtime API, and seems incomplete.
|
||||||
type OutgoingMessage struct {
|
type OutgoingMessage struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
|
// channel ID
|
||||||
Channel string `json:"channel,omitempty"`
|
Channel string `json:"channel,omitempty"`
|
||||||
Text string `json:"text,omitempty"`
|
Text string `json:"text,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
@ -121,12 +122,12 @@ type Pong struct {
|
|||||||
// NewOutgoingMessage prepares an OutgoingMessage that the user can
|
// NewOutgoingMessage prepares an OutgoingMessage that the user can
|
||||||
// use to send a message. Use this function to properly set the
|
// use to send a message. Use this function to properly set the
|
||||||
// messageID.
|
// messageID.
|
||||||
func (rtm *RTM) NewOutgoingMessage(text string, channel string) *OutgoingMessage {
|
func (rtm *RTM) NewOutgoingMessage(text string, channelID string) *OutgoingMessage {
|
||||||
id := rtm.idGen.Next()
|
id := rtm.idGen.Next()
|
||||||
return &OutgoingMessage{
|
return &OutgoingMessage{
|
||||||
ID: id,
|
ID: id,
|
||||||
Type: "message",
|
Type: "message",
|
||||||
Channel: channel,
|
Channel: channelID,
|
||||||
Text: text,
|
Text: text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,11 +135,11 @@ func (rtm *RTM) NewOutgoingMessage(text string, channel string) *OutgoingMessage
|
|||||||
// NewTypingMessage prepares an OutgoingMessage that the user can
|
// NewTypingMessage prepares an OutgoingMessage that the user can
|
||||||
// use to send as a typing indicator. Use this function to properly set the
|
// use to send as a typing indicator. Use this function to properly set the
|
||||||
// messageID.
|
// messageID.
|
||||||
func (rtm *RTM) NewTypingMessage(channel string) *OutgoingMessage {
|
func (rtm *RTM) NewTypingMessage(channelID string) *OutgoingMessage {
|
||||||
id := rtm.idGen.Next()
|
id := rtm.idGen.Next()
|
||||||
return &OutgoingMessage{
|
return &OutgoingMessage{
|
||||||
ID: id,
|
ID: id,
|
||||||
Type: "typing",
|
Type: "typing",
|
||||||
Channel: channel,
|
Channel: channelID,
|
||||||
}
|
}
|
||||||
}
|
}
|
36
vendor/github.com/matterbridge/slack/misc.go → vendor/github.com/nlopes/slack/misc.go
generated
vendored
36
vendor/github.com/matterbridge/slack/misc.go → vendor/github.com/nlopes/slack/misc.go
generated
vendored
@ -13,6 +13,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -42,6 +43,14 @@ func (s WebError) Error() string {
|
|||||||
return string(s)
|
return string(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RateLimitedError struct {
|
||||||
|
RetryAfter time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RateLimitedError) Error() string {
|
||||||
|
return fmt.Sprintf("Slack rate limit exceeded, retry after %s", e.RetryAfter)
|
||||||
|
}
|
||||||
|
|
||||||
func fileUploadReq(ctx context.Context, path, fieldname, filename string, values url.Values, r io.Reader) (*http.Request, error) {
|
func fileUploadReq(ctx context.Context, path, fieldname, filename string, values url.Values, r io.Reader) (*http.Request, error) {
|
||||||
body := &bytes.Buffer{}
|
body := &bytes.Buffer{}
|
||||||
wr := multipart.NewWriter(body)
|
wr := multipart.NewWriter(body)
|
||||||
@ -79,12 +88,7 @@ func parseResponseBody(body io.ReadCloser, intf *interface{}, debug bool) error
|
|||||||
logger.Printf("parseResponseBody: %s\n", string(response))
|
logger.Printf("parseResponseBody: %s\n", string(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(response, &intf)
|
return json.Unmarshal(response, &intf)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func postLocalWithMultipartResponse(ctx context.Context, path, fpath, fieldname string, values url.Values, intf interface{}, debug bool) error {
|
func postLocalWithMultipartResponse(ctx context.Context, path, fpath, fieldname string, values url.Values, intf interface{}, debug bool) error {
|
||||||
@ -112,8 +116,16 @@ func postWithMultipartResponse(ctx context.Context, path, name, fieldname string
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests {
|
||||||
|
retry, err := strconv.ParseInt(resp.Header.Get("Retry-After"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &RateLimitedError{time.Duration(retry) * time.Second}
|
||||||
|
}
|
||||||
|
|
||||||
// Slack seems to send an HTML body along with 5xx error codes. Don't parse it.
|
// Slack seems to send an HTML body along with 5xx error codes. Don't parse it.
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != http.StatusOK {
|
||||||
logResponse(resp, debug)
|
logResponse(resp, debug)
|
||||||
return fmt.Errorf("Slack server error: %s.", resp.Status)
|
return fmt.Errorf("Slack server error: %s.", resp.Status)
|
||||||
}
|
}
|
||||||
@ -136,8 +148,16 @@ func postForm(ctx context.Context, endpoint string, values url.Values, intf inte
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests {
|
||||||
|
retry, err := strconv.ParseInt(resp.Header.Get("Retry-After"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &RateLimitedError{time.Duration(retry) * time.Second}
|
||||||
|
}
|
||||||
|
|
||||||
// Slack seems to send an HTML body along with 5xx error codes. Don't parse it.
|
// Slack seems to send an HTML body along with 5xx error codes. Don't parse it.
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != http.StatusOK {
|
||||||
logResponse(resp, debug)
|
logResponse(resp, debug)
|
||||||
return fmt.Errorf("Slack server error: %s.", resp.Status)
|
return fmt.Errorf("Slack server error: %s.", resp.Status)
|
||||||
}
|
}
|
23
vendor/github.com/matterbridge/slack/rtm.go → vendor/github.com/nlopes/slack/rtm.go
generated
vendored
23
vendor/github.com/matterbridge/slack/rtm.go → vendor/github.com/nlopes/slack/rtm.go
generated
vendored
@ -27,17 +27,8 @@ func (api *Client) StartRTMContext(ctx context.Context) (info *Info, websocketUR
|
|||||||
if !response.Ok {
|
if !response.Ok {
|
||||||
return nil, "", response.Error
|
return nil, "", response.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// websocket.Dial does not accept url without the port (yet)
|
|
||||||
// Fixed by: https://github.com/golang/net/commit/5058c78c3627b31e484a81463acd51c7cecc06f3
|
|
||||||
// but slack returns the address with no port, so we have to fix it
|
|
||||||
api.Debugln("Using URL:", response.Info.URL)
|
api.Debugln("Using URL:", response.Info.URL)
|
||||||
websocketURL, err = websocketizeURLPort(response.Info.URL)
|
return &response.Info, response.Info.URL, nil
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("parsing response URL: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.Info, websocketURL, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectRTM calls the "rtm.connect" endpoint and returns the provided URL and the compact Info block.
|
// ConnectRTM calls the "rtm.connect" endpoint and returns the provided URL and the compact Info block.
|
||||||
@ -59,17 +50,8 @@ func (api *Client) ConnectRTMContext(ctx context.Context) (info *Info, websocket
|
|||||||
if !response.Ok {
|
if !response.Ok {
|
||||||
return nil, "", response.Error
|
return nil, "", response.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// websocket.Dial does not accept url without the port (yet)
|
|
||||||
// Fixed by: https://github.com/golang/net/commit/5058c78c3627b31e484a81463acd51c7cecc06f3
|
|
||||||
// but slack returns the address with no port, so we have to fix it
|
|
||||||
api.Debugln("Using URL:", response.Info.URL)
|
api.Debugln("Using URL:", response.Info.URL)
|
||||||
websocketURL, err = websocketizeURLPort(response.Info.URL)
|
return &response.Info, response.Info.URL, nil
|
||||||
if err != nil {
|
|
||||||
return nil, "", fmt.Errorf("parsing response URL: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.Info, websocketURL, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRTM returns a RTM, which provides a fully managed connection to
|
// NewRTM returns a RTM, which provides a fully managed connection to
|
||||||
@ -90,6 +72,7 @@ func (api *Client) NewRTMWithOptions(options *RTMOptions) *RTM {
|
|||||||
isConnected: false,
|
isConnected: false,
|
||||||
wasIntentional: true,
|
wasIntentional: true,
|
||||||
killChannel: make(chan bool),
|
killChannel: make(chan bool),
|
||||||
|
disconnected: make(chan struct{}),
|
||||||
forcePing: make(chan bool),
|
forcePing: make(chan bool),
|
||||||
rawEvents: make(chan json.RawMessage),
|
rawEvents: make(chan json.RawMessage),
|
||||||
idGen: NewSafeID(1),
|
idGen: NewSafeID(1),
|
28
vendor/github.com/matterbridge/slack/slack.go → vendor/github.com/nlopes/slack/slack.go
generated
vendored
28
vendor/github.com/matterbridge/slack/slack.go → vendor/github.com/nlopes/slack/slack.go
generated
vendored
@ -3,12 +3,13 @@ package slack
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger *log.Logger // A logger that can be set by consumers
|
var logger stdLogger // A logger that can be set by consumers
|
||||||
/*
|
/*
|
||||||
Added as a var so that we can change this for testing purposes
|
Added as a var so that we can change this for testing purposes
|
||||||
*/
|
*/
|
||||||
@ -41,12 +42,31 @@ type Client struct {
|
|||||||
debug bool
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stdLogger is a logger interface compatible with both stdlib and some
|
||||||
|
// 3rd party loggers such as logrus.
|
||||||
|
type stdLogger interface {
|
||||||
|
Print(...interface{})
|
||||||
|
Printf(string, ...interface{})
|
||||||
|
Println(...interface{})
|
||||||
|
|
||||||
|
Fatal(...interface{})
|
||||||
|
Fatalf(string, ...interface{})
|
||||||
|
Fatalln(...interface{})
|
||||||
|
|
||||||
|
Panic(...interface{})
|
||||||
|
Panicf(string, ...interface{})
|
||||||
|
Panicln(...interface{})
|
||||||
|
|
||||||
|
Output(int, string) error
|
||||||
|
}
|
||||||
|
|
||||||
// SetLogger let's library users supply a logger, so that api debugging
|
// SetLogger let's library users supply a logger, so that api debugging
|
||||||
// can be logged along with the application's debugging info.
|
// can be logged along with the application's debugging info.
|
||||||
func SetLogger(l *log.Logger) {
|
func SetLogger(l stdLogger) {
|
||||||
logger = l
|
logger = l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New creates new Client.
|
||||||
func New(token string) *Client {
|
func New(token string) *Client {
|
||||||
s := &Client{}
|
s := &Client{}
|
||||||
s.config.token = token
|
s.config.token = token
|
||||||
@ -83,12 +103,12 @@ func (api *Client) SetDebug(debug bool) {
|
|||||||
|
|
||||||
func (api *Client) Debugf(format string, v ...interface{}) {
|
func (api *Client) Debugf(format string, v ...interface{}) {
|
||||||
if api.debug {
|
if api.debug {
|
||||||
logger.Printf(format, v...)
|
logger.Output(2, fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *Client) Debugln(v ...interface{}) {
|
func (api *Client) Debugln(v ...interface{}) {
|
||||||
if api.debug {
|
if api.debug {
|
||||||
logger.Println(v...)
|
logger.Output(2, fmt.Sprintln(v...))
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -200,10 +200,7 @@ func (api *Client) SetUserAsActiveContext(ctx context.Context) error {
|
|||||||
"token": {api.config.token},
|
"token": {api.config.token},
|
||||||
}
|
}
|
||||||
_, err := userRequest(ctx, "users.setActive", values, api.debug)
|
_, err := userRequest(ctx, "users.setActive", values, api.debug)
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUserPresence changes the currently authenticated user presence
|
// SetUserPresence changes the currently authenticated user presence
|
||||||
@ -247,8 +244,8 @@ func (api *Client) GetUserIdentityContext(ctx context.Context) (*UserIdentityRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetUserPhoto changes the currently authenticated user's profile image
|
// SetUserPhoto changes the currently authenticated user's profile image
|
||||||
func (api *Client) SetUserPhoto(ctx context.Context, image string, params UserSetPhotoParams) error {
|
func (api *Client) SetUserPhoto(image string, params UserSetPhotoParams) error {
|
||||||
return api.SetUserPhoto(context.Background(), image, params)
|
return api.SetUserPhotoContext(context.Background(), image, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUserPhotoContext changes the currently authenticated user's profile image using a custom context
|
// SetUserPhotoContext changes the currently authenticated user's profile image using a custom context
|
@ -27,6 +27,7 @@ type RTM struct {
|
|||||||
IncomingEvents chan RTMEvent
|
IncomingEvents chan RTMEvent
|
||||||
outgoingMessages chan OutgoingMessage
|
outgoingMessages chan OutgoingMessage
|
||||||
killChannel chan bool
|
killChannel chan bool
|
||||||
|
disconnected chan struct{} // disconnected is closed when Disconnect is invoked, regardless of connection state. Allows for ManagedConnection to not leak.
|
||||||
forcePing chan bool
|
forcePing chan bool
|
||||||
rawEvents chan json.RawMessage
|
rawEvents chan json.RawMessage
|
||||||
wasIntentional bool
|
wasIntentional bool
|
||||||
@ -59,9 +60,14 @@ type RTMOptions struct {
|
|||||||
|
|
||||||
// Disconnect and wait, blocking until a successful disconnection.
|
// Disconnect and wait, blocking until a successful disconnection.
|
||||||
func (rtm *RTM) Disconnect() error {
|
func (rtm *RTM) Disconnect() error {
|
||||||
|
// this channel is always closed on disconnect. lets the ManagedConnection() function
|
||||||
|
// properly clean up.
|
||||||
|
close(rtm.disconnected)
|
||||||
|
|
||||||
if !rtm.isConnected {
|
if !rtm.isConnected {
|
||||||
return errors.New("Invalid call to Disconnect - Slack API is already disconnected")
|
return errors.New("Invalid call to Disconnect - Slack API is already disconnected")
|
||||||
}
|
}
|
||||||
|
|
||||||
rtm.killChannel <- true
|
rtm.killChannel <- true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
@ -99,6 +99,15 @@ func (rtm *RTM) connect(connectionCount int, useRTMStart bool) (*Info, *websocke
|
|||||||
Attempt: boff.attempts,
|
Attempt: boff.attempts,
|
||||||
ErrorObj: err,
|
ErrorObj: err,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
// check if Disconnect() has been invoked.
|
||||||
|
select {
|
||||||
|
case _ = <-rtm.disconnected:
|
||||||
|
rtm.IncomingEvents <- RTMEvent{"disconnected", &DisconnectedEvent{Intentional: true}}
|
||||||
|
return nil, nil, fmt.Errorf("disconnect received while trying to connect")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
// get time we should wait before attempting to connect again
|
// get time we should wait before attempting to connect again
|
||||||
dur := boff.Duration()
|
dur := boff.Duration()
|
||||||
rtm.Debugf("reconnection %d failed: %s", boff.attempts+1, err)
|
rtm.Debugf("reconnection %d failed: %s", boff.attempts+1, err)
|
||||||
@ -124,7 +133,8 @@ func (rtm *RTM) startRTMAndDial(useRTMStart bool) (*Info, *websocket.Conn, error
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := websocketProxyDial(url, "http://api.slack.com")
|
// Only use HTTPS for connections to prevent MITM attacks on the connection.
|
||||||
|
conn, err := websocketProxyDial(url, "https://api.slack.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -317,10 +327,13 @@ func (rtm *RTM) handleAck(event json.RawMessage) {
|
|||||||
rtm.Debugln(" -> Erroneous 'ack' event:", string(event))
|
rtm.Debugln(" -> Erroneous 'ack' event:", string(event))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ack.Ok {
|
if ack.Ok {
|
||||||
rtm.IncomingEvents <- RTMEvent{"ack", ack}
|
rtm.IncomingEvents <- RTMEvent{"ack", ack}
|
||||||
} else {
|
} else if ack.RTMResponse.Error != nil {
|
||||||
rtm.IncomingEvents <- RTMEvent{"ack_error", &AckErrorEvent{ack.Error}}
|
rtm.IncomingEvents <- RTMEvent{"ack_error", &AckErrorEvent{ack.Error}}
|
||||||
|
} else {
|
||||||
|
rtm.IncomingEvents <- RTMEvent{"ack_error", &AckErrorEvent{fmt.Errorf("ack decode failure")}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -32,8 +32,7 @@ func websocketHTTPConnect(proxy, urlString string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cc := httputil.NewProxyClientConn(p, nil)
|
cc := httputil.NewProxyClientConn(p, nil)
|
||||||
cc.Do(&req)
|
if _, err := cc.Do(&req); err != nil {
|
||||||
if err != nil && err != httputil.ErrPersistEOF {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
21
vendor/github.com/shazow/rateio/LICENSE
generated
vendored
Normal file
21
vendor/github.com/shazow/rateio/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Andrey Petrov
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
29
vendor/github.com/shazow/rateio/doc.go
generated
vendored
Normal file
29
vendor/github.com/shazow/rateio/doc.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
Package rateio provides an io interfaces for rate-limiting.
|
||||||
|
|
||||||
|
This can be used to apply rate limiting to any type that implements an io-style interface.
|
||||||
|
|
||||||
|
For example, we can use it to restrict the reading rate of a net.Conn:
|
||||||
|
|
||||||
|
type limitedConn struct {
|
||||||
|
net.Conn
|
||||||
|
io.Reader // Our rate-limited io.Reader for net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *limitedConn) Read(p []byte) (n int, err error) {
|
||||||
|
return r.Reader.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadLimitConn returns a net.Conn whose io.Reader interface is rate-limited by limiter.
|
||||||
|
func ReadLimitConn(conn net.Conn, limiter rateio.Limiter) net.Conn {
|
||||||
|
return &limitedConn{
|
||||||
|
Conn: conn,
|
||||||
|
Reader: rateio.NewReader(conn, limiter),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Then we can use ReadLimitConn to wrap our existing net.Conn and continue using
|
||||||
|
the wrapped version in its place.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package rateio
|
62
vendor/github.com/shazow/rateio/limiter.go
generated
vendored
Normal file
62
vendor/github.com/shazow/rateio/limiter.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package rateio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const minInt = -int(^uint(0)>>1) - 1
|
||||||
|
|
||||||
|
// The error returned when the read rate exceeds our specification.
|
||||||
|
var ErrRateExceeded = errors.New("Read rate exceeded.")
|
||||||
|
|
||||||
|
// Limiter is an interface for a rate limiter.
|
||||||
|
// There are a few example limiters included in the package, but feel free to go wild with your own.
|
||||||
|
type Limiter interface {
|
||||||
|
// Apply this many bytes to the limiter, return ErrRateExceeded if the defined rate is exceeded.
|
||||||
|
Count(int) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// simpleLimiter is a rate limiter that restricts Amount bytes in Frequency duration.
|
||||||
|
type simpleLimiter struct {
|
||||||
|
Amount int
|
||||||
|
Frequency time.Duration
|
||||||
|
|
||||||
|
numRead int
|
||||||
|
timeRead time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSimpleLimiter creates a Limiter that restricts a given number of bytes per frequency.
|
||||||
|
func NewSimpleLimiter(amount int, frequency time.Duration) Limiter {
|
||||||
|
return &simpleLimiter{
|
||||||
|
Amount: amount,
|
||||||
|
Frequency: frequency,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGracefulLimiter returns a Limiter that is the same as a
|
||||||
|
// SimpleLimiter but adds a grace period at the start of the rate
|
||||||
|
// limiting where it allows unlimited bytes to be read during that
|
||||||
|
// period.
|
||||||
|
func NewGracefulLimiter(amount int, frequency time.Duration, grace time.Duration) Limiter {
|
||||||
|
return &simpleLimiter{
|
||||||
|
Amount: amount,
|
||||||
|
Frequency: frequency,
|
||||||
|
numRead: minInt,
|
||||||
|
timeRead: time.Now().Add(grace),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count applies n bytes to the limiter.
|
||||||
|
func (limit *simpleLimiter) Count(n int) error {
|
||||||
|
now := time.Now()
|
||||||
|
if now.After(limit.timeRead) {
|
||||||
|
limit.numRead = 0
|
||||||
|
limit.timeRead = now.Add(limit.Frequency)
|
||||||
|
}
|
||||||
|
limit.numRead += n
|
||||||
|
if limit.numRead > limit.Amount {
|
||||||
|
return ErrRateExceeded
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
25
vendor/github.com/shazow/rateio/reader.go
generated
vendored
Normal file
25
vendor/github.com/shazow/rateio/reader.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package rateio
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
type reader struct {
|
||||||
|
io.Reader
|
||||||
|
Limiter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads data into p.
|
||||||
|
// Returns ErrRateExceeded error if our specified read is exceeded.
|
||||||
|
func (r *reader) Read(p []byte) (n int, err error) {
|
||||||
|
n, err = r.Reader.Read(p)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.Limiter.Count(n)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReader proxies an io.Reader but keeps track of bytes read based on our Limiter.
|
||||||
|
func NewReader(r io.Reader, limiter Limiter) io.Reader {
|
||||||
|
return &reader{r, limiter}
|
||||||
|
}
|
25
vendor/github.com/shazow/rateio/writer.go
generated
vendored
Normal file
25
vendor/github.com/shazow/rateio/writer.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package rateio
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
type writer struct {
|
||||||
|
io.Writer
|
||||||
|
Limiter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes the contents of p into the buffer.
|
||||||
|
// Returns ErrRateExceeded error if our specified read is exceeded.
|
||||||
|
func (w *writer) Write(p []byte) (n int, err error) {
|
||||||
|
n, err = w.Writer.Write(p)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = w.Limiter.Count(n)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWriter proxies an io.Writer but keeps track of bytes read based on our Limiter.
|
||||||
|
func NewWriter(w io.Writer, limiter Limiter) io.Writer {
|
||||||
|
return &writer{w, limiter}
|
||||||
|
}
|
21
vendor/github.com/shazow/ssh-chat/sshd/LICENSE
generated
vendored
Normal file
21
vendor/github.com/shazow/ssh-chat/sshd/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Andrey Petrov
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
72
vendor/github.com/shazow/ssh-chat/sshd/auth.go
generated
vendored
Normal file
72
vendor/github.com/shazow/ssh-chat/sshd/auth.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package sshd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Auth is used to authenticate connections based on public keys.
|
||||||
|
type Auth interface {
|
||||||
|
// Whether to allow connections without a public key.
|
||||||
|
AllowAnonymous() bool
|
||||||
|
// Given address and public key, return if the connection should be permitted.
|
||||||
|
Check(net.Addr, ssh.PublicKey) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeAuth makes an ssh.ServerConfig which performs authentication against an Auth implementation.
|
||||||
|
func MakeAuth(auth Auth) *ssh.ServerConfig {
|
||||||
|
config := ssh.ServerConfig{
|
||||||
|
NoClientAuth: false,
|
||||||
|
// Auth-related things should be constant-time to avoid timing attacks.
|
||||||
|
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||||
|
ok, err := auth.Check(conn.RemoteAddr(), key)
|
||||||
|
if !ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
perm := &ssh.Permissions{Extensions: map[string]string{
|
||||||
|
"pubkey": string(key.Marshal()),
|
||||||
|
}}
|
||||||
|
return perm, nil
|
||||||
|
},
|
||||||
|
KeyboardInteractiveCallback: func(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
|
||||||
|
if !auth.AllowAnonymous() {
|
||||||
|
return nil, errors.New("public key authentication required")
|
||||||
|
}
|
||||||
|
_, err := auth.Check(conn.RemoteAddr(), nil)
|
||||||
|
return nil, err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeNoAuth makes a simple ssh.ServerConfig which allows all connections.
|
||||||
|
// Primarily used for testing.
|
||||||
|
func MakeNoAuth() *ssh.ServerConfig {
|
||||||
|
config := ssh.ServerConfig{
|
||||||
|
NoClientAuth: false,
|
||||||
|
// Auth-related things should be constant-time to avoid timing attacks.
|
||||||
|
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||||
|
perm := &ssh.Permissions{Extensions: map[string]string{
|
||||||
|
"pubkey": string(key.Marshal()),
|
||||||
|
}}
|
||||||
|
return perm, nil
|
||||||
|
},
|
||||||
|
KeyboardInteractiveCallback: func(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fingerprint performs a SHA256 BASE64 fingerprint of the PublicKey, similar to OpenSSH.
|
||||||
|
// See: https://anongit.mindrot.org/openssh.git/commit/?id=56d1c83cdd1ac
|
||||||
|
func Fingerprint(k ssh.PublicKey) string {
|
||||||
|
hash := sha256.Sum256(k.Marshal())
|
||||||
|
return "SHA256:" + base64.StdEncoding.EncodeToString(hash[:])
|
||||||
|
}
|
76
vendor/github.com/shazow/ssh-chat/sshd/client.go
generated
vendored
Normal file
76
vendor/github.com/shazow/ssh-chat/sshd/client.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package sshd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewRandomSigner generates a random key of a desired bit length.
|
||||||
|
func NewRandomSigner(bits int) (ssh.Signer, error) {
|
||||||
|
key, err := rsa.GenerateKey(rand.Reader, bits)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ssh.NewSignerFromKey(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientConfig creates a barebones ssh.ClientConfig to be used with ssh.Dial.
|
||||||
|
func NewClientConfig(name string) *ssh.ClientConfig {
|
||||||
|
return &ssh.ClientConfig{
|
||||||
|
User: name,
|
||||||
|
Auth: []ssh.AuthMethod{
|
||||||
|
ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
|
||||||
|
return
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectShell makes a barebones SSH client session, used for testing.
|
||||||
|
func ConnectShell(host string, name string, handler func(r io.Reader, w io.WriteCloser) error) error {
|
||||||
|
config := NewClientConfig(name)
|
||||||
|
conn, err := ssh.Dial("tcp", host, config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
session, err := conn.NewSession()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
in, err := session.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := session.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
err = session.RequestPty("xterm", 80, 40, ssh.TerminalModes{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
err = session.Shell()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = session.SendRequest("ping", true, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler(out, in)
|
||||||
|
}
|
34
vendor/github.com/shazow/ssh-chat/sshd/doc.go
generated
vendored
Normal file
34
vendor/github.com/shazow/ssh-chat/sshd/doc.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package sshd
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
signer, err := ssh.ParsePrivateKey(privateKey)
|
||||||
|
|
||||||
|
config := MakeNoAuth()
|
||||||
|
config.AddHostKey(signer)
|
||||||
|
|
||||||
|
s, err := ListenSSH("0.0.0.0:2022", config)
|
||||||
|
if err != nil {
|
||||||
|
// Handle opening socket error
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
terminals := s.ServeTerminal()
|
||||||
|
|
||||||
|
for term := range terminals {
|
||||||
|
go func() {
|
||||||
|
defer term.Close()
|
||||||
|
term.SetPrompt("...")
|
||||||
|
term.AutoCompleteCallback = nil // ...
|
||||||
|
|
||||||
|
for {
|
||||||
|
line, err := term.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
term.Write(...)
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
*/
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user