Initial commit
This commit is contained in:
186
fetch.go
Normal file
186
fetch.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package main
|
||||
|
||||
import "git.tebibyte.media/sashakoshka/skipper/dom"
|
||||
import "git.tebibyte.media/sashakoshka/skipper/input"
|
||||
import "git.tebibyte.media/sashakoshka/skipper/bookmarks"
|
||||
|
||||
import "fmt"
|
||||
import "net/url"
|
||||
import "strings"
|
||||
import "git.sr.ht/~yotam/go-gemini"
|
||||
|
||||
func fetchBackward () {
|
||||
if page.loading { return }
|
||||
location := page.history.Backward()
|
||||
if location != nil {
|
||||
go fetchNoTrace(location)
|
||||
}
|
||||
}
|
||||
|
||||
func fetchForward () {
|
||||
if page.loading { return }
|
||||
location := page.history.Forward()
|
||||
if location != nil {
|
||||
go fetchNoTrace(location)
|
||||
}
|
||||
}
|
||||
|
||||
func fetch (location *url.URL) {
|
||||
fetchBack(location, false, true)
|
||||
}
|
||||
|
||||
func fetchStringUrl (stringLocation string) {
|
||||
location, _ := url.Parse(stringLocation)
|
||||
fetch(location)
|
||||
}
|
||||
|
||||
func fetchNoTrace (location *url.URL) {
|
||||
fetchBack(location, false, false)
|
||||
}
|
||||
|
||||
func fetchSource (location *url.URL) {
|
||||
fetchBack(location, true, false)
|
||||
}
|
||||
|
||||
func fetchBack (location *url.URL, viewSource bool, addToHistory bool) {
|
||||
if page.loading { return }
|
||||
|
||||
page.loading = true
|
||||
page.readingInput = false
|
||||
page.readingUrlInput = false
|
||||
input.SelectNone()
|
||||
|
||||
page.currentUrl = location
|
||||
if addToHistory {
|
||||
page.history.Add(location)
|
||||
}
|
||||
|
||||
if location.Scheme == "about" {
|
||||
switch location.Opaque {
|
||||
case "skipper":
|
||||
fetchString(aboutGemtext, page.currentUrl)
|
||||
case "home":
|
||||
fetchString(homeGemtext, page.currentUrl)
|
||||
case "bookmarks":
|
||||
fetchString(bookmarks.Gemtext(), page.currentUrl)
|
||||
default:
|
||||
fetchString (
|
||||
"# Error\n" +
|
||||
"That page does not exist.",
|
||||
page.currentUrl)
|
||||
}
|
||||
page.loading = false
|
||||
redraw()
|
||||
application.Draw()
|
||||
return
|
||||
}
|
||||
|
||||
redraw()
|
||||
application.Draw()
|
||||
|
||||
response, err := client.Fetch(location.String())
|
||||
body := response.Body
|
||||
|
||||
defer func () {
|
||||
if body != nil {
|
||||
body.Close()
|
||||
}
|
||||
} ()
|
||||
|
||||
if err != nil {
|
||||
fetchString (
|
||||
"# Error\n" +
|
||||
"There was an error connecting to " +
|
||||
location.String() + "\n\n" +
|
||||
"> " + err.Error() + "\n",
|
||||
page.currentUrl)
|
||||
response.Status = 0
|
||||
}
|
||||
|
||||
simpleStatus := gemini.SimplifyStatus(response.Status)
|
||||
|
||||
if simpleStatus == gemini.StatusRedirect {
|
||||
page.redirectCounter ++
|
||||
} else {
|
||||
page.redirectCounter = 0
|
||||
}
|
||||
|
||||
switch simpleStatus {
|
||||
case 0:
|
||||
case gemini.StatusInput:
|
||||
fetchString("# " + response.Meta, page.currentUrl)
|
||||
page.input.Reset()
|
||||
page.input.Obscure = response.Status == 11
|
||||
page.input.Select()
|
||||
page.readingInput = true
|
||||
|
||||
case gemini.StatusSuccess:
|
||||
if body != nil {
|
||||
meta := strings.Split(response.Meta, ";")
|
||||
var mime string
|
||||
if len(meta) >= 1 {
|
||||
mime = meta[0]
|
||||
}
|
||||
|
||||
if viewSource {
|
||||
setDocument(dom.ParseSource(body, page.currentUrl))
|
||||
} else if mime == "text/gemini" {
|
||||
setDocument(dom.ParseDocument(body, page.currentUrl))
|
||||
} else {
|
||||
setDocument(dom.ParseSource(body, page.currentUrl))
|
||||
}
|
||||
}
|
||||
|
||||
case gemini.StatusRedirect:
|
||||
if page.redirectCounter > 8 {
|
||||
fetchString (fmt.Sprintf (
|
||||
"# Too many redirects\n" +
|
||||
"Enough! The site has redirected us too many " +
|
||||
"times."),
|
||||
page.currentUrl)
|
||||
break
|
||||
}
|
||||
|
||||
location, err := url.Parse(response.Meta)
|
||||
if err != nil {
|
||||
fetchString (fmt.Sprintf (
|
||||
"# Error\n" +
|
||||
"The site responded with an invalid redirect:\n\n" +
|
||||
"%s",
|
||||
err.Error()), page.currentUrl)
|
||||
} else {
|
||||
page.history.Remove()
|
||||
defer func () {
|
||||
go fetchBack(location, viewSource, true)
|
||||
} ()
|
||||
}
|
||||
|
||||
case gemini.StatusTemporaryFailure, gemini.StatusPermanentFailure:
|
||||
fetchString (fmt.Sprintf (
|
||||
"# Error %d\n" +
|
||||
"The site responded with an error:\n\n" +
|
||||
"> %s",
|
||||
response.Status, response.Meta), page.currentUrl)
|
||||
|
||||
default:
|
||||
fetchString (fmt.Sprintf (
|
||||
"# Unhandled response status %d\n" +
|
||||
"Skipper doesn't know how to handle this type of " +
|
||||
"response yet.",
|
||||
response.Status), page.currentUrl)
|
||||
}
|
||||
|
||||
page.loading = false
|
||||
redraw()
|
||||
application.Draw()
|
||||
}
|
||||
|
||||
func fetchString (data string, location *url.URL) {
|
||||
setDocument(dom.ParseDocument(strings.NewReader(data), location))
|
||||
}
|
||||
|
||||
func setDocument (document *dom.Document) {
|
||||
page.document = document
|
||||
page.scroll = 0
|
||||
application.SetTitle(document.Title() + " - Skipper")
|
||||
}
|
||||
Reference in New Issue
Block a user