Compare commits

...

7 Commits

Author SHA1 Message Date
Matthew Kilgore
e47a7ff6f2 Switch to minutes for uptime, remove duplicate event on startup 2025-07-12 20:42:12 -04:00
Matthew Kilgore
57385f9ada Some cleanup 2025-07-12 16:53:13 -04:00
Matthew Kilgore
94df40b718 Even better logic for scheduling the analytics (hopefully) 2025-07-12 16:50:31 -04:00
Matthew Kilgore
c9cb1abdd9 Better analytics scheduling 2025-07-12 16:46:03 -04:00
Matthew Kilgore
76d7b3d6ca Merge branch 'main' into mk/daily-analytics
# Conflicts:
#	backend/app/api/main.go
2025-07-12 16:38:17 -04:00
Matthew Kilgore
e5ba3bb10e Clean up error handling, add uptime to analytics 2025-07-12 11:48:55 -04:00
Matthew Kilgore
a73d5887c7 Send analytics daily 2025-07-12 11:36:30 -04:00
2 changed files with 34 additions and 6 deletions

View File

@@ -6,8 +6,10 @@ import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/pressly/goose/v3"
"github.com/sysadminsmedia/homebox/backend/internal/sys/analytics"
"net/http"
"strings"
"time"
"github.com/hay-kot/httpkit/errchain"
"github.com/hay-kot/httpkit/graceful"
@@ -98,7 +100,6 @@ func run(cfg *config.Config) error {
// =========================================================================
// Initialize Database & Repos
setupStorageDir(cfg)
if strings.ToLower(cfg.Database.Driver) == "postgres" {
@@ -196,5 +197,28 @@ func run(cfg *config.Config) error {
// Start Reoccurring Tasks
registerRecurringTasks(app, cfg, runner)
// Send analytics if enabled at around midnight UTC
if cfg.Options.AllowAnalytics {
analyticsTime := time.Second
runner.AddPlugin(NewTask("send-analytics", analyticsTime, func(ctx context.Context) {
for {
now := time.Now().UTC()
nextMidnight := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 0, 0, 0, time.UTC)
dur := time.Until(nextMidnight)
analyticsTime = dur
select {
case <-ctx.Done():
return
case <-time.After(dur):
log.Debug().Msg("running send analytics")
err := analytics.Send(version, build())
if err != nil {
log.Error().Err(err).Msg("failed to send analytics")
}
}
}
}))
}
return runner.Start(context.Background())
}

View File

@@ -11,6 +11,8 @@ import (
"github.com/rs/zerolog/log"
)
var startTime = time.Now()
type Data struct {
Domain string `json:"domain"`
Name string `json:"name"`
@@ -18,7 +20,7 @@ type Data struct {
Props map[string]interface{} `json:"props"`
}
func Send(version, buildInfo string) {
func Send(version, buildInfo string) error {
hostData, _ := host.Info()
analytics := Data{
Domain: "homebox.software",
@@ -32,22 +34,23 @@ func Send(version, buildInfo string) {
"platform_version": hostData.PlatformVersion,
"kernel_arch": hostData.KernelArch,
"virt_type": hostData.VirtualizationSystem,
"uptime_min": time.Since(startTime).Minutes(),
},
}
jsonBody, err := json.Marshal(analytics)
if err != nil {
log.Error().Err(err).Msg("failed to marshal analytics data")
return
return err
}
bodyReader := bytes.NewReader(jsonBody)
req, err := http.NewRequest("POST", "https://a.sysadmins.zone/api/event", bodyReader)
if err != nil {
log.Error().Err(err).Msg("failed to create analytics request")
return
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "Homebox/"+version+"/"+buildInfo+" (https://homebox.software)")
req.Header.Set("User-Agent", "Homebox/"+version+"/(https://homebox.software)")
client := &http.Client{
Timeout: 10 * time.Second,
@@ -56,7 +59,7 @@ func Send(version, buildInfo string) {
res, err := client.Do(req)
if err != nil {
log.Error().Err(err).Msg("failed to send analytics request")
return
return err
}
defer func() {
@@ -65,4 +68,5 @@ func Send(version, buildInfo string) {
log.Error().Err(err).Msg("failed to close response body")
}
}()
return nil
}