diff options
-rw-r--r-- | entry.go | 21 | ||||
-rw-r--r-- | main.go | 45 | ||||
-rw-r--r-- | track.js | 2 |
3 files changed, 59 insertions, 9 deletions
@@ -20,9 +20,9 @@ CREATE TABLE IF NOT EXISTS entries ( );` type Entry struct { - Id int `db:"id"` + Id int `json:"-" db:"id"` Location string `json:"location" db:"location"` - Referrer string `json:"referrer" db:"referrer"` + Referrer string `json:"referrer,omitempty" db:"referrer"` StartedAt time.Time `json:"startedAt" db:"started_at"` TimeSpent int `json:"timeSpent" db:"time_spent"` ScrolledTo float32 `json:"scrolledTo" db:"scrolled_to"` @@ -36,13 +36,11 @@ func InitEntries() { log.Println("Defaulting to STATSDB=./stats.db") file = "./stats.db" } - var err error db, err = sqlx.Connect("sqlite3", file) if err != nil { log.Fatalln(err) } - _, err = db.Exec(schema) if err != nil { log.Fatalln("Could not initialize schema") @@ -61,3 +59,18 @@ func InsertEntry(entry *Entry) error { _, err := db.NamedExec(query, entry) return err } + +func CountEntries() (count uint, err error) { + err = db.Get(&count, "SELECT COUNT(*) FROM entries;") + return +} + +func AllEntries() (entries []Entry, err error) { + err = db.Select(&entries, "SELECT * FROM entries;") + return +} + +func ListEntries(from, count uint) (entries []Entry, err error) { + err = db.Select(&entries, "SELECT * FROM entries LIMIT ? OFFSET ?;", count, from) + return +} @@ -6,6 +6,7 @@ import ( "log" "net/http" "os" + "strconv" "github.com/gorilla/mux" ) @@ -16,14 +17,14 @@ var content embed.FS func handleEntryOptions(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS") + w.Header().Set("Access-Control-Allow-Methods", "OPTIONS, POST, GET") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") w.WriteHeader(http.StatusNoContent) } func handleEntryPost(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS") + w.Header().Set("Access-Control-Allow-Methods", "OPTIONS, POST, GET") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") var entry Entry err := json.NewDecoder(r.Body).Decode(&entry) @@ -39,10 +40,46 @@ func handleEntryPost(w http.ResponseWriter, r *http.Request) { log.Println("New entry for", entry.Location) } +type EntriesPage struct { + Total uint `json:"total"` + Offset uint `json:"offset"` + Size uint `json:"size"` + Entries []Entry `json:"entries"` +} + + +func handleEntryGet(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "OPTIONS, POST, GET") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + from64, _ := strconv.ParseUint(r.FormValue("from"), 10, 32) + from := uint(from64) + count, err := CountEntries() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + entries, err := ListEntries(from, 1000) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if entries == nil { + entries = []Entry{} + } + page := EntriesPage{Total: count, Offset: from, Size: uint(len(entries)), Entries: entries} + err = json.NewEncoder(w).Encode(&page) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + func handleRequests() { router := mux.NewRouter() - router.HandleFunc("/entry", handleEntryPost).Methods("POST") - router.HandleFunc("/entry", handleEntryOptions).Methods("OPTIONS") + router.HandleFunc("/entries", handleEntryOptions).Methods("OPTIONS") + router.HandleFunc("/entries", handleEntryPost).Methods("POST") + router.HandleFunc("/entries", handleEntryGet).Methods("GET") router.PathPrefix("/").Handler(http.FileServer(http.FS(content))) log.Fatal(http.ListenAndServe(configure(), router)) } @@ -12,7 +12,7 @@ scrolledTo = Math.max(scrolledTo, window.scrollY + window.innerHeight) }, false) window.addEventListener("beforeunload", ()=>{ - navigator.sendBeacon("https://stats.ignore.pl/entry", JSON.stringify({ + navigator.sendBeacon("http://stats.ignore.pl/entries", JSON.stringify({ "location": document.location.href, "referrer": document.referrer, "startedAt": startedAt, |