Skip to content

Commit

Permalink
feat(feed): add feed methods to lib backed by registry
Browse files Browse the repository at this point in the history
  • Loading branch information
b5 committed Jan 24, 2020
1 parent 899b2a0 commit 53e6eb3
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 0 deletions.
3 changes: 3 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ func NewServerRoutes(s Server) *http.ServeMux {
sh := NewSearchHandlers(s.Instance)
m.Handle("/search", s.middleware(sh.SearchHandler))

fh := NewFeedHandlers(s.Instance)
m.Handle("/feed/home", s.middleware(fh.HomeHandler))

rh := NewRootHandler(dsh, ph)
m.Handle("/", s.datasetRefMiddleware(s.middleware(rh.Handler)))

Expand Down
45 changes: 45 additions & 0 deletions api/feed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package api

import (
"net/http"

util "github.com/qri-io/apiutil"
"github.com/qri-io/dataset"
"github.com/qri-io/qri/lib"
)

// FeedHandlers provides HTTP API handlers for fetching content
// from the qri network
type FeedHandlers struct {
lib.FeedMethods
}

// NewFeedHandlers allocates a FeedHandlers pointer
func NewFeedHandlers(inst *lib.Instance) *FeedHandlers {
req := lib.NewFeedMethods(inst)
return &FeedHandlers{*req}
}

// HomeHandler shows popular content across the network
func (h *FeedHandlers) HomeHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "OPTIONS":
util.EmptyOkHandler(w, r)
case "GET":
h.homeHandler(w, r)
default:
util.NotFoundHandler(w, r)
}
}

func (h *FeedHandlers) homeHandler(w http.ResponseWriter, r *http.Request) {
res := map[string][]*dataset.Dataset{}
p := false
if err := h.Home(&p, &res); err != nil {
log.Infof("home error: %s", err.Error())
util.WriteErrResponse(w, http.StatusInternalServerError, err)
return
}

util.WriteResponse(w, res)
}
61 changes: 61 additions & 0 deletions lib/feed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package lib

import (
"context"
"fmt"

"github.com/qri-io/dataset"
)

// FeedMethods enapsulates functions for accessing feeds of content from the
// network. For example: a list of popular datasets is a feed.
type FeedMethods struct {
inst *Instance
}

// NewFeedMethods creates a feed instance
func NewFeedMethods(inst *Instance) *FeedMethods {
m := &FeedMethods{
inst: inst,
}

return m
}

// CoreRequestsName specifies this is a Methods object
func (m *FeedMethods) CoreRequestsName() string {
return "feed"
}

// Home returns a listing of datasets from a number of feeds like featured and
// popular. Each feed is keyed by string in the response
func (m *FeedMethods) Home(p *bool, res *map[string][]*dataset.Dataset) error {
if m.inst.rpc != nil {
return m.inst.rpc.Call("FeedMethods.Home", p, res)
}
ctx := context.TODO()

if m.inst.registry == nil {
return fmt.Errorf("Feed isn't available without a configured registry")
}

feed, err := m.inst.registry.HomeFeed(ctx)
if err != nil {
return err
}

*res = feed
return nil
}

// Featured asks a registry for a curated list of datasets
func (m *FeedMethods) Featured(p *ListParams, res *[]*dataset.Dataset) error {
return fmt.Errorf("featured dataset feed is not yet implemented")
}

// Recent is a feed of network datasets in reverse chronological order
// it currently can only come from a registry, but could easily be assembled
// via p2p methods
func (m *FeedMethods) Recent(p *ListParams, res *[]*dataset.Dataset) error {
return fmt.Errorf("recent dataset feed is not yet implemented")
}
1 change: 1 addition & 0 deletions lib/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func Receivers(inst *Instance) []Methods {

return []Methods{
NewDatasetRequestsInstance(inst),
NewFeedMethods(inst),
NewRegistryClientMethods(inst),
NewRemoteMethods(inst),
NewLogRequests(node, nil),
Expand Down
45 changes: 45 additions & 0 deletions registry/regclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
package regclient

import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"

"github.com/qri-io/dataset"
)

var (
Expand Down Expand Up @@ -38,3 +44,42 @@ type Config struct {
func NewClient(cfg *Config) *Client {
return &Client{cfg, HTTPClient}
}

// HomeFeed fetches the first page of featured & recent feeds in one call
func (c *Client) HomeFeed(ctx context.Context) (map[string][]*dataset.Dataset, error) {
if c.cfg.Location == "" {
return nil, ErrNoRegistry
}

// TODO (b5) - update registry endpoint name
req, err := http.NewRequest("GET", fmt.Sprintf("%s/dataset_summary/splash", c.cfg.Location), nil)
if err != nil {
return nil, err
}

res, err := c.httpClient.Do(req)
if err != nil {
if strings.Contains(err.Error(), "no such host") {
return nil, ErrNoRegistry
}
return nil, err
}
// add response to an envelope
env := struct {
Data map[string][]*dataset.Dataset
Meta struct {
Error string
Status string
Code int
}
}{}

if err := json.NewDecoder(res.Body).Decode(&env); err != nil {
return nil, err
}

if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("error %d: %s", res.StatusCode, env.Meta.Error)
}
return env.Data, nil
}

0 comments on commit 53e6eb3

Please sign in to comment.