Update sync code to handle async selectForProcessing.

This commit is contained in:
Brent Simmons 2019-12-16 12:49:07 -08:00
parent 7b7346d010
commit 3981312d6f
4 changed files with 147 additions and 106 deletions

View File

@ -195,24 +195,34 @@ final class FeedWranglerAccountDelegate: AccountDelegate {
}
}
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
func sendArticleStatus(for account: Account, completion: @escaping VoidResultCompletionBlock) {
os_log(.debug, log: log, "Sending article status...")
let syncStatuses = database.selectForProcessing()
let articleStatuses = Dictionary(grouping: syncStatuses, by: { $0.articleID })
let group = DispatchGroup()
articleStatuses.forEach { articleID, statuses in
group.enter()
caller.updateArticleStatus(articleID, statuses) {
group.leave()
database.selectForProcessing { result in
func processStatuses(_ syncStatuses: [SyncStatus]) {
let articleStatuses = Dictionary(grouping: syncStatuses, by: { $0.articleID })
let group = DispatchGroup()
articleStatuses.forEach { articleID, statuses in
group.enter()
self.caller.updateArticleStatus(articleID, statuses) {
group.leave()
}
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
completion(.success(()))
}
}
switch result {
case .success(let syncStatuses):
processStatuses(syncStatuses)
case .failure(let databaseError):
completion(.failure(databaseError))
}
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
completion(.success(()))
}
}

View File

@ -109,57 +109,67 @@ final class FeedbinAccountDelegate: AccountDelegate {
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
os_log(.debug, log: log, "Sending article statuses...")
let syncStatuses = database.selectForProcessing()
let createUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == false }
let deleteUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == true }
let createStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == true }
let deleteStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == false }
let group = DispatchGroup()
var errorOccurred = false
database.selectForProcessing { result in
group.enter()
sendArticleStatuses(createUnreadStatuses, apiCall: caller.createUnreadEntries) { result in
group.leave()
if case .failure = result {
errorOccurred = true
func processStatuses(_ syncStatuses: [SyncStatus]) {
let createUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == false }
let deleteUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == true }
let createStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == true }
let deleteStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == false }
let group = DispatchGroup()
var errorOccurred = false
group.enter()
self.sendArticleStatuses(createUnreadStatuses, apiCall: self.caller.createUnreadEntries) { result in
group.leave()
if case .failure = result {
errorOccurred = true
}
}
group.enter()
self.sendArticleStatuses(deleteUnreadStatuses, apiCall: self.caller.deleteUnreadEntries) { result in
group.leave()
if case .failure = result {
errorOccurred = true
}
}
group.enter()
self.sendArticleStatuses(createStarredStatuses, apiCall: self.caller.createStarredEntries) { result in
group.leave()
if case .failure = result {
errorOccurred = true
}
}
group.enter()
self.sendArticleStatuses(deleteStarredStatuses, apiCall: self.caller.deleteStarredEntries) { result in
group.leave()
if case .failure = result {
errorOccurred = true
}
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
if errorOccurred {
completion(.failure(FeedbinAccountDelegateError.unknown))
} else {
completion(.success(()))
}
}
}
switch result {
case .success(let syncStatuses):
processStatuses(syncStatuses)
case .failure(let databaseError):
completion(.failure(databaseError))
}
}
group.enter()
sendArticleStatuses(deleteUnreadStatuses, apiCall: caller.deleteUnreadEntries) { result in
group.leave()
if case .failure = result {
errorOccurred = true
}
}
group.enter()
sendArticleStatuses(createStarredStatuses, apiCall: caller.createStarredEntries) { result in
group.leave()
if case .failure = result {
errorOccurred = true
}
}
group.enter()
sendArticleStatuses(deleteStarredStatuses, apiCall: caller.deleteStarredEntries) { result in
group.leave()
if case .failure = result {
errorOccurred = true
}
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
if errorOccurred {
completion(.failure(FeedbinAccountDelegateError.unknown))
} else {
completion(.success(()))
}
}
}
func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
@ -531,7 +541,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
}
}
return account.update(articles, statusKey: statusKey, flag: flag)
return account.update(articles, statusKey: statusKey, flag: flag)
}
func accountDidInitialize(_ account: Account) {

View File

@ -30,24 +30,36 @@ final class FeedlySendArticleStatusesOperation: FeedlyOperation {
}
os_log(.debug, log: log, "Sending article statuses...")
let pending = database.selectForProcessing()
database.selectForProcessing { result in
switch result {
case .success(let syncStatuses):
self.processStatuses(syncStatuses)
case .failure:
self.didFinish()
}
}
}
}
private extension FeedlySendArticleStatusesOperation {
func processStatuses(_ pending: [SyncStatus]) {
let statuses: [(status: ArticleStatus.Key, flag: Bool, action: FeedlyMarkAction)] = [
(.read, false, .unread),
(.read, true, .read),
(.starred, true, .saved),
(.starred, false, .unsaved),
]
let group = DispatchGroup()
for pairing in statuses {
let articleIds = pending.filter { $0.key == pairing.status && $0.flag == pairing.flag }
guard !articleIds.isEmpty else {
continue
}
let ids = Set(articleIds.map { $0.articleID })
let database = self.database
group.enter()
@ -55,17 +67,17 @@ final class FeedlySendArticleStatusesOperation: FeedlyOperation {
assert(Thread.isMainThread)
switch result {
case .success:
database.deleteSelectedForProcessing(Array(ids)) {
database.deleteSelectedForProcessing(Array(ids)) { _ in
group.leave()
}
case .failure:
database.resetSelectedForProcessing(Array(ids)) {
database.resetSelectedForProcessing(Array(ids)) { _ in
group.leave()
}
}
}
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
self.didFinish()

View File

@ -113,42 +113,51 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
}
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
os_log(.debug, log: log, "Sending article statuses...")
let syncStatuses = database.selectForProcessing()
let createUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == false }
let deleteUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == true }
let createStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == true }
let deleteStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == false }
let group = DispatchGroup()
group.enter()
sendArticleStatuses(createUnreadStatuses, apiCall: caller.createUnreadEntries) {
group.leave()
database.selectForProcessing { result in
func processStatuses(_ syncStatuses: [SyncStatus]) {
let createUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == false }
let deleteUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == true }
let createStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == true }
let deleteStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == false }
let group = DispatchGroup()
group.enter()
self.sendArticleStatuses(createUnreadStatuses, apiCall: self.caller.createUnreadEntries) {
group.leave()
}
group.enter()
self.sendArticleStatuses(deleteUnreadStatuses, apiCall: self.caller.deleteUnreadEntries) {
group.leave()
}
group.enter()
self.sendArticleStatuses(createStarredStatuses, apiCall: self.caller.createStarredEntries) {
group.leave()
}
group.enter()
self.sendArticleStatuses(deleteStarredStatuses, apiCall: self.caller.deleteStarredEntries) {
group.leave()
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
completion(.success(()))
}
}
switch result {
case .success(let syncStatuses):
processStatuses(syncStatuses)
case .failure(let databaseError):
completion(.failure(databaseError))
}
}
group.enter()
sendArticleStatuses(deleteUnreadStatuses, apiCall: caller.deleteUnreadEntries) {
group.leave()
}
group.enter()
sendArticleStatuses(createStarredStatuses, apiCall: caller.createStarredEntries) {
group.leave()
}
group.enter()
sendArticleStatuses(deleteStarredStatuses, apiCall: caller.deleteStarredEntries) {
group.leave()
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
completion(.success(()))
}
}
func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {