Easybridge has an avatar
This commit is contained in:
parent
a4cf41536f
commit
92d380aa86
7 changed files with 196 additions and 11 deletions
|
@ -45,6 +45,12 @@ func Start(r *mxlib.Registration, c *Config) (chan error, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
err = mx.ProfileAvatar(ezbrMxId(), &connector.FileMediaObject{
|
||||||
|
Path: "easybridge.jpg",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.HandleFunc("/_matrix/app/v1/transactions/{txnId}", handleTxn)
|
router.HandleFunc("/_matrix/app/v1/transactions/{txnId}", handleTxn)
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package connector
|
package connector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A generic connector framework for instant messaging protocols.
|
A generic connector framework for instant messaging protocols.
|
||||||
|
|
||||||
|
@ -126,13 +130,14 @@ type RoomInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type MediaObject interface {
|
type MediaObject interface {
|
||||||
Size() int
|
Filename() string
|
||||||
MimeType() string
|
Size() int64
|
||||||
|
Mimetype() string
|
||||||
|
|
||||||
// AsBytes: must always be implemented
|
// Read: must always be implemented
|
||||||
AsBytes() ([]byte, error)
|
Read() (io.ReadCloser, error)
|
||||||
|
|
||||||
// AsString: not mandatory, may return an empty string
|
// URL(): not mandatory, may return an empty string
|
||||||
// If so, AsBytes() is the only way to retrieve the object
|
// If so, Read() is the only way to retrieve the object
|
||||||
AsURL() string
|
URL() string
|
||||||
}
|
}
|
||||||
|
|
50
connector/mediaobject.go
Normal file
50
connector/mediaobject.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package connector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileMediaObject struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FileMediaObject) Filename() string {
|
||||||
|
return filepath.Base(m.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FileMediaObject) Size() int64 {
|
||||||
|
fi, err := os.Stat(m.Path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return fi.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FileMediaObject) Mimetype() string {
|
||||||
|
f, err := os.Open(m.Path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
buffer := make([]byte, 512)
|
||||||
|
_, err = f.Read(buffer)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.DetectContentType(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FileMediaObject) Read() (io.ReadCloser, error) {
|
||||||
|
return os.Open(m.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FileMediaObject) URL() string {
|
||||||
|
return ""
|
||||||
|
}
|
8
main.go
8
main.go
|
@ -200,7 +200,7 @@ func main() {
|
||||||
}
|
}
|
||||||
conn.SetHandler(account)
|
conn.SetHandler(account)
|
||||||
appservice.AddAccount(account)
|
appservice.AddAccount(account)
|
||||||
go connectAndJoin(conn, params)
|
go connectAndJoin(account, params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,15 +210,15 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func connectAndJoin(conn connector.Connector, params ConfigAccount) {
|
func connectAndJoin(account *appservice.Account, params ConfigAccount) {
|
||||||
log.Printf("Connecting to %s", params.Protocol)
|
log.Printf("Connecting to %s", params.Protocol)
|
||||||
err := conn.Configure(params.Config)
|
err := account.Conn.Configure(params.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Could not connect to %s: %s", params.Protocol, err)
|
log.Printf("Could not connect to %s: %s", params.Protocol, err)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Connected to %s, now joining %#v", params.Protocol, params.Rooms)
|
log.Printf("Connected to %s, now joining %#v", params.Protocol, params.Rooms)
|
||||||
for _, room := range params.Rooms {
|
for _, room := range params.Rooms {
|
||||||
err := conn.Join(connector.RoomID(room))
|
err := account.Conn.Join(connector.RoomID(room))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Could not join %s: %s", room, err)
|
log.Printf("Could not join %s: %s", room, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,3 +83,11 @@ type RoomJoinResponse struct {
|
||||||
type RoomSendResponse struct {
|
type RoomSendResponse struct {
|
||||||
EventId string `json:"event_id"`
|
EventId string `json:"event_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UploadResponse struct {
|
||||||
|
ContentUri string `json:"content_uri"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProfileAvatarUrl struct {
|
||||||
|
AvatarUrl string `json:"avatar_url"`
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package mxlib
|
package mxlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -9,6 +10,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
|
@ -123,6 +126,29 @@ func (mx *Client) ProfileDisplayname(userid string, displayname string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mx *Client) ProfileAvatar(userid string, m connector.MediaObject) error {
|
||||||
|
var mxc *MediaObject
|
||||||
|
if mxm, ok := m.(*MediaObject); ok {
|
||||||
|
mxc = mxm
|
||||||
|
} else {
|
||||||
|
mxm, err := mx.UploadMedia(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mxc = mxm
|
||||||
|
}
|
||||||
|
mxc_uri := fmt.Sprintf("mxc://%s/%s", mxc.MxcServer, mxc.MxcMediaId)
|
||||||
|
|
||||||
|
req := ProfileAvatarUrl{
|
||||||
|
AvatarUrl: mxc_uri,
|
||||||
|
}
|
||||||
|
var rep struct{}
|
||||||
|
err := mx.PutApiCall(fmt.Sprintf("/_matrix/client/r0/profile/%s/avatar_url?user_id=%s",
|
||||||
|
url.QueryEscape(userid), url.QueryEscape(userid)),
|
||||||
|
&req, &rep)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (mx *Client) DirectoryRoom(alias string) (string, error) {
|
func (mx *Client) DirectoryRoom(alias string) (string, error) {
|
||||||
var rep DirectoryRoomResponse
|
var rep DirectoryRoomResponse
|
||||||
err := mx.GetApiCall("/_matrix/client/r0/directory/room/"+url.QueryEscape(alias), &rep)
|
err := mx.GetApiCall("/_matrix/client/r0/directory/room/"+url.QueryEscape(alias), &rep)
|
||||||
|
@ -252,3 +278,39 @@ func (mx *Client) RoomTopicAs(room string, topic string, as_user string) error {
|
||||||
}
|
}
|
||||||
return mx.PutStateAs(room, "m.room.topic", "", content, as_user)
|
return mx.PutStateAs(room, "m.room.topic", "", content, as_user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mx *Client) UploadMedia(m connector.MediaObject) (*MediaObject, error) {
|
||||||
|
reader, err := m.Read()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST",
|
||||||
|
mx.Server+"/_matrix/media/r0/upload?filename="+url.QueryEscape(m.Filename()),
|
||||||
|
reader)
|
||||||
|
req.Header.Add("Content-Type", m.Mimetype())
|
||||||
|
req.ContentLength = m.Size()
|
||||||
|
|
||||||
|
var resp UploadResponse
|
||||||
|
err = mx.DoAndParse(req, &resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mxc := strings.Split(strings.Replace(resp.ContentUri, "mxc://", "", 1), "/")
|
||||||
|
if len(mxc) != 2 {
|
||||||
|
return nil, fmt.Errorf("Invalid mxc:// returned: %s", resp.ContentUri)
|
||||||
|
}
|
||||||
|
|
||||||
|
media := &MediaObject{
|
||||||
|
mxClient: mx,
|
||||||
|
filename: m.Filename(),
|
||||||
|
size: m.Size(),
|
||||||
|
mimetype: m.Mimetype(),
|
||||||
|
MxcServer: mxc[0],
|
||||||
|
MxcMediaId: mxc[1],
|
||||||
|
}
|
||||||
|
return media, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
54
mxlib/mediaobject.go
Normal file
54
mxlib/mediaobject.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package mxlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MediaObject struct {
|
||||||
|
mxClient *Client
|
||||||
|
filename string
|
||||||
|
size int64
|
||||||
|
mimetype string
|
||||||
|
MxcServer string
|
||||||
|
MxcMediaId string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MediaObject) Filename() string {
|
||||||
|
return m.filename
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MediaObject) Size() int64 {
|
||||||
|
return m.size
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MediaObject) Mimetype() string {
|
||||||
|
return m.mimetype
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MediaObject) Read() (io.ReadCloser, error) {
|
||||||
|
req, err := http.NewRequest("GET", m.URL(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("Authorization", "Bearer "+m.mxClient.Token)
|
||||||
|
|
||||||
|
resp, err := m.mxClient.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("HTTP error %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.Body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MediaObject) URL() string {
|
||||||
|
return fmt.Sprintf("%s/_matrix/media/r0/download/%s/%s/%s",
|
||||||
|
m.mxClient.Server, m.MxcServer, m.MxcMediaId, url.QueryEscape(m.filename))
|
||||||
|
}
|
Loading…
Reference in a new issue