Skip to content

Commit 47b96cd

Browse files
committed
zones: per zone server counts API migrated
1 parent 19c0206 commit 47b96cd

File tree

7 files changed

+282
-2
lines changed

7 files changed

+282
-2
lines changed

ntpdb/models.go

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ntpdb/otel.go

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ntpdb/querier.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ntpdb/query.sql.go

Lines changed: 56 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

query.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,13 @@ where
8383
monitor_id = ?
8484
order by ts desc
8585
limit ?;
86+
87+
-- name: GetZoneByName :one
88+
select * from zones
89+
where
90+
name = sqlc.arg(name);
91+
92+
-- name: GetZoneCounts :many
93+
select * from zone_server_counts
94+
where zone_id = ?
95+
order by date;

server/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ func (srv *Server) Run() error {
195195

196196
if len(ntpconf.WebHostname()) > 0 {
197197
e.POST("/api/server/scores/:server/:mode", func(c echo.Context) error {
198-
// POST requests used to work
198+
// POST requests used to work, so make them not error out
199199
mode := c.Param("mode")
200200
server := c.Param("server")
201201
query := c.Request().URL.Query()
@@ -210,7 +210,7 @@ func (srv *Server) Run() error {
210210
}
211211
e.GET("/graph/:server/:type", srv.graphImage)
212212

213-
// e.GET("/api/server/scores/:server/:type", srv.logScores)
213+
e.GET("/api/zone/counts/:zone_name", srv.zoneCounts)
214214

215215
g.Go(func() error {
216216
return e.Start(":8030")

server/zones.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package server
2+
3+
import (
4+
"database/sql"
5+
"errors"
6+
"net/http"
7+
"strconv"
8+
"time"
9+
10+
"github.com/labstack/echo/v4"
11+
"go.ntppool.org/common/logger"
12+
"go.ntppool.org/common/tracing"
13+
"go.ntppool.org/data-api/ntpdb"
14+
)
15+
16+
func (srv *Server) zoneCounts(c echo.Context) error {
17+
log := logger.Setup()
18+
ctx, span := tracing.Tracer().Start(c.Request().Context(), "zoneCounts")
19+
defer span.End()
20+
21+
// just cache for a short time by default
22+
c.Response().Header().Set("Cache-Control", "public,max-age=240")
23+
c.Response().Header().Set("Access-Control-Allow-Origin", "*")
24+
c.Response().Header().Del("Vary")
25+
26+
q := ntpdb.NewWrappedQuerier(ntpdb.New(srv.db))
27+
28+
zone, err := q.GetZoneByName(ctx, c.Param("zone_name"))
29+
if err != nil || zone.ID == 0 {
30+
if errors.Is(err, sql.ErrNoRows) {
31+
return c.String(http.StatusNotFound, "Not found")
32+
}
33+
log.ErrorContext(ctx, "could not query for zone", "err", err)
34+
span.RecordError(err)
35+
return echo.NewHTTPError(http.StatusInternalServerError, "internal error")
36+
}
37+
38+
counts, err := q.GetZoneCounts(ctx, zone.ID)
39+
if err != nil {
40+
if !errors.Is(err, sql.ErrNoRows) {
41+
log.ErrorContext(ctx, "get counts", "err", err)
42+
span.RecordError(err)
43+
return c.String(http.StatusInternalServerError, "internal error")
44+
}
45+
}
46+
47+
type historyEntry struct {
48+
D string `json:"d"` // date
49+
Ts int `json:"ts"` // epoch timestamp
50+
Rc int `json:"rc"` // count registered
51+
Ac int `json:"ac"` // count active
52+
W int `json:"w"` // netspeed active
53+
Iv string `json:"iv"` // ip version
54+
}
55+
56+
rv := struct {
57+
History []historyEntry `json:"history"`
58+
}{}
59+
60+
skipCount := 0.0
61+
limit := 0
62+
63+
if limitParam := c.QueryParam("limit"); len(limitParam) > 0 {
64+
if limitInt, err := strconv.Atoi(limitParam); err == nil && limitInt > 0 {
65+
limit = limitInt
66+
}
67+
}
68+
69+
var mostRecentDate int64 = -1
70+
if limit > 0 {
71+
count := 0
72+
dates := map[int64]bool{}
73+
for _, c := range counts {
74+
ep := c.Date.Unix()
75+
if _, ok := dates[ep]; !ok {
76+
count++
77+
dates[ep] = true
78+
mostRecentDate = ep
79+
}
80+
}
81+
if limit < count {
82+
if limit > 1 {
83+
skipCount = float64(count) / float64(limit-1)
84+
} else {
85+
// skip everything and use the special logic that we always include the most recent date
86+
skipCount = float64(count) + 1
87+
88+
}
89+
}
90+
91+
log.DebugContext(ctx, "mod", "count", count, "limit", limit, "mod", count%limit, "skipCount", skipCount)
92+
// log.Info("limit plan", "date count", count, "limit", limit, "skipCount", skipCount)
93+
}
94+
95+
toSkip := 0.0
96+
if limit == 1 {
97+
toSkip = skipCount // we just want to look for the last entry
98+
}
99+
lastDate := int64(0)
100+
lastSkip := int64(0)
101+
skipThreshold := 0.5
102+
for _, c := range counts {
103+
cDate := c.Date.Unix()
104+
if (toSkip <= skipThreshold && cDate != lastSkip) ||
105+
lastDate == cDate ||
106+
mostRecentDate == cDate {
107+
// log.Info("adding date", "date", c.Date.Format(time.DateOnly))
108+
rv.History = append(rv.History, historyEntry{
109+
D: c.Date.Format(time.DateOnly),
110+
Ts: int(cDate),
111+
Ac: int(c.CountActive),
112+
Rc: int(c.CountRegistered),
113+
W: int(c.NetspeedActive),
114+
Iv: string(c.IpVersion),
115+
})
116+
lastDate = cDate
117+
} else {
118+
// log.Info("skipping date", "date", c.Date.Format(time.DateOnly))
119+
if lastSkip == cDate {
120+
continue
121+
}
122+
toSkip--
123+
lastSkip = cDate
124+
continue
125+
}
126+
if toSkip <= skipThreshold && skipCount > 0 {
127+
toSkip += skipCount
128+
}
129+
130+
}
131+
132+
if limit > 0 {
133+
count := 0
134+
dates := map[int]bool{}
135+
for _, c := range rv.History {
136+
ep := c.Ts
137+
if _, ok := dates[ep]; !ok {
138+
count++
139+
dates[ep] = true
140+
}
141+
}
142+
log.DebugContext(ctx, "result counts", "skipCount", skipCount, "limit", limit, "got", count)
143+
}
144+
145+
c.Response().Header().Set("Cache-Control", "s-maxage=28800, max-age=7200")
146+
return c.JSON(http.StatusOK, rv)
147+
148+
}

0 commit comments

Comments
 (0)