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/v2/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
 | 
						|
}
 |