Store read state version and resync on startup if needed
This commit is contained in:
2
database/upgrades/06-user-read-state-version.sql
Normal file
2
database/upgrades/06-user-read-state-version.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-- v6: Store user read state version
|
||||||
|
ALTER TABLE "user" ADD COLUMN read_state_version INTEGER NOT NULL DEFAULT 0;
|
||||||
@@ -22,18 +22,18 @@ func (uq *UserQuery) New() *User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (uq *UserQuery) GetByMXID(userID id.UserID) *User {
|
func (uq *UserQuery) GetByMXID(userID id.UserID) *User {
|
||||||
query := `SELECT mxid, dcid, discord_token, management_room, space_room, dm_space_room FROM "user" WHERE mxid=$1`
|
query := `SELECT mxid, dcid, discord_token, management_room, space_room, dm_space_room, read_state_version FROM "user" WHERE mxid=$1`
|
||||||
return uq.New().Scan(uq.db.QueryRow(query, userID))
|
return uq.New().Scan(uq.db.QueryRow(query, userID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uq *UserQuery) GetByID(id string) *User {
|
func (uq *UserQuery) GetByID(id string) *User {
|
||||||
query := `SELECT mxid, dcid, discord_token, management_room, space_room, dm_space_room FROM "user" WHERE dcid=$1`
|
query := `SELECT mxid, dcid, discord_token, management_room, space_room, dm_space_room, read_state_version FROM "user" WHERE dcid=$1`
|
||||||
return uq.New().Scan(uq.db.QueryRow(query, id))
|
return uq.New().Scan(uq.db.QueryRow(query, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uq *UserQuery) GetAllWithToken() []*User {
|
func (uq *UserQuery) GetAllWithToken() []*User {
|
||||||
query := `
|
query := `
|
||||||
SELECT mxid, dcid, discord_token, management_room, space_room, dm_space_room
|
SELECT mxid, dcid, discord_token, management_room, space_room, dm_space_room, read_state_version
|
||||||
FROM "user" WHERE discord_token IS NOT NULL
|
FROM "user" WHERE discord_token IS NOT NULL
|
||||||
`
|
`
|
||||||
rows, err := uq.db.Query(query)
|
rows, err := uq.db.Query(query)
|
||||||
@@ -61,11 +61,13 @@ type User struct {
|
|||||||
ManagementRoom id.RoomID
|
ManagementRoom id.RoomID
|
||||||
SpaceRoom id.RoomID
|
SpaceRoom id.RoomID
|
||||||
DMSpaceRoom id.RoomID
|
DMSpaceRoom id.RoomID
|
||||||
|
|
||||||
|
ReadStateVersion int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) Scan(row dbutil.Scannable) *User {
|
func (u *User) Scan(row dbutil.Scannable) *User {
|
||||||
var discordID, managementRoom, spaceRoom, dmSpaceRoom, discordToken sql.NullString
|
var discordID, managementRoom, spaceRoom, dmSpaceRoom, discordToken sql.NullString
|
||||||
err := row.Scan(&u.MXID, &discordID, &discordToken, &managementRoom, &spaceRoom, &dmSpaceRoom)
|
err := row.Scan(&u.MXID, &discordID, &discordToken, &managementRoom, &spaceRoom, &dmSpaceRoom, &u.ReadStateVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
u.log.Errorln("Database scan failed:", err)
|
u.log.Errorln("Database scan failed:", err)
|
||||||
@@ -82,8 +84,8 @@ func (u *User) Scan(row dbutil.Scannable) *User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) Insert() {
|
func (u *User) Insert() {
|
||||||
query := `INSERT INTO "user" (mxid, dcid, discord_token, management_room, space_room, dm_space_room) VALUES ($1, $2, $3, $4, $5, $6)`
|
query := `INSERT INTO "user" (mxid, dcid, discord_token, management_room, space_room, dm_space_room, read_state_version) VALUES ($1, $2, $3, $4, $5, $6, $7)`
|
||||||
_, err := u.db.Exec(query, u.MXID, strPtr(u.DiscordID), strPtr(u.DiscordToken), strPtr(string(u.ManagementRoom)), strPtr(string(u.SpaceRoom)), strPtr(string(u.DMSpaceRoom)))
|
_, err := u.db.Exec(query, u.MXID, strPtr(u.DiscordID), strPtr(u.DiscordToken), strPtr(string(u.ManagementRoom)), strPtr(string(u.SpaceRoom)), strPtr(string(u.DMSpaceRoom)), u.ReadStateVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
u.log.Warnfln("Failed to insert %s: %v", u.MXID, err)
|
u.log.Warnfln("Failed to insert %s: %v", u.MXID, err)
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -91,8 +93,8 @@ func (u *User) Insert() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) Update() {
|
func (u *User) Update() {
|
||||||
query := `UPDATE "user" SET dcid=$1, discord_token=$2, management_room=$3, space_room=$4, dm_space_room=$5 WHERE mxid=$6`
|
query := `UPDATE "user" SET dcid=$1, discord_token=$2, management_room=$3, space_room=$4, dm_space_room=$5, read_state_version=$6 WHERE mxid=$7`
|
||||||
_, err := u.db.Exec(query, strPtr(u.DiscordID), strPtr(u.DiscordToken), strPtr(string(u.ManagementRoom)), strPtr(string(u.SpaceRoom)), strPtr(string(u.DMSpaceRoom)), u.MXID)
|
_, err := u.db.Exec(query, strPtr(u.DiscordID), strPtr(u.DiscordToken), strPtr(string(u.ManagementRoom)), strPtr(string(u.SpaceRoom)), strPtr(string(u.DMSpaceRoom)), u.ReadStateVersion, u.MXID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
u.log.Warnfln("Failed to update %q: %v", u.MXID, err)
|
u.log.Warnfln("Failed to update %q: %v", u.MXID, err)
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -26,4 +26,4 @@ require (
|
|||||||
maunium.net/go/mauflag v1.0.0 // indirect
|
maunium.net/go/mauflag v1.0.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/bwmarrin/discordgo => gitlab.com/beeper/discordgo v0.23.3-0.20220708085215-5150e3de5797
|
replace github.com/bwmarrin/discordgo => gitlab.com/beeper/discordgo v0.23.3-0.20220708095310-09da7ef6f6de
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -30,8 +30,8 @@ github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
|
|||||||
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
|
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
|
||||||
github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0=
|
github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0=
|
||||||
github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
gitlab.com/beeper/discordgo v0.23.3-0.20220708085215-5150e3de5797 h1:G+6sujr5CBD1+GyDq9Vobj/2XhaRejXzyOVDNNWlM/E=
|
gitlab.com/beeper/discordgo v0.23.3-0.20220708095310-09da7ef6f6de h1:XSKsxfGXfUf7KTyzM1NmzYkqetqiLivUULhXr7alZX4=
|
||||||
gitlab.com/beeper/discordgo v0.23.3-0.20220708085215-5150e3de5797/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
gitlab.com/beeper/discordgo v0.23.3-0.20220708095310-09da7ef6f6de/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
|||||||
33
user.go
33
user.go
@@ -129,37 +129,32 @@ func (user *User) GetIGhost() bridge.Ghost {
|
|||||||
var _ bridge.User = (*User)(nil)
|
var _ bridge.User = (*User)(nil)
|
||||||
|
|
||||||
func (br *DiscordBridge) loadUser(dbUser *database.User, mxid *id.UserID) *User {
|
func (br *DiscordBridge) loadUser(dbUser *database.User, mxid *id.UserID) *User {
|
||||||
// If we weren't passed in a user we attempt to create one if we were given
|
|
||||||
// a matrix id.
|
|
||||||
if dbUser == nil {
|
if dbUser == nil {
|
||||||
if mxid == nil {
|
if mxid == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
dbUser = br.DB.User.New()
|
dbUser = br.DB.User.New()
|
||||||
dbUser.MXID = *mxid
|
dbUser.MXID = *mxid
|
||||||
dbUser.Insert()
|
dbUser.Insert()
|
||||||
}
|
}
|
||||||
|
|
||||||
user := br.NewUser(dbUser)
|
user := br.NewUser(dbUser)
|
||||||
|
|
||||||
// We assume the usersLock was acquired by our caller.
|
|
||||||
br.usersByMXID[user.MXID] = user
|
br.usersByMXID[user.MXID] = user
|
||||||
if user.DiscordID != "" {
|
if user.DiscordID != "" {
|
||||||
br.usersByID[user.DiscordID] = user
|
br.usersByID[user.DiscordID] = user
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.ManagementRoom != "" {
|
if user.ManagementRoom != "" {
|
||||||
// Lock the management rooms for our update
|
|
||||||
br.managementRoomsLock.Lock()
|
br.managementRoomsLock.Lock()
|
||||||
br.managementRooms[user.ManagementRoom] = user
|
br.managementRooms[user.ManagementRoom] = user
|
||||||
br.managementRoomsLock.Unlock()
|
br.managementRoomsLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *DiscordBridge) GetUserByMXID(userID id.UserID) *User {
|
func (br *DiscordBridge) GetUserByMXID(userID id.UserID) *User {
|
||||||
|
if userID == br.Bot.UserID || br.IsGhost(userID) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
br.usersLock.Lock()
|
br.usersLock.Lock()
|
||||||
defer br.usersLock.Unlock()
|
defer br.usersLock.Unlock()
|
||||||
|
|
||||||
@@ -167,7 +162,6 @@ func (br *DiscordBridge) GetUserByMXID(userID id.UserID) *User {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return br.loadUser(br.DB.User.GetByMXID(userID), &userID)
|
return br.loadUser(br.DB.User.GetByMXID(userID), &userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +173,6 @@ func (br *DiscordBridge) GetUserByID(id string) *User {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return br.loadUser(br.DB.User.GetByID(id), nil)
|
return br.loadUser(br.DB.User.GetByID(id), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +185,6 @@ func (br *DiscordBridge) NewUser(dbUser *database.User) *User {
|
|||||||
|
|
||||||
user.PermissionLevel = br.Config.Bridge.Permissions.Get(user.MXID)
|
user.PermissionLevel = br.Config.Bridge.Permissions.Get(user.MXID)
|
||||||
user.BridgeState = br.NewBridgeStateQueue(user, user.log)
|
user.BridgeState = br.NewBridgeStateQueue(user, user.log)
|
||||||
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +202,6 @@ func (br *DiscordBridge) getAllUsersWithToken() []*User {
|
|||||||
}
|
}
|
||||||
users[idx] = user
|
users[idx] = user
|
||||||
}
|
}
|
||||||
|
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,6 +529,19 @@ func (user *User) readyHandler(_ *discordgo.Session, r *discordgo.Ready) {
|
|||||||
portal := user.GetPortalByMeta(ch)
|
portal := user.GetPortalByMeta(ch)
|
||||||
user.handlePrivateChannel(portal, ch, updateTS, i < maxCreate, portalsInSpace[portal.Key.String()])
|
user.handlePrivateChannel(portal, ch, updateTS, i < maxCreate, portalsInSpace[portal.Key.String()])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.ReadState.Version > user.ReadStateVersion {
|
||||||
|
// TODO can we figure out which read states are actually new?
|
||||||
|
for _, entry := range r.ReadState.Entries {
|
||||||
|
user.messageAckHandler(nil, &discordgo.MessageAck{
|
||||||
|
MessageID: string(entry.LastMessageID),
|
||||||
|
ChannelID: entry.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
user.ReadStateVersion = r.ReadState.Version
|
||||||
|
user.Update()
|
||||||
|
}
|
||||||
|
|
||||||
user.BridgeState.Send(bridge.State{StateEvent: bridge.StateConnected})
|
user.BridgeState.Send(bridge.State{StateEvent: bridge.StateConnected})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,6 +765,11 @@ func (user *User) messageAckHandler(_ *discordgo.Session, m *discordgo.MessageAc
|
|||||||
user.log.Warnfln("Failed to mark %s/%s as read: %v", msg.MXID, msg.DiscordID, err)
|
user.log.Warnfln("Failed to mark %s/%s as read: %v", msg.MXID, msg.DiscordID, err)
|
||||||
} else {
|
} else {
|
||||||
user.log.Debugfln("Marked %s/%s as read after Discord message ack event", msg.MXID, msg.DiscordID)
|
user.log.Debugfln("Marked %s/%s as read after Discord message ack event", msg.MXID, msg.DiscordID)
|
||||||
|
if user.ReadStateVersion < m.Version {
|
||||||
|
user.ReadStateVersion = m.Version
|
||||||
|
// TODO maybe don't update every time?
|
||||||
|
user.Update()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user