gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/agent/input/slack/conn.go (about)

     1  package slack
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"sync"
     8  	"time"
     9  
    10  	"gitee.com/liuxuezhan/go-micro-v1.18.0/agent/input"
    11  	"github.com/nlopes/slack"
    12  )
    13  
    14  // Satisfies the input.Conn interface
    15  type slackConn struct {
    16  	auth *slack.AuthTestResponse
    17  	rtm  *slack.RTM
    18  	exit chan bool
    19  
    20  	sync.Mutex
    21  	names map[string]string
    22  }
    23  
    24  func (s *slackConn) run() {
    25  	// func retrieves user names and maps to IDs
    26  	setNames := func() {
    27  		names := make(map[string]string)
    28  		users, err := s.rtm.Client.GetUsers()
    29  		if err != nil {
    30  			return
    31  		}
    32  
    33  		for _, user := range users {
    34  			names[user.ID] = user.Name
    35  		}
    36  
    37  		s.Lock()
    38  		s.names = names
    39  		s.Unlock()
    40  	}
    41  
    42  	setNames()
    43  
    44  	t := time.NewTicker(time.Minute)
    45  	defer t.Stop()
    46  
    47  	for {
    48  		select {
    49  		case <-s.exit:
    50  			return
    51  		case <-t.C:
    52  			setNames()
    53  		}
    54  	}
    55  }
    56  
    57  func (s *slackConn) getName(id string) string {
    58  	s.Lock()
    59  	name := s.names[id]
    60  	s.Unlock()
    61  	return name
    62  }
    63  
    64  func (s *slackConn) Close() error {
    65  	select {
    66  	case <-s.exit:
    67  		return nil
    68  	default:
    69  		close(s.exit)
    70  	}
    71  	return nil
    72  }
    73  
    74  func (s *slackConn) Recv(event *input.Event) error {
    75  	if event == nil {
    76  		return errors.New("event cannot be nil")
    77  	}
    78  
    79  	for {
    80  		select {
    81  		case <-s.exit:
    82  			return errors.New("connection closed")
    83  		case e := <-s.rtm.IncomingEvents:
    84  			switch ev := e.Data.(type) {
    85  			case *slack.MessageEvent:
    86  				// only accept type message
    87  				if ev.Type != "message" {
    88  					continue
    89  				}
    90  
    91  				// only accept DMs or messages to me
    92  				switch {
    93  				case strings.HasPrefix(ev.Channel, "D"):
    94  				case strings.HasPrefix(ev.Text, s.auth.User):
    95  				case strings.HasPrefix(ev.Text, fmt.Sprintf("<@%s>", s.auth.UserID)):
    96  				default:
    97  					continue
    98  				}
    99  
   100  				// Strip username from text
   101  				switch {
   102  				case strings.HasPrefix(ev.Text, s.auth.User):
   103  					args := strings.Split(ev.Text, " ")[1:]
   104  					ev.Text = strings.Join(args, " ")
   105  					event.To = s.auth.User
   106  				case strings.HasPrefix(ev.Text, fmt.Sprintf("<@%s>", s.auth.UserID)):
   107  					args := strings.Split(ev.Text, " ")[1:]
   108  					ev.Text = strings.Join(args, " ")
   109  					event.To = s.auth.UserID
   110  				}
   111  
   112  				if event.Meta == nil {
   113  					event.Meta = make(map[string]interface{})
   114  				}
   115  
   116  				// fill in the blanks
   117  				event.From = ev.Channel + ":" + ev.User
   118  				event.Type = input.TextEvent
   119  				event.Data = []byte(ev.Text)
   120  				event.Meta["reply"] = ev
   121  				return nil
   122  			case *slack.InvalidAuthEvent:
   123  				return errors.New("invalid credentials")
   124  			}
   125  		}
   126  	}
   127  }
   128  
   129  func (s *slackConn) Send(event *input.Event) error {
   130  	var channel, message, name string
   131  
   132  	if len(event.To) == 0 {
   133  		return errors.New("require Event.To")
   134  	}
   135  
   136  	parts := strings.Split(event.To, ":")
   137  
   138  	if len(parts) == 2 {
   139  		channel = parts[0]
   140  		name = s.getName(parts[1])
   141  		// try using reply meta
   142  	} else if ev, ok := event.Meta["reply"]; ok {
   143  		channel = ev.(*slack.MessageEvent).Channel
   144  		name = s.getName(ev.(*slack.MessageEvent).User)
   145  	}
   146  
   147  	// don't know where to send the message
   148  	if len(channel) == 0 {
   149  		return errors.New("could not determine who message is to")
   150  	}
   151  
   152  	if len(name) == 0 || strings.HasPrefix(channel, "D") {
   153  		message = string(event.Data)
   154  	} else {
   155  		message = fmt.Sprintf("@%s: %s", name, string(event.Data))
   156  	}
   157  
   158  	s.rtm.SendMessage(s.rtm.NewOutgoingMessage(message, channel))
   159  	return nil
   160  }