forked from lug/matterbridge
		
	
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //Package matterhook provides interaction with mattermost incoming/outgoing webhooks
 | |
| package matterhook
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"crypto/tls"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"log"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/gorilla/schema"
 | |
| 	"github.com/nlopes/slack"
 | |
| )
 | |
| 
 | |
| // OMessage for mattermost incoming webhook. (send to mattermost)
 | |
| type OMessage struct {
 | |
| 	Channel     string                 `json:"channel,omitempty"`
 | |
| 	IconURL     string                 `json:"icon_url,omitempty"`
 | |
| 	IconEmoji   string                 `json:"icon_emoji,omitempty"`
 | |
| 	UserName    string                 `json:"username,omitempty"`
 | |
| 	Text        string                 `json:"text"`
 | |
| 	Attachments []slack.Attachment     `json:"attachments,omitempty"`
 | |
| 	Type        string                 `json:"type,omitempty"`
 | |
| 	Props       map[string]interface{} `json:"props"`
 | |
| }
 | |
| 
 | |
| // IMessage for mattermost outgoing webhook. (received from mattermost)
 | |
| type IMessage struct {
 | |
| 	BotID       string `schema:"bot_id"`
 | |
| 	BotName     string `schema:"bot_name"`
 | |
| 	Token       string `schema:"token"`
 | |
| 	TeamID      string `schema:"team_id"`
 | |
| 	TeamDomain  string `schema:"team_domain"`
 | |
| 	ChannelID   string `schema:"channel_id"`
 | |
| 	ChannelName string `schema:"channel_name"`
 | |
| 	Timestamp   string `schema:"timestamp"`
 | |
| 	UserID      string `schema:"user_id"`
 | |
| 	UserName    string `schema:"user_name"`
 | |
| 	PostId      string `schema:"post_id"` //nolint:golint
 | |
| 	RawText     string `schema:"raw_text"`
 | |
| 	ServiceId   string `schema:"service_id"` //nolint:golint
 | |
| 	Text        string `schema:"text"`
 | |
| 	TriggerWord string `schema:"trigger_word"`
 | |
| 	FileIDs     string `schema:"file_ids"`
 | |
| }
 | |
| 
 | |
| // Client for Mattermost.
 | |
| type Client struct {
 | |
| 	// URL for incoming webhooks on mattermost.
 | |
| 	Url        string // nolint:golint
 | |
| 	In         chan IMessage
 | |
| 	Out        chan OMessage
 | |
| 	httpclient *http.Client
 | |
| 	Config
 | |
| }
 | |
| 
 | |
| // Config for client.
 | |
| type Config struct {
 | |
| 	BindAddress        string // Address to listen on
 | |
| 	Token              string // Only allow this token from Mattermost. (Allow everything when empty)
 | |
| 	InsecureSkipVerify bool   // disable certificate checking
 | |
| 	DisableServer      bool   // Do not start server for outgoing webhooks from Mattermost.
 | |
| }
 | |
| 
 | |
| // New Mattermost client.
 | |
| func New(url string, config Config) *Client {
 | |
| 	c := &Client{Url: url, In: make(chan IMessage), Out: make(chan OMessage), Config: config}
 | |
| 	tr := &http.Transport{
 | |
| 		TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify},
 | |
| 	}
 | |
| 	c.httpclient = &http.Client{Transport: tr}
 | |
| 	if !c.DisableServer {
 | |
| 		_, _, err := net.SplitHostPort(c.BindAddress)
 | |
| 		if err != nil {
 | |
| 			log.Fatalf("incorrect bindaddress %s", c.BindAddress)
 | |
| 		}
 | |
| 		go c.StartServer()
 | |
| 	}
 | |
| 	return c
 | |
| }
 | |
| 
 | |
| // StartServer starts a webserver listening for incoming mattermost POSTS.
 | |
| func (c *Client) StartServer() {
 | |
| 	mux := http.NewServeMux()
 | |
| 	mux.Handle("/", c)
 | |
| 	srv := &http.Server{
 | |
| 		ReadTimeout:  5 * time.Second,
 | |
| 		WriteTimeout: 10 * time.Second,
 | |
| 		Handler:      mux,
 | |
| 		Addr:         c.BindAddress,
 | |
| 	}
 | |
| 	log.Printf("Listening on http://%v...\n", c.BindAddress)
 | |
| 	if err := srv.ListenAndServe(); err != nil {
 | |
| 		log.Fatal(err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // ServeHTTP implementation.
 | |
| func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | |
| 	if r.Method != "POST" {
 | |
| 		log.Println("invalid " + r.Method + " connection from " + r.RemoteAddr)
 | |
| 		http.NotFound(w, r)
 | |
| 		return
 | |
| 	}
 | |
| 	msg := IMessage{}
 | |
| 	err := r.ParseForm()
 | |
| 	if err != nil {
 | |
| 		log.Println(err)
 | |
| 		http.NotFound(w, r)
 | |
| 		return
 | |
| 	}
 | |
| 	defer r.Body.Close()
 | |
| 	decoder := schema.NewDecoder()
 | |
| 	err = decoder.Decode(&msg, r.PostForm)
 | |
| 	if err != nil {
 | |
| 		log.Println(err)
 | |
| 		http.NotFound(w, r)
 | |
| 		return
 | |
| 	}
 | |
| 	if msg.Token == "" {
 | |
| 		log.Println("no token from " + r.RemoteAddr)
 | |
| 		http.NotFound(w, r)
 | |
| 		return
 | |
| 	}
 | |
| 	if c.Token != "" {
 | |
| 		if msg.Token != c.Token {
 | |
| 			log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr)
 | |
| 			http.NotFound(w, r)
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	c.In <- msg
 | |
| }
 | |
| 
 | |
| // Receive returns an incoming message from mattermost outgoing webhooks URL.
 | |
| func (c *Client) Receive() IMessage {
 | |
| 	var msg IMessage
 | |
| 	for msg := range c.In {
 | |
| 		return msg
 | |
| 	}
 | |
| 	return msg
 | |
| }
 | |
| 
 | |
| // Send sends a msg to mattermost incoming webhooks URL.
 | |
| func (c *Client) Send(msg OMessage) error {
 | |
| 	buf, err := json.Marshal(msg)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	resp, err := c.httpclient.Post(c.Url, "application/json", bytes.NewReader(buf))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	defer resp.Body.Close()
 | |
| 
 | |
| 	// Read entire body to completion to re-use keep-alive connections.
 | |
| 	io.Copy(ioutil.Discard, resp.Body)
 | |
| 
 | |
| 	if resp.StatusCode != 200 {
 | |
| 		return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | 
