Added counting

Changed Count post URL
Archiving crashes now removes crashes that match the archive
This commit is contained in:
Caleb Gardner
2024-06-12 02:17:26 -05:00
parent df3fe83c5f
commit e3af23873f
6 changed files with 157 additions and 16 deletions
+17 -2
View File
@@ -118,11 +118,26 @@ If an error status code is returned then the body will be as follows.
### Count
API Key must have the `Count` permission.
API Key must have the `count` permission.
Request:
> POST: /count/{uuid}
> POST: /count
```json
{
id: "uuid", // Should be an empty string on first request. If invalid or too old, a new UUID will be returned.
platform: "web"
}
```
Returns:
```json
{
id: "uuid"
}
```
### User Count
+34 -1
View File
@@ -4,6 +4,7 @@ import (
"encoding/json"
"log"
"net/http"
"strings"
)
type ArchivedCrash struct {
@@ -163,6 +164,38 @@ func (b *Backend) actualCrashArchive(w http.ResponseWriter, ap App, toArchive Ar
}
err := crash.Archive(toArchive)
if err != nil {
log.Println()
log.Println("error archive crash:", err)
return
}
first, _, _ := strings.Cut(toArchive.Stack, "\n")
crashes, err := crash.Find(map[string]any{"error": toArchive.Error, "firstLine": first})
if err == ErrNotFound {
return
} else if err != nil {
ReturnError(w, http.StatusInternalServerError, "internal", "Server error")
return
}
for _, c := range crashes {
ogLen := len(c.Individual)
for i := 0; i < len(c.Individual); i++ {
ind := c.Individual[i]
if ind.Stack == toArchive.Stack {
if toArchive.Platform == "all" || toArchive.Platform == ind.Platform {
c.Individual = append(c.Individual[:i], c.Individual[i+1:]...)
i--
}
}
}
if len(c.Individual) == 0 {
err = crash.Remove(c.ID)
if err != nil {
log.Println("error removing empty crash report:", err)
}
} else if len(c.Individual) < ogLen {
err = crash.PartUpdate(c.ID, map[string]any{"individual": c.Individual})
if err != nil {
log.Println("error updating individual crash reports:", err)
}
}
}
}
+6 -3
View File
@@ -45,7 +45,7 @@ func NewBackend(keyTable Table[ApiKey], apps ...App) (*Backend, error) {
}
}
if hasLog {
b.m.HandleFunc("POST /count/{uuid}", b.countLog)
b.m.HandleFunc("POST /count", b.countLog)
b.m.HandleFunc("GET /count", b.getCount)
}
if hasCrash {
@@ -59,8 +59,7 @@ func NewBackend(keyTable Table[ApiKey], apps ...App) (*Backend, error) {
func (b *Backend) cleanupLoop() {
for range time.Tick(24 * time.Hour) {
oldTim := time.Now().Add(-30 * 24 * time.Hour)
old := (oldTim.Year() * 10000) + (int(oldTim.Month()) * 100) + oldTim.Day()
old := getDate(time.Now().Add(-30 * 24 * time.Hour))
for _, a := range b.apps {
tab := a.CountTable()
if tab == nil {
@@ -71,6 +70,10 @@ func (b *Backend) cleanupLoop() {
}
}
func getDate(t time.Time) int {
return (t.Year() * 10000) + (int(t.Month()) * 100) + t.Day()
}
func (b *Backend) EnableManagementKey(managementID string) {
b.managementKeyID = managementID
b.m.HandleFunc("DELETE /{appID}/crash/{crashID}", b.managementDeleteCrash)
+16 -3
View File
@@ -1,10 +1,23 @@
package darkstorm
import (
"os"
"fmt"
"testing"
"time"
"github.com/google/uuid"
)
func TestMain(t *testing.M) {
os.Exit(t.Run())
func TestStuff(t *testing.T) {
for i := 0; i < 50; i++ {
go func() {
id, err := uuid.NewV7()
if err != nil {
fmt.Println(err)
}
fmt.Println(id.String())
}()
}
time.Sleep(3 * time.Second)
t.Fatal("end")
}
+2 -2
View File
@@ -23,13 +23,13 @@ type CountTable interface {
Table[CountLog]
// Remove all Log items that have a CountLog.Date value less then the given value.
RemoveOldLogs(date int)
// Get count. If platform is an empty string or "all", the full count should be given
Count(platform string) int
}
type CrashTable interface {
Table[CrashReport]
// Move a crash type to archive. All instances that perfectly match that appear in CrashReport.Individual should be deleted.
// If a CrashReport ends up with an empty Individual array it should also be deleted.
// Move a crash type to archive. Crashes that match the archived crash will be automatically removed from the CrashTable.
Archive(ArchivedCrash) error
IsArchived(IndividualCrash) bool
// Add the IndividualCrash report to the crash table. If a CrashReport exists that matches, then it gets added to CrashReport.Individual.
+82 -5
View File
@@ -1,20 +1,29 @@
package darkstorm
import (
"encoding/json"
"log"
"net/http"
"time"
"github.com/google/uuid"
)
type CountLog struct {
ID string
Platform string
Date int
ID string `json:"id" bson:"_id"`
Platform string `json:"platform" bson:"platform"`
Date int `json:"date" bson:"date"`
}
func (c CountLog) GetID() string {
return c.ID
}
type countLogReq struct {
ID string
Platform string
}
func (b *Backend) countLog(w http.ResponseWriter, r *http.Request) {
hdr, err := b.VerifyHeader(w, r, "count", false)
if hdr == nil {
@@ -23,7 +32,69 @@ func (b *Backend) countLog(w http.ResponseWriter, r *http.Request) {
}
return
}
//TODO
defer r.Body.Close()
var req countLogReq
err = json.NewDecoder(r.Body).Decode(&req)
if err != nil || req.Platform == "" {
ReturnError(w, http.StatusBadRequest, "invalidBody", "Bad request")
return
}
ap := b.GetApp(hdr.Key)
count := ap.CountTable()
if count == nil {
ReturnError(w, http.StatusInternalServerError, "misconfigured", "Server Misconfigured")
return
}
curDate := getDate(time.Now())
if req.ID == "" {
err = addToCountTable(w, count, req.Platform, curDate)
if err != nil {
log.Println("error adding to count table:", err)
}
return
}
l, err := count.Get(req.ID)
if err == ErrNotFound {
err = addToCountTable(w, count, req.Platform, curDate)
if err != nil {
log.Println("error adding to count table:", err)
}
return
}
if l.Date >= curDate {
json.NewEncoder(w).Encode(map[string]string{"id": req.ID})
w.WriteHeader(http.StatusCreated)
return
}
err = count.PartUpdate(req.ID, map[string]any{"date": curDate})
if err != nil {
ReturnError(w, http.StatusInternalServerError, "internal", "Server error")
return
}
json.NewEncoder(w).Encode(map[string]string{"id": req.ID})
w.WriteHeader(http.StatusCreated)
}
func addToCountTable(w http.ResponseWriter, c CountTable, platform string, curDate int) error {
id, err := uuid.NewV7()
if err != nil {
log.Println("error generating new log UUID:", err)
ReturnError(w, http.StatusInternalServerError, "internal", "Server error")
return err
}
err = c.Insert(CountLog{
ID: id.String(),
Platform: platform,
Date: curDate,
})
if err != nil {
log.Println("error inserting new count log:", err)
ReturnError(w, http.StatusInternalServerError, "internal", "Server error")
return err
}
json.NewEncoder(w).Encode(map[string]string{"id": id.String()})
w.WriteHeader(http.StatusCreated)
return nil
}
func (b *Backend) getCount(w http.ResponseWriter, r *http.Request) {
@@ -44,5 +115,11 @@ func (b *Backend) getCount(w http.ResponseWriter, r *http.Request) {
} else {
ap = b.GetApp(hdr.Key)
}
//TODO
count := ap.CountTable()
if count == nil {
ReturnError(w, http.StatusBadRequest, "badRequest", "Trying to get user count on app that doesn't have a count table")
return
}
out := count.Count(r.URL.Query().Get("platform"))
json.NewEncoder(w).Encode(map[string]int{"count": out})
}