store: move the access_hash and username to separate per-user table

Signed-off-by: Sumner Evans <sumner.evans@automattic.com>
This commit is contained in:
Sumner Evans
2024-08-08 12:12:17 -06:00
parent aeb8fba288
commit 838f291220
7 changed files with 129 additions and 22 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ func (t *TelegramClient) getDMChatInfo(ctx context.Context, userID int64) (*brid
return nil, err
} else if len(users) == 0 {
return nil, fmt.Errorf("failed to get user info for user %d", userID)
} else if userInfo, err := t.getUserInfoFromTelegramUser(users[0]); err != nil {
} else if userInfo, err := t.getUserInfoFromTelegramUser(ctx, users[0]); err != nil {
return nil, err
} else if err = t.updateGhostWithUserInfo(ctx, userID, userInfo); err != nil {
return nil, err
+30 -13
View File
@@ -247,13 +247,19 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge
}
client.matrixParser = &matrixfmt.HTMLParser{
GetGhostDetails: func(ctx context.Context, ui id.UserID) (networkid.UserID, string, int64, bool) {
if userID, ok := tc.Bridge.Matrix.ParseGhostMXID(ui); !ok {
userID, ok := tc.Bridge.Matrix.ParseGhostMXID(ui)
if !ok {
return "", "", 0, false
} else if ghost, err := tc.Bridge.GetGhostByID(ctx, userID); err != nil {
return "", "", 0, false
} else {
return userID, ghost.Metadata.(*GhostMetadata).Username, ghost.Metadata.(*GhostMetadata).AccessHash, true
}
telegramUserID, err := ids.ParseUserID(userID)
if err != nil {
return "", "", 0, false
}
username, accessHash, found, err := tc.Store.GetScopedStore(telegramUserID).GetUserMetadata(ctx, telegramUserID)
if err != nil || !found {
return "", "", 0, false
}
return userID, username, accessHash, true
},
}
@@ -330,9 +336,15 @@ func (t *TelegramClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost)
if err != nil {
return nil, err
}
accessHash, found, err := t.ScopedStore.GetUserAccessHash(ctx, id)
if err != nil {
return nil, fmt.Errorf("failed to get access hash for user %d: %w", id, err)
} else if !found {
return nil, fmt.Errorf("access hash not found for user %d", id)
}
users, err := t.client.API().UsersGetUsers(ctx, []tg.InputUserClass{&tg.InputUser{
UserID: id,
AccessHash: ghost.Metadata.(*GhostMetadata).AccessHash,
AccessHash: accessHash,
}})
if err != nil {
return nil, err
@@ -340,20 +352,28 @@ func (t *TelegramClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost)
if len(users) == 0 {
return nil, fmt.Errorf("failed to get user info for user %d", id)
}
userInfo, err := t.getUserInfoFromTelegramUser(users[0])
userInfo, err := t.getUserInfoFromTelegramUser(ctx, users[0])
if err != nil {
return nil, err
}
return userInfo, t.updateGhostWithUserInfo(ctx, id, userInfo)
}
func (t *TelegramClient) getUserInfoFromTelegramUser(u tg.UserClass) (*bridgev2.UserInfo, error) {
func (t *TelegramClient) getUserInfoFromTelegramUser(ctx context.Context, u tg.UserClass) (*bridgev2.UserInfo, error) {
user, ok := u.(*tg.User)
if !ok {
return nil, fmt.Errorf("user is %T not *tg.User", user)
}
var identifiers []string
if !user.Min {
if user.Min {
if err := t.ScopedStore.SetUserAccessHash(ctx, user.ID, user.AccessHash); err != nil {
return nil, err
}
} else {
if err := t.ScopedStore.SetUserMetadata(ctx, user.ID, user.Username, user.AccessHash); err != nil {
return nil, err
}
if username, ok := user.GetUsername(); ok {
identifiers = append(identifiers, fmt.Sprintf("telegram:%s", username))
}
@@ -388,13 +408,10 @@ func (t *TelegramClient) getUserInfoFromTelegramUser(u tg.UserClass) (*bridgev2.
ExtraUpdates: func(ctx context.Context, ghost *bridgev2.Ghost) (changed bool) {
meta := ghost.Metadata.(*GhostMetadata)
if !user.Min {
changed = changed || meta.IsPremium != user.Premium || meta.IsBot != user.Bot || meta.Username != user.Username
changed = changed || meta.IsPremium != user.Premium || meta.IsBot != user.Bot
meta.IsPremium = user.Premium
meta.IsBot = user.Bot
meta.Username = user.Username
}
changed = changed || meta.AccessHash != user.AccessHash
meta.AccessHash = user.AccessHash
return changed
},
}, nil
+2 -4
View File
@@ -88,10 +88,8 @@ func (tg *TelegramConnector) GetDBMetaTypes() database.MetaTypes {
}
type GhostMetadata struct {
AccessHash int64 `json:"access_hash"`
IsPremium bool `json:"is_premium,omitempty"`
IsBot bool `json:"is_bot,omitempty"`
Username string `json:"username,omitempty"`
IsPremium bool `json:"is_premium,omitempty"`
IsBot bool `json:"is_bot,omitempty"`
}
type MessageMetadata struct {
+65
View File
@@ -58,6 +58,32 @@ const (
VALUES ($1, $2, $3)
ON CONFLICT (user_id, channel_id) DO UPDATE SET access_hash=excluded.access_hash
`
// User Access Hash Queries
getUserAccessHashQuery = "SELECT access_hash FROM telegram_user_metadata WHERE receiver_id=$1 AND user_id=$2"
setUserAccessHashQuery = `
INSERT INTO telegram_user_metadata (receiver_id, user_id, access_hash)
VALUES ($1, $2, $3)
ON CONFLICT (receiver_id, user_id) DO UPDATE SET access_hash=excluded.access_hash
`
// User Username Queries
getUserUsernameQuery = "SELECT username FROM telegram_user_metadata WHERE receiver_id=$1 AND user_id=$2"
setUserUsernameQuery = `
INSERT INTO telegram_user_metadata (receiver_id, user_id, username)
VALUES ($1, $2, $3)
ON CONFLICT (receiver_id, user_id) DO UPDATE SET username=excluded.username
`
// User Metadata Queries
getUserMetadataQuery = "SELECT username, access_hash FROM telegram_user_metadata WHERE receiver_id=$1 AND user_id=$2"
setUserMetadataQuery = `
INSERT INTO telegram_user_metadata (receiver_id, user_id, username, access_hash)
VALUES ($1, $2, $3, $4)
ON CONFLICT (receiver_id, user_id) DO UPDATE SET
username=excluded.username,
access_hash=excluded.access_hash
`
)
var _ session.Storage = (*ScopedStore)(nil)
@@ -170,6 +196,45 @@ func (s *ScopedStore) SetChannelAccessHash(ctx context.Context, userID int64, ch
return
}
func (s *ScopedStore) GetUserAccessHash(ctx context.Context, userID int64) (accessHash int64, found bool, err error) {
err = s.db.QueryRow(ctx, getUserAccessHashQuery, s.telegramUserID, userID).Scan(&accessHash)
if errors.Is(err, sql.ErrNoRows) {
return 0, false, nil
}
return accessHash, err == nil, err
}
func (s *ScopedStore) SetUserAccessHash(ctx context.Context, userID, accessHash int64) (err error) {
_, err = s.db.Exec(ctx, setUserAccessHashQuery, s.telegramUserID, userID, accessHash)
return
}
func (s *ScopedStore) GetUserUsername(ctx context.Context, userID int64) (username string, found bool, err error) {
err = s.db.QueryRow(ctx, getUserUsernameQuery, s.telegramUserID, userID).Scan(&username)
if errors.Is(err, sql.ErrNoRows) {
return "", false, nil
}
return username, err == nil, err
}
func (s *ScopedStore) SetUserUsername(ctx context.Context, userID int64, username string) (err error) {
_, err = s.db.Exec(ctx, setUserUsernameQuery, s.telegramUserID, userID, username)
return
}
func (s *ScopedStore) GetUserMetadata(ctx context.Context, userID int64) (username string, accessHash int64, found bool, err error) {
err = s.db.QueryRow(ctx, getUserMetadataQuery, s.telegramUserID, userID).Scan(&username, &accessHash)
if errors.Is(err, sql.ErrNoRows) {
return "", 0, false, nil
}
return username, accessHash, err == nil, err
}
func (s *ScopedStore) SetUserMetadata(ctx context.Context, userID int64, username string, accessHash int64) (err error) {
_, err = s.db.Exec(ctx, setUserMetadataQuery, s.telegramUserID, userID, username, accessHash)
return
}
// Helper Functions
func (s *ScopedStore) assertUserIDMatches(userID int64) {
@@ -31,6 +31,16 @@ CREATE TABLE telegram_channel_access_hashes (
PRIMARY KEY (user_id, channel_id)
);
CREATE TABLE telegram_user_metadata (
receiver_id INTEGER,
user_id INTEGER,
access_hash INTEGER NOT NULL,
username TEXT,
PRIMARY KEY (receiver_id, user_id)
);
CREATE TABLE telegram_file (
id TEXT PRIMARY KEY,
mxc TEXT NOT NULL,
@@ -0,0 +1,15 @@
-- v3: Move the user access hash to a table so it can be per-user
CREATE TABLE telegram_user_metadata (
receiver_id INTEGER,
user_id INTEGER,
access_hash INTEGER NOT NULL,
username TEXT,
PRIMARY KEY (receiver_id, user_id)
);
INSERT INTO telegram_user_metadata (receiver_id, user_id, access_hash, username)
SELECT ul.id, g.id, g.metadata->>'access_hash', g.metadata->>'username'
FROM user_login ul, ghost g;
+6 -4
View File
@@ -235,7 +235,7 @@ func (t *TelegramClient) updateGhost(ctx context.Context, userID int64, user *tg
if err != nil {
return err
}
userInfo, err := t.getUserInfoFromTelegramUser(user)
userInfo, err := t.getUserInfoFromTelegramUser(ctx, user)
if err != nil {
return err
}
@@ -468,10 +468,12 @@ func (t *TelegramClient) inputPeerForPortalID(ctx context.Context, portalID netw
}
switch peerType {
case ids.PeerTypeUser:
if ghost, err := t.main.Bridge.DB.Ghost.GetByID(ctx, ids.MakeUserID(id)); err != nil {
return nil, err
if accessHash, found, err := t.ScopedStore.GetUserAccessHash(ctx, id); err != nil {
return nil, fmt.Errorf("failed to get user access hash for %d: %w", id, err)
} else if !found {
return nil, fmt.Errorf("user access hash not found for %d", id)
} else {
return &tg.InputPeerUser{UserID: id, AccessHash: ghost.Metadata.(*GhostMetadata).AccessHash}, nil
return &tg.InputPeerUser{UserID: id, AccessHash: accessHash}, nil
}
case ids.PeerTypeChat:
return &tg.InputPeerChat{ChatID: id}, nil