Prevent more than one OPML import from being run at the same time.

This commit is contained in:
Maurice Parker 2019-05-17 10:44:22 -05:00
parent b89f088917
commit 0a9bf2aef0
4 changed files with 71 additions and 38 deletions

View File

@ -36,9 +36,25 @@ public enum AccountType: Int {
// TODO: more // TODO: more
} }
public enum AccountError: Error { public enum AccountError: LocalizedError {
case createErrorNotFound case createErrorNotFound
case createErrorAlreadySubscribed case createErrorAlreadySubscribed
case opmlImportInProgress
public var errorDescription: String? {
switch self {
case .opmlImportInProgress:
return NSLocalizedString("An OPML import for this account is already running.", comment: "Import running")
default:
return NSLocalizedString("An unknown error occurred.", comment: "Unknown error")
}
}
public var recoverySuggestion: String? {
return NSLocalizedString("Please try again later.", comment: "Try later")
}
} }
public final class Account: DisplayNameProvider, UnreadCountProvider, Container, Hashable { public final class Account: DisplayNameProvider, UnreadCountProvider, Container, Hashable {
@ -299,6 +315,12 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
} }
public func importOPML(_ opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) { public func importOPML(_ opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
guard !delegate.opmlImportInProgress else {
completion(.failure(AccountError.opmlImportInProgress))
return
}
delegate.importOPML(for: self, opmlFile: opmlFile) { [weak self] result in delegate.importOPML(for: self, opmlFile: opmlFile) { [weak self] result in
switch result { switch result {
case .success: case .success:
@ -312,6 +334,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
completion(.failure(error)) completion(.failure(error))
} }
} }
} }
public func markArticles(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? { public func markArticles(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? {

View File

@ -14,6 +14,8 @@ protocol AccountDelegate {
// Local account does not; some synced accounts might. // Local account does not; some synced accounts might.
var supportsSubFolders: Bool { get } var supportsSubFolders: Bool { get }
var opmlImportInProgress: Bool { get }
var server: String? { get } var server: String? { get }
var credentials: Credentials? { get set } var credentials: Credentials? { get set }
var accountMetadata: AccountMetadata? { get set } var accountMetadata: AccountMetadata? { get set }

View File

@ -32,6 +32,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
let supportsSubFolders = false let supportsSubFolders = false
let server: String? = "api.feedbin.com" let server: String? = "api.feedbin.com"
var opmlImportInProgress = false
var credentials: Credentials? { var credentials: Credentials? {
didSet { didSet {
@ -201,6 +202,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
} }
os_log(.debug, log: log, "Begin importing OPML...") os_log(.debug, log: log, "Begin importing OPML...")
opmlImportInProgress = true
caller.importOPML(opmlData: opmlData) { [weak self] result in caller.importOPML(opmlData: opmlData) { [weak self] result in
switch result { switch result {
@ -208,6 +210,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
if importResult.complete { if importResult.complete {
guard let self = self else { return } guard let self = self else { return }
os_log(.debug, log: self.log, "Import OPML done.") os_log(.debug, log: self.log, "Import OPML done.")
self.opmlImportInProgress = false
DispatchQueue.main.async { DispatchQueue.main.async {
completion(.success(())) completion(.success(()))
} }
@ -217,6 +220,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
case .failure(let error): case .failure(let error):
guard let self = self else { return } guard let self = self else { return }
os_log(.debug, log: self.log, "Import OPML failed.") os_log(.debug, log: self.log, "Import OPML failed.")
self.opmlImportInProgress = false
DispatchQueue.main.async { DispatchQueue.main.async {
completion(.failure(error)) completion(.failure(error))
} }
@ -225,41 +229,6 @@ final class FeedbinAccountDelegate: AccountDelegate {
} }
private func checkImportResult(opmlImportResultID: Int, completion: @escaping (Result<Void, Error>) -> Void) {
DispatchQueue.main.async {
Timer.scheduledTimer(withTimeInterval: 15, repeats: true) { [weak self] timer in
guard let self = self else { return }
os_log(.debug, log: self.log, "Checking status of OPML import...")
self.caller.retrieveOPMLImportResult(importID: opmlImportResultID) { result in
switch result {
case .success(let importResult):
if let result = importResult, result.complete {
os_log(.debug, log: self.log, "Checking status of OPML import successfully completed.")
timer.invalidate()
DispatchQueue.main.async {
completion(.success(()))
}
}
case .failure(let error):
os_log(.debug, log: self.log, "Import OPML check failed.")
timer.invalidate()
DispatchQueue.main.async {
completion(.failure(error))
}
}
}
}
}
}
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) { func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
caller.renameTag(oldName: folder.name ?? "", newName: name) { result in caller.renameTag(oldName: folder.name ?? "", newName: name) { result in
@ -546,6 +515,43 @@ private extension FeedbinAccountDelegate {
} }
func checkImportResult(opmlImportResultID: Int, completion: @escaping (Result<Void, Error>) -> Void) {
DispatchQueue.main.async {
Timer.scheduledTimer(withTimeInterval: 15, repeats: true) { [weak self] timer in
guard let self = self else { return }
os_log(.debug, log: self.log, "Checking status of OPML import...")
self.caller.retrieveOPMLImportResult(importID: opmlImportResultID) { result in
switch result {
case .success(let importResult):
if let result = importResult, result.complete {
os_log(.debug, log: self.log, "Checking status of OPML import successfully completed.")
timer.invalidate()
self.opmlImportInProgress = false
DispatchQueue.main.async {
completion(.success(()))
}
}
case .failure(let error):
os_log(.debug, log: self.log, "Import OPML check failed.")
timer.invalidate()
self.opmlImportInProgress = false
DispatchQueue.main.async {
completion(.failure(error))
}
}
}
}
}
}
func syncFolders(_ account: Account, _ tags: [FeedbinTag]?) { func syncFolders(_ account: Account, _ tags: [FeedbinTag]?) {
guard let tags = tags else { return } guard let tags = tags else { return }

View File

@ -18,6 +18,8 @@ public enum LocalAccountDelegateError: String, Error {
final class LocalAccountDelegate: AccountDelegate { final class LocalAccountDelegate: AccountDelegate {
let supportsSubFolders = false let supportsSubFolders = false
let opmlImportInProgress = false
let server: String? = nil let server: String? = nil
var credentials: Credentials? var credentials: Credentials?
var accountMetadata: AccountMetadata? var accountMetadata: AccountMetadata?