306 lines
10 KiB
Swift
306 lines
10 KiB
Swift
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 mapDownloadState(_ state: IosDownloadState) -> MediaDownloadState {
|
|
switch state {
|
|
case .notDownloaded:
|
|
.notDownloaded
|
|
case .downloading:
|
|
.downloading
|
|
case let .downloaded(path):
|
|
.downloaded(path: path)
|
|
case let .error(message):
|
|
.error(message)
|
|
}
|
|
}
|
|
|
|
private static func mapMedia(_ media: IosMedia) -> MessageMedia? {
|
|
switch media.kind {
|
|
case "photo":
|
|
.photo(PhotoMedia(
|
|
fileId: media.fileId,
|
|
width: media.width ?? 0,
|
|
height: media.height ?? 0,
|
|
downloadState: mapDownloadState(media.downloadState)
|
|
))
|
|
case "voice":
|
|
.voice(VoiceMedia(
|
|
fileId: media.fileId,
|
|
duration: media.duration ?? 0,
|
|
mimeType: media.mimeType,
|
|
waveform: media.waveform,
|
|
downloadState: mapDownloadState(media.downloadState)
|
|
))
|
|
default:
|
|
nil
|
|
}
|
|
}
|
|
|
|
private static func mapMessage(_ message: IosMessage, chatId: Int64) -> Message {
|
|
Message(
|
|
id: message.id,
|
|
chatId: chatId,
|
|
senderName: message.senderName,
|
|
text: message.text,
|
|
date: message.date,
|
|
mediaAlbumId: message.mediaAlbumId,
|
|
media: message.media.flatMap(mapMedia),
|
|
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
|