summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/matterbridge/gomatrix/client.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/matterbridge/gomatrix/client.go')
-rw-r--r--vendor/github.com/matterbridge/gomatrix/client.go808
1 files changed, 0 insertions, 808 deletions
diff --git a/vendor/github.com/matterbridge/gomatrix/client.go b/vendor/github.com/matterbridge/gomatrix/client.go
deleted file mode 100644
index 6dda4bc4..00000000
--- a/vendor/github.com/matterbridge/gomatrix/client.go
+++ /dev/null
@@ -1,808 +0,0 @@
-// Package gomatrix implements the Matrix Client-Server API.
-//
-// Specification can be found at http://matrix.org/docs/spec/client_server/r0.2.0.html
-package gomatrix
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "path"
- "strconv"
- "strings"
- "sync"
- "time"
-)
-
-// Client represents a Matrix client.
-type Client struct {
- HomeserverURL *url.URL // The base homeserver URL
- Prefix string // The API prefix eg '/_matrix/client/r0'
- UserID string // The user ID of the client. Used for forming HTTP paths which use the client's user ID.
- AccessToken string // The access_token for the client.
- Client *http.Client // The underlying HTTP client which will be used to make HTTP requests.
- Syncer Syncer // The thing which can process /sync responses
- Store Storer // The thing which can store rooms/tokens/ids
-
- // The ?user_id= query parameter for application services. This must be set *prior* to calling a method. If this is empty,
- // no user_id parameter will be sent.
- // See http://matrix.org/docs/spec/application_service/unstable.html#identity-assertion
- AppServiceUserID string
-
- syncingMutex sync.Mutex // protects syncingID
- syncingID uint32 // Identifies the current Sync. Only one Sync can be active at any given time.
-}
-
-// HTTPError An HTTP Error response, which may wrap an underlying native Go Error.
-type HTTPError struct {
- Contents []byte
- WrappedError error
- Message string
- Code int
-}
-
-func (e HTTPError) Error() string {
- var wrappedErrMsg string
- if e.WrappedError != nil {
- wrappedErrMsg = e.WrappedError.Error()
- }
- return fmt.Sprintf("contents=%v msg=%s code=%d wrapped=%s", e.Contents, e.Message, e.Code, wrappedErrMsg)
-}
-
-// BuildURL builds a URL with the Client's homserver/prefix/access_token set already.
-func (cli *Client) BuildURL(urlPath ...string) string {
- ps := []string{cli.Prefix}
- for _, p := range urlPath {
- ps = append(ps, p)
- }
- return cli.BuildBaseURL(ps...)
-}
-
-// BuildBaseURL builds a URL with the Client's homeserver/access_token set already. You must
-// supply the prefix in the path.
-func (cli *Client) BuildBaseURL(urlPath ...string) string {
- // copy the URL. Purposefully ignore error as the input is from a valid URL already
- hsURL, _ := url.Parse(cli.HomeserverURL.String())
- parts := []string{hsURL.Path}
- parts = append(parts, urlPath...)
- hsURL.Path = path.Join(parts...)
- // Manually add the trailing slash back to the end of the path if it's explicitly needed
- if strings.HasSuffix(urlPath[len(urlPath)-1], "/") {
- hsURL.Path = hsURL.Path + "/"
- }
- query := hsURL.Query()
- if cli.AccessToken != "" {
- query.Set("access_token", cli.AccessToken)
- }
- if cli.AppServiceUserID != "" {
- query.Set("user_id", cli.AppServiceUserID)
- }
- hsURL.RawQuery = query.Encode()
- return hsURL.String()
-}
-
-// BuildURLWithQuery builds a URL with query parameters in addition to the Client's homeserver/prefix/access_token set already.
-func (cli *Client) BuildURLWithQuery(urlPath []string, urlQuery map[string]string) string {
- u, _ := url.Parse(cli.BuildURL(urlPath...))
- q := u.Query()
- for k, v := range urlQuery {
- q.Set(k, v)
- }
- u.RawQuery = q.Encode()
- return u.String()
-}
-
-// SetCredentials sets the user ID and access token on this client instance.
-func (cli *Client) SetCredentials(userID, accessToken string) {
- cli.AccessToken = accessToken
- cli.UserID = userID
-}
-
-// ClearCredentials removes the user ID and access token on this client instance.
-func (cli *Client) ClearCredentials() {
- cli.AccessToken = ""
- cli.UserID = ""
-}
-
-// Sync starts syncing with the provided Homeserver. If Sync() is called twice then the first sync will be stopped and the
-// error will be nil.
-//
-// This function will block until a fatal /sync error occurs, so it should almost always be started as a new goroutine.
-// Fatal sync errors can be caused by:
-// - The failure to create a filter.
-// - Client.Syncer.OnFailedSync returning an error in response to a failed sync.
-// - Client.Syncer.ProcessResponse returning an error.
-// If you wish to continue retrying in spite of these fatal errors, call Sync() again.
-func (cli *Client) Sync() error {
- // Mark the client as syncing.
- // We will keep syncing until the syncing state changes. Either because
- // Sync is called or StopSync is called.
- syncingID := cli.incrementSyncingID()
- nextBatch := cli.Store.LoadNextBatch(cli.UserID)
- filterID := cli.Store.LoadFilterID(cli.UserID)
- if filterID == "" {
- filterJSON := cli.Syncer.GetFilterJSON(cli.UserID)
- resFilter, err := cli.CreateFilter(filterJSON)
- if err != nil {
- return err
- }
- filterID = resFilter.FilterID
- cli.Store.SaveFilterID(cli.UserID, filterID)
- }
-
- for {
- resSync, err := cli.SyncRequest(30000, nextBatch, filterID, false, "")
- if err != nil {
- duration, err2 := cli.Syncer.OnFailedSync(resSync, err)
- if err2 != nil {
- return err2
- }
- time.Sleep(duration)
- continue
- }
-
- // Check that the syncing state hasn't changed
- // Either because we've stopped syncing or another sync has been started.
- // We discard the response from our sync.
- if cli.getSyncingID() != syncingID {
- return nil
- }
-
- // Save the token now *before* processing it. This means it's possible
- // to not process some events, but it means that we won't get constantly stuck processing
- // a malformed/buggy event which keeps making us panic.
- cli.Store.SaveNextBatch(cli.UserID, resSync.NextBatch)
- if err = cli.Syncer.ProcessResponse(resSync, nextBatch); err != nil {
- return err
- }
-
- nextBatch = resSync.NextBatch
- }
-}
-
-func (cli *Client) incrementSyncingID() uint32 {
- cli.syncingMutex.Lock()
- defer cli.syncingMutex.Unlock()
- cli.syncingID++
- return cli.syncingID
-}
-
-func (cli *Client) getSyncingID() uint32 {
- cli.syncingMutex.Lock()
- defer cli.syncingMutex.Unlock()
- return cli.syncingID
-}
-
-// StopSync stops the ongoing sync started by Sync.
-func (cli *Client) StopSync() {
- // Advance the syncing state so that any running Syncs will terminate.
- cli.incrementSyncingID()
-}
-
-// MakeRequest makes a JSON HTTP request to the given URL.
-// The response body will be stream decoded into an interface. This will automatically stop if the response
-// body is nil.
-//
-// Returns an error if the response is not 2xx along with the HTTP body bytes if it got that far. This error is
-// an HTTPError which includes the returned HTTP status code, byte contents of the response body and possibly a
-// RespError as the WrappedError, if the HTTP body could be decoded as a RespError.
-func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{}, resBody interface{}) error {
- var req *http.Request
- var err error
- if reqBody != nil {
- buf := new(bytes.Buffer)
- if err := json.NewEncoder(buf).Encode(reqBody); err != nil {
- return err
- }
- req, err = http.NewRequest(method, httpURL, buf)
- } else {
- req, err = http.NewRequest(method, httpURL, nil)
- }
-
- if err != nil {
- return err
- }
- req.Header.Set("Content-Type", "application/json")
- res, err := cli.Client.Do(req)
- if res != nil {
- defer res.Body.Close()
- }
- if err != nil {
- return err
- }
- if res.StatusCode/100 != 2 { // not 2xx
- contents, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return err
- }
-
- var wrap error
- var respErr RespError
- if _ = json.Unmarshal(contents, &respErr); respErr.ErrCode != "" {
- wrap = respErr
- }
-
- // If we failed to decode as RespError, don't just drop the HTTP body, include it in the
- // HTTP error instead (e.g proxy errors which return HTML).
- msg := "Failed to " + method + " JSON to " + req.URL.Path
- if wrap == nil {
- msg = msg + ": " + string(contents)
- }
-
- return HTTPError{
- Contents: contents,
- Code: res.StatusCode,
- Message: msg,
- WrappedError: wrap,
- }
- }
-
- if resBody != nil && res.Body != nil {
- return json.NewDecoder(res.Body).Decode(&resBody)
- }
-
- return nil
-}
-
-// CreateFilter makes an HTTP request according to http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-user-userid-filter
-func (cli *Client) CreateFilter(filter json.RawMessage) (resp *RespCreateFilter, err error) {
- urlPath := cli.BuildURL("user", cli.UserID, "filter")
- err = cli.MakeRequest("POST", urlPath, &filter, &resp)
- return
-}
-
-// SyncRequest makes an HTTP request according to http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-sync
-func (cli *Client) SyncRequest(timeout int, since, filterID string, fullState bool, setPresence string) (resp *RespSync, err error) {
- query := map[string]string{
- "timeout": strconv.Itoa(timeout),
- }
- if since != "" {
- query["since"] = since
- }
- if filterID != "" {
- query["filter"] = filterID
- }
- if setPresence != "" {
- query["set_presence"] = setPresence
- }
- if fullState {
- query["full_state"] = "true"
- }
- urlPath := cli.BuildURLWithQuery([]string{"sync"}, query)
- err = cli.MakeRequest("GET", urlPath, nil, &resp)
- return
-}
-
-func (cli *Client) register(u string, req *ReqRegister) (resp *RespRegister, uiaResp *RespUserInteractive, err error) {
- err = cli.MakeRequest("POST", u, req, &resp)
- if err != nil {
- httpErr, ok := err.(HTTPError)
- if !ok { // network error
- return
- }
- if httpErr.Code == 401 {
- // body should be RespUserInteractive, if it isn't, fail with the error
- err = json.Unmarshal(httpErr.Contents, &uiaResp)
- return
- }
- }
- return
-}
-
-// Register makes an HTTP request according to http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
-//
-// Registers with kind=user. For kind=guest, see RegisterGuest.
-func (cli *Client) Register(req *ReqRegister) (*RespRegister, *RespUserInteractive, error) {
- u := cli.BuildURL("register")
- return cli.register(u, req)
-}
-
-// RegisterGuest makes an HTTP request according to http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
-// with kind=guest.
-//
-// For kind=user, see Register.
-func (cli *Client) RegisterGuest(req *ReqRegister) (*RespRegister, *RespUserInteractive, error) {
- query := map[string]string{
- "kind": "guest",
- }
- u := cli.BuildURLWithQuery([]string{"register"}, query)
- return cli.register(u, req)
-}
-
-// RegisterDummy performs m.login.dummy registration according to https://matrix.org/docs/spec/client_server/r0.2.0.html#dummy-auth
-//
-// Only a username and password need to be provided on the ReqRegister struct. Most local/developer homeservers will allow registration
-// this way. If the homeserver does not, an error is returned.
-//
-// This does not set credentials on the client instance. See SetCredentials() instead.
-//
-// res, err := cli.RegisterDummy(&gomatrix.ReqRegister{
-// Username: "alice",
-// Password: "wonderland",
-// })
-// if err != nil {
-// panic(err)
-// }
-// token := res.AccessToken
-func (cli *Client) RegisterDummy(req *ReqRegister) (*RespRegister, error) {
- res, uia, err := cli.Register(req)
- if err != nil && uia == nil {
- return nil, err
- }
- if uia != nil && uia.HasSingleStageFlow("m.login.dummy") {
- req.Auth = struct {
- Type string `json:"type"`
- Session string `json:"session,omitempty"`
- }{"m.login.dummy", uia.Session}
- res, _, err = cli.Register(req)
- if err != nil {
- return nil, err
- }
- }
- if res == nil {
- return nil, fmt.Errorf("registration failed: does this server support m.login.dummy?")
- }
- return res, nil
-}
-
-// Login a user to the homeserver according to http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-login
-// This does not set credentials on this client instance. See SetCredentials() instead.
-func (cli *Client) Login(req *ReqLogin) (resp *RespLogin, err error) {
- urlPath := cli.BuildURL("login")
- err = cli.MakeRequest("POST", urlPath, req, &resp)
- return
-}
-
-// Logout the current user. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-logout
-// This does not clear the credentials from the client instance. See ClearCredentials() instead.
-func (cli *Client) Logout() (resp *RespLogout, err error) {
- urlPath := cli.BuildURL("logout")
- err = cli.MakeRequest("POST", urlPath, nil, &resp)
- return
-}
-
-// Versions returns the list of supported Matrix versions on this homeserver. See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-versions
-func (cli *Client) Versions() (resp *RespVersions, err error) {
- urlPath := cli.BuildBaseURL("_matrix", "client", "versions")
- err = cli.MakeRequest("GET", urlPath, nil, &resp)
- return
-}
-
-// PublicRooms returns the list of public rooms on target server. See https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-unstable-publicrooms
-func (cli *Client) PublicRooms(limit int, since string, server string) (resp *RespPublicRooms, err error) {
- args := map[string]string{}
-
- if limit != 0 {
- args["limit"] = strconv.Itoa(limit)
- }
- if since != "" {
- args["since"] = since
- }
- if server != "" {
- args["server"] = server
- }
-
- urlPath := cli.BuildURLWithQuery([]string{"publicRooms"}, args)
- err = cli.MakeRequest("GET", urlPath, nil, &resp)
- return
-}
-
-// PublicRoomsFiltered returns a subset of PublicRooms filtered server side.
-// See https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-unstable-publicrooms
-func (cli *Client) PublicRoomsFiltered(limit int, since string, server string, filter string) (resp *RespPublicRooms, err error) {
- content := map[string]string{}
-
- if limit != 0 {
- content["limit"] = strconv.Itoa(limit)
- }
- if since != "" {
- content["since"] = since
- }
- if filter != "" {
- content["filter"] = filter
- }
-
- var urlPath string
- if server == "" {
- urlPath = cli.BuildURL("publicRooms")
- } else {
- urlPath = cli.BuildURLWithQuery([]string{"publicRooms"}, map[string]string{
- "server": server,
- })
- }
-
- err = cli.MakeRequest("POST", urlPath, content, &resp)
- return
-}
-
-// JoinRoom joins the client to a room ID or alias. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-join-roomidoralias
-//
-// If serverName is specified, this will be added as a query param to instruct the homeserver to join via that server. If content is specified, it will
-// be JSON encoded and used as the request body.
-func (cli *Client) JoinRoom(roomIDorAlias, serverName string, content interface{}) (resp *RespJoinRoom, err error) {
- var urlPath string
- if serverName != "" {
- urlPath = cli.BuildURLWithQuery([]string{"join", roomIDorAlias}, map[string]string{
- "server_name": serverName,
- })
- } else {
- urlPath = cli.BuildURL("join", roomIDorAlias)
- }
- err = cli.MakeRequest("POST", urlPath, content, &resp)
- return
-}
-
-// GetDisplayName returns the display name of the user from the specified MXID. See https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
-func (cli *Client) GetDisplayName(mxid string) (resp *RespUserDisplayName, err error) {
- urlPath := cli.BuildURL("profile", mxid, "displayname")
- err = cli.MakeRequest("GET", urlPath, nil, &resp)
- return
-}
-
-// GetOwnDisplayName returns the user's display name. See https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
-func (cli *Client) GetOwnDisplayName() (resp *RespUserDisplayName, err error) {
- urlPath := cli.BuildURL("profile", cli.UserID, "displayname")
- err = cli.MakeRequest("GET", urlPath, nil, &resp)
- return
-}
-
-// SetDisplayName sets the user's profile display name. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-profile-userid-displayname
-func (cli *Client) SetDisplayName(displayName string) (err error) {
- urlPath := cli.BuildURL("profile", cli.UserID, "displayname")
- s := struct {
- DisplayName string `json:"displayname"`
- }{displayName}
- err = cli.MakeRequest("PUT", urlPath, &s, nil)
- return
-}
-
-// GetAvatarURL gets the user's avatar URL. See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-avatar-url
-func (cli *Client) GetAvatarURL() (string, error) {
- urlPath := cli.BuildURL("profile", cli.UserID, "avatar_url")
- s := struct {
- AvatarURL string `json:"avatar_url"`
- }{}
-
- err := cli.MakeRequest("GET", urlPath, nil, &s)
- if err != nil {
- return "", err
- }
-
- return s.AvatarURL, nil
-}
-
-// GetAvatarURL gets the user's avatar URL. See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-avatar-url
-func (cli *Client) GetSenderAvatarURL(sender string) (string, error) {
- urlPath := cli.BuildURL("profile", sender, "avatar_url")
- s := struct {
- AvatarURL string `json:"avatar_url"`
- }{}
-
- err := cli.MakeRequest("GET", urlPath, nil, &s)
- if err != nil {
- return "", err
- }
-
- return s.AvatarURL, nil
-}
-
-// SetAvatarURL sets the user's avatar URL. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-profile-userid-avatar-url
-func (cli *Client) SetAvatarURL(url string) error {
- urlPath := cli.BuildURL("profile", cli.UserID, "avatar_url")
- s := struct {
- AvatarURL string `json:"avatar_url"`
- }{url}
- err := cli.MakeRequest("PUT", urlPath, &s, nil)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// SendMessageEvent sends a message event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
-// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
-func (cli *Client) SendMessageEvent(roomID string, eventType string, contentJSON interface{}) (resp *RespSendEvent, err error) {
- txnID := txnID()
- urlPath := cli.BuildURL("rooms", roomID, "send", eventType, txnID)
- err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
- return
-}
-
-// SendStateEvent sends a state event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey
-// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
-func (cli *Client) SendStateEvent(roomID, eventType, stateKey string, contentJSON interface{}) (resp *RespSendEvent, err error) {
- urlPath := cli.BuildURL("rooms", roomID, "state", eventType, stateKey)
- err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
- return
-}
-
-// SendText sends an m.room.message event into the given room with a msgtype of m.text
-// See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-text
-func (cli *Client) SendText(roomID, text string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- TextMessage{"m.text", text, "", ""})
-}
-
-func (cli *Client) SendHTML(roomID, textclear, text string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- TextMessage{"m.text", textclear, "org.matrix.custom.html", text})
-}
-
-// SendImage sends an m.room.message event into the given room with a msgtype of m.image
-// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
-func (cli *Client) SendImage(roomID, body, url string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- ImageMessage{
- MsgType: "m.image",
- Body: body,
- URL: url,
- })
-}
-
-// SendVideo sends an m.room.message event into the given room with a msgtype of m.video
-// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
-func (cli *Client) SendVideo(roomID, body, url string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- VideoMessage{
- MsgType: "m.video",
- Body: body,
- URL: url,
- })
-}
-
-// SendAudio sends an m.room.message event into the given room with a msgtype of m.audio
-// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-audio
-func (cli *Client) SendAudio(roomID, body, url, mimetype string, size uint) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- AudioMessage{
- MsgType: "m.audio",
- Body: body,
- URL: url,
- Info: AudioInfo{
- Size: size,
- Mimetype: mimetype,
- },
- })
-}
-
-// SendFile sends an m.room.message event into the given room with a msgtype of m.file
-// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-file
-func (cli *Client) SendFile(roomID, body, url, mimetype string, size uint) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- FileMessage{
- MsgType: "m.file",
- Body: body,
- URL: url,
- Info: FileInfo{
- Size: size,
- Mimetype: mimetype,
- },
- })
-}
-
-// SendNotice sends an m.room.message event into the given room with a msgtype of m.notice
-// See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-notice
-func (cli *Client) SendNotice(roomID, text string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- TextMessage{"m.notice", text, "", ""})
-}
-
-func (cli *Client) SendNoticeHTML(roomID, textclear, text string) (*RespSendEvent, error) {
- return cli.SendMessageEvent(roomID, "m.room.message",
- TextMessage{"m.notice", textclear, "org.matrix.custom.html", text})
-}
-
-// RedactEvent redacts the given event. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
-func (cli *Client) RedactEvent(roomID, eventID string, req *ReqRedact) (resp *RespSendEvent, err error) {
- txnID := txnID()
- urlPath := cli.BuildURL("rooms", roomID, "redact", eventID, txnID)
- err = cli.MakeRequest("PUT", urlPath, req, &resp)
- return
-}
-
-// CreateRoom creates a new Matrix room. See https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
-// resp, err := cli.CreateRoom(&gomatrix.ReqCreateRoom{
-// Preset: "public_chat",
-// })
-// fmt.Println("Room:", resp.RoomID)
-func (cli *Client) CreateRoom(req *ReqCreateRoom) (resp *RespCreateRoom, err error) {
- urlPath := cli.BuildURL("createRoom")
- err = cli.MakeRequest("POST", urlPath, req, &resp)
- return
-}
-
-// LeaveRoom leaves the given room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-leave
-func (cli *Client) LeaveRoom(roomID string) (resp *RespLeaveRoom, err error) {
- u := cli.BuildURL("rooms", roomID, "leave")
- err = cli.MakeRequest("POST", u, struct{}{}, &resp)
- return
-}
-
-// ForgetRoom forgets a room entirely. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-forget
-func (cli *Client) ForgetRoom(roomID string) (resp *RespForgetRoom, err error) {
- u := cli.BuildURL("rooms", roomID, "forget")
- err = cli.MakeRequest("POST", u, struct{}{}, &resp)
- return
-}
-
-// InviteUser invites a user to a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
-func (cli *Client) InviteUser(roomID string, req *ReqInviteUser) (resp *RespInviteUser, err error) {
- u := cli.BuildURL("rooms", roomID, "invite")
- err = cli.MakeRequest("POST", u, req, &resp)
- return
-}
-
-// InviteUserByThirdParty invites a third-party identifier to a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#invite-by-third-party-id-endpoint
-func (cli *Client) InviteUserByThirdParty(roomID string, req *ReqInvite3PID) (resp *RespInviteUser, err error) {
- u := cli.BuildURL("rooms", roomID, "invite")
- err = cli.MakeRequest("POST", u, req, &resp)
- return
-}
-
-// KickUser kicks a user from a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
-func (cli *Client) KickUser(roomID string, req *ReqKickUser) (resp *RespKickUser, err error) {
- u := cli.BuildURL("rooms", roomID, "kick")
- err = cli.MakeRequest("POST", u, req, &resp)
- return
-}
-
-// BanUser bans a user from a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
-func (cli *Client) BanUser(roomID string, req *ReqBanUser) (resp *RespBanUser, err error) {
- u := cli.BuildURL("rooms", roomID, "ban")
- err = cli.MakeRequest("POST", u, req, &resp)
- return
-}
-
-// UnbanUser unbans a user from a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
-func (cli *Client) UnbanUser(roomID string, req *ReqUnbanUser) (resp *RespUnbanUser, err error) {
- u := cli.BuildURL("rooms", roomID, "unban")
- err = cli.MakeRequest("POST", u, req, &resp)
- return
-}
-
-// UserTyping sets the typing status of the user. See https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
-func (cli *Client) UserTyping(roomID string, typing bool, timeout int64) (resp *RespTyping, err error) {
- req := ReqTyping{Typing: typing, Timeout: timeout}
- u := cli.BuildURL("rooms", roomID, "typing", cli.UserID)
- err = cli.MakeRequest("PUT", u, req, &resp)
- return
-}
-
-// StateEvent gets a single state event in a room. It will attempt to JSON unmarshal into the given "outContent" struct with
-// the HTTP response body, or return an error.
-// See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey
-func (cli *Client) StateEvent(roomID, eventType, stateKey string, outContent interface{}) (err error) {
- u := cli.BuildURL("rooms", roomID, "state", eventType, stateKey)
- err = cli.MakeRequest("GET", u, nil, outContent)
- return
-}
-
-// UploadLink uploads an HTTP URL and then returns an MXC URI.
-func (cli *Client) UploadLink(link string) (*RespMediaUpload, error) {
- res, err := cli.Client.Get(link)
- if res != nil {
- defer res.Body.Close()
- }
- if err != nil {
- return nil, err
- }
- return cli.UploadToContentRepo(res.Body, res.Header.Get("Content-Type"), res.ContentLength)
-}
-
-// UploadToContentRepo uploads the given bytes to the content repository and returns an MXC URI.
-// See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-media-r0-upload
-func (cli *Client) UploadToContentRepo(content io.Reader, contentType string, contentLength int64) (*RespMediaUpload, error) {
- req, err := http.NewRequest("POST", cli.BuildBaseURL("_matrix/media/r0/upload"), content)
- if err != nil {
- return nil, err
- }
- req.Header.Set("Content-Type", contentType)
- req.ContentLength = contentLength
- res, err := cli.Client.Do(req)
- if res != nil {
- defer res.Body.Close()
- }
- if err != nil {
- return nil, err
- }
- if res.StatusCode != 200 {
- contents, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return nil, HTTPError{
- Message: "Upload request failed - Failed to read response body: " + err.Error(),
- Code: res.StatusCode,
- }
- }
- return nil, HTTPError{
- Contents: contents,
- Message: "Upload request failed: " + string(contents),
- Code: res.StatusCode,
- }
- }
- var m RespMediaUpload
- if err := json.NewDecoder(res.Body).Decode(&m); err != nil {
- return nil, err
- }
- return &m, nil
-}
-
-// JoinedMembers returns a map of joined room members. See TODO-SPEC. https://github.com/matrix-org/synapse/pull/1680
-//
-// In general, usage of this API is discouraged in favour of /sync, as calling this API can race with incoming membership changes.
-// This API is primarily designed for application services which may want to efficiently look up joined members in a room.
-func (cli *Client) JoinedMembers(roomID string) (resp *RespJoinedMembers, err error) {
- u := cli.BuildURL("rooms", roomID, "joined_members")
- err = cli.MakeRequest("GET", u, nil, &resp)
- return
-}
-
-// JoinedRooms returns a list of rooms which the client is joined to. See TODO-SPEC. https://github.com/matrix-org/synapse/pull/1680
-//
-// In general, usage of this API is discouraged in favour of /sync, as calling this API can race with incoming membership changes.
-// This API is primarily designed for application services which may want to efficiently look up joined rooms.
-func (cli *Client) JoinedRooms() (resp *RespJoinedRooms, err error) {
- u := cli.BuildURL("joined_rooms")
- err = cli.MakeRequest("GET", u, nil, &resp)
- return
-}
-
-// Messages returns a list of message and state events for a room. It uses
-// pagination query parameters to paginate history in the room.
-// See https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-messages
-func (cli *Client) Messages(roomID, from, to string, dir rune, limit int) (resp *RespMessages, err error) {
- query := map[string]string{
- "from": from,
- "dir": string(dir),
- }
- if to != "" {
- query["to"] = to
- }
- if limit != 0 {
- query["limit"] = strconv.Itoa(limit)
- }
-
- urlPath := cli.BuildURLWithQuery([]string{"rooms", roomID, "messages"}, query)
- err = cli.MakeRequest("GET", urlPath, nil, &resp)
- return
-}
-
-// TurnServer returns turn server details and credentials for the client to use when initiating calls.
-// See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-voip-turnserver
-func (cli *Client) TurnServer() (resp *RespTurnServer, err error) {
- urlPath := cli.BuildURL("voip", "turnServer")
- err = cli.MakeRequest("GET", urlPath, nil, &resp)
- return
-}
-
-func txnID() string {
- return "go" + strconv.FormatInt(time.Now().UnixNano(), 10)
-}
-
-// NewClient creates a new Matrix Client ready for syncing
-func NewClient(homeserverURL, userID, accessToken string) (*Client, error) {
- hsURL, err := url.Parse(homeserverURL)
- if err != nil {
- return nil, err
- }
- // By default, use an in-memory store which will never save filter ids / next batch tokens to disk.
- // The client will work with this storer: it just won't remember across restarts.
- // In practice, a database backend should be used.
- store := NewInMemoryStore()
- cli := Client{
- AccessToken: accessToken,
- HomeserverURL: hsURL,
- UserID: userID,
- Prefix: "/_matrix/client/r0",
- Syncer: NewDefaultSyncer(userID, store),
- Store: store,
- }
- // By default, use the default HTTP client.
- cli.Client = http.DefaultClient
-
- return &cli, nil
-}