diff options
author | Alex Auvolat <alex@adnab.me> | 2020-02-26 16:07:33 +0100 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2020-02-26 16:07:33 +0100 |
commit | 67c7f7361d63a282788f159494a6f43172c8806a (patch) | |
tree | fe80e56bf8cba13ff4ffbd126dc0d6fec146d657 /db.go | |
parent | a8e87e378ea0a232cb06ef65d77fd39009270676 (diff) | |
download | easybridge-67c7f7361d63a282788f159494a6f43172c8806a.tar.gz easybridge-67c7f7361d63a282788f159494a6f43172c8806a.zip |
Move appservice/ to /
Diffstat (limited to 'db.go')
-rw-r--r-- | db.go | 266 |
1 files changed, 266 insertions, 0 deletions
@@ -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 + } +} |