Add responses/room types. Add buildURL functions with examples

This commit is contained in:
Kegan Dougal 2016-11-30 11:46:33 +00:00
parent 97f4e98e1d
commit 527c6568c9
4 changed files with 160 additions and 4 deletions

View File

@ -1,8 +1,12 @@
// 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 package gomatrix
import ( import (
"net/http" "net/http"
"net/url" "net/url"
"path"
"sync" "sync"
) )
@ -20,11 +24,49 @@ type Client struct {
// TODO: Worker and Rooms // TODO: Worker and Rooms
} }
// 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...)
query := hsURL.Query()
query.Set("access_token", cli.AccessToken)
hsURL.RawQuery = query.Encode()
return hsURL.String()
}
// BuildURLWithQuery builds a URL with query paramters 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()
}
// NewClient creates a new Matrix Client ready for syncing // NewClient creates a new Matrix Client ready for syncing
func NewClient(httpClient *http.Client, homeserverURL *url.URL, accessToken, userID string) *Client { func NewClient(homeserverURL, userID, accessToken string) (*Client, error) {
hsURL, err := url.Parse(homeserverURL)
if err != nil {
return nil, err
}
cli := Client{ cli := Client{
AccessToken: accessToken, AccessToken: accessToken,
HomeserverURL: homeserverURL, HomeserverURL: hsURL,
UserID: userID, UserID: userID,
Prefix: "/_matrix/client/r0", Prefix: "/_matrix/client/r0",
} }
@ -36,7 +78,8 @@ func NewClient(httpClient *http.Client, homeserverURL *url.URL, accessToken, use
// "load" nothing. The client will work with this storer: it just won't remember the filter // "load" nothing. The client will work with this storer: it just won't remember the filter
// ID across restarts and hence request a new one. In practice, a database backend should be used. // ID across restarts and hence request a new one. In practice, a database backend should be used.
cli.FilterStorer = NopFilterStore{} cli.FilterStorer = NopFilterStore{}
cli.Client = httpClient // By default, use the default HTTP client.
cli.Client = http.DefaultClient
return &cli return &cli, nil
} }

28
client_test.go Normal file
View File

@ -0,0 +1,28 @@
package gomatrix
import "fmt"
func ExampleBuildURLWithQuery() {
cli, _ := NewClient("https://matrix.org", "@example:matrix.org", "abcdef123456")
out := cli.BuildURLWithQuery([]string{"sync"}, map[string]string{
"filter_id": "5",
})
fmt.Println(out)
// Output: https://matrix.org/_matrix/client/r0/sync?access_token=abcdef123456&filter_id=5
}
func ExampleBuildURL() {
userID := "@example:matrix.org"
cli, _ := NewClient("https://matrix.org", userID, "abcdef123456")
out := cli.BuildURL("user", userID, "filter")
fmt.Println(out)
// Output: https://matrix.org/_matrix/client/r0/user/@example:matrix.org/filter?access_token=abcdef123456
}
func ExampleBuildBaseURL() {
userID := "@example:matrix.org"
cli, _ := NewClient("https://matrix.org", userID, "abcdef123456")
out := cli.BuildBaseURL("_matrix", "client", "r0", "directory", "room", "#matrix:matrix.org")
fmt.Println(out)
// Output: https://matrix.org/_matrix/client/r0/directory/room/%23matrix:matrix.org?access_token=abcdef123456
}

44
responses.go Normal file
View File

@ -0,0 +1,44 @@
package gomatrix
// RespCreateFilter is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-user-userid-filter
type RespCreateFilter struct {
FilterID string `json:"filter_id"`
}
// RespJoinRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-join
type RespJoinRoom struct {
RoomID string `json:"room_id"`
}
// RespSendEvent is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
type RespSendEvent struct {
EventID string `json:"event_id"`
}
// RespSync is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-sync
type RespSync struct {
NextBatch string `json:"next_batch"`
AccountData struct {
Events []Event `json:"events"`
} `json:"account_data"`
Presence struct {
Events []Event `json:"events"`
} `json:"presence"`
Rooms struct {
Join map[string]struct {
State struct {
Events []Event `json:"events"`
} `json:"state"`
Timeline struct {
Events []Event `json:"events"`
Limited bool `json:"limited"`
PrevBatch string `json:"prev_batch"`
} `json:"timeline"`
} `json:"join"`
Invite map[string]struct {
State struct {
Events []Event
} `json:"invite_state"`
} `json:"invite"`
} `json:"rooms"`
}

41
room.go Normal file
View File

@ -0,0 +1,41 @@
package gomatrix
// Room represents a single Matrix room.
type Room struct {
ID string
State map[string]map[string]*Event
}
// UpdateState updates the room's current state with the given Event. This will clobber events based
// on the type/state_key combination.
func (room Room) UpdateState(event *Event) {
_, exists := room.State[event.Type]
if !exists {
room.State[event.Type] = make(map[string]*Event)
}
room.State[event.Type][event.StateKey] = event
}
// GetStateEvent returns the state event for the given type/state_key combo, or nil.
func (room Room) GetStateEvent(eventType string, stateKey string) *Event {
stateEventMap, _ := room.State[eventType]
event, _ := stateEventMap[stateKey]
return event
}
// GetMembershipState returns the membership state of the given user ID in this room. If there is
// no entry for this member, 'leave' is returned for consistency with left users.
func (room Room) GetMembershipState(userID string) string {
state := "leave"
event := room.GetStateEvent("m.room.member", userID)
if event != nil {
membershipState, found := event.Content["membership"]
if found {
mState, isString := membershipState.(string)
if isString {
state = mState
}
}
}
return state
}