From d4544ae918feba86c58ed817b37ce687f2af5340 Mon Sep 17 00:00:00 2001 From: Jason Morley Date: Fri, 9 Apr 2021 17:16:42 -0700 Subject: [PATCH] Work around duplicate data in the Pinboard API (#81) Unfortunately it looks like the Pinboard posts/all API is returning duplicate data, meaning that we're seeing some URLs (and therefore hashes) more than once. Since we're using these for identifiers in the SwiftUI list, it's leading to crashes as it has no idea how to handle duplicate elements. This change pre-filters the data when it's returned from the Pinboard API to ensure bad data never leaks into the app. This also includes a drive-by fix to clean up the Pinboard class (used for managing the Pinboard API) in advance of adding additional methods. --- core/BookmarksCore/Common/Updater.swift | 9 +++++++-- core/BookmarksCore/Pinboard/Pinboard.swift | 11 +++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core/BookmarksCore/Common/Updater.swift b/core/BookmarksCore/Common/Updater.swift index 8584beb9..f2f2efdb 100644 --- a/core/BookmarksCore/Common/Updater.swift +++ b/core/BookmarksCore/Common/Updater.swift @@ -35,7 +35,7 @@ public class Updater { } public func start() { - Pinboard(token: self.token).fetch { [weak self] (result) in + Pinboard(token: self.token).posts_all { [weak self] (result) in switch (result) { case .failure(let error): print("Failed to fetch the posts with error \(error)") @@ -43,13 +43,18 @@ public class Updater { guard let self = self else { return } + // Pinboard seems to give us duplicate data so we maintain a set of hashes we've seen to ensure we + // only return one of each. + var identifiers = Set() var items: [Item] = [] for post in posts { guard let url = post.href, - let date = post.time else { + let date = post.time, + !identifiers.contains(post.hash) else { continue } + identifiers.insert(post.hash) items.append(Item(identifier: post.hash, title: post.description ?? "", url: url, diff --git a/core/BookmarksCore/Pinboard/Pinboard.swift b/core/BookmarksCore/Pinboard/Pinboard.swift index eeefe53d..7a2890f3 100644 --- a/core/BookmarksCore/Pinboard/Pinboard.swift +++ b/core/BookmarksCore/Pinboard/Pinboard.swift @@ -28,8 +28,11 @@ public class Pinboard { case inconsistentState(message: String) } - let baseURL = "https://api.pinboard.in/v1/" - let postsAll = "posts/all" + fileprivate let baseURL = "https://api.pinboard.in/v1/" + + fileprivate enum Path: String { + case posts_all = "posts/all" + } let token: String @@ -37,14 +40,14 @@ public class Pinboard { self.token = token } - public func fetch(completion: @escaping (Result<[Post], Swift.Error>) -> Void) { + public func posts_all(completion: @escaping (Result<[Post], Swift.Error>) -> Void) { guard let base = URL(string: baseURL) else { DispatchQueue.global(qos: .default).async { completion(.failure(Error.invalidURL(message: "Unable to construct parse base URL"))) } return } - let posts = base.appendingPathComponent(postsAll) + let posts = base.appendingPathComponent(Path.posts_all.rawValue) guard var components = URLComponents(string: posts.absoluteString) else { DispatchQueue.global(qos: .default).async { completion(.failure(Error.invalidURL(message: "Unable to parse URL components")))