3
0
mirror of https://github.com/42wim/matterbridge.git synced 2024-12-23 11:42:37 +01:00
matterbridge/matterhook/matterhook.go

169 lines
4.5 KiB
Go
Raw Normal View History

2015-10-23 23:31:14 +02:00
//Package matterhook provides interaction with mattermost incoming/outgoing webhooks
2015-10-23 17:09:08 +02:00
package matterhook
import (
"bytes"
"crypto/tls"
2015-10-23 17:09:08 +02:00
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
2016-07-11 23:22:56 +02:00
"net"
2015-10-23 17:09:08 +02:00
"net/http"
"time"
"github.com/gorilla/schema"
"github.com/slack-go/slack"
2015-10-23 17:09:08 +02:00
)
// OMessage for mattermost incoming webhook. (send to mattermost)
type OMessage struct {
2017-09-18 23:43:21 +02:00
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"`
2017-09-18 23:43:21 +02:00
Type string `json:"type,omitempty"`
Props map[string]interface{} `json:"props"`
2015-10-23 17:09:08 +02:00
}
// IMessage for mattermost outgoing webhook. (received from mattermost)
type IMessage struct {
2016-09-05 16:34:37 +02:00
BotID string `schema:"bot_id"`
BotName string `schema:"bot_name"`
2015-10-23 17:09:08 +02:00
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
2016-09-05 16:34:37 +02:00
RawText string `schema:"raw_text"`
ServiceId string `schema:"service_id"` //nolint:golint
2015-10-23 17:09:08 +02:00
Text string `schema:"text"`
TriggerWord string `schema:"trigger_word"`
FileIDs string `schema:"file_ids"`
2015-10-23 17:09:08 +02:00
}
// 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
2015-10-23 17:09:08 +02:00
Config
}
2015-10-24 18:01:15 +02:00
// Config for client.
2015-10-23 17:09:08 +02:00
type Config struct {
2015-12-12 21:26:53 +01:00
BindAddress string // Address to listen on
Token string // Only allow this token from Mattermost. (Allow everything when empty)
InsecureSkipVerify bool // disable certificate checking
2015-10-28 17:18:05 +01:00
DisableServer bool // Do not start server for outgoing webhooks from Mattermost.
2015-10-23 17:09:08 +02:00
}
// New Mattermost client.
func New(url string, config Config) *Client {
2015-10-28 17:18:05 +01:00
c := &Client{Url: url, In: make(chan IMessage), Out: make(chan OMessage), Config: config}
tr := &http.Transport{
2018-12-06 00:40:55 +01:00
TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify}, //nolint:gosec
}
c.httpclient = &http.Client{Transport: tr}
2015-10-28 17:18:05 +01:00
if !c.DisableServer {
_, _, err := net.SplitHostPort(c.BindAddress)
if err != nil {
log.Fatalf("incorrect bindaddress %s", c.BindAddress)
}
2015-10-28 17:18:05 +01:00
go c.StartServer()
}
2015-10-23 17:09:08 +02:00
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,
}
2016-07-11 23:22:56 +02:00
log.Printf("Listening on http://%v...\n", c.BindAddress)
if err := srv.ListenAndServe(); err != nil {
2015-10-23 17:09:08 +02:00
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
}
2015-10-23 17:09:08 +02:00
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
}
2015-10-24 18:01:15 +02:00
if c.Token != "" {
if msg.Token != c.Token {
log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr)
http.NotFound(w, r)
return
}
}
2015-10-23 17:09:08 +02:00
c.In <- msg
}
// Receive returns an incoming message from mattermost outgoing webhooks URL.
func (c *Client) Receive() IMessage {
2017-07-14 00:35:01 +02:00
var msg IMessage
for msg := range c.In {
return msg
2015-10-23 17:09:08 +02:00
}
2017-07-14 00:35:01 +02:00
return msg
2015-10-23 17:09:08 +02:00
}
// 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
}
2015-10-28 17:18:05 +01:00
resp, err := c.httpclient.Post(c.Url, "application/json", bytes.NewReader(buf))
2015-10-23 17:09:08 +02:00
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
}