Explorar o código

Add support for the `continuation` parameter and result for Google Reader API ID calls

Support the ``continuation parameter and result for Google Reader API ID calls. Allows clients to support paging of results / fetching additional results when the number of entries exceed the limit parameter passed in by the client.
Dave Marquard %!s(int64=3) %!d(string=hai) anos
pai
achega
74b69a4c7c
Modificáronse 2 ficheiros con 72 adicións e 9 borrados
  1. 70 8
      googlereader/handler.go
  2. 2 1
      googlereader/response.go

+ 70 - 8
googlereader/handler.go

@@ -88,8 +88,10 @@ const (
 	ParamTitle = "t"
 	// ParamQuickAdd - name of the parameter for a URL being quick subscribed to
 	ParamQuickAdd = "quickadd"
-	// ParamDestination - name fo the parameter for the new name of a tag
+	// ParamDestination - name of the parameter for the new name of a tag
 	ParamDestination = "dest"
+	// ParamContinuation -  name of the parameter for callers to pass to receive the next page of results
+	ParamContinuation = "c"
 )
 
 // StreamType represents the possible stream types
@@ -130,6 +132,7 @@ type RequestModifiers struct {
 	FilterTargets     []Stream
 	Streams           []Stream
 	Count             int
+	Offset            int
 	SortDirection     string
 	StartTime         int64
 	StopTime          int64
@@ -185,6 +188,7 @@ func (r RequestModifiers) String() string {
 		result += fmt.Sprintf("        %v\n", s)
 	}
 	result += fmt.Sprintf("Count: %d\n", r.Count)
+	result += fmt.Sprintf("Offset: %d\n", r.Offset)
 	result += fmt.Sprintf("Sort Direction: %s\n", r.SortDirection)
 	result += fmt.Sprintf("Continuation Token: %s\n", r.ContinuationToken)
 	result += fmt.Sprintf("Start Time: %d\n", r.StartTime)
@@ -243,8 +247,9 @@ func getStreamFilterModifiers(r *http.Request) (RequestModifiers, error) {
 	}
 
 	result.Count = request.QueryIntParam(r, ParamStreamMaxItems, 0)
-	result.StartTime = int64(request.QueryIntParam(r, ParamStreamStartTime, 0))
-	result.StopTime = int64(request.QueryIntParam(r, ParamStreamStopTime, 0))
+	result.Offset = request.QueryIntParam(r, ParamContinuation, 0)
+	result.StartTime = request.QueryInt64Param(r, ParamStreamStartTime, int64(0))
+	result.StopTime = request.QueryInt64Param(r, ParamStreamStopTime, int64(0))
 	return result, nil
 }
 
@@ -1120,7 +1125,9 @@ func (h *handler) handleReadingListStream(w http.ResponseWriter, r *http.Request
 			logger.Info("[GoogleReader][ReadingListStreamIDs][ClientIP=%s] xt filter type: %#v", clientIP, s)
 		}
 	}
+	builder.WithoutStatus(model.EntryStatusRemoved)
 	builder.WithLimit(rm.Count)
+	builder.WithOffset(rm.Offset)
 	builder.WithOrder(model.DefaultSortingOrder)
 	builder.WithDirection(rm.SortDirection)
 	if rm.StartTime > 0 {
@@ -1141,15 +1148,29 @@ func (h *handler) handleReadingListStream(w http.ResponseWriter, r *http.Request
 		formattedID := strconv.FormatInt(entryID, 10)
 		itemRefs = append(itemRefs, itemRef{ID: formattedID})
 	}
-	json.OK(w, r, streamIDResponse{itemRefs})
+
+	totalEntries, err := builder.CountEntries()
+	if err != nil {
+		logger.Error("[GoogleReader][/stream/items/ids#reading-list] [ClientIP=%s] %v", clientIP, err)
+		json.ServerError(w, r, err)
+		return
+	}
+	continuation := 0
+	if len(itemRefs)+rm.Offset < totalEntries {
+		continuation = len(itemRefs) + rm.Offset
+	}
+
+	json.OK(w, r, streamIDResponse{itemRefs, continuation})
 }
 
 func (h *handler) handleStarredStream(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
 	clientIP := request.ClientIP(r)
 
 	builder := h.store.NewEntryQueryBuilder(rm.UserID)
+	builder.WithoutStatus(model.EntryStatusRemoved)
 	builder.WithStarred(true)
 	builder.WithLimit(rm.Count)
+	builder.WithOffset(rm.Offset)
 	builder.WithOrder(model.DefaultSortingOrder)
 	builder.WithDirection(rm.SortDirection)
 	if rm.StartTime > 0 {
@@ -1170,14 +1191,29 @@ func (h *handler) handleStarredStream(w http.ResponseWriter, r *http.Request, rm
 		formattedID := strconv.FormatInt(entryID, 10)
 		itemRefs = append(itemRefs, itemRef{ID: formattedID})
 	}
-	json.OK(w, r, streamIDResponse{itemRefs})
+
+	totalEntries, err := builder.CountEntries()
+	if err != nil {
+		logger.Error("[GoogleReader][/stream/items/ids#starred] [ClientIP=%s] %v", clientIP, err)
+		json.ServerError(w, r, err)
+		return
+	}
+	continuation := 0
+	if len(itemRefs)+rm.Offset < totalEntries {
+		continuation = len(itemRefs) + rm.Offset
+	}
+
+	json.OK(w, r, streamIDResponse{itemRefs, continuation})
 }
 
 func (h *handler) handleReadStream(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
 	clientIP := request.ClientIP(r)
 
 	builder := h.store.NewEntryQueryBuilder(rm.UserID)
+	builder.WithoutStatus(model.EntryStatusRemoved)
 	builder.WithStatus(model.EntryStatusRead)
+	builder.WithLimit(rm.Count)
+	builder.WithOffset(rm.Offset)
 	builder.WithOrder(model.DefaultSortingOrder)
 	builder.WithDirection(rm.SortDirection)
 	if rm.StartTime > 0 {
@@ -1198,7 +1234,19 @@ func (h *handler) handleReadStream(w http.ResponseWriter, r *http.Request, rm Re
 		formattedID := strconv.FormatInt(entryID, 10)
 		itemRefs = append(itemRefs, itemRef{ID: formattedID})
 	}
-	json.OK(w, r, streamIDResponse{itemRefs})
+
+	totalEntries, err := builder.CountEntries()
+	if err != nil {
+		logger.Error("[GoogleReader][/stream/items/ids#read] [ClientIP=%s] %v", clientIP, err)
+		json.ServerError(w, r, err)
+		return
+	}
+	continuation := 0
+	if len(itemRefs)+rm.Offset < totalEntries {
+		continuation = len(itemRefs) + rm.Offset
+	}
+
+	json.OK(w, r, streamIDResponse{itemRefs, continuation})
 }
 
 func (h *handler) handleFeedStream(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
@@ -1211,8 +1259,10 @@ func (h *handler) handleFeedStream(w http.ResponseWriter, r *http.Request, rm Re
 	}
 
 	builder := h.store.NewEntryQueryBuilder(rm.UserID)
+	builder.WithoutStatus(model.EntryStatusRemoved)
 	builder.WithFeedID(feedID)
 	builder.WithLimit(rm.Count)
+	builder.WithOffset(rm.Offset)
 	builder.WithOrder(model.DefaultSortingOrder)
 	builder.WithDirection(rm.SortDirection)
 	if rm.StartTime > 0 {
@@ -1224,7 +1274,7 @@ func (h *handler) handleFeedStream(w http.ResponseWriter, r *http.Request, rm Re
 
 	rawEntryIDs, err := builder.GetEntryIDs()
 	if err != nil {
-		logger.Error("[GoogleReader][/stream/items/ids#starred] [ClientIP=%s] %v", clientIP, err)
+		logger.Error("[GoogleReader][/stream/items/ids#feed] [ClientIP=%s] %v", clientIP, err)
 		json.ServerError(w, r, err)
 		return
 	}
@@ -1233,5 +1283,17 @@ func (h *handler) handleFeedStream(w http.ResponseWriter, r *http.Request, rm Re
 		formattedID := strconv.FormatInt(entryID, 10)
 		itemRefs = append(itemRefs, itemRef{ID: formattedID})
 	}
-	json.OK(w, r, streamIDResponse{itemRefs})
+
+	totalEntries, err := builder.CountEntries()
+	if err != nil {
+		logger.Error("[GoogleReader][/stream/items/ids#feed] [ClientIP=%s] %v", clientIP, err)
+		json.ServerError(w, r, err)
+		return
+	}
+	continuation := 0
+	if len(itemRefs)+rm.Offset < totalEntries {
+		continuation = len(itemRefs) + rm.Offset
+	}
+
+	json.OK(w, r, streamIDResponse{itemRefs, continuation})
 }

+ 2 - 1
googlereader/response.go

@@ -61,7 +61,8 @@ type itemRef struct {
 }
 
 type streamIDResponse struct {
-	ItemRefs []itemRef `json:"itemRefs"`
+	ItemRefs     []itemRef `json:"itemRefs"`
+	Continuation int       `json:"continuation,omitempty,string"`
 }
 
 type tagsResponse struct {