aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--appservice/account.go18
-rw-r--r--appservice/db.go10
-rw-r--r--appservice/matrix.go275
-rw-r--r--appservice/names.go23
-rw-r--r--appservice/server.go14
-rw-r--r--appservice/util.go51
-rw-r--r--easybridge.jpgbin0 -> 39684 bytes
-rw-r--r--mxlib/client.go254
8 files changed, 328 insertions, 317 deletions
diff --git a/appservice/account.go b/appservice/account.go
index e507230..311f266 100644
--- a/appservice/account.go
+++ b/appservice/account.go
@@ -81,7 +81,7 @@ func (a *Account) joinedInternal(roomId RoomID) error {
log.Debugf("Joined %s (%s)\n", roomId, a.MatrixUser)
- err = mxRoomInvite(mx_room_id, a.MatrixUser)
+ err = mx.RoomInvite(mx_room_id, a.MatrixUser)
if err != nil && strings.Contains(err.Error(), "already in the room") {
err = nil
}
@@ -107,7 +107,7 @@ func (a *Account) leftInternal(roomId RoomID) error {
log.Printf("Left %s (%s)\n", roomId, a.MatrixUser)
- err = mxRoomKick(mx_room_id, a.MatrixUser, fmt.Sprintf("got leave room event on %s", a.Protocol))
+ err = mx.RoomKick(mx_room_id, a.MatrixUser, fmt.Sprintf("got leave room event on %s", a.Protocol))
if err != nil && strings.Contains(err.Error(), "not in the room") {
err = nil
}
@@ -130,7 +130,7 @@ func (a *Account) userInfoUpdatedInternal(user UserID, info *UserInfo) error {
}
if info.DisplayName != "" {
- err2 := mxProfileDisplayname(mx_user_id, fmt.Sprintf("%s (%s)", info.DisplayName, a.Protocol))
+ err2 := mx.ProfileDisplayname(mx_user_id, fmt.Sprintf("%s (%s)", info.DisplayName, a.Protocol))
if err2 != nil {
err = err2
}
@@ -167,7 +167,7 @@ func (a *Account) roomInfoUpdatedInternal(roomId RoomID, author UserID, info *Ro
}
if info.Topic != "" {
- err2 := mxRoomTopicAs(mx_room_id, info.Topic, as_mxid)
+ err2 := mx.RoomTopicAs(mx_room_id, info.Topic, as_mxid)
if err2 != nil {
err = err2
}
@@ -175,7 +175,7 @@ func (a *Account) roomInfoUpdatedInternal(roomId RoomID, author UserID, info *Ro
if info.Name != "" {
name := fmt.Sprintf("%s (%s)", info.Name, a.Protocol)
- err2 := mxRoomNameAs(mx_room_id, name, as_mxid)
+ err2 := mx.RoomNameAs(mx_room_id, name, as_mxid)
if err2 != nil {
err = err2
}
@@ -211,7 +211,7 @@ func (a *Account) eventInternal(event *Event) error {
return err
}
- err = mxRoomInvite(mx_room_id, mx_user_id)
+ err = mx.RoomInvite(mx_room_id, mx_user_id)
if err != nil {
if strings.Contains(err.Error(), "already in the room") {
err = nil
@@ -219,7 +219,7 @@ func (a *Account) eventInternal(event *Event) error {
return err
}
- return mxRoomJoinAs(mx_room_id, mx_user_id)
+ return mx.RoomJoinAs(mx_room_id, mx_user_id)
} else if event.Type == EVENT_LEAVE {
log.Printf("%s join %s %s", a.Protocol, event.Author, event.Room)
mx_room_id, err := dbGetMxRoom(a.Protocol, event.Room)
@@ -227,7 +227,7 @@ func (a *Account) eventInternal(event *Event) error {
return err
}
- return mxRoomLeaveAs(mx_room_id, mx_user_id)
+ return mx.RoomLeaveAs(mx_room_id, mx_user_id)
} else {
log.Printf("%s msg %s %s", a.Protocol, event.Author, event.Room)
mx_room_id := ""
@@ -249,6 +249,6 @@ func (a *Account) eventInternal(event *Event) error {
typ = "m.emote"
}
- return mxSendMessageAs(mx_room_id, typ, event.Text, mx_user_id)
+ return mx.SendMessageAs(mx_room_id, typ, event.Text, mx_user_id)
}
}
diff --git a/appservice/db.go b/appservice/db.go
index 6423b95..5cefd30 100644
--- a/appservice/db.go
+++ b/appservice/db.go
@@ -88,13 +88,13 @@ func dbGetMxRoom(protocol string, roomId connector.RoomID) (string, error) {
if must_create {
alias := roomAlias(protocol, roomId)
// Lookup alias
- mx_room_id, err := mxDirectoryRoom(fmt.Sprintf("#%s:%s", alias, config.MatrixDomain))
+ mx_room_id, err := mx.DirectoryRoom(fmt.Sprintf("#%s:%s", alias, config.MatrixDomain))
// If no alias found, create room
if err != nil {
name := fmt.Sprintf("%s (%s)", roomId, protocol)
- mx_room_id, err = mxCreateRoom(name, alias, []string{})
+ mx_room_id, err = mx.CreateRoom(name, alias, []string{})
if err != nil {
log.Printf("Could not create room for %s: %s", name, err)
return "", err
@@ -125,7 +125,7 @@ func dbGetMxPmRoom(protocol string, them connector.UserID, themMxId string, usMx
if must_create {
name := fmt.Sprintf("%s (%s)", them, protocol)
- mx_room_id, err := mxCreateDirectRoomAs([]string{usMxId}, themMxId)
+ mx_room_id, err := mx.CreateDirectRoomAs([]string{usMxId}, themMxId)
if err != nil {
log.Printf("Could not create room for %s: %s", name, err)
return "", err
@@ -161,7 +161,7 @@ func dbGetMxUser(protocol string, userId connector.UserID) (string, error) {
if must_create {
username := userMxId(protocol, userId)
- err := mxRegisterUser(username)
+ err := mx.RegisterUser(username)
if err != nil {
if mxE, ok := err.(*mxlib.MxError); !ok || mxE.ErrCode != "M_USER_IN_USE" {
log.Printf("Could not register %s: %s", username, err)
@@ -170,7 +170,7 @@ func dbGetMxUser(protocol string, userId connector.UserID) (string, error) {
}
mxid := fmt.Sprintf("@%s:%s", username, config.MatrixDomain)
- mxProfileDisplayname(mxid, fmt.Sprintf("%s (%s)", userId, protocol))
+ mx.ProfileDisplayname(mxid, fmt.Sprintf("%s (%s)", userId, protocol))
user = DbUserMap{
Protocol: protocol,
diff --git a/appservice/matrix.go b/appservice/matrix.go
deleted file mode 100644
index 6b99992..0000000
--- a/appservice/matrix.go
+++ /dev/null
@@ -1,275 +0,0 @@
-package appservice
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "net/http"
- "net/url"
- "time"
-
- log "github.com/sirupsen/logrus"
-
- "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
- . "git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
-)
-
-const EASYBRIDGE_SYSTEM_PROTOCOL string = "✯◡✯"
-
-func ezbrMxId() string {
- return fmt.Sprintf("@%s:%s", registration.SenderLocalpart, config.MatrixDomain)
-}
-
-func ezbrSystemRoom(user_mx_id string) (string, error) {
- return dbGetMxPmRoom(EASYBRIDGE_SYSTEM_PROTOCOL, connector.UserID("Easybridge"), ezbrMxId(), user_mx_id, "easybridge")
-}
-
-func ezbrSystemSend(user_mx_id string, msg string) {
- mx_room_id, err := ezbrSystemRoom(user_mx_id)
- if err == nil {
- err = mxSendMessageAs(mx_room_id, "m.text", msg, ezbrMxId())
- }
- if err != nil {
- log.Warnf("(%s) %s", user_mx_id, msg)
- }
-}
-
-func ezbrSystemSendf(user_mx_id string, format string, args ...interface{}) {
- ezbrSystemSend(user_mx_id, fmt.Sprintf(format, args...))
-}
-
-// ----
-
-var httpClient *http.Client
-
-func init() {
- tr := &http.Transport{
- MaxIdleConns: 10,
- IdleConnTimeout: 30 * time.Second,
- DisableCompression: true,
- }
- httpClient = &http.Client{Transport: tr}
-}
-
-func mxGetApiCall(endpoint string, response interface{}) error {
- log.Debugf("Matrix GET request: %s\n", endpoint)
-
- req, err := http.NewRequest("GET", config.Server+endpoint, nil)
- if err != nil {
- return err
- }
-
- return mxDoAndParse(req, response)
-}
-
-func mxPutApiCall(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", config.Server+endpoint, bytes.NewBuffer(body))
- if err != nil {
- return err
- }
- req.Header.Add("Content-Type", "application/json")
-
- return mxDoAndParse(req, response)
-}
-
-func mxPostApiCall(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", config.Server+endpoint, bytes.NewBuffer(body))
- if err != nil {
- return err
- }
- req.Header.Add("Content-Type", "application/json")
-
- return mxDoAndParse(req, response)
-}
-
-func mxDoAndParse(req *http.Request, response interface{}) error {
- req.Header.Add("Authorization", "Bearer "+registration.AsToken)
-
- resp, err := 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 mxRegisterUser(username string) error {
- req := RegisterRequest{
- Username: username,
- }
- var rep RegisterResponse
- return mxPostApiCall("/_matrix/client/r0/register?kind=user", &req, &rep)
-}
-
-func mxProfileDisplayname(userid string, displayname string) error {
- req := ProfileDisplaynameRequest{
- Displayname: displayname,
- }
- var rep struct{}
- err := mxPutApiCall(fmt.Sprintf("/_matrix/client/r0/profile/%s/displayname?user_id=%s",
- url.QueryEscape(userid), url.QueryEscape(userid)),
- &req, &rep)
- return err
-}
-
-func mxDirectoryRoom(alias string) (string, error) {
- var rep DirectoryRoomResponse
- err := mxGetApiCall("/_matrix/client/r0/directory/room/"+url.QueryEscape(alias), &rep)
- if err != nil {
- return "", err
- }
- return rep.RoomId, nil
-}
-
-func mxCreateRoom(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 := mxPostApiCall("/_matrix/client/r0/createRoom", &rq, &rep)
- if err != nil {
- return "", err
- }
- return rep.RoomId, nil
-}
-
-func mxCreateDirectRoomAs(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 := mxPostApiCall("/_matrix/client/r0/createRoom?user_id="+url.QueryEscape(as_user), &rq, &rep)
- if err != nil {
- return "", err
- }
- return rep.RoomId, nil
-}
-
-func mxRoomInvite(room string, user string) error {
- rq := RoomInviteRequest{
- UserId: user,
- }
- var rep struct{}
- err := mxPostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/invite", &rq, &rep)
- return err
-}
-
-func mxRoomKick(room string, user string, reason string) error {
- rq := RoomKickRequest{
- UserId: user,
- Reason: reason,
- }
- var rep struct{}
- err := mxPostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/kick", &rq, &rep)
- return err
-}
-
-func mxRoomJoinAs(room string, user string) error {
- rq := struct{}{}
- var rep RoomJoinResponse
- err := mxPostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/join?user_id="+url.QueryEscape(user), &rq, &rep)
- return err
-}
-
-func mxRoomLeaveAs(room string, user string) error {
- rq := struct{}{}
- var rep struct{}
- err := mxPostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/leave?user_id="+url.QueryEscape(user), &rq, &rep)
- return err
-}
-
-func mxSendAs(room string, event_type string, content map[string]interface{}, user string) error {
- txn_id := time.Now().UnixNano()
- var rep RoomSendResponse
- err := mxPutApiCall(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 mxSendMessageAs(room string, typ string, body string, user string) error {
- content := map[string]interface{}{
- "msgtype": typ,
- "body": body,
- }
- return mxSendAs(room, "m.room.message", content, user)
-}
-
-func mxPutStateAs(room string, event_type string, key string, content map[string]interface{}, as_user string) error {
- var rep RoomSendResponse
- err := mxPutApiCall(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 mxRoomNameAs(room string, name string, as_user string) error {
- content := map[string]interface{}{
- "name": name,
- }
- return mxPutStateAs(room, "m.room.name", "", content, as_user)
-}
-
-func mxRoomTopicAs(room string, topic string, as_user string) error {
- content := map[string]interface{}{
- "topic": topic,
- }
- return mxPutStateAs(room, "m.room.topic", "", content, as_user)
-}
diff --git a/appservice/names.go b/appservice/names.go
deleted file mode 100644
index 9ed00f8..0000000
--- a/appservice/names.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package appservice
-
-import (
- "fmt"
- "strings"
-
- . "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
-)
-
-func roomAlias(protocol string, id RoomID) string {
- return fmt.Sprintf("_ezbr__%s__%s", safeStringForId(string(id)), protocol)
-}
-
-func userMxId(protocol string, id UserID) string {
- return fmt.Sprintf("_ezbr__%s__%s", safeStringForId(string(id)), protocol)
-}
-
-func safeStringForId(in string) string {
- id2 := strings.ReplaceAll(in, "#", "")
- id2 = strings.ReplaceAll(id2, "@", "__")
- id2 = strings.ReplaceAll(id2, ":", "_")
- return id2
-}
diff --git a/appservice/server.go b/appservice/server.go
index aa43935..d3ecb43 100644
--- a/appservice/server.go
+++ b/appservice/server.go
@@ -24,20 +24,24 @@ type Config struct {
var registration *mxlib.Registration
var config *Config
+var mx *mxlib.Client
+
func Start(r *mxlib.Registration, c *Config) (chan error, error) {
registration = r
config = c
+ mx = mxlib.NewClient(c.Server, r.AsToken)
+
err := InitDb()
if err != nil {
return nil, err
}
- err = mxRegisterUser(registration.SenderLocalpart)
+ err = mx.RegisterUser(registration.SenderLocalpart)
if mxe, ok := err.(*mxlib.MxError); !ok || mxe.ErrCode != "M_USER_IN_USE" {
return nil, err
}
- err = mxProfileDisplayname(ezbrMxId(), fmt.Sprintf("Easybridge (%s)", EASYBRIDGE_SYSTEM_PROTOCOL))
+ err = mx.ProfileDisplayname(ezbrMxId(), fmt.Sprintf("Easybridge (%s)", EASYBRIDGE_SYSTEM_PROTOCOL))
if err != nil {
return nil, err
}
@@ -134,7 +138,7 @@ func handleTxnEvent(e *mxlib.Event) error {
ev.Room = room.RoomID
return acct.Conn.Send(ev)
} else {
- mxRoomKick(e.RoomId, e.Sender, fmt.Sprintf("Not present in %s on %s, please talk with Easybridge to rejoin", room.RoomID, room.Protocol))
+ mx.RoomKick(e.RoomId, e.Sender, fmt.Sprintf("Not present in %s on %s, please talk with Easybridge to rejoin", room.RoomID, room.Protocol))
return fmt.Errorf("not joined %s on %s", room.RoomID, room.Protocol)
}
} else {
@@ -146,7 +150,7 @@ func handleTxnEvent(e *mxlib.Event) error {
if pm_room := dbIsPmRoom(e.RoomId); pm_room != nil {
// If leaving a PM room, we must delete it
them_mx := userMxId(pm_room.Protocol, pm_room.UserID)
- mxRoomLeaveAs(e.RoomId, them_mx)
+ mx.RoomLeaveAs(e.RoomId, them_mx)
db.Delete(pm_room)
return nil
} else if room := dbIsPublicRoom(e.RoomId); room != nil {
@@ -157,7 +161,7 @@ func handleTxnEvent(e *mxlib.Event) error {
return nil
// TODO: manage autojoin list, remove this room
} else {
- mxRoomKick(e.RoomId, e.Sender, fmt.Sprintf("Not present in %s on %s, please talk with Easybridge to rejoin", room.RoomID, room.Protocol))
+ mx.RoomKick(e.RoomId, e.Sender, fmt.Sprintf("Not present in %s on %s, please talk with Easybridge to rejoin", room.RoomID, room.Protocol))
return fmt.Errorf("not joined %s on %s", room.RoomID, room.Protocol)
}
} else {
diff --git a/appservice/util.go b/appservice/util.go
new file mode 100644
index 0000000..4175fb0
--- /dev/null
+++ b/appservice/util.go
@@ -0,0 +1,51 @@
+package appservice
+
+import (
+ "fmt"
+ "strings"
+
+ log "github.com/sirupsen/logrus"
+
+ . "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
+)
+
+const EASYBRIDGE_SYSTEM_PROTOCOL string = "✯◡✯"
+
+func ezbrMxId() string {
+ return fmt.Sprintf("@%s:%s", registration.SenderLocalpart, config.MatrixDomain)
+}
+
+func ezbrSystemRoom(user_mx_id string) (string, error) {
+ return dbGetMxPmRoom(EASYBRIDGE_SYSTEM_PROTOCOL, UserID("Easybridge"), ezbrMxId(), user_mx_id, "easybridge")
+}
+
+func ezbrSystemSend(user_mx_id string, msg string) {
+ mx_room_id, err := ezbrSystemRoom(user_mx_id)
+ if err == nil {
+ err = mx.SendMessageAs(mx_room_id, "m.text", msg, ezbrMxId())
+ }
+ if err != nil {
+ log.Warnf("(%s) %s", user_mx_id, msg)
+ }
+}
+
+func ezbrSystemSendf(user_mx_id string, format string, args ...interface{}) {
+ ezbrSystemSend(user_mx_id, fmt.Sprintf(format, args...))
+}
+
+// ----
+
+func roomAlias(protocol string, id RoomID) string {
+ return fmt.Sprintf("_ezbr__%s__%s", safeStringForId(string(id)), protocol)
+}
+
+func userMxId(protocol string, id UserID) string {
+ return fmt.Sprintf("_ezbr__%s__%s", safeStringForId(string(id)), protocol)
+}
+
+func safeStringForId(in string) string {
+ id2 := strings.ReplaceAll(in, "#", "")
+ id2 = strings.ReplaceAll(id2, "@", "__")
+ id2 = strings.ReplaceAll(id2, ":", "_")
+ return id2
+}
diff --git a/easybridge.jpg b/easybridge.jpg
new file mode 100644
index 0000000..b9d83a8
--- /dev/null
+++ b/easybridge.jpg
Binary files differ
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)
+}