Staff push notifications, and revalidate embedded assets
Notifications: staff turn them on per device from a new Notifications page, pick each type (bans, gags, mutes and silences added or lifted, server down and back up) and quiet hours. A watcher polls SimpleAdmin's tables, so in-game penalties are sent too. Web Push with VAPID and RFC 8291 encryption in internal/push, standard library only. Tables in sql/push.sql, created at startup; the VAPID key is made on first start and kept in saw_settings. Penalty notifications link to the public list searching for the player (#bans?q=<steamid64>). The Android app delegates notifications (versionCode 3). Caching: pages, scripts and styles are served with Cache-Control: no-cache and an ETag, so a deploy shows up at once instead of after Cloudflare's default 4-hour browser cache.
This commit is contained in:
parent
7900bf5b3e
commit
17232bd5a2
23 changed files with 2135 additions and 12 deletions
35
main.go
35
main.go
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/go-sql-driver/mysql"
|
||||
|
||||
"git.zio.sh/cs2/simpleadmin-web/internal/live"
|
||||
"git.zio.sh/cs2/simpleadmin-web/internal/push"
|
||||
"git.zio.sh/cs2/simpleadmin-web/internal/rcon"
|
||||
"git.zio.sh/cs2/simpleadmin-web/internal/saconfig"
|
||||
"git.zio.sh/cs2/simpleadmin-web/internal/store"
|
||||
|
|
@ -33,6 +34,11 @@ import (
|
|||
//go:embed sql/rank-log.sql
|
||||
var rankLogSQL string
|
||||
|
||||
// pushSQL creates the push notification tables (see the file).
|
||||
//
|
||||
//go:embed sql/push.sql
|
||||
var pushSQL string
|
||||
|
||||
func env(key, def string) string {
|
||||
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
|
||||
return v
|
||||
|
|
@ -162,10 +168,12 @@ func run() error {
|
|||
MaxMuteDuration: maxMute,
|
||||
AndroidPackage: env("SAW_ANDROID_PACKAGE", ""),
|
||||
AndroidCerts: strings.Split(env("SAW_ANDROID_CERT_SHA256", ""), ","),
|
||||
Push: pushSender(ctx, st, baseURL),
|
||||
}, st, rc, poller, sacfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go app.RunNotifier(ctx)
|
||||
|
||||
listen := env("SAW_LISTEN", ":8080")
|
||||
hs := &http.Server{
|
||||
|
|
@ -187,6 +195,33 @@ func run() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// pushSender sets up staff notifications: the panel's tables, and the VAPID key push services know
|
||||
// it by, made on first start and kept in the database. It returns nil, turning notifications off,
|
||||
// if either fails.
|
||||
func pushSender(ctx context.Context, st *store.Store, baseURL string) *push.Sender {
|
||||
if err := st.EnsurePush(ctx, pushSQL); err != nil {
|
||||
slog.Warn("couldn't create the push notification tables; notifications are off until sql/push.sql is run", "err", err)
|
||||
return nil
|
||||
}
|
||||
saved, err := st.Setting(ctx, "vapid_private_key")
|
||||
if err == nil && saved == "" {
|
||||
var k *push.Keys
|
||||
if k, err = push.GenerateKeys(); err == nil {
|
||||
saved, err = st.SettingOnce(ctx, "vapid_private_key", k.Private())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
slog.Warn("couldn't read or make the VAPID key; notifications are off", "err", err)
|
||||
return nil
|
||||
}
|
||||
keys, err := push.ParseKeys(saved)
|
||||
if err != nil {
|
||||
slog.Warn("saw_settings has a bad vapid_private_key; notifications are off", "err", err)
|
||||
return nil
|
||||
}
|
||||
return &push.Sender{Keys: keys, Subject: baseURL, Client: &http.Client{Timeout: 15 * time.Second}}
|
||||
}
|
||||
|
||||
// openDB connects with SAW_DB_DSN, or with the DatabaseConfig in CS2-SimpleAdmin.json.
|
||||
func openDB(sacfg *saconfig.File) (*sql.DB, error) {
|
||||
var cfg *mysql.Config
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue