Compare commits
No commits in common. "255e5d7ff42995c27980abc2c060c85afeb6cab3" and "e79cdcdb57f382e071d64969eb4a7395a63b0024" have entirely different histories.
255e5d7ff4
...
e79cdcdb57
|
@ -8,7 +8,7 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
|
||||
public protocol NavigationManagerDelegate: AnyObject {
|
||||
public protocol NavigationManagerDelegate: class {
|
||||
func loadNonGeminiURL(_ url: URL)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
//
|
||||
// ActivityItemSource.swift
|
||||
// Gemini-iOS
|
||||
//
|
||||
// Created by Shadowfacts on 6/15/21.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import GeminiFormat
|
||||
import LinkPresentation
|
||||
|
||||
class ActivityItemSource: NSObject, UIActivityItemSource {
|
||||
let document: Document
|
||||
|
||||
init(document: Document) {
|
||||
self.document = document
|
||||
}
|
||||
|
||||
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
|
||||
return document.url
|
||||
}
|
||||
|
||||
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
|
||||
return document.url
|
||||
}
|
||||
|
||||
func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
|
||||
let metadata = LPLinkMetadata()
|
||||
metadata.url = document.url
|
||||
metadata.title = document.title
|
||||
return metadata
|
||||
}
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@ import UIKit
|
|||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
static let defaultHomepage = URL(string: "gemini://gemini.circumlunar.space/")!
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
SymbolCache.load()
|
||||
|
|
|
@ -303,8 +303,7 @@ class BrowserNavigationController: UIViewController {
|
|||
}
|
||||
|
||||
private func showShareSheet(_ source: UIView) {
|
||||
guard let doc = currentBrowserVC.document else { return }
|
||||
let vc = UIActivityViewController(activityItems: [ActivityItemSource(document: doc)], applicationActivities: [SetHomepageActivity()])
|
||||
let vc = UIActivityViewController(activityItems: [navigator.currentURL], applicationActivities: nil)
|
||||
vc.popoverPresentationController?.sourceView = source
|
||||
present(vc, animated: true)
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import GeminiProtocol
|
|||
import GeminiFormat
|
||||
import GeminiRenderer
|
||||
import SafariServices
|
||||
import Combine
|
||||
|
||||
class BrowserWebViewController: UIViewController {
|
||||
|
||||
|
@ -33,8 +32,6 @@ class BrowserWebViewController: UIViewController {
|
|||
private var loaded = false
|
||||
private var loadedFallback = false
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
private var errorStack: UIStackView!
|
||||
private var errorMessageLabel: UILabel!
|
||||
private var activityIndicator: UIActivityIndicatorView!
|
||||
|
@ -54,7 +51,25 @@ class BrowserWebViewController: UIViewController {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
configureRenderer()
|
||||
let documentURL = self.url
|
||||
renderer.linkPrefix = { (url: URL) -> String in
|
||||
let symbolClass: String
|
||||
if url.scheme == "gemini" {
|
||||
if url.host == documentURL.host {
|
||||
symbolClass = "arrow-right"
|
||||
} else {
|
||||
symbolClass = "link"
|
||||
}
|
||||
} else if url.scheme == "http" || url.scheme == "https" {
|
||||
symbolClass = "safari"
|
||||
} else if url.scheme == "mailto" {
|
||||
symbolClass = "envelope"
|
||||
} else {
|
||||
symbolClass = "arrow-up-left-square"
|
||||
}
|
||||
return "<span class=\"symbol \(symbolClass)\" aria-hidden=\"true\"></span>"
|
||||
|
||||
}
|
||||
|
||||
view.backgroundColor = .systemBackground
|
||||
|
||||
|
@ -107,14 +122,6 @@ class BrowserWebViewController: UIViewController {
|
|||
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||
])
|
||||
|
||||
Preferences.shared.$showLinkIcons
|
||||
.sink { [weak self] newVal in
|
||||
guard let self = self, let doc = self.document else { return }
|
||||
self.configureRenderer(showLinkIcons: newVal)
|
||||
self.renderDocument(doc)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
@ -123,31 +130,6 @@ class BrowserWebViewController: UIViewController {
|
|||
loadDocument()
|
||||
}
|
||||
|
||||
private func configureRenderer(showLinkIcons: Bool = Preferences.shared.showLinkIcons) {
|
||||
if showLinkIcons {
|
||||
let documentURL = self.url
|
||||
renderer.linkPrefix = { (url: URL) -> String in
|
||||
let symbolClass: String
|
||||
if url.scheme == "gemini" {
|
||||
if url.host == documentURL.host {
|
||||
symbolClass = "arrow-right"
|
||||
} else {
|
||||
symbolClass = "link"
|
||||
}
|
||||
} else if url.scheme == "http" || url.scheme == "https" {
|
||||
symbolClass = "safari"
|
||||
} else if url.scheme == "mailto" {
|
||||
symbolClass = "envelope"
|
||||
} else {
|
||||
symbolClass = "arrow-up-left-square"
|
||||
}
|
||||
return "<span class=\"symbol \(symbolClass)\" aria-hidden=\"true\"></span>"
|
||||
}
|
||||
} else {
|
||||
renderer.linkPrefix = nil
|
||||
}
|
||||
}
|
||||
|
||||
func reload() {
|
||||
loaded = false
|
||||
loadedFallback = false
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
//
|
||||
// HomepagePrefView.swift
|
||||
// Gemini-iOS
|
||||
//
|
||||
// Created by Shadowfacts on 6/15/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct HomepagePrefView: View {
|
||||
@State private var url: URL? = Preferences.shared.homepage
|
||||
@State private var focus = false
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
// use a custom binding to allow the state variable to be nil temporarily, and update the pref when not
|
||||
HomepagePrefTextField(value: Binding(get: {
|
||||
url
|
||||
}, set: { (newVal) in
|
||||
self.url = newVal
|
||||
if let newVal = newVal {
|
||||
Preferences.shared.homepage = newVal
|
||||
}
|
||||
}), focus: $focus)
|
||||
}
|
||||
.navigationBarTitle("Homepage")
|
||||
.onAppear {
|
||||
focus = true
|
||||
}
|
||||
.onDisappear {
|
||||
// if the text field was empty when we disappeared, reset to the default homepage
|
||||
if url == nil {
|
||||
Preferences.shared.homepage = AppDelegate.defaultHomepage
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
struct HomepagePrefTextField: UIViewRepresentable {
|
||||
@Binding private var value: URL?
|
||||
@Binding private var focus: Bool
|
||||
|
||||
init(value: Binding<URL?>, focus: Binding<Bool>) {
|
||||
self._value = value
|
||||
self._focus = focus
|
||||
}
|
||||
|
||||
func makeUIView(context: Context) -> UITextField {
|
||||
let field = UITextField()
|
||||
field.addTarget(context.coordinator, action: #selector(Coordinator.textChanged), for: .editingChanged)
|
||||
field.clearButtonMode = .whileEditing
|
||||
field.placeholder = AppDelegate.defaultHomepage.absoluteString
|
||||
// fix for text field expanding horizontally when text grows
|
||||
field.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
return field
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UITextField, context: Context) {
|
||||
uiView.text = value?.absoluteString
|
||||
context.coordinator.binding = $value
|
||||
if focus {
|
||||
DispatchQueue.main.async {
|
||||
uiView.becomeFirstResponder()
|
||||
focus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
return Coordinator(binding: $value)
|
||||
}
|
||||
|
||||
class Coordinator: NSObject {
|
||||
var binding: Binding<URL?>
|
||||
|
||||
init(binding: Binding<URL?>) {
|
||||
self.binding = binding
|
||||
}
|
||||
|
||||
@objc func textChanged(_ textField: UITextField) {
|
||||
if let text = textField.text,
|
||||
!text.isEmpty {
|
||||
if let url = URL(string: text) {
|
||||
binding.wrappedValue = url
|
||||
}
|
||||
} else {
|
||||
binding.wrappedValue = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct HomepagePrefView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
HomepagePrefView()
|
||||
}
|
||||
}
|
|
@ -77,9 +77,7 @@ class NavigationBarView: UIView {
|
|||
|
||||
@objc private func commitURL() {
|
||||
textField.resignFirstResponder()
|
||||
if let text = textField.text,
|
||||
!text.isEmpty,
|
||||
var components = URLComponents(string: text) {
|
||||
if let text = textField.text, var components = URLComponents(string: text) {
|
||||
if components.scheme == nil {
|
||||
components.scheme = "gemini"
|
||||
}
|
||||
|
|
|
@ -34,14 +34,7 @@ class Preferences: Codable, ObservableObject {
|
|||
required init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
if let stored = try container.decodeIfPresent(URL.self, forKey: .homepage) {
|
||||
homepage = stored
|
||||
}
|
||||
|
||||
theme = try container.decode(UIUserInterfaceStyle.self, forKey: .theme)
|
||||
if let stored = try container.decodeIfPresent(Bool.self, forKey: .showLinkIcons) {
|
||||
showLinkIcons = stored
|
||||
}
|
||||
|
||||
useInAppSafari = try container.decode(Bool.self, forKey: .useInAppSafari)
|
||||
useReaderMode = try container.decode(Bool.self, forKey: .useReaderMode)
|
||||
|
@ -50,28 +43,19 @@ class Preferences: Codable, ObservableObject {
|
|||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(homepage, forKey: .homepage)
|
||||
|
||||
try container.encode(theme, forKey: .theme)
|
||||
try container.encode(showLinkIcons, forKey: .showLinkIcons)
|
||||
|
||||
try container.encode(useInAppSafari, forKey: .useInAppSafari)
|
||||
try container.encode(useReaderMode, forKey: .useReaderMode)
|
||||
}
|
||||
|
||||
@Published var homepage = AppDelegate.defaultHomepage
|
||||
|
||||
@Published var theme = UIUserInterfaceStyle.unspecified
|
||||
@Published var showLinkIcons = true
|
||||
|
||||
@Published var useInAppSafari = false
|
||||
@Published var useReaderMode = false
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case homepage
|
||||
|
||||
case theme
|
||||
case showLinkIcons
|
||||
|
||||
case useInAppSafari
|
||||
case useReaderMode
|
||||
|
|
|
@ -15,8 +15,6 @@ struct PreferencesView: View {
|
|||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
untitledSection
|
||||
|
||||
appearanceSection
|
||||
|
||||
safariSection
|
||||
|
@ -25,7 +23,7 @@ struct PreferencesView: View {
|
|||
.insetOrGroupedListStyle()
|
||||
.navigationBarItems(trailing: doneButton)
|
||||
}
|
||||
.navigationViewStyle(.stack)
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
.onDisappear {
|
||||
Preferences.save()
|
||||
}
|
||||
|
@ -40,15 +38,6 @@ struct PreferencesView: View {
|
|||
.hoverEffect(.highlight)
|
||||
}
|
||||
|
||||
private var untitledSection: some View {
|
||||
Section {
|
||||
NavigationLink(destination: HomepagePrefView()) {
|
||||
Text("Homepage")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private var appearanceSection: some View {
|
||||
Section(header: Text("Appearance")) {
|
||||
Picker(selection: $preferences.theme, label: Text("Theme")) {
|
||||
|
@ -56,8 +45,6 @@ struct PreferencesView: View {
|
|||
Text("Always Light").tag(UIUserInterfaceStyle.light)
|
||||
Text("Always Dark").tag(UIUserInterfaceStyle.dark)
|
||||
}
|
||||
|
||||
Toggle("Show Link Icons", isOn: $preferences.showLinkIcons)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,9 +62,9 @@ fileprivate extension View {
|
|||
@ViewBuilder
|
||||
func insetOrGroupedListStyle() -> some View {
|
||||
if #available(iOS 14.0, *) {
|
||||
self.listStyle(.insetGrouped)
|
||||
self.listStyle(InsetGroupedListStyle())
|
||||
} else {
|
||||
self.listStyle(.grouped)
|
||||
self.listStyle(GroupedListStyle())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
if ProcessInfo.processInfo.environment.keys.contains("DEFAULT_URL") {
|
||||
initialURL = URL(string: ProcessInfo.processInfo.environment["DEFAULT_URL"]!)!
|
||||
} else {
|
||||
initialURL = Preferences.shared.homepage
|
||||
initialURL = URL(string: "gemini://gemini.circumlunar.space/")!
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
//
|
||||
// SetHomepageActivity.swift
|
||||
// Gemini-iOS
|
||||
//
|
||||
// Created by Shadowfacts on 6/15/21.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SetHomepageActivity: UIActivity {
|
||||
|
||||
override class var activityCategory: UIActivity.Category {
|
||||
return .action
|
||||
}
|
||||
|
||||
override var activityTitle: String? {
|
||||
return "Set as Homepage"
|
||||
}
|
||||
|
||||
override var activityImage: UIImage? {
|
||||
// large size more closely matches system activity images
|
||||
return UIImage(systemName: "house", withConfiguration: UIImage.SymbolConfiguration(scale: .large))
|
||||
}
|
||||
|
||||
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
|
||||
for case let url as URL in activityItems {
|
||||
return Preferences.shared.homepage != url
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override func prepare(withActivityItems activityItems: [Any]) {
|
||||
for case let url as URL in activityItems {
|
||||
Preferences.shared.homepage = url
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,9 +36,6 @@
|
|||
D62664EE24BC0BCE00DF9B88 /* MaybeLazyVStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62664ED24BC0BCE00DF9B88 /* MaybeLazyVStack.swift */; };
|
||||
D62664F024BC0D7700DF9B88 /* GeminiFormat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D62664A824BBF26A00DF9B88 /* GeminiFormat.framework */; };
|
||||
D62664FA24BC12BC00DF9B88 /* DocumentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D62664F924BC12BC00DF9B88 /* DocumentTests.swift */; };
|
||||
D653F40B267996FF004E32B1 /* ActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653F40A267996FF004E32B1 /* ActivityItemSource.swift */; };
|
||||
D653F40D26799F2F004E32B1 /* HomepagePrefView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653F40C26799F2F004E32B1 /* HomepagePrefView.swift */; };
|
||||
D653F40F2679A0AB004E32B1 /* SetHomepageActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D653F40E2679A0AB004E32B1 /* SetHomepageActivity.swift */; };
|
||||
D664673624BD07F700B0B741 /* RenderingBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = D664673524BD07F700B0B741 /* RenderingBlock.swift */; };
|
||||
D664673824BD086F00B0B741 /* RenderingBlockView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D664673724BD086F00B0B741 /* RenderingBlockView.swift */; };
|
||||
D664673A24BD0B8E00B0B741 /* Fonts.swift in Sources */ = {isa = PBXBuildFile; fileRef = D664673924BD0B8E00B0B741 /* Fonts.swift */; };
|
||||
|
@ -306,9 +303,6 @@
|
|||
D62664EB24BC0B4D00DF9B88 /* DocumentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentView.swift; sourceTree = "<group>"; };
|
||||
D62664ED24BC0BCE00DF9B88 /* MaybeLazyVStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaybeLazyVStack.swift; sourceTree = "<group>"; };
|
||||
D62664F924BC12BC00DF9B88 /* DocumentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentTests.swift; sourceTree = "<group>"; };
|
||||
D653F40A267996FF004E32B1 /* ActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityItemSource.swift; sourceTree = "<group>"; };
|
||||
D653F40C26799F2F004E32B1 /* HomepagePrefView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomepagePrefView.swift; sourceTree = "<group>"; };
|
||||
D653F40E2679A0AB004E32B1 /* SetHomepageActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetHomepageActivity.swift; sourceTree = "<group>"; };
|
||||
D664673524BD07F700B0B741 /* RenderingBlock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenderingBlock.swift; sourceTree = "<group>"; };
|
||||
D664673724BD086F00B0B741 /* RenderingBlockView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenderingBlockView.swift; sourceTree = "<group>"; };
|
||||
D664673924BD0B8E00B0B741 /* Fonts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fonts.swift; sourceTree = "<group>"; };
|
||||
|
@ -599,9 +593,6 @@
|
|||
D6BC9AD6258FC8B3008652BC /* TableOfContentsView.swift */,
|
||||
D691A64D25217C6F00348C4B /* Preferences.swift */,
|
||||
D691A66625217FD800348C4B /* PreferencesView.swift */,
|
||||
D653F40C26799F2F004E32B1 /* HomepagePrefView.swift */,
|
||||
D653F40A267996FF004E32B1 /* ActivityItemSource.swift */,
|
||||
D653F40E2679A0AB004E32B1 /* SetHomepageActivity.swift */,
|
||||
D688F618258AD231003A0A73 /* Resources */,
|
||||
D6E152AA24BFFDF600FDF9D3 /* Assets.xcassets */,
|
||||
D6E152AF24BFFDF600FDF9D3 /* LaunchScreen.storyboard */,
|
||||
|
@ -1120,14 +1111,11 @@
|
|||
D688F633258B09BB003A0A73 /* TrackpadScrollGestureRecognizer.swift in Sources */,
|
||||
D6E152A524BFFDF500FDF9D3 /* AppDelegate.swift in Sources */,
|
||||
D6E152A724BFFDF500FDF9D3 /* SceneDelegate.swift in Sources */,
|
||||
D653F40B267996FF004E32B1 /* ActivityItemSource.swift in Sources */,
|
||||
D6BC9AB3258E8E13008652BC /* ToolbarView.swift in Sources */,
|
||||
D688F64A258C17F3003A0A73 /* SymbolCache.swift in Sources */,
|
||||
D653F40F2679A0AB004E32B1 /* SetHomepageActivity.swift in Sources */,
|
||||
D688F65A258C2256003A0A73 /* BrowserNavigationController.swift in Sources */,
|
||||
D6BC9AD7258FC8B3008652BC /* TableOfContentsView.swift in Sources */,
|
||||
D688F663258C2479003A0A73 /* UIViewController+Children.swift in Sources */,
|
||||
D653F40D26799F2F004E32B1 /* HomepagePrefView.swift in Sources */,
|
||||
D691A64E25217C6F00348C4B /* Preferences.swift in Sources */,
|
||||
D6BC9ABC258E9862008652BC /* NavigationBarView.swift in Sources */,
|
||||
);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "swift-html-entities",
|
||||
"package": "HTMLEntities",
|
||||
"repositoryURL": "https://github.com/Kitura/swift-html-entities",
|
||||
"state": {
|
||||
"branch": null,
|
||||
|
|
|
@ -44,6 +44,8 @@ public struct GeminiParser {
|
|||
// URL(string:relativeTo:) does not handle // meaning the same protocol as the base URL
|
||||
urlString = baseURL.scheme! + ":" + urlString
|
||||
}
|
||||
// todo: if the URL initializer fails, should there be a .link line with a nil URL?
|
||||
let url = URL(string: urlString, relativeTo: baseURL)!.absoluteURL
|
||||
|
||||
let text: String?
|
||||
if textStart < line.endIndex {
|
||||
|
@ -52,18 +54,7 @@ public struct GeminiParser {
|
|||
text = nil
|
||||
}
|
||||
|
||||
if let url = URL(string: urlString, relativeTo: baseURL)?.absoluteURL {
|
||||
doc.lines.append(.link(url, text: text))
|
||||
} else {
|
||||
let str: String
|
||||
if let text = text {
|
||||
// todo: localize me?
|
||||
str = "\(text): \(urlString)"
|
||||
} else {
|
||||
str = urlString
|
||||
}
|
||||
doc.lines.append(.text(str))
|
||||
}
|
||||
doc.lines.append(.link(url, text: text))
|
||||
} else if line.starts(with: "#") {
|
||||
let level: Document.HeadingLevel
|
||||
if line.starts(with: "###") {
|
||||
|
|
|
@ -79,7 +79,6 @@ public class GeminiDataTask {
|
|||
self.completion(.failure(.connectionError(error)))
|
||||
} else if let message = context?.protocolMetadata(definition: GeminiProtocol.definition) as? NWProtocolFramer.Message,
|
||||
let header = message.geminiResponseHeader {
|
||||
guard isComplete else { fatalError() }
|
||||
let response = GeminiResponse(header: header, body: data)
|
||||
self.completion(.success(response))
|
||||
}
|
||||
|
|
|
@ -88,12 +88,12 @@ class GeminiProtocol: NWProtocolFramerImplementation {
|
|||
let header = GeminiResponseHeader(status: statusCode, meta: meta)
|
||||
|
||||
let message = NWProtocolFramer.Message(geminiResponseHeader: header)
|
||||
// Deliver all the input (the response body) to the client without copying.
|
||||
// What does the return value of deliverInputNoCopy mean, you ask? Why, I have no idea
|
||||
// It always returns true for a length of zero, so following the sample code and looping
|
||||
// infinitely until it returns false causes an infinite loop.
|
||||
// Additionally, calling deliverInput with an empty Data() causes an error inside Network.framework.
|
||||
// So, we just ignore the result since it doesn't seem to cause any problems ¯\_(ツ)_/¯
|
||||
_ = framer.deliverInputNoCopy(length: statusCode.isSuccess ? .max : 0, message: message, isComplete: true)
|
||||
// Just in case, set the framer to pass-through input so it never invokes this method again.
|
||||
// todo: this should work according to an apple engineer, but the request seems to hang forever on a real device
|
||||
// sometimes works fine when stepping through w/ debugger => race condition?
|
||||
// framer.passThroughInput()
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue