mirror of
https://github.com/Lomanic/presence-button-web
synced 2024-11-24 06:27:30 +00:00
Compare commits
No commits in common. "4675e76680935686c83518c1e90b8d9a6084d27f" and "663855f268decb7602150cf439e3f0d23fcf32f9" have entirely different histories.
4675e76680
...
663855f268
5
go.mod
5
go.mod
@ -1,5 +0,0 @@
|
|||||||
module github.com/Lomanic/presence-button-web
|
|
||||||
|
|
||||||
go 1.12
|
|
||||||
|
|
||||||
require github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd
|
|
2
go.sum
2
go.sum
@ -1,2 +0,0 @@
|
|||||||
github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd h1:xVrqJK3xHREMNjwjljkAUaadalWc0rRbmVuQatzmgwg=
|
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
|
87
main.go
87
main.go
@ -1,17 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
@ -53,8 +54,7 @@ var (
|
|||||||
// formerly https://www.flaticon.com/free-icon/closed_1234190, maybe try https://flaticons.net/customize.php?dir=Miscellaneous&icon=Closed.png without attribution
|
// formerly https://www.flaticon.com/free-icon/closed_1234190, maybe try https://flaticons.net/customize.php?dir=Miscellaneous&icon=Closed.png without attribution
|
||||||
false: `<?xml version="1.0" ?><svg viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:#f8991d;}.cls-2{fill:#fd0;}.cls-3{fill:#314967;}</style></defs><title/><g data-name="18 Closed Sign" id="_18_Closed_Sign"><rect class="cls-1" height="36" rx="6" ry="6" width="96" x="16" y="64"/><circle class="cls-2" cx="64" cy="28" r="6"/><path class="cls-3" d="M71.85,77.83a4.37,4.37,0,0,1,2.34,1,1.93,1.93,0,1,0,2.08-3.25A7.94,7.94,0,0,0,71.85,74c-3.13,0-5.55,2.06-5.55,4.58,0,2.74,2.64,4.21,5.35,4.58.55.11,2,.45,2.26,1,0,.57-1.38,1-2,1a5.25,5.25,0,0,1-2.79-1.16,1.93,1.93,0,1,0-2.42,3,8.73,8.73,0,0,0,5.23,2c3.12,0,5.88-2,5.88-4.82s-2.88-4.4-5.66-4.78c-1.6-.31-2-.77-2-.77C70.15,78.39,70.8,77.83,71.85,77.83Z"/><path class="cls-3" d="M40,76.34V87a2,2,0,0,0,2,2h5.83a2,2,0,0,0,0-4H44V76.34A2,2,0,0,0,40,76.34Z"/><path class="cls-3" d="M50,81.48A7.16,7.16,0,1,0,57.23,74,7.32,7.32,0,0,0,50,81.48Zm10.26,0c0,2.89-3.21,4.64-5.27,2.43-1.94-2-.71-5.86,2.2-5.86A3.29,3.29,0,0,1,60.3,81.48Z"/><path class="cls-3" d="M34.44,78.82a2,2,0,0,0,2.49-3.21A7.7,7.7,0,0,0,32.15,74a7.6,7.6,0,0,0-7.6,7.48h0c0,6.3,7.44,9.7,12.39,5.86a2,2,0,0,0-2.51-3.2,3.52,3.52,0,1,1,0-5.31Z"/><path class="cls-3" d="M87.69,78.35a2,2,0,0,0,0-4H81.8a2,2,0,0,0-2,2V87a2,2,0,0,0,1,1.75V89h6.83a2,2,0,0,0,0-4H83.81V83.65H87a2,2,0,0,0,0-4h-3.2V78.35Z"/><path class="cls-3" d="M103.09,81.64a7.29,7.29,0,0,0-7.28-7.28H93.69a2,2,0,0,0-2,2V87a2,2,0,0,0,2,2h2.13A7.31,7.31,0,0,0,103.09,81.64ZM95.81,85h-.12V78.35h.12C100.14,78.35,100.18,84.93,95.81,85Z"/><path class="cls-3" d="M92.73,98H22a4,4,0,0,1-4-4V70a4,4,0,0,1,4-4H42.55a2,2,0,0,0,0-4H32.83L59.93,34.89a8,8,0,0,0,8.13,0L81.71,48.54a2,2,0,0,0,2.83-2.83L70.88,32.06A8,8,0,0,0,64,20a2,2,0,0,0,0,4,4,4,0,0,1,2.79,6.86C63.58,34,58.24,30.08,60.51,26a2,2,0,0,0-3.49-2,8,8,0,0,0,.09,8L27.17,62H22a8,8,0,0,0-8,8V94a8,8,0,0,0,8,8H92.73A2,2,0,0,0,92.73,98Z"/><path class="cls-3" d="M106,62h-5.17L88.09,49.26a2,2,0,0,0-2.83,2.83L95.17,62H76a2,2,0,0,0,0,4h30a4,4,0,0,1,4,4V94a4,4,0,0,1-4,4H98.51a2,2,0,0,0,0,4H106a8,8,0,0,0,8-8V70A8,8,0,0,0,106,62Z"/><path class="cls-3" d="M70,62H49.22a2,2,0,0,0,0,4H70A2,2,0,0,0,70,62Z"/></g></svg>`,
|
false: `<?xml version="1.0" ?><svg viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:#f8991d;}.cls-2{fill:#fd0;}.cls-3{fill:#314967;}</style></defs><title/><g data-name="18 Closed Sign" id="_18_Closed_Sign"><rect class="cls-1" height="36" rx="6" ry="6" width="96" x="16" y="64"/><circle class="cls-2" cx="64" cy="28" r="6"/><path class="cls-3" d="M71.85,77.83a4.37,4.37,0,0,1,2.34,1,1.93,1.93,0,1,0,2.08-3.25A7.94,7.94,0,0,0,71.85,74c-3.13,0-5.55,2.06-5.55,4.58,0,2.74,2.64,4.21,5.35,4.58.55.11,2,.45,2.26,1,0,.57-1.38,1-2,1a5.25,5.25,0,0,1-2.79-1.16,1.93,1.93,0,1,0-2.42,3,8.73,8.73,0,0,0,5.23,2c3.12,0,5.88-2,5.88-4.82s-2.88-4.4-5.66-4.78c-1.6-.31-2-.77-2-.77C70.15,78.39,70.8,77.83,71.85,77.83Z"/><path class="cls-3" d="M40,76.34V87a2,2,0,0,0,2,2h5.83a2,2,0,0,0,0-4H44V76.34A2,2,0,0,0,40,76.34Z"/><path class="cls-3" d="M50,81.48A7.16,7.16,0,1,0,57.23,74,7.32,7.32,0,0,0,50,81.48Zm10.26,0c0,2.89-3.21,4.64-5.27,2.43-1.94-2-.71-5.86,2.2-5.86A3.29,3.29,0,0,1,60.3,81.48Z"/><path class="cls-3" d="M34.44,78.82a2,2,0,0,0,2.49-3.21A7.7,7.7,0,0,0,32.15,74a7.6,7.6,0,0,0-7.6,7.48h0c0,6.3,7.44,9.7,12.39,5.86a2,2,0,0,0-2.51-3.2,3.52,3.52,0,1,1,0-5.31Z"/><path class="cls-3" d="M87.69,78.35a2,2,0,0,0,0-4H81.8a2,2,0,0,0-2,2V87a2,2,0,0,0,1,1.75V89h6.83a2,2,0,0,0,0-4H83.81V83.65H87a2,2,0,0,0,0-4h-3.2V78.35Z"/><path class="cls-3" d="M103.09,81.64a7.29,7.29,0,0,0-7.28-7.28H93.69a2,2,0,0,0-2,2V87a2,2,0,0,0,2,2h2.13A7.31,7.31,0,0,0,103.09,81.64ZM95.81,85h-.12V78.35h.12C100.14,78.35,100.18,84.93,95.81,85Z"/><path class="cls-3" d="M92.73,98H22a4,4,0,0,1-4-4V70a4,4,0,0,1,4-4H42.55a2,2,0,0,0,0-4H32.83L59.93,34.89a8,8,0,0,0,8.13,0L81.71,48.54a2,2,0,0,0,2.83-2.83L70.88,32.06A8,8,0,0,0,64,20a2,2,0,0,0,0,4,4,4,0,0,1,2.79,6.86C63.58,34,58.24,30.08,60.51,26a2,2,0,0,0-3.49-2,8,8,0,0,0,.09,8L27.17,62H22a8,8,0,0,0-8,8V94a8,8,0,0,0,8,8H92.73A2,2,0,0,0,92.73,98Z"/><path class="cls-3" d="M106,62h-5.17L88.09,49.26a2,2,0,0,0-2.83,2.83L95.17,62H76a2,2,0,0,0,0,4h30a4,4,0,0,1,4,4V94a4,4,0,0,1-4,4H98.51a2,2,0,0,0,0,4H106a8,8,0,0,0,8-8V70A8,8,0,0,0,106,62Z"/><path class="cls-3" d="M70,62H49.22a2,2,0,0,0,0,4H70A2,2,0,0,0,70,62Z"/></g></svg>`,
|
||||||
}
|
}
|
||||||
db *os.File
|
db *os.File
|
||||||
matrix *gomatrix.Client
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -62,32 +62,14 @@ func init() {
|
|||||||
if val, _ := strconv.Atoi(port); val > 0 {
|
if val, _ := strconv.Atoi(port); val > 0 {
|
||||||
config.PORT = port
|
config.PORT = port
|
||||||
}
|
}
|
||||||
|
|
||||||
config.MATRIXUSERNAME = os.Getenv("MATRIXUSERNAME")
|
|
||||||
config.MATRIXACCESSTOKEN = os.Getenv("MATRIXACCESSTOKEN")
|
|
||||||
|
|
||||||
config.MATRIXROOM = os.Getenv("MATRIXROOM")
|
config.MATRIXROOM = os.Getenv("MATRIXROOM")
|
||||||
config.MATRIXOPENINGMESSAGE = os.Getenv("MATRIXOPENINGMESSAGE")
|
config.MATRIXOPENINGMESSAGE = os.Getenv("MATRIXOPENINGMESSAGE")
|
||||||
config.MATRIXCLOSINGMESSAGE = os.Getenv("MATRIXCLOSINGMESSAGE")
|
config.MATRIXCLOSINGMESSAGE = os.Getenv("MATRIXCLOSINGMESSAGE")
|
||||||
|
config.MATRIXACCESSTOKEN = os.Getenv("MATRIXACCESSTOKEN")
|
||||||
|
config.MATRIXUSERNAME = os.Getenv("MATRIXUSERNAME")
|
||||||
config.ESPUSERNAME = os.Getenv("ESPUSERNAME")
|
config.ESPUSERNAME = os.Getenv("ESPUSERNAME")
|
||||||
config.ESPPASSWORD = os.Getenv("ESPPASSWORD")
|
config.ESPPASSWORD = os.Getenv("ESPPASSWORD")
|
||||||
|
|
||||||
if config.MATRIXUSERNAME == "" {
|
|
||||||
panic("MATRIXUSERNAME is empty")
|
|
||||||
}
|
|
||||||
if config.MATRIXACCESSTOKEN == "" {
|
|
||||||
panic("MATRIXACCESSTOKEN is empty")
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
matrix, err = gomatrix.NewClient(fmt.Sprintf("https://%s", config.MATRIXUSERNAME[strings.Index(config.MATRIXUSERNAME, ":")+1:]), config.MATRIXUSERNAME, config.MATRIXACCESSTOKEN)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error creating matrix client: %s", err))
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.MATRIXROOM == "" {
|
if config.MATRIXROOM == "" {
|
||||||
panic("MATRIXROOM is empty")
|
panic("MATRIXROOM is empty")
|
||||||
}
|
}
|
||||||
@ -97,15 +79,17 @@ func init() {
|
|||||||
if config.MATRIXCLOSINGMESSAGE == "" {
|
if config.MATRIXCLOSINGMESSAGE == "" {
|
||||||
panic("MATRIXCLOSINGMESSAGE is empty")
|
panic("MATRIXCLOSINGMESSAGE is empty")
|
||||||
}
|
}
|
||||||
|
if config.MATRIXACCESSTOKEN == "" {
|
||||||
if config.ESPUSERNAME == "" {
|
panic("MATRIXACCESSTOKEN is empty")
|
||||||
panic("ESPUSERNAME is empty")
|
}
|
||||||
|
if config.MATRIXUSERNAME == "" {
|
||||||
|
panic("MATRIXUSERNAME is empty")
|
||||||
}
|
}
|
||||||
if config.ESPPASSWORD == "" {
|
if config.ESPPASSWORD == "" {
|
||||||
panic("ESPPASSWORD is empty")
|
panic("ESPPASSWORD is empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.MkdirAll(filepath.Dir(dbPath), 0755)
|
err := os.MkdirAll(filepath.Dir(dbPath), 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -113,7 +97,8 @@ func init() {
|
|||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
err = json.NewDecoder(db).Decode(&status)
|
d := json.NewDecoder(db)
|
||||||
|
d.Decode(&status)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("error unmarshalling db:", err)
|
fmt.Println("error unmarshalling db:", err)
|
||||||
}
|
}
|
||||||
@ -132,7 +117,7 @@ func checkClosure() {
|
|||||||
// the Fuz is newly closed, notify on matrix and write file to survive reboot
|
// the Fuz is newly closed, notify on matrix and write file to survive reboot
|
||||||
// TODO: matrix msg
|
// TODO: matrix msg
|
||||||
fmt.Println("the Fuz is newly closed, notify on matrix and write file to survive reboot")
|
fmt.Println("the Fuz is newly closed, notify on matrix and write file to survive reboot")
|
||||||
_, err := matrix.SendText(config.MATRIXROOM, config.MATRIXCLOSINGMESSAGE)
|
err := sendMatrixMessage(config.MATRIXUSERNAME, config.MATRIXACCESSTOKEN, config.MATRIXROOM, config.MATRIXCLOSINGMESSAGE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("err:", err)
|
fmt.Println("err:", err)
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
@ -218,7 +203,7 @@ func statusHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
if status.FuzIsOpen && (status.LastOpened.Equal(status.LastClosed) || status.LastOpened.Before(status.LastClosed)) {
|
if status.FuzIsOpen && (status.LastOpened.Equal(status.LastClosed) || status.LastOpened.Before(status.LastClosed)) {
|
||||||
// the Fuz is newly opened, notify on matrix and write file to survive reboot
|
// the Fuz is newly opened, notify on matrix and write file to survive reboot
|
||||||
fmt.Println("the Fuz is newly opened, notify on matrix and write file to survive reboot")
|
fmt.Println("the Fuz is newly opened, notify on matrix and write file to survive reboot")
|
||||||
_, err := matrix.SendText(config.MATRIXROOM, config.MATRIXOPENINGMESSAGE)
|
err := sendMatrixMessage(config.MATRIXUSERNAME, config.MATRIXACCESSTOKEN, config.MATRIXROOM, config.MATRIXOPENINGMESSAGE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("err:", err)
|
fmt.Println("err:", err)
|
||||||
return
|
return
|
||||||
@ -233,6 +218,46 @@ func statusHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sendMatrixMessage(username, accessToken, room, messageText string) error {
|
||||||
|
type Message struct {
|
||||||
|
Msgtype string `json:"msgtype"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
}
|
||||||
|
client := &http.Client{}
|
||||||
|
message := Message{
|
||||||
|
Msgtype: "m.text",
|
||||||
|
Body: messageText,
|
||||||
|
}
|
||||||
|
body := new(bytes.Buffer)
|
||||||
|
err := json.NewEncoder(body).Encode(message)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("access_token", accessToken)
|
||||||
|
v.Set("limit", "1")
|
||||||
|
url := url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: username[strings.Index(username, ":")+1:],
|
||||||
|
Path: fmt.Sprintf("/_matrix/client/r0/rooms/%s/send/m.room.message/%d", room, time.Now().UnixNano()/1000000),
|
||||||
|
RawQuery: v.Encode(),
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(http.MethodPut, url.String(), body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
resBody, _ := ioutil.ReadAll(res.Body)
|
||||||
|
fmt.Println(string(resBody))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
go updateUptime()
|
go updateUptime()
|
||||||
go checkClosure()
|
go checkClosure()
|
||||||
|
24
vendor/github.com/matrix-org/gomatrix/.gitignore
generated
vendored
24
vendor/github.com/matrix-org/gomatrix/.gitignore
generated
vendored
@ -1,24 +0,0 @@
|
|||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
|
||||||
*.o
|
|
||||||
*.a
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Folders
|
|
||||||
_obj
|
|
||||||
_test
|
|
||||||
|
|
||||||
# Architecture specific extensions/prefixes
|
|
||||||
*.[568vq]
|
|
||||||
[568vq].out
|
|
||||||
|
|
||||||
*.cgo1.go
|
|
||||||
*.cgo2.c
|
|
||||||
_cgo_defun.c
|
|
||||||
_cgo_gotypes.go
|
|
||||||
_cgo_export.*
|
|
||||||
|
|
||||||
_testmain.go
|
|
||||||
|
|
||||||
*.exe
|
|
||||||
*.test
|
|
||||||
*.prof
|
|
21
vendor/github.com/matrix-org/gomatrix/.golangci.yml
generated
vendored
21
vendor/github.com/matrix-org/gomatrix/.golangci.yml
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
run:
|
|
||||||
timeout: 5m
|
|
||||||
linters:
|
|
||||||
enable:
|
|
||||||
- vet
|
|
||||||
- vetshadow
|
|
||||||
- typecheck
|
|
||||||
- deadcode
|
|
||||||
- gocyclo
|
|
||||||
- golint
|
|
||||||
- varcheck
|
|
||||||
- structcheck
|
|
||||||
- maligned
|
|
||||||
- ineffassign
|
|
||||||
- misspell
|
|
||||||
- unparam
|
|
||||||
- goimports
|
|
||||||
- goconst
|
|
||||||
- unconvert
|
|
||||||
- errcheck
|
|
||||||
- interfacer
|
|
7
vendor/github.com/matrix-org/gomatrix/.travis.yml
generated
vendored
7
vendor/github.com/matrix-org/gomatrix/.travis.yml
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
language: go
|
|
||||||
go:
|
|
||||||
- 1.13.10
|
|
||||||
install:
|
|
||||||
- go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.24.0
|
|
||||||
- go build
|
|
||||||
script: ./hooks/pre-commit
|
|
201
vendor/github.com/matrix-org/gomatrix/LICENSE
generated
vendored
201
vendor/github.com/matrix-org/gomatrix/LICENSE
generated
vendored
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
6
vendor/github.com/matrix-org/gomatrix/README.md
generated
vendored
6
vendor/github.com/matrix-org/gomatrix/README.md
generated
vendored
@ -1,6 +0,0 @@
|
|||||||
# gomatrix
|
|
||||||
[![GoDoc](https://godoc.org/github.com/matrix-org/gomatrix?status.svg)](https://godoc.org/github.com/matrix-org/gomatrix)
|
|
||||||
|
|
||||||
A Golang Matrix client.
|
|
||||||
|
|
||||||
**THIS IS UNDER ACTIVE DEVELOPMENT: BREAKING CHANGES ARE FREQUENT.**
|
|
794
vendor/github.com/matrix-org/gomatrix/client.go
generated
vendored
794
vendor/github.com/matrix-org/gomatrix/client.go
generated
vendored
@ -1,794 +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 := append([]string{cli.Prefix}, urlPath...)
|
|
||||||
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.6.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
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogoutAll logs the current user out on all devices. See https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-logout-all
|
|
||||||
// This does not clear the credentials from the client instance. See ClearCredentails() instead.
|
|
||||||
func (cli *Client) LogoutAll() (resp *RespLogoutAll, err error) {
|
|
||||||
urlPath := cli.BuildURL("logout/all")
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStatus returns the status of the user from the specified MXID. See https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-presence-userid-status
|
|
||||||
func (cli *Client) GetStatus(mxid string) (resp *RespUserStatus, err error) {
|
|
||||||
urlPath := cli.BuildURL("presence", mxid, "status")
|
|
||||||
err = cli.MakeRequest("GET", urlPath, nil, &resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOwnStatus returns the user's status. See https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-presence-userid-status
|
|
||||||
func (cli *Client) GetOwnStatus() (resp *RespUserStatus, err error) {
|
|
||||||
return cli.GetStatus(cli.UserID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetStatus sets the user's status. See https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-presence-userid-status
|
|
||||||
func (cli *Client) SetStatus(presence, status string) (err error) {
|
|
||||||
urlPath := cli.BuildURL("presence", cli.UserID, "status")
|
|
||||||
s := struct {
|
|
||||||
Presence string `json:"presence"`
|
|
||||||
StatusMsg string `json:"status_msg"`
|
|
||||||
}{presence, status}
|
|
||||||
err = cli.MakeRequest("PUT", urlPath, &s, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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{MsgType: "m.text", Body: text})
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendFormattedText sends an m.room.message event into the given room with a msgtype of m.text, supports a subset of HTML for formatting.
|
|
||||||
// See https://matrix.org/docs/spec/client_server/r0.6.0#m-text
|
|
||||||
func (cli *Client) SendFormattedText(roomID, text, formattedText string) (*RespSendEvent, error) {
|
|
||||||
return cli.SendMessageEvent(roomID, "m.room.message",
|
|
||||||
TextMessage{MsgType: "m.text", Body: text, FormattedBody: formattedText, Format: "org.matrix.custom.html"})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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{MsgType: "m.notice", Body: 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarkRead marks eventID in roomID as read, signifying the event, and all before it have been read. See https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-receipt-receipttype-eventid
|
|
||||||
func (cli *Client) MarkRead(roomID, eventID string) error {
|
|
||||||
urlPath := cli.BuildURL("rooms", roomID, "receipt", "m.read", eventID)
|
|
||||||
return cli.MakeRequest("POST", urlPath, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
157
vendor/github.com/matrix-org/gomatrix/events.go
generated
vendored
157
vendor/github.com/matrix-org/gomatrix/events.go
generated
vendored
@ -1,157 +0,0 @@
|
|||||||
package gomatrix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html"
|
|
||||||
"regexp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Event represents a single Matrix event.
|
|
||||||
type Event struct {
|
|
||||||
StateKey *string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
|
|
||||||
Sender string `json:"sender"` // The user ID of the sender of the event
|
|
||||||
Type string `json:"type"` // The event type
|
|
||||||
Timestamp int64 `json:"origin_server_ts"` // The unix timestamp when this message was sent by the origin server
|
|
||||||
ID string `json:"event_id"` // The unique ID of this event
|
|
||||||
RoomID string `json:"room_id"` // The room the event was sent to. May be nil (e.g. for presence)
|
|
||||||
Redacts string `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
|
|
||||||
Unsigned map[string]interface{} `json:"unsigned"` // The unsigned portions of the event, such as age and prev_content
|
|
||||||
Content map[string]interface{} `json:"content"` // The JSON content of the event.
|
|
||||||
PrevContent map[string]interface{} `json:"prev_content,omitempty"` // The JSON prev_content of the event.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Body returns the value of the "body" key in the event content if it is
|
|
||||||
// present and is a string.
|
|
||||||
func (event *Event) Body() (body string, ok bool) {
|
|
||||||
value, exists := event.Content["body"]
|
|
||||||
if !exists {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
body, ok = value.(string)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageType returns the value of the "msgtype" key in the event content if
|
|
||||||
// it is present and is a string.
|
|
||||||
func (event *Event) MessageType() (msgtype string, ok bool) {
|
|
||||||
value, exists := event.Content["msgtype"]
|
|
||||||
if !exists {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
msgtype, ok = value.(string)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TextMessage is the contents of a Matrix formated message event.
|
|
||||||
type TextMessage struct {
|
|
||||||
MsgType string `json:"msgtype"`
|
|
||||||
Body string `json:"body"`
|
|
||||||
FormattedBody string `json:"formatted_body"`
|
|
||||||
Format string `json:"format"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ThumbnailInfo contains info about an thumbnail image - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
|
|
||||||
type ThumbnailInfo struct {
|
|
||||||
Height uint `json:"h,omitempty"`
|
|
||||||
Width uint `json:"w,omitempty"`
|
|
||||||
Mimetype string `json:"mimetype,omitempty"`
|
|
||||||
Size uint `json:"size,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageInfo contains info about an image - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
|
|
||||||
type ImageInfo struct {
|
|
||||||
Height uint `json:"h,omitempty"`
|
|
||||||
Width uint `json:"w,omitempty"`
|
|
||||||
Mimetype string `json:"mimetype,omitempty"`
|
|
||||||
Size uint `json:"size,omitempty"`
|
|
||||||
ThumbnailInfo ThumbnailInfo `json:"thumbnail_info,omitempty"`
|
|
||||||
ThumbnailURL string `json:"thumbnail_url,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// VideoInfo contains info about a video - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
|
|
||||||
type VideoInfo struct {
|
|
||||||
Mimetype string `json:"mimetype,omitempty"`
|
|
||||||
ThumbnailInfo ThumbnailInfo `json:"thumbnail_info"`
|
|
||||||
ThumbnailURL string `json:"thumbnail_url,omitempty"`
|
|
||||||
Height uint `json:"h,omitempty"`
|
|
||||||
Width uint `json:"w,omitempty"`
|
|
||||||
Duration uint `json:"duration,omitempty"`
|
|
||||||
Size uint `json:"size,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// VideoMessage is an m.video - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
|
|
||||||
type VideoMessage struct {
|
|
||||||
MsgType string `json:"msgtype"`
|
|
||||||
Body string `json:"body"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
Info VideoInfo `json:"info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageMessage is an m.image event
|
|
||||||
type ImageMessage struct {
|
|
||||||
MsgType string `json:"msgtype"`
|
|
||||||
Body string `json:"body"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
Info ImageInfo `json:"info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// An HTMLMessage is the contents of a Matrix HTML formated message event.
|
|
||||||
type HTMLMessage struct {
|
|
||||||
Body string `json:"body"`
|
|
||||||
MsgType string `json:"msgtype"`
|
|
||||||
Format string `json:"format"`
|
|
||||||
FormattedBody string `json:"formatted_body"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileInfo contains info about an file - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-file
|
|
||||||
type FileInfo struct {
|
|
||||||
Mimetype string `json:"mimetype,omitempty"`
|
|
||||||
Size uint `json:"size,omitempty"` //filesize in bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileMessage is an m.file event - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-file
|
|
||||||
type FileMessage struct {
|
|
||||||
MsgType string `json:"msgtype"`
|
|
||||||
Body string `json:"body"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
Filename string `json:"filename"`
|
|
||||||
Info FileInfo `json:"info,omitempty"`
|
|
||||||
ThumbnailURL string `json:"thumbnail_url,omitempty"`
|
|
||||||
ThumbnailInfo ImageInfo `json:"thumbnail_info,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocationMessage is an m.location event - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-location
|
|
||||||
type LocationMessage struct {
|
|
||||||
MsgType string `json:"msgtype"`
|
|
||||||
Body string `json:"body"`
|
|
||||||
GeoURI string `json:"geo_uri"`
|
|
||||||
ThumbnailURL string `json:"thumbnail_url,omitempty"`
|
|
||||||
ThumbnailInfo ImageInfo `json:"thumbnail_info,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AudioInfo contains info about an file - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-audio
|
|
||||||
type AudioInfo struct {
|
|
||||||
Mimetype string `json:"mimetype,omitempty"`
|
|
||||||
Size uint `json:"size,omitempty"` //filesize in bytes
|
|
||||||
Duration uint `json:"duration,omitempty"` //audio duration in ms
|
|
||||||
}
|
|
||||||
|
|
||||||
// AudioMessage is an m.audio event - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-audio
|
|
||||||
type AudioMessage struct {
|
|
||||||
MsgType string `json:"msgtype"`
|
|
||||||
Body string `json:"body"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
Info AudioInfo `json:"info,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var htmlRegex = regexp.MustCompile("<[^<]+?>")
|
|
||||||
|
|
||||||
// GetHTMLMessage returns an HTMLMessage with the body set to a stripped version of the provided HTML, in addition
|
|
||||||
// to the provided HTML.
|
|
||||||
func GetHTMLMessage(msgtype, htmlText string) HTMLMessage {
|
|
||||||
return HTMLMessage{
|
|
||||||
Body: html.UnescapeString(htmlRegex.ReplaceAllLiteralString(htmlText, "")),
|
|
||||||
MsgType: msgtype,
|
|
||||||
Format: "org.matrix.custom.html",
|
|
||||||
FormattedBody: htmlText,
|
|
||||||
}
|
|
||||||
}
|
|
90
vendor/github.com/matrix-org/gomatrix/filter.go
generated
vendored
90
vendor/github.com/matrix-org/gomatrix/filter.go
generated
vendored
@ -1,90 +0,0 @@
|
|||||||
// Copyright 2017 Jan Christian Grünhage
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package gomatrix
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
//Filter is used by clients to specify how the server should filter responses to e.g. sync requests
|
|
||||||
//Specified by: https://matrix.org/docs/spec/client_server/r0.2.0.html#filtering
|
|
||||||
type Filter struct {
|
|
||||||
AccountData FilterPart `json:"account_data,omitempty"`
|
|
||||||
EventFields []string `json:"event_fields,omitempty"`
|
|
||||||
EventFormat string `json:"event_format,omitempty"`
|
|
||||||
Presence FilterPart `json:"presence,omitempty"`
|
|
||||||
Room RoomFilter `json:"room,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoomFilter is used to define filtering rules for room events
|
|
||||||
type RoomFilter struct {
|
|
||||||
AccountData FilterPart `json:"account_data,omitempty"`
|
|
||||||
Ephemeral FilterPart `json:"ephemeral,omitempty"`
|
|
||||||
IncludeLeave bool `json:"include_leave,omitempty"`
|
|
||||||
NotRooms []string `json:"not_rooms,omitempty"`
|
|
||||||
Rooms []string `json:"rooms,omitempty"`
|
|
||||||
State FilterPart `json:"state,omitempty"`
|
|
||||||
Timeline FilterPart `json:"timeline,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// FilterPart is used to define filtering rules for specific categories of events
|
|
||||||
type FilterPart struct {
|
|
||||||
NotRooms []string `json:"not_rooms,omitempty"`
|
|
||||||
Rooms []string `json:"rooms,omitempty"`
|
|
||||||
Limit int `json:"limit,omitempty"`
|
|
||||||
NotSenders []string `json:"not_senders,omitempty"`
|
|
||||||
NotTypes []string `json:"not_types,omitempty"`
|
|
||||||
Senders []string `json:"senders,omitempty"`
|
|
||||||
Types []string `json:"types,omitempty"`
|
|
||||||
ContainsURL *bool `json:"contains_url,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate checks if the filter contains valid property values
|
|
||||||
func (filter *Filter) Validate() error {
|
|
||||||
if filter.EventFormat != "client" && filter.EventFormat != "federation" {
|
|
||||||
return errors.New("Bad event_format value. Must be one of [\"client\", \"federation\"]")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultFilter returns the default filter used by the Matrix server if no filter is provided in the request
|
|
||||||
func DefaultFilter() Filter {
|
|
||||||
return Filter{
|
|
||||||
AccountData: DefaultFilterPart(),
|
|
||||||
EventFields: nil,
|
|
||||||
EventFormat: "client",
|
|
||||||
Presence: DefaultFilterPart(),
|
|
||||||
Room: RoomFilter{
|
|
||||||
AccountData: DefaultFilterPart(),
|
|
||||||
Ephemeral: DefaultFilterPart(),
|
|
||||||
IncludeLeave: false,
|
|
||||||
NotRooms: nil,
|
|
||||||
Rooms: nil,
|
|
||||||
State: DefaultFilterPart(),
|
|
||||||
Timeline: DefaultFilterPart(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultFilterPart returns the default filter part used by the Matrix server if no filter is provided in the request
|
|
||||||
func DefaultFilterPart() FilterPart {
|
|
||||||
return FilterPart{
|
|
||||||
NotRooms: nil,
|
|
||||||
Rooms: nil,
|
|
||||||
Limit: 20,
|
|
||||||
NotSenders: nil,
|
|
||||||
NotTypes: nil,
|
|
||||||
Senders: nil,
|
|
||||||
Types: nil,
|
|
||||||
}
|
|
||||||
}
|
|
3
vendor/github.com/matrix-org/gomatrix/go.mod
generated
vendored
3
vendor/github.com/matrix-org/gomatrix/go.mod
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
module github.com/matrix-org/gomatrix
|
|
||||||
|
|
||||||
go 1.12
|
|
69
vendor/github.com/matrix-org/gomatrix/identifier.go
generated
vendored
69
vendor/github.com/matrix-org/gomatrix/identifier.go
generated
vendored
@ -1,69 +0,0 @@
|
|||||||
package gomatrix
|
|
||||||
|
|
||||||
// Identifier is the interface for https://matrix.org/docs/spec/client_server/r0.6.0#identifier-types
|
|
||||||
type Identifier interface {
|
|
||||||
// Returns the identifier type
|
|
||||||
// https://matrix.org/docs/spec/client_server/r0.6.0#identifier-types
|
|
||||||
Type() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserIdentifier is the Identifier for https://matrix.org/docs/spec/client_server/r0.6.0#matrix-user-id
|
|
||||||
type UserIdentifier struct {
|
|
||||||
IDType string `json:"type"` // Set by NewUserIdentifer
|
|
||||||
User string `json:"user"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type implements the Identifier interface
|
|
||||||
func (i UserIdentifier) Type() string {
|
|
||||||
return "m.id.user"
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewUserIdentifier creates a new UserIdentifier with IDType set to "m.id.user"
|
|
||||||
func NewUserIdentifier(user string) UserIdentifier {
|
|
||||||
return UserIdentifier{
|
|
||||||
IDType: "m.id.user",
|
|
||||||
User: user,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ThirdpartyIdentifier is the Identifier for https://matrix.org/docs/spec/client_server/r0.6.0#third-party-id
|
|
||||||
type ThirdpartyIdentifier struct {
|
|
||||||
IDType string `json:"type"` // Set by NewThirdpartyIdentifier
|
|
||||||
Medium string `json:"medium"`
|
|
||||||
Address string `json:"address"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type implements the Identifier interface
|
|
||||||
func (i ThirdpartyIdentifier) Type() string {
|
|
||||||
return "m.id.thirdparty"
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewThirdpartyIdentifier creates a new UserIdentifier with IDType set to "m.id.user"
|
|
||||||
func NewThirdpartyIdentifier(medium, address string) ThirdpartyIdentifier {
|
|
||||||
return ThirdpartyIdentifier{
|
|
||||||
IDType: "m.id.thirdparty",
|
|
||||||
Medium: medium,
|
|
||||||
Address: address,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PhoneIdentifier is the Identifier for https://matrix.org/docs/spec/client_server/r0.6.0#phone-number
|
|
||||||
type PhoneIdentifier struct {
|
|
||||||
IDType string `json:"type"` // Set by NewPhoneIdentifier
|
|
||||||
Country string `json:"country"`
|
|
||||||
Phone string `json:"phone"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type implements the Identifier interface
|
|
||||||
func (i PhoneIdentifier) Type() string {
|
|
||||||
return "m.id.phone"
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPhoneIdentifier creates a new UserIdentifier with IDType set to "m.id.user"
|
|
||||||
func NewPhoneIdentifier(country, phone string) PhoneIdentifier {
|
|
||||||
return PhoneIdentifier{
|
|
||||||
IDType: "m.id.phone",
|
|
||||||
Country: country,
|
|
||||||
Phone: phone,
|
|
||||||
}
|
|
||||||
}
|
|
79
vendor/github.com/matrix-org/gomatrix/requests.go
generated
vendored
79
vendor/github.com/matrix-org/gomatrix/requests.go
generated
vendored
@ -1,79 +0,0 @@
|
|||||||
package gomatrix
|
|
||||||
|
|
||||||
// ReqRegister is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
|
|
||||||
type ReqRegister struct {
|
|
||||||
Username string `json:"username,omitempty"`
|
|
||||||
BindEmail bool `json:"bind_email,omitempty"`
|
|
||||||
Password string `json:"password,omitempty"`
|
|
||||||
DeviceID string `json:"device_id,omitempty"`
|
|
||||||
InitialDeviceDisplayName string `json:"initial_device_display_name"`
|
|
||||||
Auth interface{} `json:"auth,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReqLogin is the JSON request for http://matrix.org/docs/spec/client_server/r0.6.0.html#post-matrix-client-r0-login
|
|
||||||
type ReqLogin struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Identifier Identifier `json:"identifier,omitempty"`
|
|
||||||
Password string `json:"password,omitempty"`
|
|
||||||
Medium string `json:"medium,omitempty"`
|
|
||||||
User string `json:"user,omitempty"`
|
|
||||||
Address string `json:"address,omitempty"`
|
|
||||||
Token string `json:"token,omitempty"`
|
|
||||||
DeviceID string `json:"device_id,omitempty"`
|
|
||||||
InitialDeviceDisplayName string `json:"initial_device_display_name,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReqCreateRoom is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
|
||||||
type ReqCreateRoom struct {
|
|
||||||
Visibility string `json:"visibility,omitempty"`
|
|
||||||
RoomAliasName string `json:"room_alias_name,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Topic string `json:"topic,omitempty"`
|
|
||||||
Invite []string `json:"invite,omitempty"`
|
|
||||||
Invite3PID []ReqInvite3PID `json:"invite_3pid,omitempty"`
|
|
||||||
CreationContent map[string]interface{} `json:"creation_content,omitempty"`
|
|
||||||
InitialState []Event `json:"initial_state,omitempty"`
|
|
||||||
Preset string `json:"preset,omitempty"`
|
|
||||||
IsDirect bool `json:"is_direct,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReqRedact is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
|
|
||||||
type ReqRedact struct {
|
|
||||||
Reason string `json:"reason,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReqInvite3PID is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#id57
|
|
||||||
// It is also a JSON object used in https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
|
||||||
type ReqInvite3PID struct {
|
|
||||||
IDServer string `json:"id_server"`
|
|
||||||
Medium string `json:"medium"`
|
|
||||||
Address string `json:"address"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReqInviteUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
|
|
||||||
type ReqInviteUser struct {
|
|
||||||
UserID string `json:"user_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReqKickUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
|
|
||||||
type ReqKickUser struct {
|
|
||||||
Reason string `json:"reason,omitempty"`
|
|
||||||
UserID string `json:"user_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReqBanUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
|
|
||||||
type ReqBanUser struct {
|
|
||||||
Reason string `json:"reason,omitempty"`
|
|
||||||
UserID string `json:"user_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReqUnbanUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
|
|
||||||
type ReqUnbanUser struct {
|
|
||||||
UserID string `json:"user_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReqTyping is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
|
|
||||||
type ReqTyping struct {
|
|
||||||
Typing bool `json:"typing"`
|
|
||||||
Timeout int64 `json:"timeout"`
|
|
||||||
}
|
|
210
vendor/github.com/matrix-org/gomatrix/responses.go
generated
vendored
210
vendor/github.com/matrix-org/gomatrix/responses.go
generated
vendored
@ -1,210 +0,0 @@
|
|||||||
package gomatrix
|
|
||||||
|
|
||||||
// RespError is the standard JSON error response from Homeservers. It also implements the Golang "error" interface.
|
|
||||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#api-standards
|
|
||||||
type RespError struct {
|
|
||||||
ErrCode string `json:"errcode"`
|
|
||||||
Err string `json:"error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error returns the errcode and error message.
|
|
||||||
func (e RespError) Error() string {
|
|
||||||
return e.ErrCode + ": " + e.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespVersions is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-versions
|
|
||||||
type RespVersions struct {
|
|
||||||
Versions []string `json:"versions"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespPublicRooms is the JSON response for http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#get-matrix-client-unstable-publicrooms
|
|
||||||
type RespPublicRooms struct {
|
|
||||||
TotalRoomCountEstimate int `json:"total_room_count_estimate"`
|
|
||||||
PrevBatch string `json:"prev_batch"`
|
|
||||||
NextBatch string `json:"next_batch"`
|
|
||||||
Chunk []PublicRoom `json:"chunk"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespLeaveRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-leave
|
|
||||||
type RespLeaveRoom struct{}
|
|
||||||
|
|
||||||
// RespForgetRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-forget
|
|
||||||
type RespForgetRoom struct{}
|
|
||||||
|
|
||||||
// RespInviteUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
|
|
||||||
type RespInviteUser struct{}
|
|
||||||
|
|
||||||
// RespKickUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
|
|
||||||
type RespKickUser struct{}
|
|
||||||
|
|
||||||
// RespBanUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
|
|
||||||
type RespBanUser struct{}
|
|
||||||
|
|
||||||
// RespUnbanUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
|
|
||||||
type RespUnbanUser struct{}
|
|
||||||
|
|
||||||
// RespTyping is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
|
|
||||||
type RespTyping struct{}
|
|
||||||
|
|
||||||
// RespJoinedRooms is the JSON response for TODO-SPEC https://github.com/matrix-org/synapse/pull/1680
|
|
||||||
type RespJoinedRooms struct {
|
|
||||||
JoinedRooms []string `json:"joined_rooms"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespJoinedMembers is the JSON response for TODO-SPEC https://github.com/matrix-org/synapse/pull/1680
|
|
||||||
type RespJoinedMembers struct {
|
|
||||||
Joined map[string]struct {
|
|
||||||
DisplayName *string `json:"display_name"`
|
|
||||||
AvatarURL *string `json:"avatar_url"`
|
|
||||||
} `json:"joined"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespMessages is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-messages
|
|
||||||
type RespMessages struct {
|
|
||||||
Start string `json:"start"`
|
|
||||||
Chunk []Event `json:"chunk"`
|
|
||||||
End string `json:"end"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespMediaUpload is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-media-r0-upload
|
|
||||||
type RespMediaUpload struct {
|
|
||||||
ContentURI string `json:"content_uri"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespUserInteractive is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#user-interactive-authentication-api
|
|
||||||
type RespUserInteractive struct {
|
|
||||||
Flows []struct {
|
|
||||||
Stages []string `json:"stages"`
|
|
||||||
} `json:"flows"`
|
|
||||||
Params map[string]interface{} `json:"params"`
|
|
||||||
Session string `json:"session"`
|
|
||||||
Completed []string `json:"completed"`
|
|
||||||
ErrCode string `json:"errcode"`
|
|
||||||
Error string `json:"error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasSingleStageFlow returns true if there exists at least 1 Flow with a single stage of stageName.
|
|
||||||
func (r RespUserInteractive) HasSingleStageFlow(stageName string) bool {
|
|
||||||
for _, f := range r.Flows {
|
|
||||||
if len(f.Stages) == 1 && f.Stages[0] == stageName {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespUserDisplayName is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
|
|
||||||
type RespUserDisplayName struct {
|
|
||||||
DisplayName string `json:"displayname"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespUserStatus is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-presence-userid-status
|
|
||||||
type RespUserStatus struct {
|
|
||||||
Presence string `json:"presence"`
|
|
||||||
StatusMsg string `json:"status_msg"`
|
|
||||||
LastActiveAgo int `json:"last_active_ago"`
|
|
||||||
CurrentlyActive bool `json:"currently_active"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespRegister is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
|
|
||||||
type RespRegister struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
DeviceID string `json:"device_id"`
|
|
||||||
HomeServer string `json:"home_server"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
UserID string `json:"user_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespLogin is the JSON response for http://matrix.org/docs/spec/client_server/r0.6.0.html#post-matrix-client-r0-login
|
|
||||||
type RespLogin struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
DeviceID string `json:"device_id"`
|
|
||||||
HomeServer string `json:"home_server"`
|
|
||||||
UserID string `json:"user_id"`
|
|
||||||
WellKnown DiscoveryInformation `json:"well_known"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiscoveryInformation is the JSON Response for https://matrix.org/docs/spec/client_server/r0.6.0#get-well-known-matrix-client and a part of the JSON Response for https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-login
|
|
||||||
type DiscoveryInformation struct {
|
|
||||||
Homeserver struct {
|
|
||||||
BaseURL string `json:"base_url"`
|
|
||||||
} `json:"m.homeserver"`
|
|
||||||
IdentityServer struct {
|
|
||||||
BaseURL string `json:"base_url"`
|
|
||||||
} `json:"m.identitiy_server"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespLogout is the JSON response for http://matrix.org/docs/spec/client_server/r0.6.0.html#post-matrix-client-r0-logout
|
|
||||||
type RespLogout struct{}
|
|
||||||
|
|
||||||
// RespLogoutAll is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-logout-all
|
|
||||||
type RespLogoutAll struct{}
|
|
||||||
|
|
||||||
// RespCreateRoom is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
|
||||||
type RespCreateRoom struct {
|
|
||||||
RoomID string `json:"room_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 {
|
|
||||||
Leave 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:"leave"`
|
|
||||||
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"`
|
|
||||||
Ephemeral struct {
|
|
||||||
Events []Event `json:"events"`
|
|
||||||
} `json:"ephemeral"`
|
|
||||||
} `json:"join"`
|
|
||||||
Invite map[string]struct {
|
|
||||||
State struct {
|
|
||||||
Events []Event
|
|
||||||
} `json:"invite_state"`
|
|
||||||
} `json:"invite"`
|
|
||||||
} `json:"rooms"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespTurnServer is the JSON response from a Turn Server
|
|
||||||
type RespTurnServer struct {
|
|
||||||
Username string `json:"username"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
TTL int `json:"ttl"`
|
|
||||||
URIs []string `json:"uris"`
|
|
||||||
}
|
|
63
vendor/github.com/matrix-org/gomatrix/room.go
generated
vendored
63
vendor/github.com/matrix-org/gomatrix/room.go
generated
vendored
@ -1,63 +0,0 @@
|
|||||||
package gomatrix
|
|
||||||
|
|
||||||
// Room represents a single Matrix room.
|
|
||||||
type Room struct {
|
|
||||||
ID string
|
|
||||||
State map[string]map[string]*Event
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicRoom represents the information about a public room obtainable from the room directory
|
|
||||||
type PublicRoom struct {
|
|
||||||
CanonicalAlias string `json:"canonical_alias"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
WorldReadable bool `json:"world_readable"`
|
|
||||||
Topic string `json:"topic"`
|
|
||||||
NumJoinedMembers int `json:"num_joined_members"`
|
|
||||||
AvatarURL string `json:"avatar_url"`
|
|
||||||
RoomID string `json:"room_id"`
|
|
||||||
GuestCanJoin bool `json:"guest_can_join"`
|
|
||||||
Aliases []string `json:"aliases"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRoom creates a new Room with the given ID
|
|
||||||
func NewRoom(roomID string) *Room {
|
|
||||||
// Init the State map and return a pointer to the Room
|
|
||||||
return &Room{
|
|
||||||
ID: roomID,
|
|
||||||
State: make(map[string]map[string]*Event),
|
|
||||||
}
|
|
||||||
}
|
|
65
vendor/github.com/matrix-org/gomatrix/store.go
generated
vendored
65
vendor/github.com/matrix-org/gomatrix/store.go
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
package gomatrix
|
|
||||||
|
|
||||||
// Storer is an interface which must be satisfied to store client data.
|
|
||||||
//
|
|
||||||
// You can either write a struct which persists this data to disk, or you can use the
|
|
||||||
// provided "InMemoryStore" which just keeps data around in-memory which is lost on
|
|
||||||
// restarts.
|
|
||||||
type Storer interface {
|
|
||||||
SaveFilterID(userID, filterID string)
|
|
||||||
LoadFilterID(userID string) string
|
|
||||||
SaveNextBatch(userID, nextBatchToken string)
|
|
||||||
LoadNextBatch(userID string) string
|
|
||||||
SaveRoom(room *Room)
|
|
||||||
LoadRoom(roomID string) *Room
|
|
||||||
}
|
|
||||||
|
|
||||||
// InMemoryStore implements the Storer interface.
|
|
||||||
//
|
|
||||||
// Everything is persisted in-memory as maps. It is not safe to load/save filter IDs
|
|
||||||
// or next batch tokens on any goroutine other than the syncing goroutine: the one
|
|
||||||
// which called Client.Sync().
|
|
||||||
type InMemoryStore struct {
|
|
||||||
Filters map[string]string
|
|
||||||
NextBatch map[string]string
|
|
||||||
Rooms map[string]*Room
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveFilterID to memory.
|
|
||||||
func (s *InMemoryStore) SaveFilterID(userID, filterID string) {
|
|
||||||
s.Filters[userID] = filterID
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadFilterID from memory.
|
|
||||||
func (s *InMemoryStore) LoadFilterID(userID string) string {
|
|
||||||
return s.Filters[userID]
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveNextBatch to memory.
|
|
||||||
func (s *InMemoryStore) SaveNextBatch(userID, nextBatchToken string) {
|
|
||||||
s.NextBatch[userID] = nextBatchToken
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadNextBatch from memory.
|
|
||||||
func (s *InMemoryStore) LoadNextBatch(userID string) string {
|
|
||||||
return s.NextBatch[userID]
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveRoom to memory.
|
|
||||||
func (s *InMemoryStore) SaveRoom(room *Room) {
|
|
||||||
s.Rooms[room.ID] = room
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadRoom from memory.
|
|
||||||
func (s *InMemoryStore) LoadRoom(roomID string) *Room {
|
|
||||||
return s.Rooms[roomID]
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInMemoryStore constructs a new InMemoryStore.
|
|
||||||
func NewInMemoryStore() *InMemoryStore {
|
|
||||||
return &InMemoryStore{
|
|
||||||
Filters: make(map[string]string),
|
|
||||||
NextBatch: make(map[string]string),
|
|
||||||
Rooms: make(map[string]*Room),
|
|
||||||
}
|
|
||||||
}
|
|
168
vendor/github.com/matrix-org/gomatrix/sync.go
generated
vendored
168
vendor/github.com/matrix-org/gomatrix/sync.go
generated
vendored
@ -1,168 +0,0 @@
|
|||||||
package gomatrix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"runtime/debug"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Syncer represents an interface that must be satisfied in order to do /sync requests on a client.
|
|
||||||
type Syncer interface {
|
|
||||||
// Process the /sync response. The since parameter is the since= value that was used to produce the response.
|
|
||||||
// This is useful for detecting the very first sync (since=""). If an error is return, Syncing will be stopped
|
|
||||||
// permanently.
|
|
||||||
ProcessResponse(resp *RespSync, since string) error
|
|
||||||
// OnFailedSync returns either the time to wait before retrying or an error to stop syncing permanently.
|
|
||||||
OnFailedSync(res *RespSync, err error) (time.Duration, error)
|
|
||||||
// GetFilterJSON for the given user ID. NOT the filter ID.
|
|
||||||
GetFilterJSON(userID string) json.RawMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultSyncer is the default syncing implementation. You can either write your own syncer, or selectively
|
|
||||||
// replace parts of this default syncer (e.g. the ProcessResponse method). The default syncer uses the observer
|
|
||||||
// pattern to notify callers about incoming events. See DefaultSyncer.OnEventType for more information.
|
|
||||||
type DefaultSyncer struct {
|
|
||||||
UserID string
|
|
||||||
Store Storer
|
|
||||||
listeners map[string][]OnEventListener // event type to listeners array
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnEventListener can be used with DefaultSyncer.OnEventType to be informed of incoming events.
|
|
||||||
type OnEventListener func(*Event)
|
|
||||||
|
|
||||||
// NewDefaultSyncer returns an instantiated DefaultSyncer
|
|
||||||
func NewDefaultSyncer(userID string, store Storer) *DefaultSyncer {
|
|
||||||
return &DefaultSyncer{
|
|
||||||
UserID: userID,
|
|
||||||
Store: store,
|
|
||||||
listeners: make(map[string][]OnEventListener),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessResponse processes the /sync response in a way suitable for bots. "Suitable for bots" means a stream of
|
|
||||||
// unrepeating events. Returns a fatal error if a listener panics.
|
|
||||||
func (s *DefaultSyncer) ProcessResponse(res *RespSync, since string) (err error) {
|
|
||||||
if !s.shouldProcessResponse(res, since) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
err = fmt.Errorf("ProcessResponse panicked! userID=%s since=%s panic=%s\n%s", s.UserID, since, r, debug.Stack())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for roomID, roomData := range res.Rooms.Join {
|
|
||||||
room := s.getOrCreateRoom(roomID)
|
|
||||||
for _, event := range roomData.State.Events {
|
|
||||||
event.RoomID = roomID
|
|
||||||
room.UpdateState(&event)
|
|
||||||
s.notifyListeners(&event)
|
|
||||||
}
|
|
||||||
for _, event := range roomData.Timeline.Events {
|
|
||||||
event.RoomID = roomID
|
|
||||||
s.notifyListeners(&event)
|
|
||||||
}
|
|
||||||
for _, event := range roomData.Ephemeral.Events {
|
|
||||||
event.RoomID = roomID
|
|
||||||
s.notifyListeners(&event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for roomID, roomData := range res.Rooms.Invite {
|
|
||||||
room := s.getOrCreateRoom(roomID)
|
|
||||||
for _, event := range roomData.State.Events {
|
|
||||||
event.RoomID = roomID
|
|
||||||
room.UpdateState(&event)
|
|
||||||
s.notifyListeners(&event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for roomID, roomData := range res.Rooms.Leave {
|
|
||||||
room := s.getOrCreateRoom(roomID)
|
|
||||||
for _, event := range roomData.Timeline.Events {
|
|
||||||
if event.StateKey != nil {
|
|
||||||
event.RoomID = roomID
|
|
||||||
room.UpdateState(&event)
|
|
||||||
s.notifyListeners(&event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnEventType allows callers to be notified when there are new events for the given event type.
|
|
||||||
// There are no duplicate checks.
|
|
||||||
func (s *DefaultSyncer) OnEventType(eventType string, callback OnEventListener) {
|
|
||||||
_, exists := s.listeners[eventType]
|
|
||||||
if !exists {
|
|
||||||
s.listeners[eventType] = []OnEventListener{}
|
|
||||||
}
|
|
||||||
s.listeners[eventType] = append(s.listeners[eventType], callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
// shouldProcessResponse returns true if the response should be processed. May modify the response to remove
|
|
||||||
// stuff that shouldn't be processed.
|
|
||||||
func (s *DefaultSyncer) shouldProcessResponse(resp *RespSync, since string) bool {
|
|
||||||
if since == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// This is a horrible hack because /sync will return the most recent messages for a room
|
|
||||||
// as soon as you /join it. We do NOT want to process those events in that particular room
|
|
||||||
// because they may have already been processed (if you toggle the bot in/out of the room).
|
|
||||||
//
|
|
||||||
// Work around this by inspecting each room's timeline and seeing if an m.room.member event for us
|
|
||||||
// exists and is "join" and then discard processing that room entirely if so.
|
|
||||||
// TODO: We probably want to process messages from after the last join event in the timeline.
|
|
||||||
for roomID, roomData := range resp.Rooms.Join {
|
|
||||||
for i := len(roomData.Timeline.Events) - 1; i >= 0; i-- {
|
|
||||||
e := roomData.Timeline.Events[i]
|
|
||||||
if e.Type == "m.room.member" && e.StateKey != nil && *e.StateKey == s.UserID {
|
|
||||||
m := e.Content["membership"]
|
|
||||||
mship, ok := m.(string)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if mship == "join" {
|
|
||||||
_, ok := resp.Rooms.Join[roomID]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
delete(resp.Rooms.Join, roomID) // don't re-process messages
|
|
||||||
delete(resp.Rooms.Invite, roomID) // don't re-process invites
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// getOrCreateRoom must only be called by the Sync() goroutine which calls ProcessResponse()
|
|
||||||
func (s *DefaultSyncer) getOrCreateRoom(roomID string) *Room {
|
|
||||||
room := s.Store.LoadRoom(roomID)
|
|
||||||
if room == nil { // create a new Room
|
|
||||||
room = NewRoom(roomID)
|
|
||||||
s.Store.SaveRoom(room)
|
|
||||||
}
|
|
||||||
return room
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DefaultSyncer) notifyListeners(event *Event) {
|
|
||||||
listeners, exists := s.listeners[event.Type]
|
|
||||||
if !exists {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, fn := range listeners {
|
|
||||||
fn(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnFailedSync always returns a 10 second wait period between failed /syncs, never a fatal error.
|
|
||||||
func (s *DefaultSyncer) OnFailedSync(res *RespSync, err error) (time.Duration, error) {
|
|
||||||
return 10 * time.Second, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFilterJSON returns a filter with a timeline limit of 50.
|
|
||||||
func (s *DefaultSyncer) GetFilterJSON(userID string) json.RawMessage {
|
|
||||||
return json.RawMessage(`{"room":{"timeline":{"limit":50}}}`)
|
|
||||||
}
|
|
26
vendor/github.com/matrix-org/gomatrix/tags.go
generated
vendored
26
vendor/github.com/matrix-org/gomatrix/tags.go
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
// Copyright 2019 Sumukha PK
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package gomatrix
|
|
||||||
|
|
||||||
// TagContent contains the data for an m.tag message type
|
|
||||||
// https://matrix.org/docs/spec/client_server/r0.4.0.html#m-tag
|
|
||||||
type TagContent struct {
|
|
||||||
Tags map[string]TagProperties `json:"tags"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TagProperties contains the properties of a Tag
|
|
||||||
type TagProperties struct {
|
|
||||||
Order float32 `json:"order,omitempty"` // Empty values must be neglected
|
|
||||||
}
|
|
130
vendor/github.com/matrix-org/gomatrix/userids.go
generated
vendored
130
vendor/github.com/matrix-org/gomatrix/userids.go
generated
vendored
@ -1,130 +0,0 @@
|
|||||||
package gomatrix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const lowerhex = "0123456789abcdef"
|
|
||||||
|
|
||||||
// encode the given byte using quoted-printable encoding (e.g "=2f")
|
|
||||||
// and writes it to the buffer
|
|
||||||
// See https://golang.org/src/mime/quotedprintable/writer.go
|
|
||||||
func encode(buf *bytes.Buffer, b byte) {
|
|
||||||
buf.WriteByte('=')
|
|
||||||
buf.WriteByte(lowerhex[b>>4])
|
|
||||||
buf.WriteByte(lowerhex[b&0x0f])
|
|
||||||
}
|
|
||||||
|
|
||||||
// escape the given alpha character and writes it to the buffer
|
|
||||||
func escape(buf *bytes.Buffer, b byte) {
|
|
||||||
buf.WriteByte('_')
|
|
||||||
if b == '_' {
|
|
||||||
buf.WriteByte('_') // another _
|
|
||||||
} else {
|
|
||||||
buf.WriteByte(b + 0x20) // ASCII shift A-Z to a-z
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldEncode(b byte) bool {
|
|
||||||
return b != '-' && b != '.' && b != '_' && !(b >= '0' && b <= '9') && !(b >= 'a' && b <= 'z') && !(b >= 'A' && b <= 'Z')
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldEscape(b byte) bool {
|
|
||||||
return (b >= 'A' && b <= 'Z') || b == '_'
|
|
||||||
}
|
|
||||||
|
|
||||||
func isValidByte(b byte) bool {
|
|
||||||
return isValidEscapedChar(b) || (b >= '0' && b <= '9') || b == '.' || b == '=' || b == '-'
|
|
||||||
}
|
|
||||||
|
|
||||||
func isValidEscapedChar(b byte) bool {
|
|
||||||
return b == '_' || (b >= 'a' && b <= 'z')
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeUserLocalpart encodes the given string into Matrix-compliant user ID localpart form.
|
|
||||||
// See http://matrix.org/docs/spec/intro.html#mapping-from-other-character-sets
|
|
||||||
//
|
|
||||||
// This returns a string with only the characters "a-z0-9._=-". The uppercase range A-Z
|
|
||||||
// are encoded using leading underscores ("_"). Characters outside the aforementioned ranges
|
|
||||||
// (including literal underscores ("_") and equals ("=")) are encoded as UTF8 code points (NOT NCRs)
|
|
||||||
// and converted to lower-case hex with a leading "=". For example:
|
|
||||||
// Alph@Bet_50up => _alph=40_bet=5f50up
|
|
||||||
func EncodeUserLocalpart(str string) string {
|
|
||||||
strBytes := []byte(str)
|
|
||||||
var outputBuffer bytes.Buffer
|
|
||||||
for _, b := range strBytes {
|
|
||||||
if shouldEncode(b) {
|
|
||||||
encode(&outputBuffer, b)
|
|
||||||
} else if shouldEscape(b) {
|
|
||||||
escape(&outputBuffer, b)
|
|
||||||
} else {
|
|
||||||
outputBuffer.WriteByte(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return outputBuffer.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeUserLocalpart decodes the given string back into the original input string.
|
|
||||||
// Returns an error if the given string is not a valid user ID localpart encoding.
|
|
||||||
// See http://matrix.org/docs/spec/intro.html#mapping-from-other-character-sets
|
|
||||||
//
|
|
||||||
// This decodes quoted-printable bytes back into UTF8, and unescapes casing. For
|
|
||||||
// example:
|
|
||||||
// _alph=40_bet=5f50up => Alph@Bet_50up
|
|
||||||
// Returns an error if the input string contains characters outside the
|
|
||||||
// range "a-z0-9._=-", has an invalid quote-printable byte (e.g. not hex), or has
|
|
||||||
// an invalid _ escaped byte (e.g. "_5").
|
|
||||||
func DecodeUserLocalpart(str string) (string, error) {
|
|
||||||
strBytes := []byte(str)
|
|
||||||
var outputBuffer bytes.Buffer
|
|
||||||
for i := 0; i < len(strBytes); i++ {
|
|
||||||
b := strBytes[i]
|
|
||||||
if !isValidByte(b) {
|
|
||||||
return "", fmt.Errorf("Byte pos %d: Invalid byte", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
if b == '_' { // next byte is a-z and should be upper-case or is another _ and should be a literal _
|
|
||||||
if i+1 >= len(strBytes) {
|
|
||||||
return "", fmt.Errorf("Byte pos %d: expected _[a-z_] encoding but ran out of string", i)
|
|
||||||
}
|
|
||||||
if !isValidEscapedChar(strBytes[i+1]) { // invalid escaping
|
|
||||||
return "", fmt.Errorf("Byte pos %d: expected _[a-z_] encoding", i)
|
|
||||||
}
|
|
||||||
if strBytes[i+1] == '_' {
|
|
||||||
outputBuffer.WriteByte('_')
|
|
||||||
} else {
|
|
||||||
outputBuffer.WriteByte(strBytes[i+1] - 0x20) // ASCII shift a-z to A-Z
|
|
||||||
}
|
|
||||||
i++ // skip next byte since we just handled it
|
|
||||||
} else if b == '=' { // next 2 bytes are hex and should be buffered ready to be read as utf8
|
|
||||||
if i+2 >= len(strBytes) {
|
|
||||||
return "", fmt.Errorf("Byte pos: %d: expected quote-printable encoding but ran out of string", i)
|
|
||||||
}
|
|
||||||
dst := make([]byte, 1)
|
|
||||||
_, err := hex.Decode(dst, strBytes[i+1:i+3])
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
outputBuffer.WriteByte(dst[0])
|
|
||||||
i += 2 // skip next 2 bytes since we just handled it
|
|
||||||
} else { // pass through
|
|
||||||
outputBuffer.WriteByte(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return outputBuffer.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtractUserLocalpart extracts the localpart portion of a user ID.
|
|
||||||
// See http://matrix.org/docs/spec/intro.html#user-identifiers
|
|
||||||
func ExtractUserLocalpart(userID string) (string, error) {
|
|
||||||
if len(userID) == 0 || userID[0] != '@' {
|
|
||||||
return "", fmt.Errorf("%s is not a valid user id", userID)
|
|
||||||
}
|
|
||||||
return strings.TrimPrefix(
|
|
||||||
strings.SplitN(userID, ":", 2)[0], // @foo:bar:8448 => [ "@foo", "bar:8448" ]
|
|
||||||
"@", // remove "@" prefix
|
|
||||||
), nil
|
|
||||||
}
|
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -1,2 +0,0 @@
|
|||||||
# github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd
|
|
||||||
github.com/matrix-org/gomatrix
|
|
Loading…
Reference in New Issue
Block a user