aboutsummaryrefslogtreecommitdiff
path: root/db.go
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2020-02-26 16:07:33 +0100
committerAlex Auvolat <alex@adnab.me>2020-02-26 16:07:33 +0100
commit67c7f7361d63a282788f159494a6f43172c8806a (patch)
treefe80e56bf8cba13ff4ffbd126dc0d6fec146d657 /db.go
parenta8e87e378ea0a232cb06ef65d77fd39009270676 (diff)
downloadeasybridge-67c7f7361d63a282788f159494a6f43172c8806a.tar.gz
easybridge-67c7f7361d63a282788f159494a6f43172c8806a.zip
Move appservice/ to /
Diffstat (limited to 'db.go')
-rw-r--r--db.go266
1 files changed, 266 insertions, 0 deletions
diff --git a/db.go b/db.go
new file mode 100644
index 0000000..fe3d1e3
--- /dev/null
+++ b/db.go
@@ -0,0 +1,266 @@
+package main
+
+import (
+ "fmt"
+ "sync"
+
+ "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"
+ "golang.org/x/crypto/blake2b"
+
+ "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
+ "git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
+)
+
+var db *gorm.DB
+
+func InitDb() error {
+ var err error
+
+ db, err = gorm.Open(config.DbType, config.DbPath)
+ if err != nil {
+ return err
+ }
+
+ db.AutoMigrate(&DbCache{})
+
+ db.AutoMigrate(&DbUserMap{})
+ db.Model(&DbUserMap{}).AddIndex("idx_protocol_user", "protocol", "user_id")
+
+ db.AutoMigrate(&DbRoomMap{})
+ db.Model(&DbRoomMap{}).AddIndex("idx_protocol_room", "protocol", "room_id")
+
+ db.AutoMigrate(&DbPmRoomMap{})
+ db.Model(&DbPmRoomMap{}).AddIndex("idx_protocol_user_account_user", "protocol", "user_id", "mx_user_id", "account_name")
+
+ return nil
+}
+
+// Long-term cache entries
+type DbCache struct {
+ gorm.Model
+
+ Key string `gorm:"unique_index"`
+ Value string
+}
+
+// User mapping between protocol user IDs and puppeted matrix ids
+type DbUserMap struct {
+ gorm.Model
+
+ Protocol string
+ UserID connector.UserID
+ MxUserID string `gorm:"index:mxuserid"`
+}
+
+// Room mapping between Matrix rooms and outside rooms
+type DbRoomMap struct {
+ gorm.Model
+
+ // Network protocol
+ Protocol string
+
+ // Room id on the bridged network
+ RoomID connector.RoomID
+
+ // Bridged room matrix id
+ MxRoomID string `gorm:"index:mxroomid"`
+}
+
+// Room mapping between Matrix rooms and private messages
+type DbPmRoomMap struct {
+ gorm.Model
+
+ // User id and account name of the local end viewed on Matrix
+ MxUserID string
+ Protocol string
+ AccountName string
+
+ // User id to reach them
+ UserID connector.UserID
+
+ // Bridged room for PMs
+ MxRoomID string `gorm:"index:mxroomoid"`
+}
+
+// ---- Simple locking mechanism
+
+var dbLocks [256]sync.Mutex
+
+func dbLockSlot(key string) {
+ slot := blake2b.Sum512([]byte(key))[0]
+ dbLocks[slot].Lock()
+}
+
+func dbUnlockSlot(key string) {
+ slot := blake2b.Sum512([]byte(key))[0]
+ dbLocks[slot].Unlock()
+}
+
+// ----
+
+func dbCacheGet(key string) string {
+ var entry DbCache
+ if db.Where(&DbCache{Key: key}).First(&entry).RecordNotFound() {
+ return ""
+ } else {
+ return entry.Value
+ }
+}
+
+func dbCachePut(key string, value string) {
+ var entry DbCache
+ db.Where(&DbCache{Key: key}).Assign(&DbCache{Value: value}).FirstOrCreate(&entry)
+}
+
+func dbCacheTestAndSet(key string, value string) bool {
+ dbLockSlot(key)
+ defer dbUnlockSlot(key)
+
+ // True if value was changed, false if was already set
+ if dbCacheGet(key) != value {
+ dbCachePut(key, value)
+ return true
+ }
+ return false
+}
+
+func dbGetMxRoom(protocol string, roomId connector.RoomID) (string, error) {
+ slot_key := fmt.Sprintf("room: %s / %s", protocol, roomId)
+ dbLockSlot(slot_key)
+ defer dbUnlockSlot(slot_key)
+
+ var room DbRoomMap
+
+ // Check if room exists in our mapping,
+ // If not create it
+ must_create := db.First(&room, DbRoomMap{
+ Protocol: protocol,
+ RoomID: roomId,
+ }).RecordNotFound()
+ if must_create {
+ alias := roomAlias(protocol, roomId)
+ // Lookup alias
+ mx_room_id, err := mx.DirectoryRoom(fmt.Sprintf("#%s:%s", alias, config.MatrixDomain))
+
+ // If no alias found, create room
+ if err != nil {
+ name := fmt.Sprintf("%s (%s)", roomId, protocol)
+
+ mx_room_id, err = mx.CreateRoom(name, alias, []string{})
+ if err != nil {
+ log.Printf("Could not create room for %s: %s", name, err)
+ return "", err
+ }
+ }
+
+ room = DbRoomMap{
+ Protocol: protocol,
+ RoomID: roomId,
+ MxRoomID: mx_room_id,
+ }
+ db.Create(&room)
+ }
+ log.Debugf("Got room id: %s", room.MxRoomID)
+
+ return room.MxRoomID, nil
+}
+
+func dbGetMxPmRoom(protocol string, them connector.UserID, themMxId string, usMxId string, usAccount string) (string, error) {
+ slot_key := fmt.Sprintf("pmroom: %s / %s / %s / %s", protocol, usMxId, usAccount, them)
+ dbLockSlot(slot_key)
+ defer dbUnlockSlot(slot_key)
+
+ var room DbPmRoomMap
+
+ must_create := db.First(&room, DbPmRoomMap{
+ MxUserID: usMxId,
+ Protocol: protocol,
+ AccountName: usAccount,
+ UserID: them,
+ }).RecordNotFound()
+ if must_create {
+ name := fmt.Sprintf("%s (%s)", them, protocol)
+
+ mx_room_id, err := mx.CreateDirectRoomAs([]string{usMxId}, themMxId)
+ if err != nil {
+ log.Printf("Could not create room for %s: %s", name, err)
+ return "", err
+ }
+
+ //err = mxRoomJoinAs(mx_room_id, themMxId)
+ //if err != nil {
+ // log.Printf("Could not join %s as %s", mx_room_id, themMxId)
+ // return "", err
+ //}
+
+ room = DbPmRoomMap{
+ MxUserID: usMxId,
+ Protocol: protocol,
+ AccountName: usAccount,
+ UserID: them,
+ MxRoomID: mx_room_id,
+ }
+ db.Create(&room)
+ }
+ log.Debugf("Got PM room id: %s", room.MxRoomID)
+
+ return room.MxRoomID, nil
+}
+
+func dbGetMxUser(protocol string, userId connector.UserID) (string, error) {
+ slot_key := fmt.Sprintf("user: %s / %s", protocol, userId)
+ dbLockSlot(slot_key)
+ defer dbUnlockSlot(slot_key)
+
+ var user DbUserMap
+
+ must_create := db.First(&user, DbUserMap{
+ Protocol: protocol,
+ UserID: userId,
+ }).RecordNotFound()
+ if must_create {
+ username := userMxId(protocol, userId)
+
+ err := mx.RegisterUser(username)
+ if err != nil {
+ if mxE, ok := err.(*mxlib.MxError); !ok || mxE.ErrCode != "M_USER_IN_USE" {
+ log.Printf("Could not register %s: %s", username, err)
+ return "", err
+ }
+ }
+
+ mxid := fmt.Sprintf("@%s:%s", username, config.MatrixDomain)
+ mx.ProfileDisplayname(mxid, fmt.Sprintf("%s (%s)", userId, protocol))
+
+ user = DbUserMap{
+ Protocol: protocol,
+ UserID: userId,
+ MxUserID: mxid,
+ }
+ db.Create(&user)
+ }
+
+ return user.MxUserID, nil
+}
+
+func dbIsPmRoom(mxRoomId string) *DbPmRoomMap {
+ var pm_room DbPmRoomMap
+ if db.First(&pm_room, DbPmRoomMap{MxRoomID: mxRoomId}).RecordNotFound() {
+ return nil
+ } else {
+ return &pm_room
+ }
+}
+
+func dbIsPublicRoom(mxRoomId string) *DbRoomMap {
+ var room DbRoomMap
+ if db.First(&room, DbRoomMap{MxRoomID: mxRoomId}).RecordNotFound() {
+ return nil
+ } else {
+ return &room
+ }
+}