0.1.38 gateway

This commit is contained in:
ponzischeme89
2026-08-14 09:40:03 +12:00
parent abc392d30b
commit 5e2ed3d12e
2847 changed files with 1072928 additions and 3783 deletions
+95
View File
@@ -119,6 +119,101 @@ type JourneyActionStat struct {
Journeys int64 `json:"journeys"`
}
// ViewStats is app use measured at the launcher, rather than media playback. A visit is a
// foreground journey that reached home; a viewer is one signed-in profile in that window.
type ViewStats struct {
Visits int64 `json:"visits"`
Viewers int64 `json:"viewers"`
}
type ViewBucket struct {
Label string `json:"label"`
Visits int64 `json:"visits"`
Viewers int64 `json:"viewers"`
}
type ViewsReport struct {
Today ViewStats `json:"today"`
LastWeek ViewStats `json:"lastWeek"`
Daily []ViewBucket `json:"daily"`
Hourly []ViewBucket `json:"hourly"`
BusiestHour string `json:"busiestHour"`
}
// ViewsReport aggregates only app launcher openings. `journey_start` remains in the
// predicate so deployments gain a useful history before clients begin sending home_open.
func (s *Store) ViewsReport(ctx context.Context, now time.Time) (ViewsReport, error) {
var out ViewsReport
location, err := time.LoadLocation("Pacific/Auckland")
if err != nil {
location = time.UTC
}
localNow := now.In(location)
todayStart := time.Date(localNow.Year(), localNow.Month(), localNow.Day(), 0, 0, 0, 0, location).UTC()
// The dashboard comparison ends at the same elapsed point in last week's day, not at
// midnight, so a morning view is compared with another morning rather than a full day.
lastWeekStart := todayStart.AddDate(0, 0, -7)
lastWeekEnd := lastWeekStart.Add(now.Sub(todayStart))
count := func(start, end time.Time) (ViewStats, error) {
var value ViewStats
err := s.pool.QueryRow(ctx, `SELECT count(DISTINCT journey_id), count(DISTINCT emby_user_id)
FROM journey_events WHERE occurred_at >= $1 AND occurred_at < $2
AND action IN ('home_open', 'journey_start')`, start, end).Scan(&value.Visits, &value.Viewers)
return value, err
}
if out.Today, err = count(todayStart, now); err != nil {
return out, fmt.Errorf("store: today views: %w", err)
}
if out.LastWeek, err = count(lastWeekStart, lastWeekEnd); err != nil {
return out, fmt.Errorf("store: last-week views: %w", err)
}
rows, err := s.pool.Query(ctx, `SELECT to_char(timezone('Pacific/Auckland', occurred_at), 'YYYY-MM-DD'),
count(DISTINCT journey_id), count(DISTINCT emby_user_id)
FROM journey_events WHERE occurred_at >= $1 AND action IN ('home_open', 'journey_start')
GROUP BY 1 ORDER BY 1`, todayStart.AddDate(0, 0, -29))
if err != nil {
return out, fmt.Errorf("store: daily views: %w", err)
}
for rows.Next() {
var bucket ViewBucket
if err := rows.Scan(&bucket.Label, &bucket.Visits, &bucket.Viewers); err != nil {
rows.Close()
return out, err
}
out.Daily = append(out.Daily, bucket)
}
if err := rows.Err(); err != nil {
rows.Close()
return out, err
}
rows.Close()
rows, err = s.pool.Query(ctx, `SELECT to_char(timezone('Pacific/Auckland', occurred_at), 'HH24:00'),
count(DISTINCT journey_id), count(DISTINCT emby_user_id)
FROM journey_events WHERE occurred_at >= $1 AND occurred_at < $2 AND action IN ('home_open', 'journey_start')
GROUP BY 1 ORDER BY 1`, todayStart, now)
if err != nil {
return out, fmt.Errorf("store: hourly views: %w", err)
}
var busiestVisits int64
for rows.Next() {
var bucket ViewBucket
if err := rows.Scan(&bucket.Label, &bucket.Visits, &bucket.Viewers); err != nil {
rows.Close()
return out, err
}
out.Hourly = append(out.Hourly, bucket)
if bucket.Visits > busiestVisits {
busiestVisits = bucket.Visits
out.BusiestHour = bucket.Label
}
}
if err := rows.Err(); err != nil {
rows.Close()
return out, err
}
return out, nil
}
// Event kinds. Impressions say a row was drawn; focus says the remote actually landed
// on it and for how long; select says something was opened from it.
const (