Fixed JSON handling/output for the client library

This commit is contained in:
James Mills 2017-06-23 00:08:43 -07:00
parent 9905aa689a
commit 97f53e068d
No known key found for this signature in database
GPG Key ID: AC4C014F1440EBD6
2 changed files with 55 additions and 25 deletions

View File

@ -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.

View File

@ -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))