bombadillo/gopher/gopher.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
}