From cb535196e23d7639fc662335e7ca374187dfac95 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 28 Dec 2024 23:43:50 -0500 Subject: [PATCH] Fix signing into API-restricted instances Closes #556 --- .../Sources/Pachyderm/Model/NodeInfo.swift | 6 +++ .../InstanceSelectorTableViewController.swift | 53 ++++++++++++++----- .../Instance Cell/InstanceTableViewCell.swift | 27 +++------- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/Packages/Pachyderm/Sources/Pachyderm/Model/NodeInfo.swift b/Packages/Pachyderm/Sources/Pachyderm/Model/NodeInfo.swift index 1c3ab39d..f839d835 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Model/NodeInfo.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Model/NodeInfo.swift @@ -11,9 +11,15 @@ import Foundation public struct NodeInfo: Decodable, Sendable, Equatable { public let version: String public let software: Software + public let metadata: Metadata public struct Software: Decodable, Sendable, Equatable { public let name: String public let version: String } + + public struct Metadata: Decodable, Sendable, Equatable { + public let nodeName: String + public let nodeDescription: String + } } diff --git a/Tusker/Screens/Onboarding/InstanceSelectorTableViewController.swift b/Tusker/Screens/Onboarding/InstanceSelectorTableViewController.swift index 17f34f94..df867120 100644 --- a/Tusker/Screens/Onboarding/InstanceSelectorTableViewController.swift +++ b/Tusker/Screens/Onboarding/InstanceSelectorTableViewController.swift @@ -75,13 +75,14 @@ class InstanceSelectorTableViewController: UITableViewController { dataSource = UITableViewDiffableDataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in switch item { - case let .selected(_, instance): + case let .selected(_, info): let cell = tableView.dequeueReusableCell(withIdentifier: instanceCell, for: indexPath) as! InstanceTableViewCell - cell.updateUI(instance: instance) + cell.updateUI(info: info) return cell case let .recommended(instance): let cell = tableView.dequeueReusableCell(withIdentifier: instanceCell, for: indexPath) as! InstanceTableViewCell - cell.updateUI(instance: instance) + let info = Info(host: instance.domain, description: instance.description, thumbnail: instance.proxiedThumbnailURL, adult: instance.category == "adult") + cell.updateUI(info: info) return cell } }) @@ -164,22 +165,20 @@ class InstanceSelectorTableViewController: UITableViewController { return } - let client = Client(baseURL: url, session: .appDefault) - let request = Client.getInstanceV1() - client.run(request) { (response) in + checkSpecificInstance(url: url) { (info) in var snapshot = self.dataSource.snapshot() if snapshot.indexOfSection(.selected) != nil { snapshot.deleteSections([.selected]) } - if case let .success(instance, _) = response { + if let info { if snapshot.indexOfSection(.recommendedInstances) != nil { snapshot.insertSections([.selected], beforeSection: .recommendedInstances) } else { snapshot.appendSections([.selected]) } - snapshot.appendItems([.selected(url, instance)], toSection: .selected) + snapshot.appendItems([.selected(url, info)], toSection: .selected) DispatchQueue.main.async { self.dataSource.apply(snapshot) { @@ -194,6 +193,29 @@ class InstanceSelectorTableViewController: UITableViewController { } } + private func checkSpecificInstance(url: URL, completionHandler: @escaping (Info?) -> Void) { + let client = Client(baseURL: url, session: .appDefault) + let request = Client.getInstanceV1() + client.run(request) { response in + switch response { + case .success(let instance, _): + let host = url.host ?? URLComponents(string: instance.uri)?.host ?? instance.uri + let info = Info(host: host, description: instance.shortDescription ?? instance.description, thumbnail: instance.thumbnail, adult: false) + completionHandler(info) + case .failure(_): + Task { + do { + let nodeInfo = try await client.nodeInfo() + let info = Info(host: url.host!, description: nodeInfo.metadata.nodeDescription, thumbnail: nil, adult: false) + completionHandler(info) + } catch { + completionHandler(nil) + } + } + } + } + } + private func loadRecommendedInstances() { InstanceSelector.getInstances(category: nil) { (response) in DispatchQueue.main.async { @@ -312,13 +334,13 @@ extension InstanceSelectorTableViewController { case recommendedInstances } enum Item: Equatable, Hashable, Sendable { - case selected(URL, InstanceV1) + case selected(URL, Info) case recommended(InstanceSelector.Instance) static func ==(lhs: Item, rhs: Item) -> Bool { switch (lhs, rhs) { - case let (.selected(urlA, instanceA), .selected(urlB, instanceB)): - return urlA == urlB && instanceA.uri == instanceB.uri + case let (.selected(urlA, _), .selected(urlB, _)): + return urlA == urlB case let (.recommended(a), .recommended(b)): return a.domain == b.domain default: @@ -328,16 +350,21 @@ extension InstanceSelectorTableViewController { func hash(into hasher: inout Hasher) { switch self { - case let .selected(url, instance): + case let .selected(url, _): hasher.combine(0) hasher.combine(url) - hasher.combine(instance.uri) case let .recommended(instance): hasher.combine(1) hasher.combine(instance.domain) } } } + struct Info: Hashable { + let host: String + let description: String + let thumbnail: URL? + let adult: Bool + } } extension InstanceSelectorTableViewController: UISearchResultsUpdating { diff --git a/Tusker/Views/Instance Cell/InstanceTableViewCell.swift b/Tusker/Views/Instance Cell/InstanceTableViewCell.swift index a89a9d03..5b277617 100644 --- a/Tusker/Views/Instance Cell/InstanceTableViewCell.swift +++ b/Tusker/Views/Instance Cell/InstanceTableViewCell.swift @@ -16,8 +16,7 @@ class InstanceTableViewCell: UITableViewCell { @IBOutlet weak var adultLabel: UILabel! @IBOutlet weak var descriptionTextView: ContentTextView! - var instance: InstanceV1? - var selectorInstance: InstanceSelector.Instance? + private var instance: InstanceSelectorTableViewController.Info? private var thumbnailTask: Task? @@ -44,25 +43,14 @@ class InstanceTableViewCell: UITableViewCell { backgroundConfiguration = .appListGroupedCell(for: state) } - func updateUI(instance: InstanceSelector.Instance) { - self.selectorInstance = instance - self.instance = nil - - domainLabel.text = instance.domain - adultLabel.isHidden = instance.category != "adult" - descriptionTextView.setBodyTextFromHTML(instance.description) - updateThumbnail(url: instance.proxiedThumbnailURL) - } - - func updateUI(instance: InstanceV1) { - self.instance = instance - self.selectorInstance = nil + func updateUI(info: InstanceSelectorTableViewController.Info) { + self.instance = info - domainLabel.text = URLComponents(string: instance.uri)?.host ?? instance.uri - adultLabel.isHidden = true - descriptionTextView.setBodyTextFromHTML(instance.shortDescription ?? instance.description) + domainLabel.text = info.host + adultLabel.isHidden = !info.adult + descriptionTextView.setBodyTextFromHTML(info.description) - if let thumbnail = instance.thumbnail { + if let thumbnail = info.thumbnail { updateThumbnail(url: thumbnail) } else { thumbnailImageView.image = nil @@ -85,7 +73,6 @@ class InstanceTableViewCell: UITableViewCell { thumbnailTask?.cancel() instance = nil - selectorInstance = nil } }