Convert importOPML to async await.

This commit is contained in:
Brent Simmons 2024-03-26 21:10:05 -07:00
parent 887e35068e
commit 91b0e7158a
12 changed files with 99 additions and 92 deletions

View File

@ -428,28 +428,22 @@ public enum FetchType {
try await delegate.syncArticleStatus(for: self)
}
public func importOPML(_ opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
public func importOPML(_ opmlFile: URL) async throws {
guard !delegate.isOPMLImportInProgress else {
completion(.failure(AccountError.opmlImportInProgress))
return
throw AccountError.opmlImportInProgress
}
delegate.importOPML(for: self, opmlFile: opmlFile) { [weak self] result in
switch result {
case .success:
guard let self = self else { return }
// Reset the last fetch date to get the article history for the added feeds.
self.metadata.lastArticleFetchStartTime = nil
Task { @MainActor in
try? await self.refreshAll()
}
case .failure(let error):
completion(.failure(error))
}
try await delegate.importOPML(for: self, opmlFile: opmlFile)
// Reset the last fetch date to get the article history for the added feeds.
metadata.lastArticleFetchStartTime = nil
Task { @MainActor in
try? await self.refreshAll()
}
}
public func suspendNetwork() {
delegate.suspendNetwork()
}

View File

@ -30,7 +30,7 @@ import Secrets
func sendArticleStatus(for account: Account) async throws
func refreshArticleStatus(for account: Account) async throws
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void)
func importOPML(for account:Account, opmlFile: URL) async throws
func createFolder(for account: Account, name: String, completion: @escaping (Result<Folder, Error>) -> Void)
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void)

View File

@ -180,7 +180,21 @@ enum CloudKitAccountDelegateError: LocalizedError {
}
}
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
func importOPML(for account: Account, opmlFile: URL) async throws {
try await withCheckedThrowingContinuation { continuation in
self.importOPML(for: account, opmlFile: opmlFile) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
guard refreshProgress.isComplete else {
completion(.success(()))
return

View File

@ -279,7 +279,21 @@ final class FeedbinAccountDelegate: AccountDelegate {
}
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
func importOPML(for account: Account, opmlFile: URL) async throws {
try await withCheckedThrowingContinuation { continuation in
self.importOPML(for: account, opmlFile: opmlFile) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
var fileData: Data?

View File

@ -255,7 +255,21 @@ final class FeedlyAccountDelegate: AccountDelegate {
operationQueue.addOperations([ingestUnread, ingestStarred])
}
func importOPML(for account: Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
func importOPML(for account: Account, opmlFile: URL) async throws {
try await withCheckedThrowingContinuation { continuation in
self.importOPML(for: account, opmlFile: opmlFile) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
private func importOPML(for account: Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
let data: Data
do {

View File

@ -67,50 +67,21 @@ final class LocalAccountDelegate: AccountDelegate {
func refreshArticleStatus(for account: Account) async throws {
}
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
func importOPML(for account:Account, opmlFile: URL) async throws {
Task { @MainActor in
var fileData: Data?
let opmlData = try Data(contentsOf: opmlFile)
let parserData = ParserData(url: opmlFile.absoluteString, data: opmlData)
do {
fileData = try Data(contentsOf: opmlFile)
} catch {
completion(.failure(error))
return
}
let opmlDocument = try RSOPMLParser.parseOPML(with: parserData)
guard let children = opmlDocument.children else {
return
}
guard let opmlData = fileData else {
completion(.success(()))
return
}
let parserData = ParserData(url: opmlFile.absoluteString, data: opmlData)
var opmlDocument: RSOPMLDocument?
do {
opmlDocument = try RSOPMLParser.parseOPML(with: parserData)
} catch {
completion(.failure(error))
return
}
guard let loadDocument = opmlDocument else {
completion(.success(()))
return
}
guard let children = loadDocument.children else {
return
}
BatchUpdate.shared.perform {
account.loadOPMLItems(children)
}
completion(.success(()))
BatchUpdate.shared.perform {
account.loadOPMLItems(children)
}
}
func createFeed(for account: Account, url urlString: String, name: String?, container: Container, validateFeed: Bool, completion: @escaping (Result<Feed, Error>) -> Void) {
guard let url = URL(string: urlString) else {
completion(.failure(LocalAccountDelegateError.invalidParameter))

View File

@ -393,8 +393,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
}
func importOPML(for account: Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> ()) {
completion(.success(()))
func importOPML(for account: Account, opmlFile: URL) async throws {
}
func createFolder(for account: Account, name: String, completion: @escaping (Result<Folder, Error>) -> ()) {

View File

@ -338,7 +338,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
}
}
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
func importOPML(for account:Account, opmlFile: URL) async throws {
}
func createFolder(for account: Account, name: String, completion: @escaping (Result<Folder, Error>) -> Void) {

View File

@ -47,12 +47,12 @@ private extension NNW3ImportController {
guard let opmlURL = convertToOPMLFile(subscriptionsPlistURL: subscriptionsPlistURL) else {
return
}
account.importOPML(opmlURL) { result in
try? FileManager.default.removeItem(at: opmlURL)
switch result {
case .success:
break
case .failure(let error):
Task { @MainActor in
do {
try await account.importOPML(opmlURL)
try? FileManager.default.removeItem(at: opmlURL)
} catch {
NSApplication.shared.presentError(error)
}
}

View File

@ -10,7 +10,7 @@ import AppKit
import Account
import UniformTypeIdentifiers
class ImportOPMLWindowController: NSWindowController {
final class ImportOPMLWindowController: NSWindowController {
@IBOutlet weak var accountPopUpButton: NSPopUpButton!
private weak var hostWindow: NSWindow?
@ -90,18 +90,17 @@ class ImportOPMLWindowController: NSWindowController {
panel.allowsOtherFileTypes = false
panel.beginSheetModal(for: hostWindow!) { modalResult in
if modalResult == NSApplication.ModalResponse.OK, let url = panel.url {
account.importOPML(url) { result in
switch result {
case .success:
break
case .failure(let error):
NSApplication.shared.presentError(error)
}
guard modalResult == NSApplication.ModalResponse.OK, let url = panel.url else {
return
}
Task { @MainActor in
do {
try await account.importOPML(url)
} catch {
NSApplication.shared.presentError(error)
}
}
}
}
}

View File

@ -12,9 +12,11 @@ import Account
@MainActor struct DefaultFeedsImporter {
static func importDefaultFeeds(account: Account) {
let defaultFeedsURL = Bundle.main.url(forResource: "DefaultFeeds", withExtension: "opml")!
AccountManager.shared.defaultAccount.importOPML(defaultFeedsURL) { result in }
}
}
let defaultFeedsURL = Bundle.main.url(forResource: "DefaultFeeds", withExtension: "opml")!
Task { @MainActor in
try? await AccountManager.shared.defaultAccount.importOPML(defaultFeedsURL)
}
}
}

View File

@ -349,12 +349,13 @@ class SettingsViewController: UITableViewController {
extension SettingsViewController: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
for url in urls {
opmlAccount?.importOPML(url) { result in
switch result {
case .success:
break
case .failure:
Task { @MainActor in
do {
try await opmlAccount?.importOPML(url)
} catch {
let title = NSLocalizedString("Import Failed", comment: "Import Failed")
let message = NSLocalizedString("We were unable to process the selected file. Please ensure that it is a properly formatted OPML file.", comment: "Import Failed Message")
self.presentError(title: title, message: message)
@ -362,7 +363,6 @@ extension SettingsViewController: UIDocumentPickerDelegate {
}
}
}
}
// MARK: Private