diff --git a/cmd/pinger/.main.go.swp b/cmd/pinger/.main.go.swp deleted file mode 100644 index c6350c1..0000000 Binary files a/cmd/pinger/.main.go.swp and /dev/null differ diff --git a/cmd/pinger/main.go b/cmd/pinger/main.go index edd9735..0c44fd9 100644 --- a/cmd/pinger/main.go +++ b/cmd/pinger/main.go @@ -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() } diff --git a/go.mod b/go.mod index 51384a3..3db96cd 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/ncruces/go-strftime v1.0.0 // 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/net v0.43.0 // indirect golang.org/x/sys v0.43.0 // indirect diff --git a/go.sum b/go.sum index 5ef2be4..f98d4c2 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,8 @@ 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/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 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/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=