Skip to content

Commit

Permalink
Improve code
Browse files Browse the repository at this point in the history
  • Loading branch information
mvasilak committed Mar 5, 2025
1 parent ca751d7 commit 9e17188
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 97 deletions.
31 changes: 13 additions & 18 deletions Zotero/Controllers/PDFWorkerController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,26 +116,21 @@ final class PDFWorkerController {
}

func setupObserver(for pdfWorkerWebViewHandler: PDFWorkerWebViewHandler) {
pdfWorkerWebViewHandler.observable
.subscribe(onNext: { [weak self] in
guard let self else { return }
process(result: $0, self: self)
})
.disposed(by: disposeBag)

func process(result: Result<PDFWorkerWebViewHandler.PDFWorkerData, Error>, self: PDFWorkerController) {
pdfWorkerWebViewHandler.observable.subscribe(onNext: { [weak self] result in
guard let self else { return }
switch result {
case .success(let data):
switch data {
case .recognizerData(let data), .fullText(let data):
cleanupPDFWorker(for: work) { $0?.on(.next(Update(work: work, kind: .extractedData(data: data)))) }
}

case .failure(let error):
DDLogError("PDFWorkerController: recognizer failed - \(error)")
cleanupPDFWorker(for: work) { $0?.on(.next(Update(work: work, kind: .failed))) }
}
}
})
.disposed(by: disposeBag)
}
}
}
Expand All @@ -162,22 +157,22 @@ final class PDFWorkerController {

private func cleanupPDFWorker(for work: PDFWork, completion: ((_ subject: PublishSubject<Update>?) -> Void)?) {
if DispatchQueue.getSpecific(key: dispatchSpecificKey) == accessQueueLabel {
cleanup(for: work, completion: completion, self: self)
cleanup(for: work, completion: completion, controller: self)
} else {
accessQueue.async(flags: .barrier) { [weak self] in
guard let self else { return }
cleanup(for: work, completion: completion, self: self)
cleanup(for: work, completion: completion, controller: self)
}
}

func cleanup(for work: PDFWork, completion: ((_ subject: PublishSubject<Update>?) -> Void)?, self: PDFWorkerController) {
let subject = subjectsByPDFWork[work]
queue.removeAll(where: { $0 == work })
subjectsByPDFWork[work] = nil
func cleanup(for work: PDFWork, completion: ((_ subject: PublishSubject<Update>?) -> Void)?, controller: PDFWorkerController) {
let subject = controller.subjectsByPDFWork[work]
controller.queue.removeAll(where: { $0 == work })
controller.subjectsByPDFWork[work] = nil
DDLogInfo("PDFWorkerController: cleaned up for \(work)")
pdfWorkerWebViewHandlersByPDFWork.removeValue(forKey: work)?.webViewHandler.removeFromSuperviewAsynchronously()
controller.pdfWorkerWebViewHandlersByPDFWork.removeValue(forKey: work)?.webViewHandler.removeFromSuperviewAsynchronously()
completion?(subject)
startWorkIfNeeded()
controller.startWorkIfNeeded()
}
}
}
146 changes: 67 additions & 79 deletions Zotero/Controllers/RecognizerController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,34 +182,30 @@ final class RecognizerController {
pdfWorkerController.queue(work: PDFWorkerController.PDFWork(file: task.file, kind: .recognizer))
.subscribe(onNext: { [weak self] update in
guard let self else { return }
process(update: update, self: self)
switch update.kind {
case .failed:
DDLogError("RecognizerController: \(task) - recognizer failed")
cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .failed(.recognizerFailed)))) }

case .cancelled:
cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .cancelled))) }

case .inProgress:
break

case .extractedData(let data):
switch update.work.kind {
case .recognizer:
DDLogInfo("RecognizerController: \(task) - extracted recognizer data")
startRemoteRecognition(for: task, with: data)

case .fullText:
DDLogError("RecognizerController: \(task) - PDF worker error")
cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .failed(.pdfWorkerError)))) }
}
}
})
.disposed(by: disposeBag)

func process(update: PDFWorkerController.Update, self: RecognizerController) {
switch update.kind {
case .failed:
DDLogError("RecognizerController: \(task) - recognizer failed")
cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .failed(.recognizerFailed)))) }

case .cancelled:
cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .cancelled))) }

case .inProgress:
break

case .extractedData(let data):
switch update.work.kind {
case .recognizer:
DDLogInfo("RecognizerController: \(task) - extracted recognizer data")
startRemoteRecognition(for: task, with: data)

case .fullText:
DDLogError("RecognizerController: \(task) - PDF worker error")
cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .failed(.pdfWorkerError)))) }
}
}
}
}
}

Expand All @@ -223,10 +219,31 @@ final class RecognizerController {
statesByTask[task] = .remoteRecognitionInProgress(data: data)

apiClient.send(request: RecognizerRequest(parameters: data)).subscribe(
onSuccess: { [weak self] (response: (RemoteRecognizerResponse, HTTPURLResponse)) in
onSuccess: { [weak self] (responseTuple: (RemoteRecognizerResponse, HTTPURLResponse)) in
guard let self else { return }
DDLogInfo("RecognizerController: \(task) - remote recognizer response received")
process(response: response.0, self: self)
let response = responseTuple.0
var identifiers: [RecognizerIdentifier] = []
if let identifier = response.arxiv {
identifiers.append(.arXiv(identifier))
}
if let identifier = response.doi {
identifiers.append(.doi(identifier))
}
if let identifier = response.isbn {
identifiers.append(.isbn(identifier))
}
if let identifier = response.title {
identifiers.append(.title(identifier))
}
guard !identifiers.isEmpty else {
cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .failed(.remoteRecognizerFailed)))) }
return
}
enqueueNextIdentifierLookup(for: task) { state in
guard case .remoteRecognitionInProgress = state else { return nil }
return (response, identifiers)
}
},
onFailure: { [weak self] error in
guard let self else { return }
Expand All @@ -236,30 +253,6 @@ final class RecognizerController {
)
.disposed(by: disposeBag)
}

func process(response: RemoteRecognizerResponse, self: RecognizerController) {
var identifiers: [RecognizerIdentifier] = []
if let identifier = response.arxiv {
identifiers.append(.arXiv(identifier))
}
if let identifier = response.doi {
identifiers.append(.doi(identifier))
}
if let identifier = response.isbn {
identifiers.append(.isbn(identifier))
}
if let identifier = response.title {
identifiers.append(.title(identifier))
}
guard !identifiers.isEmpty else {
cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .failed(.remoteRecognizerFailed)))) }
return
}
enqueueNextIdentifierLookup(for: task) { state in
guard case .remoteRecognitionInProgress = state else { return nil }
return (response, identifiers)
}
}
}

private func enqueueNextIdentifierLookup(
Expand All @@ -270,24 +263,24 @@ final class RecognizerController {
}
) {
if DispatchQueue.getSpecific(key: dispatchSpecificKey) == accessQueueLabel {
_enqueueNextIdentifierLookup(for: task, self: self)
_enqueueNextIdentifierLookup(for: task, controller: self)
} else {
accessQueue.async(flags: .barrier) { [weak self] in
guard let self else { return }
_enqueueNextIdentifierLookup(for: task, self: self)
_enqueueNextIdentifierLookup(for: task, controller: self)
}
}

func _enqueueNextIdentifierLookup(for task: Task, self: RecognizerController) {
guard let state = statesByTask[task] else {
startRecognitionIfNeeded()
func _enqueueNextIdentifierLookup(for task: Task, controller: RecognizerController) {
guard let state = controller.statesByTask[task] else {
controller.startRecognitionIfNeeded()
return
}
guard let (response, pendingIdentifiers) = getResponseAndIdentifiers(state) else {
cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .failed(.unexpectedState)))) }
controller.cleanupTask(for: task) { $0?.on(.next(Update(task: task, kind: .failed(.unexpectedState)))) }
return
}
lookupNextIdentifier(for: task, with: response, pendingIdentifiers: pendingIdentifiers)
controller.lookupNextIdentifier(for: task, with: response, pendingIdentifiers: pendingIdentifiers)
}
}

Expand Down Expand Up @@ -340,14 +333,8 @@ final class RecognizerController {
return lookupWebViewHandler

func setupObserver(for lookupWebViewHandler: LookupWebViewHandler) {
lookupWebViewHandler.observable
.subscribe(onNext: { [weak self] in
guard let self else { return }
process(result: $0, self: self)
})
.disposed(by: disposeBag)

func process(result: Result<LookupWebViewHandler.LookupData, Swift.Error>, self: RecognizerController) {
lookupWebViewHandler.observable.subscribe(onNext: { [weak self] result in
guard let self else { return }
switch result {
case .success(let data):
switch data {
Expand Down Expand Up @@ -391,7 +378,8 @@ final class RecognizerController {
DDLogError("RecognizerController: \(task) - identifier lookup failed - \(error)")
enqueueNextIdentifierLookup(for: task)
}
}
})
.disposed(by: disposeBag)
}
}
}
Expand Down Expand Up @@ -500,27 +488,27 @@ final class RecognizerController {

private func cleanupTask(for task: Task, completion: ((_ subject: PublishSubject<Update>?) -> Void)?) {
if DispatchQueue.getSpecific(key: dispatchSpecificKey) == accessQueueLabel {
cleanup(for: task, completion: completion, self: self)
cleanup(for: task, completion: completion, controller: self)
} else {
accessQueue.async(flags: .barrier) { [weak self] in
guard let self else { return }
cleanup(for: task, completion: completion, self: self)
cleanup(for: task, completion: completion, controller: self)
}
}

func cleanup(for task: Task, completion: ((_ subject: PublishSubject<Update>?) -> Void)?, self: RecognizerController) {
let subject = queue[task] ?? subjectsByTask[task]
queue[task] = nil
subjectsByTask[task] = nil
statesByTask[task] = nil
if case .createParentForItem(let libraryId, let key) = task.kind, var libraryLatestUpdates = latestUpdates[libraryId] {
func cleanup(for task: Task, completion: ((_ subject: PublishSubject<Update>?) -> Void)?, controller: RecognizerController) {
let subject = controller.queue[task] ?? controller.subjectsByTask[task]
controller.queue[task] = nil
controller.subjectsByTask[task] = nil
controller.statesByTask[task] = nil
if case .createParentForItem(let libraryId, let key) = task.kind, var libraryLatestUpdates = controller.latestUpdates[libraryId] {
libraryLatestUpdates[key] = nil
latestUpdates[libraryId] = libraryLatestUpdates
controller.latestUpdates[libraryId] = libraryLatestUpdates
}
DDLogInfo("RecognizerController: \(task) - cleaned up")
lookupWebViewHandlersByTask.removeValue(forKey: task)?.webViewHandler.removeFromSuperviewAsynchronously()
controller.lookupWebViewHandlersByTask.removeValue(forKey: task)?.webViewHandler.removeFromSuperviewAsynchronously()
completion?(subject)
startRecognitionIfNeeded()
controller.startRecognitionIfNeeded()
}
}

Expand Down

0 comments on commit 9e17188

Please sign in to comment.