diff --git a/apple/OmnivoreKit/Sources/App/AppExtensions/Share/ShareExtensionScene.swift b/apple/OmnivoreKit/Sources/App/AppExtensions/Share/ShareExtensionScene.swift index 74aaba17d..0d555bbe2 100644 --- a/apple/OmnivoreKit/Sources/App/AppExtensions/Share/ShareExtensionScene.swift +++ b/apple/OmnivoreKit/Sources/App/AppExtensions/Share/ShareExtensionScene.swift @@ -67,9 +67,10 @@ final class ShareExtensionViewModel: ObservableObject { let linkedItem = try? await services.dataService.persistPageScrapePayload(pageScrapePayload, requestId: requestId) if let linkedItem = linkedItem { - // Sync with server now that we saved the item locally - services.dataService.syncLocalCreatedLinkedItem(item: linkedItem) updateStatus(newStatus: .saved) + + await services.dataService.syncLocalCreatedLinkedItem(item: linkedItem) + updateStatus(newStatus: .synced) } else { updateStatus(newStatus: .failed(error: SaveArticleError.unknown(description: "Unable to save page"))) } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SavePDF.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SavePDF.swift index a6cbfb5d8..63577afdd 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SavePDF.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SavePDF.swift @@ -26,9 +26,7 @@ private struct UploadFileRequestPayload { } private extension DataService { - // swiftlint:disable:next line_length - // func uploadFileRequestPublisher(pageScrapePayload: PageScrapePayload, requestId: String?) -> AnyPublisher { - func uploadFileRequestPublisher(item: LinkedItem) -> AnyPublisher { + public func uploadFileRequest(item: LinkedItem) async throws -> URL { enum MutationResult { case success(payload: UploadFileRequestPayload) case error(errorCode: Enums.UploadFileRequestErrorCode?) @@ -63,84 +61,51 @@ private extension DataService { let path = appEnvironment.graphqlPath let headers = networker.defaultHeaders - return Deferred { - Future { promise in - send(mutation, to: path, headers: headers) { result in - print("result of upload file request", result) - switch result { - case let .success(payload): - if let graphqlError = payload.errors { - promise(.failure(.unknown(description: graphqlError.first.debugDescription))) - } - - switch payload.data { - case let .success(payload): - promise(.success(payload)) - case let .error(errorCode): - switch errorCode { - case .unauthorized: - promise(.failure(.unauthorized)) - default: - promise(.failure(.unknown(description: errorCode.debugDescription))) - } - } - case .failure: - promise(.failure(.badData)) + return try await withCheckedThrowingContinuation { continuation in + send(mutation, to: path, headers: headers) { result in + switch result { + case let .success(payload): + if let graphqlError = payload.errors { + continuation.resume( + throwing: SaveArticleError.unknown(description: graphqlError.first.debugDescription) + ) + return } + + switch payload.data { + case let .success(payload): + if let urlString = payload.urlString, let url = URL(string: urlString) { + continuation.resume(returning: url) + } else { + continuation.resume(throwing: SaveArticleError.unknown(description: "No upload URL")) + } + case let .error(errorCode: errorCode): + switch errorCode { + case .unauthorized: + continuation.resume(throwing: SaveArticleError.unauthorized) + default: + continuation.resume(throwing: SaveArticleError.unknown(description: errorCode?.rawValue ?? "unknown")) + } + } + case let .failure(error): + continuation.resume(throwing: SaveArticleError.make(from: error)) } } } - .eraseToAnyPublisher() } - // swiftlint:disable:next line_length - public func uploadFilePublisher(item: LinkedItem) -> AnyPublisher { - var urlComponents = URLComponents(url: appEnvironment.serverBaseURL, resolvingAgainstBaseURL: true)! - // let headers = networker.defaultHeaders - - urlComponents.path = "/api/page/pdf" - urlComponents.queryItems = [URLQueryItem(name: "url", value: item.pageURLString), URLQueryItem(name: "clientRequestId", value: item.unwrappedID)] - + public func uploadFile(item: LinkedItem, url: URL) -> URLSessionTask? { if let localPdfURL = item.localPdfURL, let localUrl = URL(string: localPdfURL) { - print("UPLOADING TO URL", urlComponents.url) - var request = URLRequest(url: urlComponents.url!) + var request = URLRequest(url: url) request.httpMethod = "PUT" - - networker.defaultHeaders.forEach { (key: String, value: String) in - request.addValue(value, forHTTPHeaderField: key) - } request.setValue("application/pdf", forHTTPHeaderField: "content-type") let task = networker.backgroundSession.uploadTask(with: request, fromFile: localUrl) task.resume() + return task + } else { + return nil } - - // Just return immediately at this point. - return Empty(completeImmediately: true).eraseToAnyPublisher() -// return "".publisher.eraseToAnyPublisher() -// return networker.urlSession.dataTaskPublisher(for: request) -// .tryMap { data, response -> String in -// let serverResponse = ServerResponse(data: data, response: response) -// if serverResponse.httpUrlResponse?.statusCode == 200, let fileUploadID = fileUploadConfig.uploadID { -// return fileUploadID -// } -// -// throw ServerError(serverResponse: serverResponse) -// } -// .mapError { error -> SaveArticleError in -// let serverResponse = ServerResponse(error: error) -// NetworkRequestLogger.log(request: request, serverResponse: serverResponse) -// let serverError = ServerError(serverResponse: serverResponse) -// switch serverError { -// case .noConnection, .timeout: -// return .network -// case .unauthenticated: -// return .unauthorized -// case .unknown: -// return .unknown(description: "upload to file server failed") -// } -// } -// .eraseToAnyPublisher() } // swiftlint:disable:next line_length diff --git a/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift b/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift index 798369406..6e6058c07 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift @@ -35,40 +35,38 @@ extension DataService { } } - public func syncLocalCreatedLinkedItem(item: LinkedItem) { + public func syncLocalCreatedLinkedItem(item: LinkedItem) async -> Bool { switch item.contentReader { case "PDF": // SaveFile - uploadFilePublisher(item: item) - .sink(receiveCompletion: { [weak self] _ in - print("received PDF saved completion") - }, receiveValue: { [weak self] _ in - print("recived save PDF value", item) - }) - .store(in: &subscriptions) - case "WEB": - if item.originalHtml != nil { - savePagePublisher(item: item) - .sink(receiveCompletion: { [weak self] _ in - print("received page saved completion") - }, receiveValue: { [weak self] _ in - print("recived save page value", item) - }) - .store(in: &subscriptions) - } else { - saveUrlPublisher(item: item) - .sink(receiveCompletion: { [weak self] _ in - print("received url saved completion") - }, receiveValue: { [weak self] _ in -// print("recived save url value", item) - }) - .store(in: &subscriptions) + do { + let uploadRequest = try await uploadFileRequest(item: item) + uploadFile(item: item, url: uploadRequest) + } catch { + logger.debug("Failed to upload PDF LinkedItem: \(error.localizedDescription)") + return false } - case .none: - print("NONE HANDLER") - case .some: - print("SOME HANDLER") + case "WEB": + do { + if item.originalHtml != nil { + try await savePage(item: item) + } else { + try await saveURL(item: item) + } + item.serverSyncStatus = Int64(ServerSyncStatus.isNSync.rawValue) + print("ITEMS SYNCED") + try backgroundContext.save() + return true + } catch { + print("Error saving", error) + backgroundContext.rollback() + logger.debug("Failed to sync LinkedItem: \(error.localizedDescription)") + return false + } + default: + return false } + return false } private func syncLinkedItems(unsyncedLinkedItems: [LinkedItem]) { @@ -77,7 +75,8 @@ extension DataService { switch syncStatus { case .needsCreation: - syncLocalCreatedLinkedItem(item: item) + // syncLocalCreatedLinkedItem(item: item) + break case .isNSync, .isSyncing: break case .needsDeletion: diff --git a/apple/OmnivoreKit/Sources/Views/ShareExtensionView.swift b/apple/OmnivoreKit/Sources/Views/ShareExtensionView.swift index 9ab0d82fa..11e80f41b 100644 --- a/apple/OmnivoreKit/Sources/Views/ShareExtensionView.swift +++ b/apple/OmnivoreKit/Sources/Views/ShareExtensionView.swift @@ -143,7 +143,20 @@ public struct ShareExtensionChildView: View { Spacer() - if case ShareExtensionStatus.saved = status { + switch status { + case .processing: + HStack { + Spacer() + Text("Saving...") + Spacer() + } + case .saved: + HStack { + Spacer() + Text("Syncing...") + Spacer() + } + case .synced: HStack(spacing: 4) { Text("Saved to Omnivore") .font(.appTitleThree) @@ -154,19 +167,43 @@ public struct ShareExtensionChildView: View { .lineLimit(nil) } .padding() - } else if case let ShareExtensionStatus.failed(error) = status { + case let .failed(error: error): HStack { Spacer() - Text(error.displayMessage) + Text("Failed to save:" + error.displayMessage) Spacer() } - } else { + case let .syncFailed(error: error): HStack { Spacer() - Text("Saving...") + Text("Failed to sync:" + error.displayMessage) Spacer() } } +// if case ShareExtensionStatus.saved = status { +// HStack(spacing: 4) { +// Text("Saved to Omnivore") +// .font(.appTitleThree) +// .foregroundColor(.appGrayText) +// .padding(.trailing, 16) +// .multilineTextAlignment(.center) +// .fixedSize(horizontal: false, vertical: true) +// .lineLimit(nil) +// } +// .padding() +// } else if case let ShareExtensionStatus.failed(error) = status { +// HStack { +// Spacer() +// Text(error.displayMessage) +// Spacer() +// } +// } else { +// HStack { +// Spacer() +// Text("Saving...") +// Spacer() +// } +// } ScrollView { if FeatureFlag.enableRemindersFromShareExtension {