Post

Telegram研究:联系人同步

Telegram研究:联系人同步

联系人相关操作和同步

  • 1、拉取联系人列表(初始化、更新)
  • 2、删除联系人
  • 3、增加联系人
  • 4、修改联系人昵称
  • 5、联系人头像变化
  • 6、搜索联系人

1、拉取联系人列表(初始化、更新)

1.1、关键字
1
2
3
4
5
6
7
8
9
10
// 生成对比参数
`hashForCountAndIds`
// 到服务器对比
`updatedRemoteContactPeers` -> `Api.functions.contacts.getContacts`
// 手动导入的手机通讯录的人数
`transaction.replaceRemoteContactCount(totalCount)`
// 更新用户
`updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(users: partUsers))`
// 更新联系人id列表
`transaction.replaceContactPeerIds(updatedIds)`

AppDelegate.swift SharedAccountContextImpl -> init -> account.resetStateManagement

Account.swift restartContactManagement -> contactSyncManager.beginSync

ContactSyncManager.swift beginSync(importableContacts:xxx) -> self.impl.with -> ContactSyncManagerImpl -> beginSync(importableContacts:xxx) -> strongSelf.addOperation(.waitForUpdatedState) strongSelf.addOperation(.updatePresences) strongSelf.addOperation(.sync(importableContacts: importableContacts))

-> updateOperations -> startOperation -> 读取在线时间 -> .updatePresences -> updateContactPresences -> 可引入的联系人 -> .sync(importableContacts) -> syncContactsOnce(network:…)

submodules/TelegramCore/Sources/TelegramEngine/Contacts/

ContactManagement.swift syncContactsOnce(network:...) -> postbox.transaction -> 本地表contactsTable获取联系人id列表: transaction.getContactPeerIds() -> scan -> 获取全部 本地表metadataTable获取联系人人数: transaction.getRemoteContactCount() -> get -> .RemoteContactCount

totalCount+peerIds -> 对id进行排序 -> hashForCountAndIds -> hash -> 去服务器对比 -> updatedRemoteContactPeers -> Api.functions.contacts.getContacts(hash: hash) -> FunctionDescription(name: “contacts.getContacts”, parameters: [(“hash”,…)]) -> Api.parse ->

没有变就不处理: .contactsNotModified 变化了就会返回人员、总数: .contacts(_, savedCount, users)

-> appliedUpdatedPeers = updatedPeers -> (peers, totalCount) = peersAndPresences -> postbox.transaction

更新总数 transaction.replaceRemoteContactCount(totalCount) -> postbox?.replaceRemoteContactCount -> metadataTable.setRemoteContactCount -> valueBox.set 更新用户 如果本地没有数据,一般是刚卸载安装 -> 按500人分组 -> 每次都已有id与接口id进行并集 -> updatedIds.formUnion(partUsers.map { $0.peerId }) -> transaction.replaceContactPeerIds(updatedIds) 如果本地有数据。直接更新id -> transaction.replaceContactPeerIds(Set(peers.users.keys))

postbox?.replaceContactPeerIds -> contactsTable.replace

ContactTable -> beforeCommit -> 对比历史的数据、最新的数据 -> removedPeerIds + addedPeerIds -> 遍历删除 -> 遍历增加

override func beforeCommit() { if let peerIdsBeforeModification = self.peerIdsBeforeModification { if let peerIds = self.peerIds { let removedPeerIds = peerIdsBeforeModification.subtracting(peerIds) let addedPeerIds = peerIds.subtracting(peerIdsBeforeModification)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
            let sharedKey = self.key(PeerId(0))
            
            for peerId in removedPeerIds {
                self.valueBox.remove(self.table, key: self.key(peerId, sharedKey: sharedKey), secure: false)
                self.peerNameIndexTable.setPeerCategoryState(peerId: peerId, category: [.contacts], includes: false)
            }
            
            for peerId in addedPeerIds {
                self.valueBox.set(self.table, key: self.key(peerId, sharedKey: sharedKey), value: MemoryBuffer())
                self.peerNameIndexTable.setPeerCategoryState(peerId: peerId, category: [.contacts], includes: true)
            }
        } else {
            assertionFailure()
        }
        
        self.peerIdsBeforeModification = nil
    }

    if !self.useCaches {
        self.peerIds = nil
    }
}

syncContactsOnce -> updatedRemoteContactPeers -> Api.functions.contacts.getContacts(hash: hash)

只要开启事务处理 postbox.transaction -> 处理完事务里的内容业务逻辑 -> beginInternalTransaction -> internalTransaction -> valueBox.begin() -> beforeCommit -> 跟新所有表的缓存 -> … peerTable.transactionUpdatedPeers(contactsTable:…) … -> valueBox.commit

// 更新用户信息 updatePeersCustom(transaction: transaction, peers: parsedPeers, update: { _, updated in updated }) updatePeersInternal -> postbox?.updatePeers -> self.peerTable.set(updatedPeer) self.peerNameIndexTable.markPeerNameUpdated self.peerNameIndexTable.markPeerNameUpdated

// 更新用户在线信息 updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peers.users)


tg通过uid的排序然后combineInt64Hash组合hash,对比数据是否有变化

有些项目里,请求联系人接口时,会返回联系人的最后变化时间,下次同步数据时把时间最为参数,服务端对比,如果同步时间变化了就会有数据返回,然后全部保存这个更新时间作为下次请求时的参数

最后变更时间关心的是数据是否有变化,即使先加A,然后再移除A,实际数据没变化 实现方案1:每条操作都有独立的时间,且是逻辑删除,这样取最后一条时间比较,方便做增量更新 方案1随着时间的变化,记录的数据会很大,但是可以追溯有哪些变化

实现方案2:可以物理删除,但是有一个专门的表记录每个人的联系人列表的最后操作时间 方案2表里会有记录哪些新增,以及一条最后变更时间,数据量相对小些,但是没法追述变化了什么

tg的hash的方式是真实对比了联系人数据是否有了变化,tg类似方案2

This post is licensed under CC BY 4.0 by the author.