This commit is contained in:
Alex 2020-02-17 19:02:26 +01:00
parent 531b59bf95
commit a4dd3b310d
9 changed files with 142 additions and 144 deletions

View File

@ -10,10 +10,10 @@ import (
)
type Account struct {
MatrixUser string
MatrixUser string
AccountName string
Protocol string
Conn Connector
Protocol string
Conn Connector
JoinedRooms map[RoomID]bool
}
@ -240,4 +240,3 @@ func (a *Account) eventInternal(event *Event) error {
return mxSendMessageAs(mx_room_id, typ, event.Text, mx_user_id)
}
}

View File

@ -3,14 +3,14 @@ package appservice
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/jinzhu/gorm/dialects/postgres"
_ "github.com/jinzhu/gorm/dialects/sqlite"
log "github.com/sirupsen/logrus"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
)
var db *gorm.DB
@ -40,7 +40,7 @@ type DbUserMap struct {
gorm.Model
Protocol string
UserID connector.UserID
UserID connector.UserID
MxUserID string `gorm:"index:mxuserid"`
}
@ -63,8 +63,8 @@ type DbPmRoomMap struct {
gorm.Model
// User id and account name of the local end viewed on Matrix
MxUserID string
Protocol string
MxUserID string
Protocol string
AccountName string
// User id to reach them
@ -83,7 +83,7 @@ func dbGetMxRoom(protocol string, roomId connector.RoomID) (string, error) {
// If not create it
must_create := db.First(&room, DbRoomMap{
Protocol: protocol,
RoomID: roomId,
RoomID: roomId,
}).RecordNotFound()
if must_create {
alias := roomAlias(protocol, roomId)
@ -103,7 +103,7 @@ func dbGetMxRoom(protocol string, roomId connector.RoomID) (string, error) {
room = DbRoomMap{
Protocol: protocol,
RoomID: roomId,
RoomID: roomId,
MxRoomID: mx_room_id,
}
db.Create(&room)
@ -117,10 +117,10 @@ func dbGetMxPmRoom(protocol string, them connector.UserID, themMxId string, usMx
var room DbPmRoomMap
must_create := db.First(&room, DbPmRoomMap{
MxUserID: usMxId,
Protocol: protocol,
MxUserID: usMxId,
Protocol: protocol,
AccountName: usAccount,
UserID: them,
UserID: them,
}).RecordNotFound()
if must_create {
name := fmt.Sprintf("%s (%s)", them, protocol)
@ -138,11 +138,11 @@ func dbGetMxPmRoom(protocol string, them connector.UserID, themMxId string, usMx
}
room = DbPmRoomMap{
MxUserID: usMxId,
Protocol: protocol,
MxUserID: usMxId,
Protocol: protocol,
AccountName: usAccount,
UserID: them,
MxRoomID: mx_room_id,
UserID: them,
MxRoomID: mx_room_id,
}
db.Create(&room)
}
@ -156,7 +156,7 @@ func dbGetMxUser(protocol string, userId connector.UserID) (string, error) {
must_create := db.First(&user, DbUserMap{
Protocol: protocol,
UserID: userId,
UserID: userId,
}).RecordNotFound()
if must_create {
username := userMxId(protocol, userId)
@ -174,7 +174,7 @@ func dbGetMxUser(protocol string, userId connector.UserID) (string, error) {
user = DbUserMap{
Protocol: protocol,
UserID: userId,
UserID: userId,
MxUserID: mxid,
}
db.Create(&user)

View File

@ -1,12 +1,12 @@
package appservice
import (
"fmt"
"net/url"
"net/http"
"time"
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
log "github.com/sirupsen/logrus"
@ -33,7 +33,7 @@ func init() {
func mxGetApiCall(endpoint string, response interface{}) error {
log.Debugf("Matrix GET request: %s\n", endpoint)
req, err := http.NewRequest("GET", config.Server + endpoint, nil)
req, err := http.NewRequest("GET", config.Server+endpoint, nil)
if err != nil {
return err
}
@ -49,7 +49,7 @@ func mxPutApiCall(endpoint string, data interface{}, response interface{}) error
log.Debugf("Matrix PUT request: %s %s\n", endpoint, string(body))
req, err := http.NewRequest("PUT", config.Server + endpoint, bytes.NewBuffer(body))
req, err := http.NewRequest("PUT", config.Server+endpoint, bytes.NewBuffer(body))
if err != nil {
return err
}
@ -66,7 +66,7 @@ func mxPostApiCall(endpoint string, data interface{}, response interface{}) erro
log.Debugf("Matrix POST request: %s %s\n", endpoint, string(body))
req, err := http.NewRequest("POST", config.Server + endpoint, bytes.NewBuffer(body))
req, err := http.NewRequest("POST", config.Server+endpoint, bytes.NewBuffer(body))
if err != nil {
return err
}
@ -76,7 +76,7 @@ func mxPostApiCall(endpoint string, data interface{}, response interface{}) erro
}
func mxDoAndParse(req *http.Request, response interface{}) error {
req.Header.Add("Authorization", "Bearer " + registration.AsToken)
req.Header.Add("Authorization", "Bearer "+registration.AsToken)
resp, err := httpClient.Do(req)
if err != nil {
@ -125,7 +125,7 @@ func mxProfileDisplayname(userid string, displayname string) error {
func mxDirectoryRoom(alias string) (string, error) {
var rep DirectoryRoomResponse
err := mxGetApiCall("/_matrix/client/r0/directory/room/" + url.QueryEscape(alias), &rep)
err := mxGetApiCall("/_matrix/client/r0/directory/room/"+url.QueryEscape(alias), &rep)
if err != nil {
return "", err
}
@ -134,18 +134,18 @@ func mxDirectoryRoom(alias string) (string, error) {
func mxCreateRoom(name string, alias string, invite []string) (string, error) {
rq := CreateRoomRequest{
Preset: "private_chat",
Preset: "private_chat",
RoomAliasName: alias,
Name: name,
Topic: "",
Invite: invite,
CreationContent: map[string]interface{} {
Name: name,
Topic: "",
Invite: invite,
CreationContent: map[string]interface{}{
"m.federate": false,
},
PowerLevels: map[string]interface{} {
PowerLevels: map[string]interface{}{
"invite": 100,
"events": map[string]interface{} {
"m.room.topic": 0,
"events": map[string]interface{}{
"m.room.topic": 0,
"m.room.avatar": 0,
},
},
@ -161,19 +161,19 @@ func mxCreateRoom(name string, alias string, invite []string) (string, error) {
func mxCreateDirectRoomAs(name string, invite []string, as_user string) (string, error) {
rq := CreateRoomNoAliasRequest{
Preset: "private_chat",
Name: name,
Topic: "",
Name: name,
Topic: "",
Invite: invite,
CreationContent: map[string]interface{} {
CreationContent: map[string]interface{}{
"m.federate": false,
},
PowerLevels: map[string]interface{} {
PowerLevels: map[string]interface{}{
"invite": 100,
},
IsDirect: true,
}
var rep CreateRoomResponse
err := mxPostApiCall("/_matrix/client/r0/createRoom?user_id=" + url.QueryEscape(as_user), &rq, &rep)
err := mxPostApiCall("/_matrix/client/r0/createRoom?user_id="+url.QueryEscape(as_user), &rq, &rep)
if err != nil {
return "", err
}
@ -185,7 +185,7 @@ func mxRoomInvite(room string, user string) error {
UserId: user,
}
var rep struct{}
err := mxPostApiCall("/_matrix/client/r0/rooms/" + url.QueryEscape(room) + "/invite", &rq, &rep)
err := mxPostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/invite", &rq, &rep)
return err
}
@ -195,21 +195,21 @@ func mxRoomKick(room string, user string, reason string) error {
Reason: reason,
}
var rep struct{}
err := mxPostApiCall("/_matrix/client/r0/rooms/" + url.QueryEscape(room) + "/kick", &rq, &rep)
err := mxPostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/kick", &rq, &rep)
return err
}
func mxRoomJoinAs(room string, user string) error {
rq := struct{}{}
var rep RoomJoinResponse
err := mxPostApiCall("/_matrix/client/r0/rooms/" + url.QueryEscape(room) + "/join?user_id=" + url.QueryEscape(user), &rq, &rep)
err := mxPostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/join?user_id="+url.QueryEscape(user), &rq, &rep)
return err
}
func mxRoomLeaveAs(room string, user string) error {
rq := struct{}{}
var rep struct{}
err := mxPostApiCall("/_matrix/client/r0/rooms/" + url.QueryEscape(room) + "/leave?user_id=" + url.QueryEscape(user), &rq, &rep)
err := mxPostApiCall("/_matrix/client/r0/rooms/"+url.QueryEscape(room)+"/leave?user_id="+url.QueryEscape(user), &rq, &rep)
return err
}
@ -224,9 +224,9 @@ func mxSendAs(room string, event_type string, content map[string]interface{}, us
}
func mxSendMessageAs(room string, typ string, body string, user string) error {
content := map[string]interface{} {
content := map[string]interface{}{
"msgtype": typ,
"body": body,
"body": body,
}
return mxSendAs(room, "m.room.message", content, user)
}
@ -241,14 +241,14 @@ func mxPutStateAs(room string, event_type string, key string, content map[string
}
func mxRoomNameAs(room string, name string, as_user string) error {
content := map[string]interface{} {
content := map[string]interface{}{
"name": name,
}
return mxPutStateAs(room, "m.room.name", "", content, as_user)
}
func mxRoomTopicAs(room string, topic string, as_user string) error {
content := map[string]interface{} {
content := map[string]interface{}{
"topic": topic,
}
return mxPutStateAs(room, "m.room.topic", "", content, as_user)

View File

@ -3,25 +3,24 @@ package appservice
import (
"encoding/json"
"fmt"
"strings"
"net/http"
"strings"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
)
type Config struct {
HttpBindAddr string
Server string
DbType string
DbPath string
Server string
DbType string
DbPath string
MatrixDomain string
}
var registration *mxlib.Registration
var config *Config

View File

@ -8,11 +8,11 @@ package connector
- A connector represents a connection to an outgoing service (IRC, XMPP, etc)
It satisfies a generic interface representing the actions that can be called
(send messages, join room, etc)
- A handler represents a consumer of events happening on a connection
It satisfies a generic interface representing the events that can happend
(message received, rooms autojoined, etc)
- A connector implements a given protocol that has an identifier
Each protocol identifier determines a namespace for user identifiers
and room identifiers which are globally unique for all connections using
@ -82,6 +82,7 @@ type Handler interface {
}
type EventType int
const (
EVENT_JOIN EventType = iota
EVENT_LEAVE
@ -114,12 +115,12 @@ type Event struct {
type UserInfo struct {
DisplayName string
Avatar MediaObject
Avatar MediaObject
}
type RoomInfo struct {
Name string
Topic string
Name string
Topic string
Picture MediaObject
}

View File

@ -1,10 +1,10 @@
package irc
import (
"time"
"fmt"
_ "os"
"strings"
"fmt"
"time"
"github.com/lrstanley/girc"
@ -19,19 +19,19 @@ type IRC struct {
handler Handler
connected bool
timeout int
timeout int
nick string
name string
nick string
name string
server string
conn *girc.Client
conn *girc.Client
}
func (irc *IRC) SetHandler(h Handler) {
irc.handler = h
}
func(irc *IRC) Protocol() string {
func (irc *IRC) Protocol() string {
return "irc"
}
@ -64,9 +64,9 @@ func (irc *IRC) Configure(c Configuration) error {
client := girc.New(girc.Config{
Server: irc.server,
Port: port,
Nick: irc.nick,
User: irc.nick,
Port: port,
Nick: irc.nick,
User: irc.nick,
//Out: os.Stderr,
SSL: ssl,
})
@ -85,7 +85,7 @@ func (irc *IRC) Configure(c Configuration) error {
go irc.connectLoop(client)
for i := 0; i < 42; i++ {
time.Sleep(time.Duration(1)*time.Second)
time.Sleep(time.Duration(1) * time.Second)
if irc.conn != client {
break
}
@ -245,9 +245,9 @@ func (irc *IRC) ircConnected(c *girc.Client, e girc.Event) {
func (irc *IRC) ircPrivmsg(c *girc.Client, e girc.Event) {
ev := &Event{
Type: EVENT_MESSAGE,
Type: EVENT_MESSAGE,
Author: UserID(e.Source.Name + "@" + irc.server),
Text: e.Last(),
Text: e.Last(),
}
if e.IsFromChannel() {
ev.Room = RoomID(e.Params[0] + "@" + irc.server)
@ -265,9 +265,9 @@ func (irc *IRC) ircJoin(c *girc.Client, e girc.Event) {
} else {
user := UserID(e.Source.Name + "@" + irc.server)
ev := &Event{
Type: EVENT_JOIN,
Type: EVENT_JOIN,
Author: user,
Room: room,
Room: room,
}
irc.handler.Event(ev)
irc.handler.UserInfoUpdated(user, &UserInfo{
@ -283,9 +283,9 @@ func (irc *IRC) ircPart(c *girc.Client, e girc.Event) {
} else {
user := UserID(e.Source.Name + "@" + irc.server)
ev := &Event{
Type: EVENT_LEAVE,
Type: EVENT_LEAVE,
Author: user,
Room: room,
Room: room,
}
irc.handler.Event(ev)
irc.handler.UserInfoUpdated(user, &UserInfo{
@ -304,9 +304,9 @@ func (irc *IRC) ircNamreply(c *girc.Client, e girc.Event) {
src := girc.ParseSource(name)
if src.Name != irc.nick {
irc.handler.Event(&Event{
Type: EVENT_JOIN,
Type: EVENT_JOIN,
Author: UserID(src.Name + "@" + irc.server),
Room: room,
Room: room,
})
}
}

62
main.go
View File

@ -1,41 +1,41 @@
package main
import (
"fmt"
"crypto/rand"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
_ "fmt"
"io/ioutil"
"os"
_"strings"
_ "strings"
_ "time"
_ "fmt"
"encoding/json"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/appservice"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/connector/irc"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/connector/xmpp"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
)
type ConfigAccount struct {
Protocol string `json:"protocol"`
Rooms []string `json:"rooms"`
Config map[string]string `json:"config"`
Protocol string `json:"protocol"`
Rooms []string `json:"rooms"`
Config map[string]string `json:"config"`
}
type ConfigFile struct {
HttpBindAddr string`json:"http_bind_addr"`
Registration string `json:"registration"`
Server string `json:"homeserver_url"`
DbType string `json:"db_type"`
DbPath string `json:"db_path"`
MatrixDomain string `json:"matrix_domain"`
Accounts map[string]map[string]ConfigAccount `json:"accounts"`
HttpBindAddr string `json:"http_bind_addr"`
Registration string `json:"registration"`
Server string `json:"homeserver_url"`
DbType string `json:"db_type"`
DbPath string `json:"db_path"`
MatrixDomain string `json:"matrix_domain"`
Accounts map[string]map[string]ConfigAccount `json:"accounts"`
}
var configFlag = flag.String("config", "./config.json", "Configuration file path")
@ -47,10 +47,10 @@ func readConfig() ConfigFile {
config_file := ConfigFile{
HttpBindAddr: "0.0.0.0:8321",
Registration: "./registration.yaml",
Server: "http://localhost:8008",
DbType: "sqlite3",
DbPath: "easybridge.db",
Accounts: map[string]map[string]ConfigAccount{},
Server: "http://localhost:8008",
DbType: "sqlite3",
DbPath: "easybridge.db",
Accounts: map[string]map[string]ConfigAccount{},
}
_, err := os.Stat(*configFlag)
@ -96,22 +96,22 @@ func readRegistration(file string) mxlib.Registration {
}
reg := mxlib.Registration{
Id: "Easybridge",
Url: "http://localhost:8321",
AsToken: hex.EncodeToString(rnd[:32]),
HsToken: hex.EncodeToString(rnd[32:]),
Id: "Easybridge",
Url: "http://localhost:8321",
AsToken: hex.EncodeToString(rnd[:32]),
HsToken: hex.EncodeToString(rnd[32:]),
SenderLocalpart: "_ezbr_",
Namespaces: mxlib.RegistrationNamespaceSet{
Users: []mxlib.RegistrationNamespace{
mxlib.RegistrationNamespace{
Exclusive: true,
Regex: "@_ezbr_.*",
Regex: "@_ezbr_.*",
},
},
Aliases: []mxlib.RegistrationNamespace{
mxlib.RegistrationNamespace{
Exclusive: true,
Regex: "#_ezbr_.*",
Regex: "#_ezbr_.*",
},
},
Rooms: []mxlib.RegistrationNamespace{},
@ -166,9 +166,9 @@ func main() {
as_config := &appservice.Config{
HttpBindAddr: config.HttpBindAddr,
Server: config.Server,
DbType: config.DbType,
DbPath: config.DbPath,
Server: config.Server,
DbType: config.DbType,
DbPath: config.DbPath,
MatrixDomain: config.MatrixDomain,
}
@ -189,10 +189,10 @@ func main() {
log.Fatalf("Invalid protocol %s", params.Protocol)
}
account := &appservice.Account{
MatrixUser: fmt.Sprintf("@%s:%s", user, config.MatrixDomain),
MatrixUser: fmt.Sprintf("@%s:%s", user, config.MatrixDomain),
AccountName: name,
Protocol: params.Protocol,
Conn: conn,
Protocol: params.Protocol,
Conn: conn,
JoinedRooms: map[connector.RoomID]bool{},
}
conn.SetHandler(account)

View File

@ -6,7 +6,7 @@ import (
type MxError struct {
ErrCode string `json:"errcode"`
ErrMsg string `json:"error"`
ErrMsg string `json:"error"`
}
func (e *MxError) Error() string {
@ -18,12 +18,12 @@ type Transaction struct {
}
type Event struct {
Content map[string]interface{} `json:"content"`
Type string `json:"type"`
EventId string `json:"event_id"`
RoomId string `json:"room_id"`
Sender string `json:"sender"`
OriginServerTs int `json:"origin_server_ts"`
Content map[string]interface{} `json:"content"`
Type string `json:"type"`
EventId string `json:"event_id"`
RoomId string `json:"room_id"`
Sender string `json:"sender"`
OriginServerTs int `json:"origin_server_ts"`
}
type RegisterRequest struct {
@ -31,9 +31,9 @@ type RegisterRequest struct {
}
type RegisterResponse struct {
UserId string `json:"user_id"`
UserId string `json:"user_id"`
AccessToken string `json:"access_token"`
DeviceId string `json:"device_id"`
DeviceId string `json:"device_id"`
}
type ProfileDisplaynameRequest struct {
@ -41,23 +41,23 @@ type ProfileDisplaynameRequest struct {
}
type CreateRoomRequest struct {
Preset string `json:"preset"`
RoomAliasName string `json:"room_alias_name"`
Name string `json:"name"`
Topic string `json:"topic"`
Invite []string `json:"invite"`
Preset string `json:"preset"`
RoomAliasName string `json:"room_alias_name"`
Name string `json:"name"`
Topic string `json:"topic"`
Invite []string `json:"invite"`
CreationContent map[string]interface{} `json:"creation_content"`
PowerLevels map[string]interface{} `json:"power_level_content_override"`
PowerLevels map[string]interface{} `json:"power_level_content_override"`
}
type CreateRoomNoAliasRequest struct {
Preset string `json:"preset"`
Name string `json:"name"`
Topic string `json:"topic"`
Invite []string `json:"invite"`
Preset string `json:"preset"`
Name string `json:"name"`
Topic string `json:"topic"`
Invite []string `json:"invite"`
CreationContent map[string]interface{} `json:"creation_content"`
PowerLevels map[string]interface{} `json:"power_level_content_override"`
IsDirect bool `json:"is_direct"`
PowerLevels map[string]interface{} `json:"power_level_content_override"`
IsDirect bool `json:"is_direct"`
}
type CreateRoomResponse struct {
@ -65,7 +65,7 @@ type CreateRoomResponse struct {
}
type DirectoryRoomResponse struct {
RoomId string `json:"room_id"`
RoomId string `json:"room_id"`
Servers []string `json:"string"`
}
@ -84,4 +84,3 @@ type RoomJoinResponse struct {
type RoomSendResponse struct {
EventId string `json:"event_id"`
}

View File

@ -5,21 +5,21 @@ import (
)
type Registration struct {
Id string `yaml:"id"`
Url string `yaml:"url"`
AsToken string `yaml:"as_token"`
HsToken string `yaml:"hs_token"`
SenderLocalpart string `yaml:"sender_localpart"`
Namespaces RegistrationNamespaceSet `yaml:"namespaces"`
Id string `yaml:"id"`
Url string `yaml:"url"`
AsToken string `yaml:"as_token"`
HsToken string `yaml:"hs_token"`
SenderLocalpart string `yaml:"sender_localpart"`
Namespaces RegistrationNamespaceSet `yaml:"namespaces"`
}
type RegistrationNamespaceSet struct {
Users []RegistrationNamespace `yaml:"users"`
Users []RegistrationNamespace `yaml:"users"`
Aliases []RegistrationNamespace `yaml:"aliases"`
Rooms []RegistrationNamespace `yaml:"rooms"`
Rooms []RegistrationNamespace `yaml:"rooms"`
}
type RegistrationNamespace struct {
Exclusive bool `yaml:"exclusive"`
Regex string `yaml:"regex"`
Exclusive bool `yaml:"exclusive"`
Regex string `yaml:"regex"`
}