WIP: request specific number of URLs

Amolith created

Change summary

helperfuncs.go | 43 +++++++++++++++++++++++++++++++++++++++++++
readHandler.go | 45 +++++++++++++++++++++------------------------
2 files changed, 64 insertions(+), 24 deletions(-)

Detailed changes

helperfuncs.go 🔗

@@ -5,6 +5,7 @@
 package main
 
 import (
+	"errors"
 	"fmt"
 	"log"
 	"strings"
@@ -28,6 +29,48 @@ func (m model) create(name string, url string) string {
 	return fmt.Sprint("URL mapped to ", name, "\n")
 }
 
+// read() accepts a start variable for the first link in a set (implying reverse
+// iteration), an end variable for the last link in a set (implying forward
+// iteration), and a count variable for the number of requested entries. The
+// requested set is returned as JSON.
+func (m model) read(start string, end string, count int) (map[string]string, error) {
+	links := make(map[string]string)
+
+	if !(count > 0) {
+		return nil, errors.New("Count parameter is required")
+	}
+
+	err := m.database.View(func(txn *badger.Txn) error {
+		opts := badger.DefaultIteratorOptions
+		opts.PrefetchSize = 10
+		if start != "" && end == "" {
+			opts.Reverse = true
+		}
+		iterator := txn.NewIterator(opts)
+		if start != "" && end == "" {
+			iterator.Seek([]byte(end))
+		} else if start == "" && end != "" {
+			iterator.Seek([]byte(start))
+		}
+		defer iterator.Close()
+		for iterator.Rewind(); iterator.Valid(); iterator.Next() {
+			err := iterator.Item().Value(func(v []byte) error {
+				links[string(iterator.Item().Key())] = string(v)
+				return nil
+			})
+			if err != nil {
+				return err
+			}
+		}
+		return nil
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return links, nil
+}
+
 // Update modifies a shortened link
 func (m model) update(name string, url string, oldName string) string {
 	m.create(name, url)

readHandler.go 🔗

@@ -8,9 +8,8 @@ import (
 	"encoding/json"
 	"log"
 	"net/http"
+	"strconv"
 	"strings"
-
-	"github.com/dgraph-io/badger/v3"
 )
 
 func (m model) readHandler(writer http.ResponseWriter, request *http.Request) {
@@ -18,38 +17,36 @@ func (m model) readHandler(writer http.ResponseWriter, request *http.Request) {
 	token = strings.TrimPrefix(token, "Bearer ")
 
 	if token != m.AccessToken {
-		http.Error(writer, "401 Unauthorized: You do not have permission to view shortlinks", 403)
+		http.Error(writer, "403 Forbidden: You do not have permission to view shortlinks", 403)
 		return
 	}
 
-	links := make(map[string]string)
-
-	err := m.database.View(func(txn *badger.Txn) error {
-		opts := badger.DefaultIteratorOptions
-		opts.PrefetchSize = 10
-		iterator := txn.NewIterator(opts)
-		defer iterator.Close()
-		for iterator.Rewind(); iterator.Valid(); iterator.Next() {
-			item := iterator.Item()
-			k := item.Key()
-			err := item.Value(func(v []byte) error {
-				links[string(k)] = string(v)
-				return nil
-			})
-			if err != nil {
-				return err
-			}
-		}
-		return nil
-	})
+	query := request.URL.Query()
+
+	start := query.Get("start")
+	end := query.Get("end")
+	countQuery := query.Get("count")
+	if countQuery == "" {
+		http.Error(writer, "400 Bad Request: Count parameter is required", 400)
+	}
+
+	count, err := strconv.Atoi(countQuery)
 	if err != nil {
-		log.Println(err)
+		http.Error(writer, err.Error(), 400)
+		return
+	}
+
+	links, err := m.read(start, end, count)
+	if err != nil {
+		http.Error(writer, err.Error(), 400)
+		return
 	}
 
 	json, err := json.Marshal(links)
 	if err != nil {
 		log.Println(err)
 	}
+
 	_, err = writer.Write(json)
 	if err != nil {
 		log.Println(err)