import Foundation #if TELE_IOS_USE_LOCAL_FFI import tele_ios_ffi #elseif TELE_IOS_TYPECHECK_UNIFFI import tele_ios_ffiFFI #endif #if TELE_IOS_USE_LOCAL_FFI || TELE_IOS_TYPECHECK_UNIFFI public actor UniFfiSessionBridge: SessionBridge { private let handle: SessionHandle private let defaultLimit: Int32 public init(account: Account, useFakeTdlib: Bool = true, defaultLimit: Int32 = 100) throws { self.handle = try createSession(config: IosSessionConfig( accountId: account.id, displayName: account.displayName, databasePath: account.databasePath.path, useFakeTdlib: useFakeTdlib )) self.defaultLimit = defaultLimit } public init(handle: SessionHandle, defaultLimit: Int32 = 100) { self.handle = handle self.defaultLimit = defaultLimit } public func authState() async throws -> AuthState { Self.mapAuthState(handle.authState()) } public func networkState() async throws -> NetworkState { Self.mapNetworkState(handle.networkState()) } public func pollEvents() async throws -> [SessionEvent] { handle.pollEvents().map(Self.mapEvent) } public func sendPhoneNumber(_ phone: String) async throws { try handle.sendPhoneNumber(phone: phone) } public func sendCode(_ code: String) async throws { try handle.sendCode(code: code) } public func sendPassword(_ password: String) async throws { try handle.sendPassword(password: password) } public func loadFolders() async throws -> [Folder] { handle.loadFolders().map(Self.mapFolder) } public func loadChats(folderId: Int32?) async throws -> [ChatSummary] { let chats = if let folderId { try handle.loadFolderChats(folderId: folderId, limit: defaultLimit) } else { try handle.loadChats(limit: defaultLimit) } return chats.map(Self.mapChatSummary) } public func loadHistory(chatId: Int64) async throws -> [Message] { try handle.loadHistory(chatId: chatId, limit: defaultLimit) .map { Self.mapMessage($0, chatId: chatId) } } public func searchMessages(chatId: Int64, query: String) async throws -> [Message] { try handle.searchMessages(chatId: chatId, query: query) .map { Self.mapMessage($0.message, chatId: $0.chatId) } } public func openProfile(chatId: Int64) async throws -> Profile { try Self.mapProfile(handle.openProfile(chatId: chatId)) } public func leaveChat(chatId: Int64) async throws { try handle.leaveChat(chatId: chatId) } public func sendMessage(chatId: Int64, text: String, replyToMessageId: Int64?) async throws -> Message { try Self.mapMessage( handle.sendMessage(chatId: chatId, text: text, replyToMessageId: replyToMessageId), chatId: chatId ) } public func editMessage(chatId: Int64, messageId: Int64, text: String) async throws -> Message { try Self.mapMessage( handle.editMessage(chatId: chatId, messageId: messageId, text: text), chatId: chatId ) } public func deleteMessages(chatId: Int64, messageIds: [Int64]) async throws { try handle.deleteMessages(chatId: chatId, messageIds: messageIds, revoke: true) } public func forwardMessages(toChatId: Int64, fromChatId: Int64, messageIds: [Int64]) async throws { try handle.forwardMessages(toChatId: toChatId, fromChatId: fromChatId, messageIds: messageIds) } public func react(chatId: Int64, messageId: Int64, reaction: String) async throws -> [Reaction] { try handle.react(chatId: chatId, messageId: messageId, reaction: reaction) .map(Self.mapReaction) } public func pinnedMessages(chatId: Int64) async throws -> [Message] { try handle.pinnedMessages(chatId: chatId) .map { Self.mapMessage($0, chatId: chatId) } } public func copyPayload(chatId: Int64, messageId: Int64) async throws -> String { try handle.copyPayload(chatId: chatId, messageId: messageId) } public func setDraft(chatId: Int64, text: String) async throws { try handle.setDraft(chatId: chatId, text: text) } public func downloadPhoto(fileId: Int32) async throws -> DownloadedFile { try Self.mapDownloadedFile(handle.downloadPhoto(fileId: fileId)) } public func downloadVoice(fileId: Int32) async throws -> DownloadedFile { try Self.mapDownloadedFile(handle.downloadVoice(fileId: fileId)) } private static func mapAuthState(_ state: IosAuthState) -> AuthState { switch state { case .waitTdlibParameters: .waitTdlibParameters case .waitPhoneNumber: .waitPhoneNumber case .waitCode: .waitCode case .waitPassword: .waitPassword case .ready: .ready case .closed: .closed case let .error(message): .error(message) } } private static func mapNetworkState(_ state: IosNetworkState) -> NetworkState { switch state { case .waitingForNetwork: .waitingForNetwork case .connectingToProxy: .connectingToProxy case .connecting: .connecting case .updating: .updating case .ready: .ready } } private static func mapTypingState(_ state: IosTypingState) -> TypingState { switch state { case .idle: .idle case let .typing(chatId, userId, text): .typing(chatId: chatId, userId: userId, text: text) } } private static func mapFolder(_ folder: IosFolder) -> Folder { Folder(id: folder.id, name: folder.name) } private static func mapDraft(_ draft: IosDraft) -> Draft { Draft(chatId: draft.chatId, text: draft.text) } private static func mapChatSummary(_ chat: IosChatSummary) -> ChatSummary { ChatSummary( id: chat.id, title: chat.title, username: chat.username, lastMessage: chat.lastMessage, unreadCount: chat.unreadCount, unreadMentionCount: chat.unreadMentionCount, isPinned: chat.isPinned, folderIds: chat.folderIds, isMuted: chat.isMuted, draft: chat.draft.map(mapDraft) ) } private static func mapReaction(_ reaction: IosReaction) -> Reaction { Reaction(emoji: reaction.emoji, count: reaction.count, isChosen: reaction.isChosen) } private static func mapMessage(_ message: IosMessage, chatId: Int64) -> Message { Message( id: message.id, chatId: chatId, senderName: message.senderName, text: message.text, isOutgoing: message.isOutgoing, isRead: message.isRead, editDate: message.editDate, replyText: message.reply?.text, forwardSenderName: message.forward?.senderName, reactions: message.reactions.map(mapReaction) ) } private static func mapProfile(_ profile: IosProfile) -> Profile { Profile( chatId: profile.chatId, title: profile.title, username: profile.username, bio: profile.bio ?? profile.description, isGroup: profile.isGroup, memberCount: profile.memberCount ) } private static func mapDownloadedFile(_ file: IosDownloadedFile) -> DownloadedFile { DownloadedFile(fileId: file.fileId, path: file.path) } private static func mapEvent(_ event: IosEvent) -> SessionEvent { switch event { case let .authChanged(state): .authChanged(mapAuthState(state)) case let .chatListChanged(chats): .chatListChanged(chats.map(mapChatSummary)) case let .folderListChanged(folders): .folderListChanged(folders.map(mapFolder)) case let .messageAdded(chatId, message): .messageAdded(chatId, mapMessage(message, chatId: chatId)) case let .messageUpdated(chatId, message): .messageUpdated(chatId, mapMessage(message, chatId: chatId)) case let .messageDeleted(chatId, messageIds): .messageDeleted(chatId, messageIds) case let .reactionChanged(chatId, messageId, reactions): .reactionChanged(chatId, messageId, reactions.map(mapReaction)) case let .incomingNotificationCandidate(chat, message, senderName): .incomingNotificationCandidate( mapChatSummary(chat), mapMessage(message, chatId: chat.id), senderName ) case let .networkChanged(state): .networkChanged(mapNetworkState(state)) case let .typingChanged(state): .typingChanged(mapTypingState(state)) case let .draftChanged(draft): .draftChanged(mapDraft(draft)) case let .profileLoaded(profile): .profileLoaded(mapProfile(profile)) case let .mediaDownloadProgress(fileId, downloadedSize, totalSize): .mediaDownloadProgress(fileId: fileId, downloadedSize: downloadedSize, totalSize: totalSize) } } } #endif