Fixed JSON handling/output for the client library
This commit is contained in:
parent
9905aa689a
commit
97f53e068d
60
gopher.go
60
gopher.go
|
@ -99,11 +99,6 @@ var (
|
||||||
// ItemType represents the type of an item
|
// ItemType represents the type of an item
|
||||||
type ItemType byte
|
type ItemType byte
|
||||||
|
|
||||||
// MarshalJSON returns a JSON mashaled byte array of an ItemType
|
|
||||||
func (it ItemType) MarshalJSON() ([]byte, error) {
|
|
||||||
return []byte(fmt.Sprintf("%q", string(byte(it)))), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a human friendly represation of an ItemType
|
// Return a human friendly represation of an ItemType
|
||||||
func (it ItemType) String() string {
|
func (it ItemType) String() string {
|
||||||
switch it {
|
switch it {
|
||||||
|
@ -152,14 +147,33 @@ func (it ItemType) String() string {
|
||||||
|
|
||||||
// Item describes an entry in a directory listing.
|
// Item describes an entry in a directory listing.
|
||||||
type Item struct {
|
type Item struct {
|
||||||
Type ItemType
|
Type ItemType `json:"type"`
|
||||||
Description string
|
Description string `json:"description"`
|
||||||
Selector string
|
Selector string `json:"selector"`
|
||||||
Host string
|
Host string `json:"host"`
|
||||||
Port int
|
Port int `json:"port"`
|
||||||
|
|
||||||
// non-standard extensions (ignored by standard clients)
|
// non-standard extensions (ignored by standard clients)
|
||||||
Extras []string
|
Extras []string `json:"extras"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON serializes an Item into a JSON structure
|
||||||
|
func (i Item) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Selector string `json:"selector"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
Extras []string `json:"extras"`
|
||||||
|
}{
|
||||||
|
Type: string(i.Type),
|
||||||
|
Description: i.Description,
|
||||||
|
Selector: i.Selector,
|
||||||
|
Host: i.Host,
|
||||||
|
Port: i.Port,
|
||||||
|
Extras: i.Extras,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalText serializes an Item into an array of bytes
|
// MarshalText serializes an Item into an array of bytes
|
||||||
|
@ -241,7 +255,9 @@ func (i *Item) isDirectoryLike() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Directory representes a Gopher Menu of Items
|
// Directory representes a Gopher Menu of Items
|
||||||
type Directory []Item
|
type Directory struct {
|
||||||
|
Items []Item `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
// ToJSON returns the Directory as JSON bytes
|
// ToJSON returns the Directory as JSON bytes
|
||||||
func (d *Directory) ToJSON() ([]byte, error) {
|
func (d *Directory) ToJSON() ([]byte, error) {
|
||||||
|
@ -252,7 +268,7 @@ func (d *Directory) ToJSON() ([]byte, error) {
|
||||||
// ToText returns the Directory as UTF-8 encoded bytes
|
// ToText returns the Directory as UTF-8 encoded bytes
|
||||||
func (d *Directory) ToText() ([]byte, error) {
|
func (d *Directory) ToText() ([]byte, error) {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
for _, i := range *d {
|
for _, i := range d.Items {
|
||||||
val, err := i.MarshalText()
|
val, err := i.MarshalText()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -368,25 +384,25 @@ func (i *Item) FetchFile() (io.Reader, error) {
|
||||||
// Calling this on an Item whose type is not DIRECTORY will return an error.
|
// Calling this on an Item whose type is not DIRECTORY will return an error.
|
||||||
func (i *Item) FetchDirectory() (Directory, error) {
|
func (i *Item) FetchDirectory() (Directory, error) {
|
||||||
if !i.isDirectoryLike() {
|
if !i.isDirectoryLike() {
|
||||||
return nil, errors.New("cannot fetch a file as a directory")
|
return Directory{}, errors.New("cannot fetch a file as a directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := net.Dial("tcp", i.Host+":"+strconv.Itoa(i.Port))
|
conn, err := net.Dial("tcp", i.Host+":"+strconv.Itoa(i.Port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return Directory{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Write([]byte(i.Selector + CRLF))
|
_, err = conn.Write([]byte(i.Selector + CRLF))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return Directory{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var d Directory
|
|
||||||
|
|
||||||
reader := bufio.NewReader(conn)
|
reader := bufio.NewReader(conn)
|
||||||
scanner := bufio.NewScanner(reader)
|
scanner := bufio.NewScanner(reader)
|
||||||
scanner.Split(bufio.ScanLines)
|
scanner.Split(bufio.ScanLines)
|
||||||
|
|
||||||
|
var items []Item
|
||||||
|
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := strings.Trim(scanner.Text(), "\r\n")
|
line := strings.Trim(scanner.Text(), "\r\n")
|
||||||
|
|
||||||
|
@ -398,16 +414,16 @@ func (i *Item) FetchDirectory() (Directory, error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
var i Item
|
item := Item{}
|
||||||
err := i.parse(line)
|
err := item.parse(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error parsing %q: %q", line, err)
|
log.Printf("Error parsing %q: %q", line, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
d = append(d, i)
|
items = append(items, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
return d, nil
|
return Directory{items}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request repsesnts an inbound request to a listening server.
|
// Request repsesnts an inbound request to a listening server.
|
||||||
|
|
|
@ -43,13 +43,27 @@ func TestGet(t *testing.T) {
|
||||||
|
|
||||||
t.Logf("res: %s", string(b))
|
t.Logf("res: %s", string(b))
|
||||||
|
|
||||||
assert.Len(res.Dir, 1)
|
assert.Len(res.Dir.Items, 1)
|
||||||
|
|
||||||
assert.Equal(res.Dir[0].Type, gopher.INFO)
|
assert.Equal(res.Dir.Items[0].Type, gopher.INFO)
|
||||||
assert.Equal(res.Dir[0].Description, "Hello World!")
|
assert.Equal(res.Dir.Items[0].Description, "Hello World!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileServer(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
res, err := gopher.Get("gopher://localhost:7000/")
|
||||||
|
assert.Nil(err)
|
||||||
|
assert.Len(res.Dir.Items, 5)
|
||||||
|
|
||||||
|
json, err := res.Dir.ToJSON()
|
||||||
|
assert.Nil(err)
|
||||||
|
|
||||||
|
assert.JSONEq(string(json), `{"items":[{"type":"0","description":"LICENSE","selector":"LICENSE","host":"127.0.0.1","port":7000,"extras":null},{"type":"0","description":"README.md","selector":"README.md","host":"127.0.0.1","port":7000,"extras":null},{"type":"1","description":"examples","selector":"examples","host":"127.0.0.1","port":7000,"extras":null},{"type":"0","description":"gopher.go","selector":"gopher.go","host":"127.0.0.1","port":7000,"extras":null},{"type":"0","description":"gopher_test.go","selector":"gopher_test.go","host":"127.0.0.1","port":7000,"extras":null}]}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
gopher.Handle("/", gopher.FileServer(gopher.Dir(".")))
|
||||||
gopher.HandleFunc("/hello", hello)
|
gopher.HandleFunc("/hello", hello)
|
||||||
go func() {
|
go func() {
|
||||||
log.Fatal(gopher.ListenAndServe("localhost:7000", nil))
|
log.Fatal(gopher.ListenAndServe("localhost:7000", nil))
|
||||||
|
|
Loading…
Reference in New Issue