Skip to content

Instantly share code, notes, and snippets.

@fiorix
Created November 19, 2015 17:13
Show Gist options
  • Save fiorix/e99d182608fa6b32d1bd to your computer and use it in GitHub Desktop.
Save fiorix/e99d182608fa6b32d1bd to your computer and use it in GitHub Desktop.
Slack bot from da hood: tehcloud
package main
import (
"flag"
"log"
"os"
"os/exec"
"strings"
"github.com/nlopes/slack"
)
func main() {
ad := os.Getenv("TC_ACTIONS_DIR")
if ad == "" {
ad = "./tcbroot"
}
debug := flag.Bool("slack-debug", os.Getenv("TC_SLACK_DEBUG") == "1", "enable slack debug")
key := flag.String("slack-key", os.Getenv("TC_SLACK_KEY"), "slack key for authorization")
actionsDir := flag.String("actions-dir", ad, "dir with tehcloud action scripts")
flag.Parse()
log.SetPrefix("[tehcloud] ")
tc, err := New(&Config{
Debug: *debug,
Key: *key,
ActionsDir: *actionsDir,
})
if err != nil {
log.Fatal(err)
}
tc.Run()
}
// Config is the configuration for the tehcloud bot.
type Config struct {
// Debug enables slack debug messages.
Debug bool
// Key is the Slack key for authorization.
// Obtain a key by registering your bot at:
// http://{team}.slack.com/services/new/bot
Key string
// ActionsDir is the directory with your action scripts.
//
// These can be bash, python, or any executable program.
//
// Whenever we see a message on Slack starting with '!',
// the subsequent text, until the first space, is treated
// as an executable command in the ActionsDir.
//
// For example, a message like `!echo hello world`
// on Slack executes the `echo` command in the ActionsDir,
// passing parameters "hello world" from the chat text.
// That script can be a simple `echo $*` to echo it back.
//
// Action scripts are executed with the slack user's
// information as environment variables. See Env below.
ActionsDir string
}
// TehCloud is a bot on the cloud.
type TehCloud interface {
Run() // Run the bot.
}
// New creates and initializes a new TehCloud object.
func New(c *Config) (TehCloud, error) {
conn := slack.New(c.Key)
conn.SetDebug(c.Debug)
rtm := conn.NewRTM()
go rtm.ManageConnection()
tc := &tehCloud{c, rtm}
return tc, nil
}
type tehCloud struct {
conf *Config
rtm *slack.RTM
}
// Start implements the TehCloud interface.
func (tc *tehCloud) Run() {
for ev := range tc.rtm.IncomingEvents {
switch ev.Data.(type) {
case *slack.MessageEvent:
tc.messageEvent(ev.Data.(*slack.MessageEvent))
default:
// TODO: log? this includes channel chat.
}
}
}
func (tc *tehCloud) messageEvent(ev *slack.MessageEvent) {
if len(ev.Msg.Text) < 2 || ev.Msg.Text[0] != '!' {
return
}
parts := strings.SplitN(ev.Msg.Text[1:], " ", 2)
if len(parts) == 1 {
parts = append(parts, "")
}
var msgtyp string
switch ev.Msg.Channel[0] {
case 'C':
msgtyp = "public"
case 'D':
msgtyp = "private"
}
user := tc.rtm.GetInfo().GetUserByID(ev.Msg.User)
cmd := &exec.Cmd{
Path: parts[0],
Args: []string{parts[0], parts[1]},
Env: []string{
"MSGTYPE=" + msgtyp,
"USER_NAME=" + user.Name,
"USER_REAL_NAME=" + user.RealName,
"USER_FIRST_NAME=" + user.Profile.FirstName,
"USER_LAST_NAME=" + user.Profile.LastName,
"USER_EMAIL=" + user.Profile.Email,
"USER_SKYPE=" + user.Profile.Skype,
"USER_PHONE=" + user.Profile.Phone,
"USER_IMAGE24=" + user.Profile.Image24,
"USER_IMAGE32=" + user.Profile.Image24,
"USER_IMAGE48=" + user.Profile.Image48,
"USER_IMAGE72=" + user.Profile.Image72,
"USER_IMAGE192=" + user.Profile.Image192,
"USER_TITLE=" + user.Profile.Title,
},
Dir: tc.conf.ActionsDir,
}
output, err := cmd.CombinedOutput()
if err != nil {
fullcmd := cmd.Path + " " + strings.Join(cmd.Args, " ")
log.Printf("failed to run command %q: %v", fullcmd, err)
return
}
tc.rtm.SendMessage(tc.rtm.NewOutgoingMessage(
string(output),
ev.Msg.Channel,
))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment