omada-bandwidth/main.go
2025-02-04 22:07:45 +01:00

119 lines
3.2 KiB
Go

package main
import (
"encoding/json"
"fmt"
"net/http"
"time"
"git.tordarus.net/tordarus/channel"
"git.tordarus.net/tordarus/envvars"
"git.tordarus.net/tordarus/gmath"
omada "git.tordarus.net/tordarus/omada-api"
omadamodel "git.tordarus.net/tordarus/omada-api/model"
"git.tordarus.net/tordarus/slices"
)
var ( // flags
FlagSiteNames = envvars.StringSlice("SITES", ",", []string{})
FlagOmadaURL = envvars.String("OMADA_URL", "http://localhost:8088")
FlagOmadaID = envvars.String("OMADA_ID", "")
FlagOmadaClientID = envvars.String("OMADA_CLIENT_ID", "")
FlagOmadaClientSecret = envvars.String("OMADA_CLIENT_SECRET", "")
FlagOmadaUsername = envvars.String("OMADA_USERNAME", "")
FlagOmadaPassword = envvars.String("OMADA_PASSWORD", "")
FlagRefreshInterval = envvars.Duration("REFRESH_INTERVAL", 30*time.Second)
FlagRefreshBeforeExpiration = envvars.Duration("REFRESH_BEFORE", time.Minute)
FlagHttpInterface = envvars.String("HTTP_INTERFACE", "")
FlagHttpPort = envvars.Uint16("HTTP_PORT", 8080)
)
var MinRefreshInterval = 30 * time.Second
var CurrentTraffic = &TrafficStats{}
func main() {
FlagRefreshInterval = gmath.Max(FlagRefreshInterval, MinRefreshInterval)
api, err := omada.NewApi(omada.ApiConfig{
BasePath: FlagOmadaURL,
OmadaID: FlagOmadaID,
ClientID: FlagOmadaClientID,
ClientSecret: FlagOmadaClientSecret,
Username: FlagOmadaUsername,
Password: FlagOmadaPassword,
})
if err != nil {
panic(err)
}
go StartHttpServer()
sites := slices.Ref(slices.Filter(
channel.ToSlice(channel.Map(api.GetSites(), channel.Result[omadamodel.Site].GetUnsafe)),
FilterSitesByName(FlagSiteNames...),
))
ticker := time.NewTicker(FlagRefreshInterval)
lastTick := time.Now()
CalculateSiteTraffic(api, sites, 0)
for now := range ticker.C {
CurrentTraffic = CalculateSiteTraffic(api, sites, now.Sub(lastTick))
lastTick = now
}
}
func CalculateSiteTraffic(api *omada.Api, sites []*omadamodel.Site, duration time.Duration) *TrafficStats {
siteTraffics := map[string]*SiteTraffic{}
for _, site := range sites {
trafficByClient := map[string]TrafficRate{}
clientRequests := channel.ToSlice(api.GetClients(site.ID))
for _, clientReq := range clientRequests {
client, err := clientReq.Get()
if err != nil {
panic(err)
}
traffic := CalculateClientTraffic(site, &client, duration)
trafficByClient[client.Name] = traffic
}
siteTraffics[site.Name] = NewSiteTraffic(trafficByClient)
}
return NewTrafficStats(siteTraffics)
}
func FilterSitesByName(allowedSiteNames ...string) func(site omadamodel.Site) bool {
if len(allowedSiteNames) == 0 {
return func(site omadamodel.Site) bool { return true }
}
siteNames := slices.ToStructMap(allowedSiteNames)
return func(site omadamodel.Site) bool {
_, ok := siteNames[site.Name]
return ok
}
}
func StartHttpServer() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if err := json.NewEncoder(w).Encode(CurrentTraffic); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
})
connString := fmt.Sprintf("%s:%d", FlagHttpInterface, FlagHttpPort)
if err := http.ListenAndServe(connString, nil); err != nil {
panic(err)
}
}