mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-08 19:10:53 +00:00
Add phone number resolve support
This commit is contained in:
parent
85c244b462
commit
7440958274
@ -0,0 +1,41 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
|
||||
public final class CachedResolvedByPhonePeer: Codable {
|
||||
public let peerId: PeerId?
|
||||
public let timestamp: Int32
|
||||
|
||||
public static func key(name: String) -> ValueBoxKey {
|
||||
let key: ValueBoxKey
|
||||
if let nameData = name.data(using: .utf8) {
|
||||
key = ValueBoxKey(length: nameData.count)
|
||||
nameData.withUnsafeBytes { rawBytes -> Void in
|
||||
let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: Int8.self)
|
||||
|
||||
memcpy(key.memory, bytes, nameData.count)
|
||||
}
|
||||
} else {
|
||||
key = ValueBoxKey(length: 0)
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
public init(peerId: PeerId?, timestamp: Int32) {
|
||||
self.peerId = peerId
|
||||
self.timestamp = timestamp
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
self.peerId = (try container.decodeIfPresent(Int64.self, forKey: "p")).flatMap(PeerId.init)
|
||||
self.timestamp = try container.decode(Int32.self, forKey: "t")
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: StringCodingKey.self)
|
||||
|
||||
try container.encodeIfPresent(self.peerId?.toInt64(), forKey: "p")
|
||||
try container.encode(self.timestamp, forKey: "t")
|
||||
}
|
||||
}
|
@ -82,6 +82,7 @@ public struct Namespaces {
|
||||
public static let cachedPeerExportedInvitations: Int8 = 17
|
||||
public static let cachedSendAsPeers: Int8 = 18
|
||||
public static let availableReactions: Int8 = 19
|
||||
public static let resolvedByPhonePeers: Int8 = 20
|
||||
}
|
||||
|
||||
public struct UnorderedItemList {
|
||||
|
@ -77,3 +77,66 @@ func _internal_resolvePeerByName(account: Account, name: String, ageLimit: Int32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let resolvedByPhonePeersCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 150, highWaterItemCount: 200)
|
||||
|
||||
func _internal_resolvePeerByPhone(account: Account, phone: String, ageLimit: Int32 = 2 * 60 * 60 * 24) -> Signal<PeerId?, NoError> {
|
||||
var normalizedPhone = phone
|
||||
if normalizedPhone.hasPrefix("+") {
|
||||
normalizedPhone = String(normalizedPhone[normalizedPhone.index(after: normalizedPhone.startIndex)...])
|
||||
}
|
||||
|
||||
return account.postbox.transaction { transaction -> CachedResolvedByPhonePeer? in
|
||||
return transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByPhonePeers, key: CachedResolvedByPhonePeer.key(name: normalizedPhone)))?.get(CachedResolvedByPhonePeer.self)
|
||||
} |> mapToSignal { cachedEntry -> Signal<PeerId?, NoError> in
|
||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||
if let cachedEntry = cachedEntry, cachedEntry.timestamp <= timestamp && cachedEntry.timestamp >= timestamp - ageLimit {
|
||||
return .single(cachedEntry.peerId)
|
||||
} else {
|
||||
return account.network.request(Api.functions.contacts.resolvePhone(phone: normalizedPhone))
|
||||
|> mapError { _ -> Void in
|
||||
return Void()
|
||||
}
|
||||
|> mapToSignal { result -> Signal<PeerId?, Void> in
|
||||
return account.postbox.transaction { transaction -> PeerId? in
|
||||
var peerId: PeerId? = nil
|
||||
|
||||
switch result {
|
||||
case let .resolvedPeer(apiPeer, chats, users):
|
||||
var peers: [PeerId: Peer] = [:]
|
||||
|
||||
for user in users {
|
||||
if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) {
|
||||
peers[user.id] = user
|
||||
}
|
||||
}
|
||||
|
||||
for chat in chats {
|
||||
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||
peers[groupOrChannel.id] = groupOrChannel
|
||||
}
|
||||
}
|
||||
|
||||
if let peer = peers[apiPeer.peerId] {
|
||||
peerId = peer.id
|
||||
|
||||
updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated -> Peer in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||
if let entry = CodableEntry(CachedResolvedByPhonePeer(peerId: peerId, timestamp: timestamp)) {
|
||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByPhonePeers, key: CachedResolvedByPhonePeer.key(name: normalizedPhone)), entry: entry, collectionSpec: resolvedByNamePeersCollectionSpec)
|
||||
}
|
||||
return peerId
|
||||
}
|
||||
|> castError(Void.self)
|
||||
}
|
||||
|> `catch` { _ -> Signal<PeerId?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,18 @@ public extension TelegramEngine {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func resolvePeerByPhone(phone: String, ageLimit: Int32 = 2 * 60 * 60 * 24) -> Signal<EnginePeer?, NoError> {
|
||||
return _internal_resolvePeerByPhone(account: self.account, phone: phone, ageLimit: ageLimit)
|
||||
|> mapToSignal { peerId -> Signal<EnginePeer?, NoError> in
|
||||
guard let peerId = peerId else {
|
||||
return .single(nil)
|
||||
}
|
||||
return self.account.postbox.transaction { transaction -> EnginePeer? in
|
||||
return transaction.getPeer(peerId).flatMap(EnginePeer.init)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func updatedRemotePeer(peer: PeerReference) -> Signal<Peer, UpdatedRemotePeerError> {
|
||||
return _internal_updatedRemotePeer(postbox: self.account.postbox, network: self.account.network, peer: peer)
|
||||
|
@ -605,6 +605,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
|
||||
if parsedUrl.host == "resolve" {
|
||||
if let components = URLComponents(string: "/?" + query) {
|
||||
var phone: String?
|
||||
var domain: String?
|
||||
var start: String?
|
||||
var startGroup: String?
|
||||
@ -614,7 +615,9 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
if let queryItems = components.queryItems {
|
||||
for queryItem in queryItems {
|
||||
if let value = queryItem.value {
|
||||
if queryItem.name == "domain" {
|
||||
if queryItem.name == "phone" {
|
||||
phone = value
|
||||
} else if queryItem.name == "domain" {
|
||||
domain = value
|
||||
} else if queryItem.name == "start" {
|
||||
start = value
|
||||
@ -633,7 +636,9 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
||||
}
|
||||
}
|
||||
|
||||
if let domain = domain {
|
||||
if let phone = phone {
|
||||
convertedUrl = "https://t.me/+\(phone)"
|
||||
} else if let domain = domain {
|
||||
var result = "https://t.me/\(domain)"
|
||||
if let post = post, let postValue = Int(post) {
|
||||
result += "/\(postValue)"
|
||||
|
@ -41,6 +41,7 @@ public enum ParsedInternalUrl {
|
||||
case share(url: String?, text: String?, to: String?)
|
||||
case wallpaper(WallpaperUrlParameter)
|
||||
case theme(String)
|
||||
case phone(String)
|
||||
}
|
||||
|
||||
private enum ParsedUrl {
|
||||
@ -154,7 +155,12 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
||||
} else if pathComponents[0].hasPrefix(phonebookUsernamePathPrefix), let idValue = Int64(String(pathComponents[0][pathComponents[0].index(pathComponents[0].startIndex, offsetBy: phonebookUsernamePathPrefix.count)...])) {
|
||||
return .peerId(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(idValue)))
|
||||
} else if pathComponents[0].hasPrefix("+") || pathComponents[0].hasPrefix("%20") {
|
||||
return .join(String(pathComponents[0].dropFirst()))
|
||||
let component = pathComponents[0].replacingOccurrences(of: "%20", with: "+")
|
||||
if component.rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789+").inverted) == nil {
|
||||
return .phone(component.replacingOccurrences(of: "+", with: ""))
|
||||
} else {
|
||||
return .join(String(component.dropFirst()))
|
||||
}
|
||||
}
|
||||
return .peerName(peerName, nil)
|
||||
} else if pathComponents.count == 2 || pathComponents.count == 3 {
|
||||
@ -350,6 +356,16 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
|
||||
|
||||
private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) -> Signal<ResolvedUrl?, NoError> {
|
||||
switch url {
|
||||
case let .phone(phone):
|
||||
return context.engine.peers.resolvePeerByPhone(phone: phone)
|
||||
|> take(1)
|
||||
|> map { peer -> ResolvedUrl? in
|
||||
if let peer = peer?._asPeer() {
|
||||
return .peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil))
|
||||
} else {
|
||||
return .peer(nil, .info)
|
||||
}
|
||||
}
|
||||
case let .peerName(name, parameter):
|
||||
return context.engine.peers.resolvePeerByName(name: name)
|
||||
|> take(1)
|
||||
@ -383,11 +399,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
||||
return .single(.joinVoiceChat(peer.id, invite))
|
||||
}
|
||||
} else {
|
||||
if let peer = peer as? TelegramUser, peer.botInfo == nil {
|
||||
return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil)))
|
||||
} else {
|
||||
return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil)))
|
||||
}
|
||||
return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil)))
|
||||
}
|
||||
} else {
|
||||
return .single(.peer(nil, .info))
|
||||
|
Loading…
x
Reference in New Issue
Block a user