From a4cf41536fc8eef743cd330b86e784079100ec6c Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 21 Feb 2020 14:27:42 +0100 Subject: Refactor: move all mx* functions to mxlib/client.go --- mxlib/client.go | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 mxlib/client.go (limited to 'mxlib') diff --git a/mxlib/client.go b/mxlib/client.go new file mode 100644 index 0000000..2385d6e --- /dev/null +++ b/mxlib/client.go @@ -0,0 +1,254 @@ +package mxlib + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "net/url" + "time" + + log "github.com/sirupsen/logrus" +) + +type Client struct { + Server string + Token string + httpClient *http.Client +} + +func NewClient(server string, token string) *Client { + tr := &http.Transport{ + MaxIdleConns: 10, + IdleConnTimeout: 30 * time.Second, + DisableCompression: true, + } + return &Client{ + Server: server, + Token: token, + httpClient: &http.Client{Transport: tr}, + } +} + +func (mx *Client) GetApiCall(endpoint string, response interface{}) error { + log.Debugf("Matrix GET request: %s\n", endpoint) + + req, err := http.NewRequest("GET", mx.Server+endpoint, nil) + if err != nil { + return err + } + + return mx.DoAndParse(req, response) +} + +func (mx *Client) PutApiCall(endpoint string, data interface{}, response interface{}) error { + body, err := json.Marshal(data) + if err != nil { + return err + } + + log.Debugf("Matrix PUT request: %s %s\n", endpoint, string(body)) + + req, err := http.NewRequest("PUT", mx.Server+endpoint, bytes.NewBuffer(body)) + if err != nil { + return err + } + req.Header.Add("Content-Type", "application/json") + + return mx.DoAndParse(req, response) +} + +func (mx *Client) PostApiCall(endpoint string, data interface{}, response interface{}) error { + body, err := json.Marshal(data) + if err != nil { + return err + } + + log.Debugf("Matrix POST request: %s %s\n", endpoint, string(body)) + + req, err := http.NewRequest("POST", mx.Server+endpoint, bytes.NewBuffer(body)) + if err != nil { + return err + } + req.Header.Add("Content-Type", "application/json") + + return mx.DoAndParse(req, response) +} + +func (mx *Client) DoAndParse(req *http.Request, response interface{}) error { + req.Header.Add("Authorization", "Bearer "+mx.Token) + + resp, err := mx.httpClient.Do(req) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + var e MxError + err = json.NewDecoder(resp.Body).Decode(&e) + if err != nil { + return err + } + log.Debugf("Response (%d): %#v\n", resp.StatusCode, e) + return &e + } + + err = json.NewDecoder(resp.Body).Decode(response) + if err != nil { + return err + } + + log.Debugf("Response: %#v\n", response) + return nil +} + +// ---- + +func (mx *Client) RegisterUser(username string) error { + req := RegisterRequest{ + Username: username, + } + var rep RegisterResponse + return mx.PostApiCall("/_matrix/client/r0/register?kind=user", &req, &rep) +} + +func (mx *Client) ProfileDisplayname(userid string, displayname string) error { + req := ProfileDisplaynameRequest{ + Displayname: displayname, + } + var rep struct{} + err := mx.PutApiCall(fmt.Sprintf("/_matrix/client/r0/profile/%s/displayname?user_id=%s", + url.QueryEscape(userid), url.QueryEscape(userid)), + &req, &rep) + return err +} + +func (mx *Client) DirectoryRoom(alias string) (string, error) { + var rep DirectoryRoomResponse + err := mx.GetApiCall("/_matrix/client/r0/directory/room/"+url.QueryEscape(alias), &rep) + if err != nil { + return "", err + } + return rep.RoomId, nil +} + +func (mx *Client) CreateRoom(name string, alias string, invite []string) (string, error) { + rq := CreateRoomRequest{ + Preset: "private_chat", + RoomAliasName: alias, + Name: name, + Topic: "", + Invite: invite, + CreationContent: map[string]interface{}{ + "m.federate": false, + }, + PowerLevels: map[string]interface{}{ + "invite": 100, + "events": map[string]interface{}{ + "m.room.topic": 0, + "m.room.avatar": 0, + }, + }, + } + var rep CreateRoomResponse + err := mx.PostApiCall("/_matrix/client/r0/createRoom", &rq, &rep) + if err != nil { + return "", err + } + return rep.RoomId, nil +} + +func (mx *Client) CreateDirectRoomAs(invite []string, as_user string) (string, error) { + rq := CreateDirectRoomRequest{ + Preset: "private_chat", + Topic: "", + Invite: invite, + CreationContent: map[string]interface{}{ + "m.federate": false, + }, + PowerLevels: map[string]interface{}{ + "invite": 100, + }, + IsDirect: true, + } + var rep CreateRoomResponse + err := mx.PostApiCall("/_matrix/client/r0/createRoom?user_id="+url.QueryEscape(as_user), &rq, &rep) + if err != nil { + return "", err + } + return rep.RoomId, nil +} + +func (mx *Client) RoomInvite(room string, user string) error { + rq := RoomInviteRequest{ + UserId: user, + } + var rep struct{} + err := mx.PostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/invite", &rq, &rep) + return err +} + +func (mx *Client) RoomKick(room string, user string, reason string) error { + rq := RoomKickRequest{ + UserId: user, + Reason: reason, + } + var rep struct{} + err := mx.PostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/kick", &rq, &rep) + return err +} + +func (mx *Client) RoomJoinAs(room string, user string) error { + rq := struct{}{} + var rep RoomJoinResponse + err := mx.PostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/join?user_id="+url.QueryEscape(user), &rq, &rep) + return err +} + +func (mx *Client) RoomLeaveAs(room string, user string) error { + rq := struct{}{} + var rep struct{} + err := mx.PostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/leave?user_id="+url.QueryEscape(user), &rq, &rep) + return err +} + +func (mx *Client) SendAs(room string, event_type string, content map[string]interface{}, user string) error { + txn_id := time.Now().UnixNano() + var rep RoomSendResponse + err := mx.PutApiCall(fmt.Sprintf( + "/_matrix/client/r0/rooms/%s/send/%s/%d?user_id=%s", + url.QueryEscape(room), event_type, txn_id, url.QueryEscape(user)), + &content, &rep) + return err +} + +func (mx *Client) SendMessageAs(room string, typ string, body string, user string) error { + content := map[string]interface{}{ + "msgtype": typ, + "body": body, + } + return mx.SendAs(room, "m.room.message", content, user) +} + +func (mx *Client) PutStateAs(room string, event_type string, key string, content map[string]interface{}, as_user string) error { + var rep RoomSendResponse + err := mx.PutApiCall(fmt.Sprintf( + "/_matrix/client/r0/rooms/%s/state/%s/%s?user_id=%s", + url.QueryEscape(room), event_type, key, url.QueryEscape(as_user)), + &content, &rep) + return err +} + +func (mx *Client) RoomNameAs(room string, name string, as_user string) error { + content := map[string]interface{}{ + "name": name, + } + return mx.PutStateAs(room, "m.room.name", "", content, as_user) +} + +func (mx *Client) RoomTopicAs(room string, topic string, as_user string) error { + content := map[string]interface{}{ + "topic": topic, + } + return mx.PutStateAs(room, "m.room.topic", "", content, as_user) +} -- cgit v1.2.3