Initial commit: DSH Web Manager
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.misaka.ren/m1saka/dsh-web/internal/store"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RunQuotaMonitor reports soft quota crossings; it never claims to constrain
|
||||
// runtime writes and never deletes user data to recover capacity.
|
||||
func (a *API) RunQuotaMonitor(ctx context.Context) {
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
exceeded := map[string]bool{}
|
||||
for {
|
||||
a.checkQuotas(ctx, exceeded)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *API) checkQuotas(ctx context.Context, exceeded map[string]bool) {
|
||||
rows, err := a.s.DB.QueryContext(ctx, "SELECT id,quota FROM users")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var users []store.User
|
||||
for rows.Next() {
|
||||
var u store.User
|
||||
if rows.Scan(&u.ID, &u.Quota) != nil {
|
||||
rows.Close()
|
||||
return
|
||||
}
|
||||
users = append(users, u)
|
||||
}
|
||||
err = rows.Err()
|
||||
rows.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, u := range users {
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
used, err := a.userUsage(u)
|
||||
if err != nil {
|
||||
log.Printf("quota usage unavailable for user %s", u.ID)
|
||||
continue
|
||||
}
|
||||
over := used > u.Quota
|
||||
if over && !exceeded[u.ID] {
|
||||
a.s.AddAudit(u.ID, "quota.exceeded", u.ID, "soft quota exceeded; runtime writes remain unrestricted")
|
||||
}
|
||||
if !over && exceeded[u.ID] {
|
||||
a.s.AddAudit(u.ID, "quota.recovered", u.ID, "")
|
||||
}
|
||||
exceeded[u.ID] = over
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user