Created
July 16, 2016 23:32
-
-
Save zeisss/5943fcadca3f992ac4f883eb58fcf4e9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM golang:1.6 | |
RUN go get github.com/nlopes/slack | |
COPY main.go /go/src/main.go | |
CMD ["go", "run", "/go/src/main.go"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"github.com/nlopes/slack" | |
"syscall" | |
"os/signal" | |
"fmt" | |
"log" | |
"strings" | |
"os" | |
) | |
type CommunityConfig struct { | |
Comment string | |
BotToken string | |
ChannelName string | |
} | |
type Message struct { | |
Text string | |
Username string | |
} | |
// FindChannelID resolves the given channelName to either a real channel or a group/private channel | |
func FindChannelID(api *slack.Client, channelName string) (string, error) { | |
channels, err := api.GetChannels(true) | |
if err != nil { | |
return "", err | |
} | |
for _, c := range channels { | |
if c.Name == channelName { | |
return c.ID, nil | |
} | |
} | |
groups, err := api.GetGroups(true) | |
if err != nil { | |
return "", err | |
} | |
for _, g := range groups { | |
if g.Name == channelName { | |
return g.ID, nil | |
} | |
} | |
return "", fmt.Errorf("No channel found") | |
} | |
func Listen(cfg CommunityConfig, broadcast chan<- Message, publish <-chan Message) { | |
api := slack.New(cfg.BotToken) | |
channelID, err := FindChannelID(api, cfg.ChannelName) | |
if err != nil { | |
panic("Failed to read channel '" + cfg.ChannelName + "': " + err.Error()) | |
} | |
fmt.Printf("%s: %s => %#v\n", cfg.Comment, cfg.ChannelName, channelID) | |
rtm := api.NewRTM() | |
go rtm.ManageConnection() | |
Loop: | |
for { | |
select { | |
case outgoing := <- publish: | |
fmt.Printf("%s: Sending %s\n", cfg.Comment, outgoing.Text) | |
api.PostMessage( | |
channelID, | |
outgoing.Text, | |
slack.PostMessageParameters{ | |
Username: outgoing.Username, | |
UnfurlMedia: true, | |
UnfurlLinks: true, | |
}, | |
) | |
case msg := <-rtm.IncomingEvents: | |
switch ev := msg.Data.(type) { | |
case *slack.HelloEvent, *slack.ReconnectUrlEvent, *slack.PresenceChangeEvent, | |
*slack.ConnectedEvent, *slack.ConnectingEvent, *slack.LatencyReport, | |
*slack.UserTypingEvent, *slack.ChannelCreatedEvent, | |
*slack.ChannelJoinedEvent: | |
case *slack.MessageEvent: | |
if ev.Channel != channelID { // we only want to listen to the specified channels | |
continue | |
} | |
if ev.User == "" { // we only want to forward real user message | |
continue | |
} | |
// rtm.SendMessage(rtm.NewOutgoingMessage(ev.Text, ev.Channel)) | |
user := rtm.GetInfo().GetUserByID(ev.User) | |
if user.IsBot { | |
continue | |
} | |
fmt.Printf("Message: %#v\n", ev) | |
fmt.Printf("user: %#v\n", user) | |
broadcast <- Message{ | |
Text: ev.Text, | |
Username: user.Name, | |
} | |
case *slack.RTMError: | |
fmt.Printf("Error: %s\n", ev.Error()) | |
case *slack.InvalidAuthEvent: | |
fmt.Printf("Invalid credentials") | |
break Loop | |
default: | |
// Ignore other events.. | |
fmt.Printf("Unhandled: %#v\n", msg.Data) | |
} | |
} | |
} | |
} | |
func RunSlackBouncer(configs []CommunityConfig) { | |
publishers := make([]chan Message, len(configs)) | |
for id, comm := range configs { | |
broadcast := make(chan Message, 1) // The listener will write messages in here for the other channels | |
publisher := make(chan Message, 1) // The listener will read from here for publishing messages to his channel | |
publishers[id] = publisher | |
go Listen(comm, broadcast, publisher) | |
go func(id int, broadcast <-chan Message) { | |
for message := range broadcast { | |
// redistribute the message to all other channels | |
for idx, publisher := range publishers { | |
if idx == id { | |
continue | |
} | |
publisher <- message | |
} | |
} | |
}(id, broadcast) | |
} | |
} | |
func main() { | |
logger := log.New(os.Stdout, "slack-bot: ", log.Lshortfile|log.LstdFlags) | |
slack.SetLogger(logger) | |
communities := []CommunityConfig{} | |
for _, arg := range os.Args[1:] { | |
s := strings.Split(arg, ":") | |
if len(s) != 3 { | |
panic("Unexpected argument format, expected 'name:token:channel': " + arg) | |
} | |
communities = append(communities, CommunityConfig{ | |
Comment: s[0], | |
BotToken: s[1], | |
ChannelName: s[2], | |
}) | |
} | |
if len(communities) <= 1 { | |
panic("Expected at least 2 arguments.") | |
} | |
RunSlackBouncer(communities) | |
sigc := make(chan os.Signal, 1) | |
signal.Notify(sigc, | |
syscall.SIGHUP, | |
syscall.SIGINT, | |
syscall.SIGTERM, | |
syscall.SIGQUIT) | |
<-sigc | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment