Compare commits

..

3 Commits

Author SHA1 Message Date
bel 2e339cff36 execute template w queries
cicd / ci (push) Failing after 36s
2026-06-28 00:14:25 -06:00
bel 52c00adfe7 pings record to sqlite 2026-06-27 23:59:55 -06:00
bel 1be18b80d2 digineo req superuser 2026-06-27 17:35:15 -06:00
4 changed files with 244 additions and 19 deletions
-19
View File
@@ -1,19 +0,0 @@
package main
import (
"context"
"log"
"gitea.bel.blue/bel/with"
)
func main() {
if err := with.Context(run); err != nil {
panic(err)
}
}
func run(ctx context.Context) error {
log.Fatal("RUN")
return ctx.Err()
}
+232
View File
@@ -0,0 +1,232 @@
package main
import (
_ "embed"
"html/template"
"net/http"
"context"
"database/sql"
"flag"
"fmt"
"log"
"math/rand"
"net"
"os"
"sync"
"time"
"gitea.bel.blue/bel/with"
)
func main() {
if err := with.Context(run); err != nil {
panic(err)
}
}
type S struct {
*sql.DB
}
func run(ctx context.Context) error {
return with.Sqlite(ctx, "/tmp/pinger.db", func(db *sql.DB) error {
s := S{
DB: db,
}
if err := s.init(ctx); err != nil {
return err
}
wg := &sync.WaitGroup{}
defer wg.Wait()
for _, foo := range []func(context.Context) error{
s.pingAndRecord,
s.listen,
} {
foo := foo
wg.Go(func() {
if err := foo(ctx); err != nil {
panic(err)
}
})
}
return ctx.Err()
})
}
func (s S) init(ctx context.Context) error {
for _, q := range []string{
`CREATE TABLE IF NOT EXISTS "pinger_to" (
id NUMBER NOT NULL UNIQUE
, addr TEXT NOT NULL UNIQUE
)`,
`CREATE TABLE IF NOT EXISTS "pinger_pings" (
start TIMESTAMP NOT NULL
, ms NUMBER NOT NULL
, ok BOOLEAN NOT NULL DEFAULT false
, to_id NUMBER
, FOREIGN KEY (to_id) REFERENCES "pinger_to"(id)
)`,
//`ALTER TABLE "pinger_pings" SET UNLOGGED`,
} {
if _, err := s.ExecContext(ctx, q); err != nil {
return err
}
}
return ctx.Err()
}
//go:embed index.html.tmpl
var IndexTemplate string
func (s S) listen(ctx context.Context) error {
t := template.New("template")
t.Funcs(map[string]any{
"query": func(q string) ([]map[string]any, error) {
rows, err := s.QueryContext(ctx, q)
if err != nil {
return nil, err
}
defer rows.Close()
columns, err := rows.Columns()
if err != nil {
return nil, err
}
results := []map[string]any{}
for rows.Next() {
var scanners []any
for range columns {
var a any
scanners = append(scanners, &a)
}
if err := rows.Scan(scanners...); err != nil {
return nil, err
}
result := map[string]any{}
for i, column := range columns {
result[column] = scanners[i]
}
results = append(results, result)
}
return results, rows.Err()
},
})
t, err := t.Parse(IndexTemplate)
if err != nil {
return err
}
server := &http.Server{
Addr: ":10000",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := t.Execute(w, map[string]any{
"DB": s.DB,
}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}),
}
go func() {
<-ctx.Done()
server.Close()
}()
if err := server.ListenAndServe(); err != nil && ctx.Err() == nil {
return err
}
return nil
}
func (s S) pingAndRecord(ctx context.Context) error {
ctx, can := context.WithCancel(ctx)
defer can()
fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
target := fs.String("t", "google.com", "target")
port := fs.String("p", "80", "target port")
interval := fs.Duration("i", time.Second, "between conns")
if err := fs.Parse(os.Args[1:]); err != nil {
return err
}
addr := fmt.Sprintf("%s:%s", *target, *port)
if _, err := s.ExecContext(ctx, `
INSERT INTO "pinger_to" (id, addr)
VALUES ($1, $2)
ON CONFLICT (addr) DO NOTHING
`, rand.Int(), addr); err != nil {
return err
}
var toId int
if row := s.QueryRowContext(ctx, `
SELECT id
FROM "pinger_to"
WHERE addr=$1
`, addr); row.Err() != nil {
return row.Err()
} else if err := row.Scan(&toId); err != nil {
return err
}
type record struct {
start time.Time
ms time.Duration
ok bool
}
records := make(chan record, 100)
defer close(records)
go func() {
for record := range records {
if _, err := s.ExecContext(ctx, `
INSERT INTO "pinger_pings"
(start, ms, ok, to_id)
VALUES
($1, $2, $3, $4)
`, record.start, record.ms.Milliseconds(), record.ok, toId); err != nil {
log.Println("!", err)
}
}
}()
c := time.NewTicker(*interval)
go func() {
<-ctx.Done()
c.Stop()
}()
dialer := &net.Dialer{
Timeout: time.Second,
}
for {
select {
case <-c.C:
case <-ctx.Done():
return nil
}
func() {
ctx, can := context.WithTimeout(ctx, *interval)
defer can()
start := time.Now()
conn, err := dialer.DialContext(ctx, "tcp", addr)
select {
case records <- record{
start: start,
ms: time.Since(start),
ok: err == nil,
}:
default:
}
if err == nil {
conn.Close()
}
}()
}
return ctx.Err()
}
+4
View File
@@ -5,13 +5,17 @@ go 1.25.0
require gitea.bel.blue/bel/with v0.0.0-20260527141310-eadcabb7fe54 require gitea.bel.blue/bel/with v0.0.0-20260527141310-eadcabb7fe54
require ( require (
github.com/digineo/go-logwrap v0.0.0-20181106161722-a178c58ea3f0 // indirect
github.com/digineo/go-ping v1.2.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/lib/pq v1.11.2 // indirect github.com/lib/pq v1.11.2 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e // indirect
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/sys v0.43.0 // indirect golang.org/x/sys v0.43.0 // indirect
modernc.org/libc v1.67.6 // indirect modernc.org/libc v1.67.6 // indirect
modernc.org/mathutil v1.7.1 // indirect modernc.org/mathutil v1.7.1 // indirect
+8
View File
@@ -1,3 +1,7 @@
github.com/digineo/go-logwrap v0.0.0-20181106161722-a178c58ea3f0 h1:OT/LKmj81wMymnWXaKaKBR9n1vPlu+GC0VVKaZP6kzs=
github.com/digineo/go-logwrap v0.0.0-20181106161722-a178c58ea3f0/go.mod h1:DmqdumeAKGQNU5E8MN0ruT5ZGx8l/WbAsMbXCXcSEts=
github.com/digineo/go-ping v1.2.0 h1:/9vEsoCRtQvol5vRMA2pE8guuhUVDSJB2ok2nKuJJbA=
github.com/digineo/go-ping v1.2.0/go.mod h1:cXJTVTs7mthQ41c/nWykPYuhlDQwCN0ba5LyOnyYv8Y=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
@@ -14,10 +18,14 @@ github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOF
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e h1:nt2877sKfojlHCTOBXbpWjBkuWKritFaGIfgQwbQUls=
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e/go.mod h1:B4+Kq1u5FlULTjFSM707Q6e/cOHFv0z/6QRoxubDIQ8=
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=