Skip to content

Instantly share code, notes, and snippets.

@DanielOaks
Created December 3, 2018 15:28
Show Gist options
  • Save DanielOaks/a66839c5b1b3441dde34dd6ae4165c95 to your computer and use it in GitHub Desktop.
Save DanielOaks/a66839c5b1b3441dde34dd6ae4165c95 to your computer and use it in GitHub Desktop.
package main
import (
"log"
"fmt"
"strings"
"sync"
"strconv"
"net"
"github.com/nlopes/slack"
"github.com/nlopes/slack/slackutilsx"
"github.com/goshuirc/eventmgr"
"github.com/goshuirc/irc-go/client"
"github.com/goshuirc/irc-go/ircfmt"
"github.com/goshuirc/irc-go/ircmap"
)
const (
slackAPIToken = "slack-token-here"
slackChannel = "test-irc"
ircNick = "test-proxy"
ircUser = "test"
ircRealName = "test proxy"
// ircHost = "localhost"
// ircPort = 6667
// ircTLS = false
ircHost = "chat.freenode.net"
ircPort = 6697
ircTLS = true
ircChannel = "#test"
ircHereTag = "@here"
)
const (
ircActionPrefix = "\x01ACTION "
)
// rawIRCHandler prints raw IRC messages to and from the server.
func rawIRCHandler(event string, info eventmgr.InfoMap) {
// sc := info["server"].(*gircclient.ServerConnection)
// direction := info["direction"].(string)
// line := info["data"].(string)
// var arrow string
// if direction == "in" {
// arrow = "<- "
// } else {
// arrow = " ->"
// }
// fmt.Println("IRC:", sc.Name, arrow, ircfmt.Escape(strings.Trim(line, "\r\n")))
}
func main() {
// stores whether we're shutting down for whatever reason
var shuttingDown bool
// waitgroup, so we exit correctly
var wg sync.WaitGroup
// define irc things
reactor := gircclient.NewReactor()
server := reactor.CreateServer("srv")
// starting slack api
api := slack.New(slackAPIToken)
// 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
}
slackChannelID := ""
for _, group := range groups {
fmt.Printf("Slack Channel Listing: ID: %s, Name: %s\n", group.ID, group.Name)
if group.Name == slackChannel {
slackChannelID = group.ID
}
}
if slackChannelID == "" {
log.Fatalf("Could not find Slack channel named [%s]\n", slackChannel)
return
}
// start slack rtm stuff
rtm := api.NewRTM()
go rtm.ManageConnection()
// receiving slack messages
wg.Add(1)
go func() {
defer wg.Done()
defer func() {
shuttingDown = true
server.Shutdown("Closing Connection")
}()
for msg := range rtm.IncomingEvents {
if shuttingDown {
fmt.Println("SlackRTM: shuttingDown is true")
return
}
// 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)
case *slack.MessageEvent:
// fmt.Printf("Message: %v\n", ev)
// kill the bot
// we listen for this in all channels so it even happens in pm, etc
if strings.TrimSpace(ev.Text) == "!quit" {
fmt.Println("SlackRTM: !quit command received from Slack")
return
}
// only respond to proper cmds in the channel we're listening on
if ev.Channel != slackChannelID {
continue
}
// only forward slack messages that start with "!public "
if !strings.HasPrefix(ev.Text, "!public ") {
continue
}
t := strings.TrimPrefix(ev.Text, "!public ")
msg := fmt.Sprintf("[ID:%s] %s", ev.User, t)
u, err := api.GetUserInfo(ev.User)
if err == nil {
msg = fmt.Sprintf("[%s] %s", u.Name, t)
fmt.Println("SlackRTM: Sending message public:", msg)
rtm.SendMessage(rtm.NewOutgoingMessage(fmt.Sprintf("Sending message publicly: %s\n", msg), slackChannelID))
server.Msg(nil, ircChannel, msg, false)
} else {
fmt.Println("SlackRTM: Could not send msg publicly:", msg, "-", err.Error())
rtm.SendMessage(rtm.NewOutgoingMessage(fmt.Sprintf("Could not send message publicly: %s - %s\n", msg, err.Error()), slackChannelID))
}
fmt.Println("Slack:", msg)
// case *slack.PresenceChangeEvent:
// fmt.Printf("Presence Change: %v\n", ev)
case *slack.LatencyReport:
fmt.Printf("SlackRTM: Current latency: %v\n", ev.Value)
case *slack.RTMError:
fmt.Printf("SlackRTM: Error: %s\n", ev.Error())
return
case *slack.InvalidAuthEvent:
fmt.Printf("SlackRTM: Invalid credentials")
return
default:
// Ignore other events..
// fmt.Printf("Unexpected: %v\n", msg.Data)
}
}
}()
// connect to irc
server.InitialNick = ircNick
server.InitialUser = ircUser
server.InitialRealName = ircRealName
server.JoinChannel(ircChannel, "", false)
// attach irc events
server.RegisterEvent("in", "PRIVMSG", func (event string, info eventmgr.InfoMap) {
sc := info["server"].(*gircclient.ServerConnection)
target, _ := ircmap.Casefold(sc.Casemapping, info["params"].([]string)[0])
if target != ircChannel {
return
}
prefix := strings.Split(strings.Split(info["prefix"].(string), "!")[0], "@")[0]
sentMsg := ircfmt.Escape(info["params"].([]string)[1])
msg := fmt.Sprintf("<%s> %s", prefix, sentMsg)
if strings.HasPrefix(sentMsg, ircActionPrefix) {
msg = fmt.Sprintf("*%s %s", prefix, strings.TrimSuffix(strings.TrimPrefix(sentMsg, ircActionPrefix), "\x01"))
}
msg = slackutilsx.EscapeMessage(msg)
if strings.Contains(msg, ircHereTag) {
msg = strings.Replace(msg, ircHereTag, "<!here>", -1)
}
rtm.PostMessage(slackChannelID, slack.MsgOptionText(msg, false))
fmt.Println("IRC:", sc.Name, target, "<" + info["prefix"].(string) + ">", ircfmt.Escape(info["params"].([]string)[1]))
}, 0)
server.RegisterEvent("in", "raw", rawIRCHandler, 0)
server.RegisterEvent("out", "raw", rawIRCHandler, 0)
// connect
err = server.Connect(net.JoinHostPort(ircHost, strconv.Itoa(ircPort)), ircTLS, nil)
if err != nil {
log.Fatalln("IRC: Connection error:", err.Error())
}
// start irc loop
wg.Add(1)
go func() {
defer wg.Done()
defer func() { shuttingDown = true }()
server.ReceiveLoop()
}()
// wait for everything to exit
wg.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment