Fix some build errors.

This commit is contained in:
Brent Simmons 2024-04-06 22:09:17 -07:00
parent 7311c25d35
commit bd077687c1
5 changed files with 91 additions and 62 deletions

View File

@ -14,7 +14,7 @@ typealias AccountError = CommonError // Temporary, for compatibility with existi
public extension CommonError {
@MainActor public var account: Account? {
@MainActor var account: Account? {
if case .wrappedError(_, let accountID, _) = self {
return AccountManager.shared.existingAccount(with: accountID)
} else {
@ -22,7 +22,7 @@ public extension CommonError {
}
}
@MainActor public static func wrappedError(error: Error, account: Account) -> AccountError {
@MainActor static func wrappedError(error: Error, account: Account) -> CommonError {
wrappedError(error: error, accountID: account.accountID, accountName: account.nameForDisplay)
}
}

View File

@ -47,20 +47,19 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
}
}
weak var accountMetadata: AccountMetadata? {
didSet {
caller.accountMetadata = accountMetadata
}
}
weak var accountMetadata: AccountMetadata?
var refreshProgress = DownloadProgress(numberOfTasks: 0)
init(dataFolder: String, transport: Transport?, variant: ReaderAPIVariant, secretsProvider: SecretsProvider) {
let databasePath = (dataFolder as NSString).appendingPathComponent("Sync.sqlite3")
database = SyncDatabase(databasePath: databasePath)
self.database = SyncDatabase(databasePath: databasePath)
self.variant = variant
if transport != nil {
caller = ReaderAPICaller(transport: transport!, secretsProvider: secretsProvider)
self.caller = ReaderAPICaller(transport: transport!, secretsProvider: secretsProvider)
} else {
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData
@ -75,11 +74,11 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
sessionConfiguration.httpAdditionalHeaders = userAgentHeaders
}
caller = ReaderAPICaller(transport: URLSession(configuration: sessionConfiguration), secretsProvider: secretsProvider)
self.caller = ReaderAPICaller(transport: URLSession(configuration: sessionConfiguration), secretsProvider: secretsProvider)
}
caller.delegate = self
caller.variant = variant
self.variant = variant
}
func receiveRemoteNotification(for account: Account, userInfo: [AnyHashable : Any]) async {
@ -102,7 +101,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
try? await refreshArticleStatus(for: account)
refreshProgress.completeTask()
try? await refreshMissingArticles(account)
await refreshMissingArticles(account)
refreshProgress.clear()
} catch {
@ -177,7 +176,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
do {
let articleIDs = try await caller.retrieveItemIDs(type: .starred)
try await syncArticleStarredState(account: account, articleIDs: articleIDs)
await syncArticleStarredState(account: account, articleIDs: articleIDs)
} catch {
errorOccurred = true
os_log(.info, log: self.log, "Retrieving starred entries failed: %@.", error.localizedDescription)
@ -185,7 +184,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
os_log(.debug, log: self.log, "Done refreshing article statuses.")
if errorOccurred {
throw ReaderAPIAccountDelegateError.unknown
throw ReaderAPIError.unknown
}
}
@ -195,7 +194,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
func createFolder(for account: Account, name: String) async throws -> Folder {
guard let folder = account.ensureFolder(with: name) else {
throw ReaderAPIAccountDelegateError.invalidParameter
throw ReaderAPIError.invalidParameter
}
return folder
}
@ -260,15 +259,18 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
if self.variant == .theOldReader {
account.removeFolder(folder: folder)
} else {
try await caller.deleteTag(folder: folder)
if let folderExternalID = folder.externalID {
try await caller.deleteTag(folderExternalID: folderExternalID)
}
account.removeFolder(folder: folder)
}
}
@discardableResult
func createFeed(for account: Account, url: String, name: String?, container: Container, validateFeed: Bool) async throws -> Feed {
guard let url = URL(string: url) else {
throw ReaderAPIAccountDelegateError.invalidParameter
throw ReaderAPIError.invalidParameter
}
refreshProgress.addToNumberOfTasksAndRemaining(2)
@ -284,7 +286,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
throw AccountError.createErrorNotFound
}
let subResult = try await caller.createSubscription(url: bestFeedSpecifier.urlString, name: name, folder: container as? Folder)
let subResult = try await caller.createSubscription(url: bestFeedSpecifier.urlString, name: name)
refreshProgress.completeTask()
switch subResult {
@ -305,7 +307,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
// This error should never happen
guard let subscriptionID = feed.externalID else {
assert(feed.externalID != nil)
throw ReaderAPIAccountDelegateError.invalidParameter
throw ReaderAPIError.invalidParameter
}
refreshProgress.addToNumberOfTasksAndRemaining(1)
@ -325,7 +327,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
guard let subscriptionID = feed.externalID else {
assert(feed.externalID != nil)
throw ReaderAPIAccountDelegateError.invalidParameter
throw ReaderAPIError.invalidParameter
}
refreshProgress.addToNumberOfTasksAndRemaining(1)
@ -360,7 +362,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
let sourceTag = (sourceContainer as? Folder)?.name,
let destinationTag = (destinationContainer as? Folder)?.name
else {
throw ReaderAPIAccountDelegateError.invalidParameter
throw ReaderAPIError.invalidParameter
}
refreshProgress.addToNumberOfTasksAndRemaining(1)
@ -475,7 +477,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
caller.cancelAll()
}
/// Suspend the SQLLite databases
/// Suspend the SQLite databases
func suspendDatabase() {
Task {
@ -895,3 +897,28 @@ private extension ReaderAPIAccountDelegate {
}
}
}
extension ReaderAPIAccountDelegate: ReaderAPICallerDelegate {
var endpointURL: URL? {
accountMetadata?.endpointURL
}
var lastArticleFetchStartTime: Date? {
get {
accountMetadata?.lastArticleFetchStartTime
}
set {
accountMetadata?.lastArticleFetchStartTime = newValue
}
}
var lastArticleFetchEndTime: Date? {
get {
accountMetadata?.lastArticleFetchEndTime
}
set {
accountMetadata?.lastArticleFetchEndTime = newValue
}
}
}

View File

@ -15,7 +15,7 @@ struct Browser {
///
/// The user-assigned default browser, or `nil` if none was assigned
/// (i.e., the system default should be used).
static var defaultBrowser: MacWebBrowser? {
@MainActor static var defaultBrowser: MacWebBrowser? {
if let bundleID = AppDefaults.shared.defaultBrowserID, let browser = MacWebBrowser(bundleIdentifier: bundleID) {
return browser
}

View File

@ -12,6 +12,7 @@ import Tree
import Articles
import Account
import Parser
import CommonErrors
// Run add-feed sheet.
// If it returns with URL and optional name,
@ -69,10 +70,10 @@ import Parser
let feed = try await account.createFeed(url: url.absoluteString, name: title, container: container, validateFeed: true)
NotificationCenter.default.post(name: .UserDidAddFeed, object: self, userInfo: [UserInfoKey.feed: feed])
} catch AccountError.createErrorAlreadySubscribed {
} catch CommonError.createErrorAlreadySubscribed {
self.showAlreadySubscribedError(url.absoluteString)
} catch AccountError.createErrorNotFound {
} catch CommonError.createErrorNotFound {
self.showNoFeedsErrorMessage()
} catch {

View File

@ -13,10 +13,10 @@ import CommonErrors
public protocol ReaderAPICallerDelegate: AnyObject {
var endpointURL: URL? { get }
@MainActor var endpointURL: URL? { get }
var lastArticleFetchStartTime: Date? { get set }
var lastArticleFetchEndTime: Date? { get set }
@MainActor var lastArticleFetchStartTime: Date? { get set }
@MainActor var lastArticleFetchEndTime: Date? { get set }
}
public enum CreateReaderAPISubscriptionResult: Sendable {
@ -25,15 +25,26 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
case notFound
}
@MainActor final class ReaderAPICaller {
@MainActor public final class ReaderAPICaller {
enum ItemIDType {
public enum ItemIDType {
case unread
case starred
case allForAccount
case allForFeed
}
public weak var delegate: ReaderAPICallerDelegate?
public var variant: ReaderAPIVariant = .generic
public var credentials: Credentials?
public var server: String? {
get {
return apiBaseURL?.host
}
}
private enum ReaderState: String {
case read = "user/-/state/com.google/read"
case starred = "user/-/state/com.google/starred"
@ -63,17 +74,6 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
private var accessToken: String?
weak var delegate: ReaderAPICallerDelegate?
var variant: ReaderAPIVariant = .generic
var credentials: Credentials?
var server: String? {
get {
return apiBaseURL?.host
}
}
private var apiBaseURL: URL? {
get {
switch variant {
@ -85,7 +85,8 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
}
}
init(transport: Transport, secretsProvider: SecretsProvider) {
/// The delegate should be set in a subsequent call.
public init(transport: Transport, secretsProvider: SecretsProvider) {
self.transport = transport
self.secretsProvider = secretsProvider
@ -96,11 +97,11 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
self.uriComponentAllowed = urlHostAllowed
}
func cancelAll() {
public func cancelAll() {
transport.cancelAll()
}
func validateCredentials(endpoint: URL) async throws -> Credentials? {
public func validateCredentials(endpoint: URL) async throws -> Credentials? {
guard let credentials else {
throw CredentialsError.incompleteCredentials
@ -173,7 +174,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
return accessToken
}
func retrieveTags() async throws -> [ReaderAPITag]? {
public func retrieveTags() async throws -> [ReaderAPITag]? {
guard let baseURL = apiBaseURL else {
throw CredentialsError.incompleteCredentials
@ -198,7 +199,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
return wrapper?.tags
}
func renameTag(oldName: String, newName: String) async throws {
public func renameTag(oldName: String, newName: String) async throws {
guard let baseURL = apiBaseURL else {
throw CredentialsError.incompleteCredentials
@ -223,7 +224,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
}
func deleteTag(folderExternalID: String) async throws {
public func deleteTag(folderExternalID: String) async throws {
guard let baseURL = apiBaseURL else {
throw CredentialsError.incompleteCredentials
@ -241,7 +242,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
try await self.transport.send(request: request, method: HTTPMethod.post, payload: postData!)
}
func retrieveSubscriptions() async throws -> [ReaderAPISubscription]? {
public func retrieveSubscriptions() async throws -> [ReaderAPISubscription]? {
guard let baseURL = apiBaseURL else {
throw CredentialsError.incompleteCredentials
@ -262,7 +263,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
return container?.subscriptions
}
func createSubscription(url: String, name: String?) async throws -> CreateReaderAPISubscriptionResult {
public func createSubscription(url: String, name: String?) async throws -> CreateReaderAPISubscriptionResult {
guard let baseURL = apiBaseURL else {
throw CredentialsError.incompleteCredentials
@ -305,12 +306,12 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
return .created(subscription)
}
func renameSubscription(subscriptionID: String, newName: String) async throws {
public func renameSubscription(subscriptionID: String, newName: String) async throws {
try await changeSubscription(subscriptionID: subscriptionID, title: newName)
}
func deleteSubscription(subscriptionID: String) async throws {
public func deleteSubscription(subscriptionID: String) async throws {
guard let baseURL = apiBaseURL else {
throw CredentialsError.incompleteCredentials
@ -328,17 +329,17 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
try await self.transport.send(request: request, method: HTTPMethod.post, payload: postData!)
}
func createTagging(subscriptionID: String, tagName: String) async throws {
public func createTagging(subscriptionID: String, tagName: String) async throws {
try await changeSubscription(subscriptionID: subscriptionID, addTagName: tagName)
}
func deleteTagging(subscriptionID: String, tagName: String) async throws {
public func deleteTagging(subscriptionID: String, tagName: String) async throws {
try await changeSubscription(subscriptionID: subscriptionID, removeTagName: tagName)
}
func moveSubscription(subscriptionID: String, sourceTag: String, destinationTag: String) async throws {
public func moveSubscription(subscriptionID: String, sourceTag: String, destinationTag: String) async throws {
try await changeSubscription(subscriptionID: subscriptionID, removeTagName: sourceTag, addTagName: destinationTag)
}
@ -374,7 +375,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
try await transport.send(request: request, method: HTTPMethod.post, payload: postData!)
}
func retrieveEntries(articleIDs: [String]) async throws -> [ReaderAPIEntry]? {
public func retrieveEntries(articleIDs: [String]) async throws -> [ReaderAPIEntry]? {
guard !articleIDs.isEmpty else {
return [ReaderAPIEntry]()
@ -412,7 +413,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
return entryWrapper.entries
}
func retrieveItemIDs(type: ItemIDType, feedID: String? = nil) async throws -> [String] {
public func retrieveItemIDs(type: ItemIDType, feedID: String? = nil) async throws -> [String] {
guard let baseURL = apiBaseURL else {
throw CredentialsError.incompleteCredentials
@ -510,22 +511,22 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
return try await retrieveItemIDs(type: type, url: callURL, dateInfo: dateInfo, itemIDs: totalItemIDs, continuation: entries?.continuation)
}
func createUnreadEntries(entries: [String]) async throws {
public func createUnreadEntries(entries: [String]) async throws {
try await updateStateToEntries(entries: entries, state: .read, add: false)
}
func deleteUnreadEntries(entries: [String]) async throws {
public func deleteUnreadEntries(entries: [String]) async throws {
try await updateStateToEntries(entries: entries, state: .read, add: true)
}
func createStarredEntries(entries: [String]) async throws {
public func createStarredEntries(entries: [String]) async throws {
try await updateStateToEntries(entries: entries, state: .starred, add: true)
}
func deleteStarredEntries(entries: [String]) async throws {
public func deleteStarredEntries(entries: [String]) async throws {
try await updateStateToEntries(entries: entries, state: .starred, add: false)
}