truckstop/message/matrix.go

181 lines
4.5 KiB
Go

package message
import (
"bytes"
"fmt"
"io/ioutil"
"local/truckstop/config"
"local/truckstop/logtr"
"net/http"
"regexp"
"strings"
"time"
"github.com/matrix-org/gomatrix"
)
type Matrix struct {
mock bool
homeserver string
username string
token string
room string
continuation string
}
func NewMatrix() Matrix {
conf := config.Get().Message.Matrix
return Matrix{
homeserver: conf.Homeserver,
username: conf.Username,
token: conf.Token,
room: conf.Room,
mock: conf.Mock,
continuation: GetMatrixContinuation(),
}
}
func (m Matrix) getclient() (*gomatrix.Client, error) {
return gomatrix.NewClient(m.homeserver, m.username, m.token)
}
func (m Matrix) Continuation() string {
return m.continuation
}
func (m *Matrix) Receive() ([]Message, error) {
if m.mock {
logtr.Infof("matrix.Receive()")
messages := make([]Message, 0)
for k := range config.Get().Clients {
messages = append(messages, Message{Timestamp: time.Now(), Sender: k, Content: "!state nc"})
if k == "bel" {
messages = append(messages, Message{Timestamp: time.Now(), Sender: k, Content: "!help"})
}
if k == "broc" {
messages = append(messages, Message{Timestamp: time.Now(), Sender: k, Content: "!available 2148-10-" + fmt.Sprint(time.Now().Unix()%28)})
}
}
return messages, nil
}
clients := config.Get().Clients
matrixIDs := map[string]struct{}{}
for k := range clients {
matrixIDs[clients[k].IDs.Matrix] = struct{}{}
}
if len(matrixIDs) == 0 {
return nil, nil
}
c, err := m.getclient()
if err != nil {
return nil, err
}
messages := make([]Message, 0)
result, err := c.Messages(m.room, "999999999999999999", m.Continuation(), 'b', 50)
if err != nil {
return nil, err
}
logtr.Debugf("%s => {Start:%s End:%v};; %v, (%d)", m.Continuation(), result.Start, result.End, err, len(result.Chunk))
m.continuation = result.End
for _, event := range result.Chunk {
if _, ok := matrixIDs[event.Sender]; !ok {
continue
}
switch event.Type {
case "m.room.message":
b, ok := event.Body()
if ok {
messages = append(messages, Message{Timestamp: time.Unix(0, event.Timestamp*int64(time.Millisecond)), Sender: event.Sender, Content: strings.TrimSpace(b)})
}
}
}
clientChange := regexp.MustCompile("@[a-z]+$")
logtr.Debugf("rewriting messages based on @abc")
for i := range messages {
if found := clientChange.FindString(messages[i].Content); found != "" {
messages[i].Content = strings.TrimSpace(strings.ReplaceAll(messages[i].Content, found, ""))
messages[i].Sender = found[1:]
} else {
for k, v := range config.Get().Clients {
if v.IDs.Matrix == messages[i].Sender {
messages[i].Sender = k
}
}
}
messages[i].Content = strings.TrimSpace(messages[i].Content)
}
logtr.Debugf("rewriting messages based on ! CoMmAnD ...")
for i := range messages {
if strings.HasPrefix(messages[i].Content, "!") {
messages[i].Content = "!" + strings.TrimSpace(messages[i].Content[1:])
splits := strings.Split(messages[i].Content, " ")
messages[i].Content = strings.ToLower(splits[0]) + " " + strings.Join(splits, " ")
}
}
return messages, nil
}
func (m Matrix) Send(text string) error {
if m.mock {
logtr.Infof("matrix.Send(%s)", text)
return nil
}
c, err := m.getclient()
if err != nil {
return err
}
_, err = c.SendText(m.room, text)
return err
}
func (m Matrix) SendImage(uri string) error {
if m.mock {
logtr.Infof("matrix.SendImage(%s)", uri)
return nil
}
response, err := http.Get(uri)
if err != nil {
return err
}
if response.StatusCode != http.StatusOK {
b, _ := ioutil.ReadAll(response.Body)
response.Body.Close()
return fmt.Errorf("failed to get %s: (%d) %s", uri, response.StatusCode, b)
}
b, err := ioutil.ReadAll(response.Body)
response.Body.Close()
if err != nil {
return err
}
c, err := m.getclient()
if err != nil {
return err
}
mediaUpload, err := c.UploadToContentRepo(bytes.NewReader(b), "image/jpeg", int64(len(b)))
if err != nil {
return err
}
publicURI := mediaUpload.ContentURI
resp, err := c.SendImage(m.room, "img", publicURI)
logtr.Debugf("sent image %s => %s: %+v", uri, publicURI, resp)
return err
}
func SetMatrixContinuation(continuation string) {
db := config.Get().DB()
db.Set(getMatrixContinuationKey(), []byte(continuation))
}
func GetMatrixContinuation() string {
db := config.Get().DB()
b, _ := db.Get(getMatrixContinuationKey())
if b == nil {
return "0"
}
return string(b)
}
func getMatrixContinuationKey() string {
return "matrix_continuation"
}