mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-18 07:24:31 +01:00
86 lines
2.2 KiB
Go
86 lines
2.2 KiB
Go
package period
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
metricsutils "github.com/yusing/godoxy/internal/metrics/utils"
|
|
apitypes "github.com/yusing/goutils/apitypes"
|
|
"github.com/yusing/goutils/http/httpheaders"
|
|
"github.com/yusing/goutils/http/websocket"
|
|
)
|
|
|
|
type ResponseType[AggregateT any] struct {
|
|
Total int `json:"total"`
|
|
Data AggregateT `json:"data"`
|
|
}
|
|
|
|
// ServeHTTP serves the data for the given period.
|
|
//
|
|
// If the period is not specified, it serves the last result.
|
|
//
|
|
// If the period is specified, it serves the data for the given period.
|
|
//
|
|
// If the period is invalid, it returns a 400 error.
|
|
//
|
|
// If the data is not found, it returns a 204 error.
|
|
//
|
|
// If the request is a websocket request, it serves the data for the given period for every interval.
|
|
func (p *Poller[T, AggregateT]) ServeHTTP(c *gin.Context) {
|
|
period := Filter(c.Query("period"))
|
|
query := c.Request.URL.Query()
|
|
|
|
if httpheaders.IsWebsocket(c.Request.Header) {
|
|
interval := metricsutils.QueryDuration(query, "interval", 0)
|
|
|
|
if interval < PollInterval {
|
|
interval = PollInterval
|
|
}
|
|
websocket.PeriodicWrite(c, interval, func() (any, error) {
|
|
return p.GetRespData(period, query)
|
|
})
|
|
} else {
|
|
data, err := p.GetRespData(period, query)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, apitypes.Error("bad request", err))
|
|
return
|
|
}
|
|
if data == nil {
|
|
c.JSON(http.StatusNoContent, apitypes.Error("no data"))
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, data)
|
|
}
|
|
}
|
|
|
|
// GetRespData returns the aggregated data for the given period and query.
|
|
//
|
|
// When period is specified:
|
|
//
|
|
// It returns a map with the total and the data.
|
|
// It returns an error if the period or query is invalid.
|
|
//
|
|
// When period is not specified:
|
|
//
|
|
// It returns the last result.
|
|
// It returns nil if no last result is found.
|
|
func (p *Poller[T, AggregateT]) GetRespData(period Filter, query url.Values) (any, error) {
|
|
if period == "" {
|
|
return p.GetLastResult(), nil
|
|
}
|
|
rangeData, ok := p.Get(period)
|
|
if !ok {
|
|
return nil, errors.New("invalid period")
|
|
}
|
|
total, aggregated := p.aggregate(rangeData, query)
|
|
if total == -1 {
|
|
return nil, errors.New("bad request")
|
|
}
|
|
return map[string]any{
|
|
"total": total,
|
|
"data": aggregated,
|
|
}, nil
|
|
}
|