|
|
@ -4,7 +4,6 @@ import ( |
|
|
|
"fmt" |
|
|
|
"sync" |
|
|
|
|
|
|
|
"github.com/hashicorp/golang-lru" |
|
|
|
"github.com/jinzhu/gorm" |
|
|
|
_ "github.com/jinzhu/gorm/dialects/mysql" |
|
|
|
_ "github.com/jinzhu/gorm/dialects/postgres" |
|
|
@ -17,7 +16,6 @@ import ( |
|
|
|
) |
|
|
|
|
|
|
|
var db *gorm.DB |
|
|
|
var dbCache *lru.TwoQueueCache |
|
|
|
|
|
|
|
func InitDb() error { |
|
|
|
var err error |
|
|
@ -39,15 +37,10 @@ func InitDb() error { |
|
|
|
db.Model(&DbRoomMap{}).AddIndex("idx_room_map_protocol_room", "protocol", "room_id") |
|
|
|
|
|
|
|
db.AutoMigrate(&DbPmRoomMap{}) |
|
|
|
db.Model(&DbPmRoomMap{}).AddIndex("idx_pm_room_map_protocol_user_account_user", "protocol", "user_id", "mx_user_id", "account_name") |
|
|
|
db.Model(&DbPmRoomMap{}).AddIndex("idx_pm_room_map_protocol_user_account_user", "protocol", "mx_user_id", "account_name", "user_id") |
|
|
|
|
|
|
|
db.AutoMigrate(&DbKv{}) |
|
|
|
|
|
|
|
dbCache, err = lru.New2Q(10000) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
@ -63,7 +56,7 @@ type DbAccountConfig struct { |
|
|
|
|
|
|
|
// List of joined channels to be re-joined on reconnect
|
|
|
|
type DbJoinedRoom struct { |
|
|
|
ID uint `gorm:"primary_key"` |
|
|
|
ID uint `gorm:"primaryKey;autoIncrement:true"` |
|
|
|
|
|
|
|
// User id and account name
|
|
|
|
MxUserID string |
|
|
@ -76,22 +69,23 @@ type DbJoinedRoom struct { |
|
|
|
|
|
|
|
// User mapping between protocol user IDs and puppeted matrix ids
|
|
|
|
type DbUserMap struct { |
|
|
|
ID uint `gorm:"primary_key"` |
|
|
|
ID uint `gorm:"primaryKey;autoIncrement:true"` |
|
|
|
|
|
|
|
// Protocol and user ID on the bridged network
|
|
|
|
Protocol string |
|
|
|
UserID connector.UserID |
|
|
|
|
|
|
|
// Puppetted Matrix ID
|
|
|
|
MxUserID string `gorm:"index"` |
|
|
|
} |
|
|
|
|
|
|
|
// Room mapping between Matrix rooms and outside rooms
|
|
|
|
type DbRoomMap struct { |
|
|
|
ID uint `gorm:"primary_key"` |
|
|
|
ID uint `gorm:"primaryKey;autoIncrement:true"` |
|
|
|
|
|
|
|
// Network protocol
|
|
|
|
// Network protocol and room ID on the bridged network
|
|
|
|
Protocol string |
|
|
|
|
|
|
|
// Room id on the bridged network
|
|
|
|
RoomID connector.RoomID |
|
|
|
RoomID connector.RoomID |
|
|
|
|
|
|
|
// Bridged room matrix id
|
|
|
|
MxRoomID string `gorm:"index"` |
|
|
@ -99,14 +93,14 @@ type DbRoomMap struct { |
|
|
|
|
|
|
|
// Room mapping between Matrix rooms and private messages
|
|
|
|
type DbPmRoomMap struct { |
|
|
|
ID uint `gorm:"primary_key"` |
|
|
|
ID uint `gorm:"primaryKey;autoIncrement:true"` |
|
|
|
|
|
|
|
// User id and account name of the local end viewed on Matrix
|
|
|
|
MxUserID string |
|
|
|
Protocol string |
|
|
|
AccountName string |
|
|
|
|
|
|
|
// User id to reach them
|
|
|
|
// User id to reach them on the bridged network
|
|
|
|
UserID connector.UserID |
|
|
|
|
|
|
|
// Bridged room for PMs
|
|
|
@ -115,14 +109,13 @@ type DbPmRoomMap struct { |
|
|
|
|
|
|
|
// Key-value store for various things
|
|
|
|
type DbKv struct { |
|
|
|
Key string `gorm:"primary_key"` |
|
|
|
Key string `gorm:"primaryKey"` |
|
|
|
Value string |
|
|
|
} |
|
|
|
|
|
|
|
// ---- Simple locking mechanism
|
|
|
|
// Slot keys are strings that identify the object we are acting upon
|
|
|
|
// They define which lock to lock for a certain operation
|
|
|
|
// They are also used as keys in the LRU cache
|
|
|
|
|
|
|
|
var dbLocks [256]sync.Mutex |
|
|
|
|
|
|
@ -138,17 +131,7 @@ func dbUnlockSlot(key string) { |
|
|
|
|
|
|
|
// ---- Key-value store supporting atomic test-and-set
|
|
|
|
|
|
|
|
func dbKvSlotKey(key string) string { |
|
|
|
return "kv:" + key |
|
|
|
} |
|
|
|
|
|
|
|
func dbKvGet(key string) string { |
|
|
|
slot_key := dbKvSlotKey(key) |
|
|
|
|
|
|
|
if ent, ok := dbCache.Get(slot_key); ok { |
|
|
|
return ent.(string) |
|
|
|
} |
|
|
|
|
|
|
|
var entry DbKv |
|
|
|
if db.Where(&DbKv{Key: key}).First(&entry).RecordNotFound() { |
|
|
|
return "" |
|
|
@ -158,10 +141,8 @@ func dbKvGet(key string) string { |
|
|
|
} |
|
|
|
|
|
|
|
func dbKvPut(key string, value string) { |
|
|
|
slot_key := dbKvSlotKey(key) |
|
|
|
|
|
|
|
dbLockSlot(slot_key) |
|
|
|
defer dbUnlockSlot(slot_key) |
|
|
|
dbLockSlot(key) |
|
|
|
defer dbUnlockSlot(key) |
|
|
|
|
|
|
|
dbKvPutLocked(key, value) |
|
|
|
} |
|
|
@ -169,18 +150,13 @@ func dbKvPut(key string, value string) { |
|
|
|
// Variant of dbKvPut that does not take a lock,
|
|
|
|
// use this if the slot is already locked
|
|
|
|
func dbKvPutLocked(key string, value string) { |
|
|
|
slot_key := dbKvSlotKey(key) |
|
|
|
|
|
|
|
var entry DbKv |
|
|
|
db.Where(&DbKv{Key: key}).Assign(&DbKv{Value: value}).FirstOrCreate(&entry) |
|
|
|
dbCache.Add(slot_key, value) |
|
|
|
} |
|
|
|
|
|
|
|
func dbKvTestAndSet(key string, value string) bool { |
|
|
|
slot_key := dbKvSlotKey(key) |
|
|
|
|
|
|
|
dbLockSlot(slot_key) |
|
|
|
defer dbUnlockSlot(slot_key) |
|
|
|
dbLockSlot(key) |
|
|
|
defer dbUnlockSlot(key) |
|
|
|
|
|
|
|
// True if value was changed, false if was already set
|
|
|
|
if dbKvGet(key) == value { |
|
|
@ -199,10 +175,6 @@ func dbGetMxRoom(protocol string, roomId connector.RoomID) (string, error) { |
|
|
|
dbLockSlot(slot_key) |
|
|
|
defer dbUnlockSlot(slot_key) |
|
|
|
|
|
|
|
if cached, ok := dbCache.Get(slot_key); ok { |
|
|
|
return cached.(string), nil |
|
|
|
} |
|
|
|
|
|
|
|
// Check if room exists in our mapping,
|
|
|
|
// If not create it
|
|
|
|
var room DbRoomMap |
|
|
@ -239,16 +211,10 @@ func dbGetMxRoom(protocol string, roomId connector.RoomID) (string, error) { |
|
|
|
} |
|
|
|
|
|
|
|
log.Tracef("%s -> %s", slot_key, room.MxRoomID) |
|
|
|
dbCache.Add(slot_key, room.MxRoomID) |
|
|
|
|
|
|
|
return room.MxRoomID, nil |
|
|
|
} |
|
|
|
|
|
|
|
func dbPmRoomSlotKey(room *DbPmRoomMap) string { |
|
|
|
return fmt.Sprintf("pmroom:%s/%s/%s/%s", |
|
|
|
room.Protocol, room.MxUserID, room.AccountName, room.UserID) |
|
|
|
} |
|
|
|
|
|
|
|
func dbGetMxPmRoom(protocol string, them connector.UserID, themMxId string, usMxId string, usAccount string) (string, error) { |
|
|
|
map_key := &DbPmRoomMap{ |
|
|
|
MxUserID: usMxId, |
|
|
@ -256,15 +222,11 @@ func dbGetMxPmRoom(protocol string, them connector.UserID, themMxId string, usMx |
|
|
|
AccountName: usAccount, |
|
|
|
UserID: them, |
|
|
|
} |
|
|
|
slot_key := dbPmRoomSlotKey(map_key) |
|
|
|
slot_key := fmt.Sprintf("pmroom:%s/%s/%s/%s", protocol, usMxId, usAccount, them) |
|
|
|
|
|
|
|
dbLockSlot(slot_key) |
|
|
|
defer dbUnlockSlot(slot_key) |
|
|
|
|
|
|
|
if cached, ok := dbCache.Get(slot_key); ok { |
|
|
|
return cached.(string), nil |
|
|
|
} |
|
|
|
|
|
|
|
var room DbPmRoomMap |
|
|
|
must_create := db.First(&room, map_key).RecordNotFound() |
|
|
|
|
|
|
@ -288,19 +250,12 @@ func dbGetMxPmRoom(protocol string, them connector.UserID, themMxId string, usMx |
|
|
|
} |
|
|
|
|
|
|
|
log.Tracef("%s -> %s", slot_key, room.MxRoomID) |
|
|
|
dbCache.Add(slot_key, room.MxRoomID) |
|
|
|
|
|
|
|
return room.MxRoomID, nil |
|
|
|
} |
|
|
|
|
|
|
|
func dbDeletePmRoom(room *DbPmRoomMap) { |
|
|
|
slot_key := dbPmRoomSlotKey(room) |
|
|
|
|
|
|
|
dbLockSlot(slot_key) |
|
|
|
defer dbUnlockSlot(slot_key) |
|
|
|
|
|
|
|
db.Delete(room) |
|
|
|
dbCache.Remove(slot_key) |
|
|
|
} |
|
|
|
|
|
|
|
func dbGetMxUser(protocol string, userId connector.UserID) (string, error) { |
|
|
@ -309,10 +264,6 @@ func dbGetMxUser(protocol string, userId connector.UserID) (string, error) { |
|
|
|
dbLockSlot(slot_key) |
|
|
|
defer dbUnlockSlot(slot_key) |
|
|
|
|
|
|
|
if cached, ok := dbCache.Get(slot_key); ok { |
|
|
|
return cached.(string), nil |
|
|
|
} |
|
|
|
|
|
|
|
var user DbUserMap |
|
|
|
|
|
|
|
must_create := db.First(&user, DbUserMap{ |
|
|
@ -342,7 +293,6 @@ func dbGetMxUser(protocol string, userId connector.UserID) (string, error) { |
|
|
|
} |
|
|
|
|
|
|
|
log.Tracef("%s -> %s", slot_key, user.MxUserID) |
|
|
|
dbCache.Add(slot_key, user.MxUserID) |
|
|
|
|
|
|
|
return user.MxUserID, nil |
|
|
|
} |
|
|
|