2024-10-23 08:55:19 -04:00
|
|
|
package alerting
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "embed"
|
2024-10-30 09:49:45 -04:00
|
|
|
"errors"
|
2024-10-23 08:55:19 -04:00
|
|
|
"html/template"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
2024-11-03 07:19:03 -05:00
|
|
|
"dynatron.me/x/stillbox/pkg/config"
|
|
|
|
"dynatron.me/x/stillbox/pkg/database"
|
2024-11-03 08:09:49 -05:00
|
|
|
"dynatron.me/x/stillbox/pkg/talkgroups"
|
2024-10-23 08:55:19 -04:00
|
|
|
|
2024-10-31 00:10:53 -04:00
|
|
|
"dynatron.me/x/stillbox/internal/common"
|
2024-10-30 09:49:45 -04:00
|
|
|
"dynatron.me/x/stillbox/internal/jsontime"
|
2024-10-23 08:55:19 -04:00
|
|
|
"dynatron.me/x/stillbox/internal/trending"
|
|
|
|
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
//go:embed stats.html
|
|
|
|
var statsTemplateFile string
|
|
|
|
|
2024-10-25 15:34:59 -04:00
|
|
|
type stats interface {
|
|
|
|
PrivateRoutes(chi.Router)
|
|
|
|
}
|
|
|
|
|
2024-10-23 08:55:19 -04:00
|
|
|
var (
|
|
|
|
funcMap = template.FuncMap{
|
2024-10-31 00:10:53 -04:00
|
|
|
"f": common.FmtFloat,
|
2024-10-30 09:49:45 -04:00
|
|
|
"dict": func(values ...interface{}) (map[string]interface{}, error) {
|
|
|
|
if len(values)%2 != 0 {
|
|
|
|
return nil, errors.New("invalid dict call")
|
|
|
|
}
|
|
|
|
dict := make(map[string]interface{}, len(values)/2)
|
|
|
|
for i := 0; i < len(values); i += 2 {
|
|
|
|
key, ok := values[i].(string)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("dict keys must be strings")
|
|
|
|
}
|
|
|
|
dict[key] = values[i+1]
|
|
|
|
}
|
|
|
|
return dict, nil
|
|
|
|
},
|
|
|
|
"formTime": func(t jsontime.Time) string {
|
|
|
|
return time.Time(t).Format("2006-01-02T15:04")
|
|
|
|
},
|
|
|
|
"ago": func(s string) (string, error) {
|
|
|
|
d, err := time.ParseDuration(s)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return time.Now().Add(-d).Format("2006-01-02T15:04"), nil
|
|
|
|
},
|
2024-10-23 08:55:19 -04:00
|
|
|
}
|
|
|
|
statTmpl = template.Must(template.New("stats").Funcs(funcMap).Parse(statsTemplateFile))
|
|
|
|
)
|
|
|
|
|
2024-10-25 15:34:59 -04:00
|
|
|
func (as *alerter) PrivateRoutes(r chi.Router) {
|
2024-10-30 09:49:45 -04:00
|
|
|
r.Get("/tgstats", as.tgStatsHandler)
|
|
|
|
r.Post("/tgstats", as.simulateHandler)
|
2024-10-31 00:10:53 -04:00
|
|
|
r.Get("/testnotify", as.testNotifyHandler)
|
2024-10-23 08:55:19 -04:00
|
|
|
}
|
|
|
|
|
2024-10-25 15:34:59 -04:00
|
|
|
func (as *noopAlerter) PrivateRoutes(r chi.Router) {}
|
|
|
|
|
2024-10-30 09:49:45 -04:00
|
|
|
func (as *alerter) tgStatsHandler(w http.ResponseWriter, r *http.Request) {
|
2024-10-23 08:55:19 -04:00
|
|
|
ctx := r.Context()
|
|
|
|
db := database.FromCtx(ctx)
|
|
|
|
|
2024-11-04 23:41:52 -05:00
|
|
|
tgs, err := db.GetTalkgroupsWithLearnedByPackedIDs(ctx, as.packedScoredTGs())
|
2024-10-23 08:55:19 -04:00
|
|
|
if err != nil {
|
|
|
|
log.Error().Err(err).Msg("stats TG get failed")
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-11-04 23:41:52 -05:00
|
|
|
tgMap := make(map[talkgroups.ID]database.GetTalkgroupsWithLearnedByPackedIDsRow, len(tgs))
|
2024-10-23 08:55:19 -04:00
|
|
|
for _, t := range tgs {
|
2024-11-04 23:41:52 -05:00
|
|
|
tgMap[talkgroups.ID{System: uint32(t.System.ID), Talkgroup: uint32(t.Talkgroup.Tgid)}] = t
|
2024-10-23 08:55:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
renderData := struct {
|
2024-11-04 23:41:52 -05:00
|
|
|
TGs map[talkgroups.ID]database.GetTalkgroupsWithLearnedByPackedIDsRow
|
2024-11-03 08:09:49 -05:00
|
|
|
Scores trending.Scores[talkgroups.ID]
|
2024-10-30 09:49:45 -04:00
|
|
|
LastScore time.Time
|
|
|
|
Simulation *Simulation
|
|
|
|
Config config.Alerting
|
2024-10-23 08:55:19 -04:00
|
|
|
}{
|
2024-10-30 09:49:45 -04:00
|
|
|
TGs: tgMap,
|
|
|
|
Scores: as.scores,
|
|
|
|
LastScore: as.lastScore,
|
|
|
|
Config: as.cfg,
|
|
|
|
Simulation: as.sim,
|
2024-10-23 08:55:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
err = statTmpl.Execute(w, renderData)
|
|
|
|
if err != nil {
|
|
|
|
log.Error().Err(err).Msg("stat template exec")
|
|
|
|
}
|
|
|
|
}
|