pings record to sqlite

This commit is contained in:
bel
2026-06-27 23:59:55 -06:00
parent 1be18b80d2
commit 52c00adfe7
4 changed files with 143 additions and 5 deletions
Binary file not shown.
+140 -5
View File
@@ -2,12 +2,17 @@ package main
import (
"context"
"database/sql"
"flag"
"fmt"
"log"
"math/rand"
"net"
"os"
"sync"
"time"
"gitea.bel.blue/bel/with"
"github.com/digineo/go-ping"
)
func main() {
@@ -16,18 +21,148 @@ func main() {
}
}
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()
}
func (S) listen(ctx context.Context) error {
return ctx.Err()
}
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
}
pinger, err := ping.New("", "::")
if err != nil {
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
}
defer pinger.Close()
log.Fatal("RUN")
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()
}