161 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package slack
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/micro/go-micro/agent/input"
 | |
| 	"github.com/nlopes/slack"
 | |
| )
 | |
| 
 | |
| // Satisfies the input.Conn interface
 | |
| type slackConn struct {
 | |
| 	auth *slack.AuthTestResponse
 | |
| 	rtm  *slack.RTM
 | |
| 	exit chan bool
 | |
| 
 | |
| 	sync.Mutex
 | |
| 	names map[string]string
 | |
| }
 | |
| 
 | |
| func (s *slackConn) run() {
 | |
| 	// func retrieves user names and maps to IDs
 | |
| 	setNames := func() {
 | |
| 		names := make(map[string]string)
 | |
| 		users, err := s.rtm.Client.GetUsers()
 | |
| 		if err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		for _, user := range users {
 | |
| 			names[user.ID] = user.Name
 | |
| 		}
 | |
| 
 | |
| 		s.Lock()
 | |
| 		s.names = names
 | |
| 		s.Unlock()
 | |
| 	}
 | |
| 
 | |
| 	setNames()
 | |
| 
 | |
| 	t := time.NewTicker(time.Minute)
 | |
| 	defer t.Stop()
 | |
| 
 | |
| 	for {
 | |
| 		select {
 | |
| 		case <-s.exit:
 | |
| 			return
 | |
| 		case <-t.C:
 | |
| 			setNames()
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *slackConn) getName(id string) string {
 | |
| 	s.Lock()
 | |
| 	name := s.names[id]
 | |
| 	s.Unlock()
 | |
| 	return name
 | |
| }
 | |
| 
 | |
| func (s *slackConn) Close() error {
 | |
| 	select {
 | |
| 	case <-s.exit:
 | |
| 		return nil
 | |
| 	default:
 | |
| 		close(s.exit)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (s *slackConn) Recv(event *input.Event) error {
 | |
| 	if event == nil {
 | |
| 		return errors.New("event cannot be nil")
 | |
| 	}
 | |
| 
 | |
| 	for {
 | |
| 		select {
 | |
| 		case <-s.exit:
 | |
| 			return errors.New("connection closed")
 | |
| 		case e := <-s.rtm.IncomingEvents:
 | |
| 			switch ev := e.Data.(type) {
 | |
| 			case *slack.MessageEvent:
 | |
| 				// only accept type message
 | |
| 				if ev.Type != "message" {
 | |
| 					continue
 | |
| 				}
 | |
| 
 | |
| 				// only accept DMs or messages to me
 | |
| 				switch {
 | |
| 				case strings.HasPrefix(ev.Channel, "D"):
 | |
| 				case strings.HasPrefix(ev.Text, s.auth.User):
 | |
| 				case strings.HasPrefix(ev.Text, fmt.Sprintf("<@%s>", s.auth.UserID)):
 | |
| 				default:
 | |
| 					continue
 | |
| 				}
 | |
| 
 | |
| 				// Strip username from text
 | |
| 				switch {
 | |
| 				case strings.HasPrefix(ev.Text, s.auth.User):
 | |
| 					args := strings.Split(ev.Text, " ")[1:]
 | |
| 					ev.Text = strings.Join(args, " ")
 | |
| 					event.To = s.auth.User
 | |
| 				case strings.HasPrefix(ev.Text, fmt.Sprintf("<@%s>", s.auth.UserID)):
 | |
| 					args := strings.Split(ev.Text, " ")[1:]
 | |
| 					ev.Text = strings.Join(args, " ")
 | |
| 					event.To = s.auth.UserID
 | |
| 				}
 | |
| 
 | |
| 				if event.Meta == nil {
 | |
| 					event.Meta = make(map[string]interface{})
 | |
| 				}
 | |
| 
 | |
| 				// fill in the blanks
 | |
| 				event.From = ev.Channel + ":" + ev.User
 | |
| 				event.Type = input.TextEvent
 | |
| 				event.Data = []byte(ev.Text)
 | |
| 				event.Meta["reply"] = ev
 | |
| 				return nil
 | |
| 			case *slack.InvalidAuthEvent:
 | |
| 				return errors.New("invalid credentials")
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *slackConn) Send(event *input.Event) error {
 | |
| 	var channel, message, name string
 | |
| 
 | |
| 	if len(event.To) == 0 {
 | |
| 		return errors.New("require Event.To")
 | |
| 	}
 | |
| 
 | |
| 	parts := strings.Split(event.To, ":")
 | |
| 
 | |
| 	if len(parts) == 2 {
 | |
| 		channel = parts[0]
 | |
| 		name = s.getName(parts[1])
 | |
| 		// try using reply meta
 | |
| 	} else if ev, ok := event.Meta["reply"]; ok {
 | |
| 		channel = ev.(*slack.MessageEvent).Channel
 | |
| 		name = s.getName(ev.(*slack.MessageEvent).User)
 | |
| 	}
 | |
| 
 | |
| 	// don't know where to send the message
 | |
| 	if len(channel) == 0 {
 | |
| 		return errors.New("could not determine who message is to")
 | |
| 	}
 | |
| 
 | |
| 	if len(name) == 0 || strings.HasPrefix(channel, "D") {
 | |
| 		message = string(event.Data)
 | |
| 	} else {
 | |
| 		message = fmt.Sprintf("@%s: %s", name, string(event.Data))
 | |
| 	}
 | |
| 
 | |
| 	s.rtm.SendMessage(s.rtm.NewOutgoingMessage(message, channel))
 | |
| 	return nil
 | |
| }
 |