Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,6 @@ bundled/translators
bundled/styles
bundled/locales
bundled/note_editor
bundled/pdf_worker
bundled/document_worker
Zotero/Controllers/Citation/citation/utilities
bundled/reader
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
[submodule "reader"]
path = reader
url = https://github.com/zotero/reader.git
[submodule "pdf-worker"]
path = pdf-worker
url = https://github.com/zotero/pdf-worker
[submodule "document-worker"]
path = document-worker
url = https://github.com/zotero/document-worker
2 changes: 1 addition & 1 deletion FeatureGates.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) FEATURE_GATE_PDF_WORKER
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) FEATURE_GATE_DOCUMENT_WORKER
8 changes: 4 additions & 4 deletions ZShare/View Controllers/ShareViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ final class ShareViewController: UIViewController {
private var fileStorage: FileStorage!
private var debugLogging: DebugLogging!
private var schemaController: SchemaController!
private var pdfWorkerController: PDFWorkerController!
private var documentWorkerController: DocumentWorkerController!
private var secureStorage: KeychainSecureStorage!
private var viewModel: ExtensionViewModel!
private var storeCancellable: AnyCancellable?
Expand Down Expand Up @@ -756,7 +756,7 @@ final class ShareViewController: UIViewController {
let translatorsController = TranslatorsAndStylesController(apiClient: apiClient, bundledDataStorage: bundledDataStorage, fileStorage: fileStorage)
let secureStorage = KeychainSecureStorage()
let webDavController = WebDavControllerImpl(dbStorage: dbStorage, fileStorage: fileStorage, sessionStorage: SecureWebDavSessionStorage(secureStorage: secureStorage))
let pdfWorkerController = PDFWorkerController(fileStorage: fileStorage)
let documentWorkerController = DocumentWorkerController(fileStorage: fileStorage)

apiClient.set(authToken: ("Bearer " + session.apiToken))
translatorsController.updateFromRepo(type: .shareExtension)
Expand All @@ -766,7 +766,7 @@ final class ShareViewController: UIViewController {
self.dbStorage = dbStorage
self.bundledDataStorage = bundledDataStorage
self.translatorsController = translatorsController
self.pdfWorkerController = pdfWorkerController
self.documentWorkerController = documentWorkerController
self.secureStorage = secureStorage

self.viewModel = self.createViewModel(for: session.userId, dbStorage: dbStorage, apiClient: apiClient, schemaController: schemaController, fileStorage: fileStorage,
Expand All @@ -786,7 +786,7 @@ final class ShareViewController: UIViewController {
let syncController = SyncController(userId: userId, apiClient: apiClient, dbStorage: dbStorage, fileStorage: fileStorage, schemaController: schemaController, dateParser: dateParser,
backgroundUploaderContext: backgroundUploadContext, webDavController: webDavController, attachmentDownloader: attachmentDownloader, syncDelayIntervals: DelayIntervals.sync, maxRetryCount: DelayIntervals.retry.count)
let recognizerController = RecognizerController(
pdfWorkerController: pdfWorkerController,
documentWorkerController: documentWorkerController,
apiClient: apiClient,
translatorsController: translatorsController,
schemaController: schemaController,
Expand Down
2 changes: 1 addition & 1 deletion ZShare/ViewModels/ExtensionViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ final class ExtensionViewModel {
copyFile(from: url.path, to: tmpFile)
.subscribe(onSuccess: { [weak self] _ in
guard let self else { return }
guard FeatureGates.enabled.contains(.pdfWorker), fileStorage.isPdf(file: tmpFile), let file = tmpFile as? FileData else {
guard FeatureGates.enabled.contains(.documentWorker), fileStorage.isPdf(file: tmpFile), let file = tmpFile as? FileData else {
updateState(with: .processed)
return
}
Expand Down
64 changes: 32 additions & 32 deletions Zotero.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions Zotero/Controllers/Controllers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ final class Controllers {
userControllers?.backgroundUploadObserver.cancelAllUploads()
// Cancel all Recognizer Tasks
userControllers?.recognizerController.cancellAllTasks()
// Cancel all PDF workers
userControllers?.pdfWorkerController.cancellAllWorks()
// Cancel all document workers
userControllers?.documentWorkerController.cancellAllWorks()
// Clear user controllers
let dbStorage = userControllers?.dbStorage
userControllers = nil
Expand All @@ -304,7 +304,7 @@ final class UserControllers {
let fileDownloader: AttachmentDownloader
let remoteFileDownloader: RemoteAttachmentDownloader
let identifierLookupController: IdentifierLookupController
let pdfWorkerController: PDFWorkerController
let documentWorkerController: DocumentWorkerController
let recognizerController: RecognizerController
let webSocketController: APIWebSocketController
let fileCleanupController: AttachmentFileCleanupController
Expand Down Expand Up @@ -395,9 +395,9 @@ final class UserControllers {
dateParser: controllers.dateParser,
remoteFileDownloader: remoteFileDownloader
)
pdfWorkerController = PDFWorkerController(fileStorage: controllers.fileStorage)
documentWorkerController = DocumentWorkerController(fileStorage: controllers.fileStorage)
recognizerController = RecognizerController(
pdfWorkerController: pdfWorkerController,
documentWorkerController: documentWorkerController,
apiClient: controllers.apiClient,
translatorsController: controllers.translatorsAndStylesController,
schemaController: controllers.schemaController,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// PDFWorkerController.swift
// DocumentWorkerController.swift
// Zotero
//
// Created by Miltiadis Vasilakis on 3/2/25.
Expand All @@ -12,7 +12,7 @@ import OrderedCollections
import CocoaLumberjackSwift
import RxSwift

final class PDFWorkerController {
final class DocumentWorkerController {
// MARK: Types
enum Priority {
case `default`
Expand Down Expand Up @@ -49,15 +49,15 @@ final class PDFWorkerController {
let priority: Priority
fileprivate(set) var state: State = .pending
fileprivate var subjectsByWork: OrderedDictionary<Work, PublishSubject<Update>> = [:]
fileprivate var handler: PDFWorkerJSHandler?
fileprivate var handler: DocumentWorkerJSHandler?

init(file: FileData, shouldCacheData: Bool, priority: Priority) {
self.file = file
self.shouldCacheData = shouldCacheData
self.priority = priority
}

static func == (lhs: PDFWorkerController.Worker, rhs: PDFWorkerController.Worker) -> Bool {
static func == (lhs: DocumentWorkerController.Worker, rhs: DocumentWorkerController.Worker) -> Bool {
lhs.id == rhs.id
}

Expand Down Expand Up @@ -129,18 +129,18 @@ final class PDFWorkerController {
private var queuedByPriority: [Priority: OrderedSet<Worker>] = [:]
private var runningByPriority: [Priority: OrderedSet<Worker>] = [:]
private var failed: Set<Worker> = []
private var preloadedPDFWorkerHandler: PDFWorkerJSHandler?
private var preloadedDocumentWorkerHandler: DocumentWorkerJSHandler?

// MARK: Object Lifecycle
init(fileStorage: FileStorage) {
dispatchSpecificKey = DispatchSpecificKey<String>()
accessQueueLabel = "org.zotero.PDFWorkerController.accessQueue"
accessQueueLabel = "org.zotero.DocumentWorkerController.accessQueue"
accessQueue = DispatchQueue(label: accessQueueLabel, qos: .userInteractive, attributes: .concurrent)
accessQueue.setSpecific(key: dispatchSpecificKey, value: accessQueueLabel)
self.fileStorage = fileStorage
disposeBag = DisposeBag()
accessQueue.async(flags: .barrier) { [weak self] in
self?.preloadPDFWorkerIfIdle()
self?.preloadDocumentWorkerIfIdle()
}
}

Expand Down Expand Up @@ -193,12 +193,12 @@ final class PDFWorkerController {
// Assign preparing state and place in proper queue, then prepare worker handler.
updateStateAndQueues(for: worker, state: .preparing)
// Prepare worker handler.
let pdfWorkerHandler = preloadedPDFWorkerHandler ?? PDFWorkerJSHandler()
let documentWorkerHandler = preloadedDocumentWorkerHandler ?? DocumentWorkerJSHandler()
// Setup handler for worker, consume preloaded handler, just in case it was used, assign queued state and place in proper queue.
setup(pdfWorkerHandler: pdfWorkerHandler, for: worker)
preloadedPDFWorkerHandler = nil
setup(documentWorkerHandler: documentWorkerHandler, for: worker)
preloadedDocumentWorkerHandler = nil
accessQueue.async(flags: .barrier) { [weak self] in
self?.preloadPDFWorkerIfIdle()
self?.preloadDocumentWorkerIfIdle()
}
updateStateAndQueues(for: worker, state: .queued)
// Start work if needed to run queued worker.
Expand Down Expand Up @@ -226,14 +226,14 @@ final class PDFWorkerController {
return subject.asObservable()
}

private func setup(pdfWorkerHandler: PDFWorkerJSHandler, for worker: Worker) {
pdfWorkerHandler.workFile = worker.file
pdfWorkerHandler.shouldCacheWorkData = worker.shouldCacheData
setupObserver(in: worker, for: pdfWorkerHandler)
worker.handler = pdfWorkerHandler
private func setup(documentWorkerHandler: DocumentWorkerJSHandler, for worker: Worker) {
documentWorkerHandler.workFile = worker.file
documentWorkerHandler.shouldCacheWorkData = worker.shouldCacheData
setupObserver(in: worker, for: documentWorkerHandler)
worker.handler = documentWorkerHandler

func setupObserver(in worker: Worker, for pdfWorkerHandler: PDFWorkerJSHandler) {
pdfWorkerHandler.observable.subscribe(onNext: { [weak self, weak worker] event in
func setupObserver(in worker: Worker, for documentWorkerHandler: DocumentWorkerJSHandler) {
documentWorkerHandler.observable.subscribe(onNext: { [weak self, weak worker] event in
guard let self else { return }
accessQueue.async(flags: .barrier) { [weak self, weak worker] in
guard let self, let worker, let work = Work(id: event.workId), worker.subjectsByWork[work] != nil else { return }
Expand All @@ -245,7 +245,7 @@ final class PDFWorkerController {
}

case .failure(let error):
DDLogError("PDFWorkerController: recognizer failed - \(error)")
DDLogError("DocumentWorkerController: recognizer failed - \(error)")
finishWork(work, in: worker) { $0?.on(.next(Update(work: work, kind: .failed))) }
}
}
Expand All @@ -266,7 +266,7 @@ final class PDFWorkerController {
}
}
guard let worker else { return }
guard let pdfWorkerHandler = worker.handler, let work = worker.subjectsByWork.keys.first, let subject = worker.subjectsByWork[work] else {
guard let documentWorkerHandler = worker.handler, let work = worker.subjectsByWork.keys.first, let subject = worker.subjectsByWork[work] else {
// This shouldn't happen, move worker back to ready state.
updateStateAndQueues(for: worker, state: .ready)
startWorkIfNeeded()
Expand All @@ -278,10 +278,10 @@ final class PDFWorkerController {
subject.on(.next(Update(work: work, kind: .inProgress)))
switch work {
case .recognizer:
pdfWorkerHandler.recognize(workId: work.id)
documentWorkerHandler.recognize(workId: work.id)

case .fullText(let pages):
pdfWorkerHandler.getFullText(pages: pages, workId: work.id)
documentWorkerHandler.getFullText(pages: pages, workId: work.id)
}
// Start another work if needed.
startWorkIfNeeded()
Expand All @@ -297,17 +297,17 @@ final class PDFWorkerController {
}
}

func finishWork(_ work: Work, worker: Worker, completion: ((_ subject: PublishSubject<Update>?) -> Void)?, controller: PDFWorkerController) {
func finishWork(_ work: Work, worker: Worker, completion: ((_ subject: PublishSubject<Update>?) -> Void)?, controller: DocumentWorkerController) {
let subject = worker.subjectsByWork.removeValue(forKey: work)
controller.updateStateAndQueues(for: worker, state: worker.subjectsByWork.isEmpty ? .ready : .queued)
DDLogInfo("PDFWorkerController: finished \(work) in \(worker)")
DDLogInfo("DocumentWorkerController: finished \(work) in \(worker)")
completion?(subject)
controller.startWorkIfNeeded()
}
}

func cancelWork(_ work: Work, in worker: Worker) {
DDLogInfo("PDFWorkerController: cancelled \(work) in \(worker)")
DDLogInfo("DocumentWorkerController: cancelled \(work) in \(worker)")
finishWork(work, in: worker) { $0?.on(.next(Update(work: work, kind: .cancelled))) }
}

Expand All @@ -321,8 +321,8 @@ final class PDFWorkerController {
}
}

func cancelAllWorks(in worker: Worker, startNextWorkIfNeeded: Bool, controller: PDFWorkerController) {
DDLogInfo("PDFWorkerController: cancel all works in \(worker)")
func cancelAllWorks(in worker: Worker, startNextWorkIfNeeded: Bool, controller: DocumentWorkerController) {
DDLogInfo("DocumentWorkerController: cancel all works in \(worker)")
// Immediately release worker handler and assign pending state to worker. If another work is queued for this worker, a new handler will be created.
worker.handler = nil
controller.updateStateAndQueues(for: worker, state: .pending)
Expand All @@ -332,7 +332,7 @@ final class PDFWorkerController {
worker.subjectsByWork.removeAll()
guard startNextWorkIfNeeded else { return }
controller.startWorkIfNeeded()
controller.preloadPDFWorkerIfIdle()
controller.preloadDocumentWorkerIfIdle()
}
}

Expand All @@ -343,7 +343,7 @@ final class PDFWorkerController {
func cancellAllWorks() {
accessQueue.async(flags: .barrier) { [weak self] in
guard let self else { return }
DDLogInfo("PDFWorkerController: cancel all works")
DDLogInfo("DocumentWorkerController: cancel all works")
var workers: Set<Worker> = []
workers.formUnion(preparing)
workers.formUnion(ready)
Expand All @@ -358,12 +358,12 @@ final class PDFWorkerController {
}
}

private func preloadPDFWorkerIfIdle() {
guard preloadedPDFWorkerHandler == nil,
private func preloadDocumentWorkerIfIdle() {
guard preloadedDocumentWorkerHandler == nil,
ready.isEmpty,
preparing.isEmpty,
!Priority.inDescendingOrder.contains(where: { !queuedByPriority[$0, default: []].isEmpty || !runningByPriority[$0, default: []].isEmpty })
else { return }
preloadedPDFWorkerHandler = PDFWorkerJSHandler()
preloadedDocumentWorkerHandler = DocumentWorkerJSHandler()
}
}
Loading