diff --git a/ConversationsClassic/AppData/Store/MessagesStore.swift b/ConversationsClassic/AppData/Store/MessagesStore.swift index fcd4b4b..586ff3f 100644 --- a/ConversationsClassic/AppData/Store/MessagesStore.swift +++ b/ConversationsClassic/AppData/Store/MessagesStore.swift @@ -12,7 +12,7 @@ final class MessagesStore: ObservableObject { private let client: Client private var messagesCancellable: AnyCancellable? - private let archiveMessageFetcher = ArchiveMessageFetcher() + private let archiver = ArchiveMessageFetcher() init(roster: Roster, client: Client) { self.client = client @@ -65,103 +65,170 @@ private extension MessagesStore { .receive(on: DispatchQueue.main) .sink { _ in } receiveValue: { [weak self] messages in - self?.messages = messages - if messages.isEmpty { - self?.requestLastArchivedMessages() + guard let self else { return } + self.messages = messages + Task { + await self.archiver.initialFetch(messages, self.roster, self.client) } } } } -// MARK: - Archived messages +// MARK: - Fetch archived messages extension MessagesStore { - func requestEarliestArchivedMessages() { - guard let beforeId = messages.last?.id else { return } + func fetchForward() { Task { - await archiveMessageFetcher.fetchBeforeMessages(roster, client, beforeId: beforeId) + await archiver.fetchForward(roster, client) } } - func requestLatestArchivedMessages() { - guard let afterId = messages.first?.id else { return } + func fetchBackward() { Task { - await archiveMessageFetcher.fetchAfterMessages(roster, client, afterId: afterId) - } - } - - private func requestLastArchivedMessages() { - Task { - await archiveMessageFetcher.fetchLastMessages(roster, client) + await archiver.fetchBackward(roster, client) } } } private actor ArchiveMessageFetcher { - private var afterAvailable = true - private var beforeAvailable = true - private var isFetching = false - private var fetchingIsPossinle = true + private var initFetchStarted = false + private var forwardRsm: RSM.Query? + private var backwardRsm: RSM.Query? - func fetchLastMessages(_ roster: Roster, _ client: Client) async { - if !fetchingIsPossinle { return } - while isFetching { - await Task.yield() - } - isFetching = true + func initialFetch(_ messages: [Message], _ roster: Roster, _ client: Client) async { + if initFetchStarted { return } + initFetchStarted = true - let query: RSM.Query = .init(lastItems: Const.mamRequestLimit) do { - _ = try await client.fetchArchiveMessages(for: roster, query: query) - } catch AppError.featureNotSupported { - fetchingIsPossinle = false - } catch { - logIt(.error, "Error requesting archived messages: \(error)") - } - - isFetching = false - } - - func fetchBeforeMessages(_ roster: Roster, _ client: Client, beforeId: String) async { - if !fetchingIsPossinle || !beforeAvailable { return } - while isFetching { - await Task.yield() - } - isFetching = true - - let query: RSM.Query = .init(before: beforeId, max: Const.mamRequestLimit) - do { - let result = try await client.fetchArchiveMessages(for: roster, query: query) - if result.complete { - beforeAvailable = false + if let firstExistId = messages.first?.id { + let result = try await client.fetchArchiveMessages(for: roster, query: .init(before: firstExistId, max: Const.mamRequestLimit)) + result.complete ? forwardRsm = nil : (forwardRsm = .init(after: result.rsm?.last, max: Const.mamRequestLimit)) + result.complete ? backwardRsm = nil : (backwardRsm = .init(before: result.rsm?.first, max: Const.mamRequestLimit)) + } else { + let result = try await client.fetchArchiveMessages(for: roster, query: .init(lastItems: Const.mamRequestLimit)) + result.complete ? backwardRsm = nil : (backwardRsm = .init(before: result.rsm?.first, max: Const.mamRequestLimit)) } - } catch AppError.featureNotSupported { - fetchingIsPossinle = false } catch { logIt(.error, "Error requesting archived messages: \(error)") + initFetchStarted = false } - - isFetching = false } - func fetchAfterMessages(_ roster: Roster, _ client: Client, afterId: String) async { - if !fetchingIsPossinle || !afterAvailable { return } - while isFetching { - await Task.yield() + func fetchForward(_ roster: Roster, _ client: Client) { + guard let rsm = forwardRsm else { return } + Task { + let result = try await client.fetchArchiveMessages(for: roster, query: rsm) + result.complete ? (forwardRsm = nil) : (forwardRsm = .init(after: result.rsm?.last, max: Const.mamRequestLimit)) } - isFetching = true - - let query: RSM.Query = .init(after: afterId, max: Const.mamRequestLimit) - do { - let result = try await client.fetchArchiveMessages(for: roster, query: query) - if result.complete { - afterAvailable = false - } - } catch AppError.featureNotSupported { - fetchingIsPossinle = false - } catch { - logIt(.error, "Error requesting archived messages: \(error)") - } - - isFetching = false } + + func fetchBackward(_ roster: Roster, _ client: Client) { + guard let rsm = backwardRsm else { return } + Task { + let result = try await client.fetchArchiveMessages(for: roster, query: rsm) + result.complete ? (backwardRsm = nil) : (backwardRsm = .init(before: result.rsm?.first, max: Const.mamRequestLimit)) + } + } + + // func fetchBackward(_ roster: Roster, _ client: Client) { + // guard let rsm = backwardRsm else { return } + // Task { + // let result = try await client.fetchArchiveMessages(for: roster, query: rsm) + // result.complete ? (backwardRsm = nil) : (backwardRsm = .init(before: result.rsm?.first, max: Const.mamRequestLimit)) + // } + // } } + +// MARK: - Archived messages +// extension MessagesStore { +// func requestEarliestArchivedMessages() { +// guard let beforeId = messages.first?.id else { return } +// Task { +// await archiveMessageFetcher.fetchAfterMessages(roster, client, afterId: beforeId) +// // await archiveMessageFetcher.fetchBeforeMessages(roster, client, beforeId: beforeId) +// } +// } +// +// func requestLatestArchivedMessages() { +// guard let afterId = messages.last?.id else { return } +// Task { +// await archiveMessageFetcher.fetchBeforeMessages(roster, client, beforeId: afterId) +// // await archiveMessageFetcher.fetchAfterMessages(roster, client, afterId: afterId) +// } +// } +// +// private func requestLastArchivedMessages() { +// Task { +// await archiveMessageFetcher.fetchLastMessages(roster, client) +// } +// } +// } + +// private actor ArchiveMessageFetcher { +// private var afterAvailable = true +// private var beforeAvailable = true +// private var isFetching = false +// private var fetchingIsPossinle = true +// +// func fetchLastMessages(_ roster: Roster, _ client: Client) async { +// if !fetchingIsPossinle { return } +// while isFetching { +// await Task.yield() +// } +// isFetching = true +// +// let query: RSM.Query = .init(lastItems: Const.mamRequestLimit) +// do { +// _ = try await client.fetchArchiveMessages(for: roster, query: query) +// } catch AppError.featureNotSupported { +// fetchingIsPossinle = false +// } catch { +// logIt(.error, "Error requesting archived messages: \(error)") +// } +// +// isFetching = false +// } +// +// func fetchBeforeMessages(_ roster: Roster, _ client: Client, beforeId: String) async { +// if !fetchingIsPossinle || !beforeAvailable { return } +// while isFetching { +// await Task.yield() +// } +// isFetching = true +// +// let query: RSM.Query = .init(before: beforeId, max: Const.mamRequestLimit) +// do { +// let result = try await client.fetchArchiveMessages(for: roster, query: query) +// if result.complete { +// beforeAvailable = false +// } +// } catch AppError.featureNotSupported { +// fetchingIsPossinle = false +// } catch { +// logIt(.error, "Error requesting archived messages: \(error)") +// } +// +// isFetching = false +// } +// +// func fetchAfterMessages(_ roster: Roster, _ client: Client, afterId: String) async { +// if !fetchingIsPossinle || !afterAvailable { return } +// while isFetching { +// await Task.yield() +// } +// isFetching = true +// +// let query: RSM.Query = .init(after: afterId, max: Const.mamRequestLimit) +// do { +// let result = try await client.fetchArchiveMessages(for: roster, query: query) +// if result.complete { +// afterAvailable = false +// } +// } catch AppError.featureNotSupported { +// fetchingIsPossinle = false +// } catch { +// logIt(.error, "Error requesting archived messages: \(error)") +// } +// +// isFetching = false +// } +// } diff --git a/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift b/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift index cc3c0f8..a46d116 100644 --- a/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift +++ b/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift @@ -46,7 +46,7 @@ struct ConversationScreen: View { autoScroll = true } if message.id == messages.last?.id { - messagesStore.requestEarliestArchivedMessages() + messagesStore.fetchBackward() } } .onDisappear {