130 lines
2.9 KiB
Go
130 lines
2.9 KiB
Go
// Contains the building blocks of a gopher client: history, url, and view.
|
|
// History handles the browsing session and view represents individual
|
|
// text based resources, the url represents a parsed url.
|
|
package gopher
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
//------------------------------------------------\\
|
|
// + + + V A R I A B L E S + + + \\
|
|
//--------------------------------------------------\\
|
|
|
|
// types is a map of gophertypes to a string representing their
|
|
// type, to be used when displaying gophermaps
|
|
var types = map[string]string{
|
|
"0": "TXT",
|
|
"1": "MAP",
|
|
"h": "HTM",
|
|
"3": "ERR",
|
|
"4": "BIN",
|
|
"5": "DOS",
|
|
"s": "SND",
|
|
"g": "GIF",
|
|
"I": "IMG",
|
|
"9": "BIN",
|
|
"7": "FTS",
|
|
"6": "UUE",
|
|
"p": "PNG",
|
|
}
|
|
|
|
//------------------------------------------------\\
|
|
// + + + F U N C T I O N S + + + \\
|
|
//--------------------------------------------------\\
|
|
|
|
// Retrieve makes a request to a Url and resturns
|
|
// the response as []byte/error. This function is
|
|
// available to use directly, but in most implementations
|
|
// using the "Visit" receiver of the History struct will
|
|
// be better.
|
|
func Retrieve(u Url) ([]byte, error) {
|
|
nullRes := make([]byte, 0)
|
|
timeOut := time.Duration(5) * time.Second
|
|
|
|
if u.Host == "" || u.Port == "" {
|
|
return nullRes, errors.New("Incomplete request url")
|
|
}
|
|
|
|
addr := u.Host + ":" + u.Port
|
|
|
|
conn, err := net.DialTimeout("tcp", addr, timeOut)
|
|
if err != nil {
|
|
return nullRes, err
|
|
}
|
|
|
|
send := u.Resource + "\n"
|
|
if u.Scheme == "http" || u.Scheme == "https" {
|
|
send = u.Gophertype
|
|
}
|
|
|
|
_, err = conn.Write([]byte(send))
|
|
if err != nil {
|
|
return nullRes, err
|
|
}
|
|
|
|
result, err := ioutil.ReadAll(conn)
|
|
if err != nil {
|
|
return nullRes, err
|
|
}
|
|
|
|
return result, err
|
|
}
|
|
|
|
// Visit is a high level combination of a few different
|
|
// types that makes it easy to create a Url, make a request
|
|
// to that Url, and add the response and Url to a View.
|
|
// Returns a copy of the view and an error (or nil).
|
|
func Visit(addr, openhttp string) (View, error) {
|
|
u, err := MakeUrl(addr)
|
|
if err != nil {
|
|
return View{}, err
|
|
}
|
|
|
|
if u.Gophertype == "h" {
|
|
if res, tf := isWebLink(u.Resource); tf && strings.ToUpper(openhttp) == "TRUE" {
|
|
err := OpenBrowser(res)
|
|
if err != nil {
|
|
return View{}, err
|
|
}
|
|
|
|
return View{}, fmt.Errorf("")
|
|
}
|
|
}
|
|
|
|
text, err := Retrieve(u)
|
|
if err != nil {
|
|
return View{}, err
|
|
}
|
|
|
|
var pageContent []string
|
|
if u.IsBinary && u.Gophertype != "7" {
|
|
pageContent = []string{string(text)}
|
|
} else {
|
|
pageContent = strings.Split(string(text), "\n")
|
|
}
|
|
|
|
return MakeView(u, pageContent), nil
|
|
}
|
|
|
|
func getType(t string) string {
|
|
if val, ok := types[t]; ok {
|
|
return val
|
|
}
|
|
|
|
return "???"
|
|
}
|
|
|
|
func isWebLink(resource string) (string, bool) {
|
|
split := strings.SplitN(resource, ":", 2)
|
|
if first := strings.ToUpper(split[0]); first == "URL" && len(split) > 1 {
|
|
return split[1], true
|
|
}
|
|
return "", false
|
|
}
|