Make redirects work

This commit is contained in:
Shadowfacts 2020-07-15 22:34:15 -04:00
parent bd48fc8dbb
commit 2d05e318ff
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
2 changed files with 39 additions and 25 deletions

View File

@ -13,8 +13,7 @@ import GeminiProtocol
struct ContentView: View { struct ContentView: View {
let navigator: NavigationManager let navigator: NavigationManager
@State var task: GeminiDataTask? @State var task: GeminiDataTask?
@State var document: Document? @State var state: ViewState = .loading
@State var errorMessage: String?
var body: some View { var body: some View {
mainView mainView
@ -24,17 +23,18 @@ struct ContentView: View {
@ViewBuilder @ViewBuilder
private var mainView: some View { private var mainView: some View {
if let document = document { switch state {
DocumentView(document: document, changeURL: navigator.changeURL) case .loading:
} else if let errorMessage = errorMessage { loadingView
.onAppear(perform: self.loadDocument)
case let .error(message):
VStack { VStack {
Text("An error occurred") Text("An error occurred")
.font(.headline) .font(.headline)
Text(errorMessage) Text(message)
} }
} else { case let .document(doc):
loadingView DocumentView(document: doc, changeURL: navigator.changeURL)
.onAppear(perform: self.loadDocument)
} }
} }
@ -50,25 +50,39 @@ struct ContentView: View {
private func loadDocument() { private func loadDocument() {
let url = navigator.currentURL let url = navigator.currentURL
task = try! GeminiDataTask(url: url, completion: { (response) in task = try! GeminiDataTask(url: url, completion: { (response) in
self.task = nil
switch response { switch response {
case let .failure(error): case let .failure(error):
self.errorMessage = error.localizedDescription state = .error(error.localizedDescription)
case let .success(response): case let .success(response):
guard let text = response.bodyText else { if response.status.isRedirect {
self.errorMessage = "Response had no body text" if let redirect = URL(string: response.meta) {
return navigator.changeURL(redirect)
loadDocument()
} else {
state = .error("Invalid redirect URL: '\(response.meta)'")
}
} else if response.status.isSuccess,
let text = response.bodyText {
state = .document(GeminiParser.parse(text: text, baseURL: url))
} else {
state = .error("Unknown error: \(response.header)")
} }
self.document = GeminiParser.parse(text: text, baseURL: url)
} }
self.task = nil
}) })
task!.resume() task!.resume()
} }
private func urlChanged(_ newValue: URL) { private func urlChanged(_ newValue: URL) {
self.task = nil state = .loading
self.document = nil }
self.errorMessage = nil }
extension ContentView {
enum ViewState {
case loading
case document(Document)
case error(String)
} }
} }

View File

@ -35,15 +35,15 @@ public extension GeminiResponseHeader {
case certificateNotValid = 62 case certificateNotValid = 62
// Status type helpers // Status type helpers
var isInput: Bool { rawValue / 10 == 1 } public var isInput: Bool { rawValue / 10 == 1 }
var isSuccess: Bool { rawValue / 10 == 2 } public var isSuccess: Bool { rawValue / 10 == 2 }
var isRedirect: Bool { rawValue / 10 == 3 } public var isRedirect: Bool { rawValue / 10 == 3 }
var isTemporaryFailure: Bool { rawValue / 10 == 4 } public var isTemporaryFailure: Bool { rawValue / 10 == 4 }
var isPermanentFailure: Bool { rawValue / 10 == 5 } public var isPermanentFailure: Bool { rawValue / 10 == 5 }
var isClientCertificateRequired: Bool { rawValue / 10 == 6 } public var isClientCertificateRequired: Bool { rawValue / 10 == 6 }
// Other helpers // Other helpers
var isFailure: Bool { isTemporaryFailure || isPermanentFailure } public var isFailure: Bool { isTemporaryFailure || isPermanentFailure }
} }
} }