From 037e8efcc6bfc8588c289b493be061e341589da8 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Thu, 12 Feb 2026 14:34:24 -0300 Subject: [PATCH] count: support reading filters from stdin like req. --- count.go | 89 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 39 deletions(-) diff --git a/count.go b/count.go index 2fa4407..493bcce 100644 --- a/count.go +++ b/count.go @@ -9,13 +9,14 @@ import ( "fiatjaf.com/nostr" "fiatjaf.com/nostr/nip45" "fiatjaf.com/nostr/nip45/hyperloglog" + "github.com/mailru/easyjson" "github.com/urfave/cli/v3" ) var count = &cli.Command{ Name: "count", Usage: "generates encoded COUNT messages and optionally use them to talk to relays", - Description: `outputs a nip45 request (the flags are mostly the same as 'nak req').`, + Description: `like 'nak req', but does a "COUNT" call instead. Will attempt to perform HyperLogLog aggregation if more than one relay is specified.`, DisableSliceFlagSeparator: true, Flags: reqFilterFlags, ArgsUsage: "[relay...]", @@ -37,52 +38,62 @@ var count = &cli.Command{ } } - filter := nostr.Filter{} - - if err := applyFlagsToFilter(c, &filter); err != nil { - return err - } - - successes := 0 - if len(relayUrls) > 0 { - var hll *hyperloglog.HyperLogLog - if offset := nip45.HyperLogLogEventPubkeyOffsetForFilter(filter); offset != -1 && len(relayUrls) > 1 { - hll = hyperloglog.New(offset) - } - for _, relayUrl := range relayUrls { - relay, _ := sys.Pool.EnsureRelay(relayUrl) - count, hllRegisters, err := relay.Count(ctx, filter, nostr.SubscriptionOptions{ - Label: "nak-count", - }) - fmt.Fprintf(os.Stderr, "%s%s: ", strings.Repeat(" ", biggerUrlSize-len(relayUrl)), relayUrl) - - if err != nil { - fmt.Fprintf(os.Stderr, "error: %s\n", err) + // go line by line from stdin or run once with input from flags + for stdinFilter := range getJsonsOrBlank() { + filter := nostr.Filter{} + if stdinFilter != "" { + if err := easyjson.Unmarshal([]byte(stdinFilter), &filter); err != nil { + ctx = lineProcessingError(ctx, "invalid filter '%s' received from stdin: %s", stdinFilter, err) continue } + } - var hasHLLStr string - if hll != nil && len(hllRegisters) == 256 { - hll.MergeRegisters(hllRegisters) - hasHLLStr = " (hll)" + if err := applyFlagsToFilter(c, &filter); err != nil { + return err + } + + successes := 0 + if len(relayUrls) > 0 { + var hll *hyperloglog.HyperLogLog + if offset := nip45.HyperLogLogEventPubkeyOffsetForFilter(filter); offset != -1 && len(relayUrls) > 1 { + hll = hyperloglog.New(offset) } + for _, relayUrl := range relayUrls { + relay, _ := sys.Pool.EnsureRelay(relayUrl) + count, hllRegisters, err := relay.Count(ctx, filter, nostr.SubscriptionOptions{ + Label: "nak-count", + }) + fmt.Fprintf(os.Stderr, "%s%s: ", strings.Repeat(" ", biggerUrlSize-len(relayUrl)), relayUrl) - fmt.Fprintf(os.Stderr, "%d%s\n", count, hasHLLStr) - successes++ + if err != nil { + fmt.Fprintf(os.Stderr, "error: %s\n", err) + continue + } + + var hasHLLStr string + if hll != nil && len(hllRegisters) == 256 { + hll.MergeRegisters(hllRegisters) + hasHLLStr = " (hll)" + } + + fmt.Fprintf(os.Stderr, "%d%s\n", count, hasHLLStr) + successes++ + } + if successes == 0 { + return fmt.Errorf("all relays have failed") + } else if hll != nil { + fmt.Fprintf(os.Stderr, "HyperLogLog sum: %d\n", hll.Count()) + } + } else { + // no relays given, will just print the filter + var result string + j, _ := json.Marshal([]any{"COUNT", "nak", filter}) + result = string(j) + stdout(result) } - if successes == 0 { - return fmt.Errorf("all relays have failed") - } else if hll != nil { - fmt.Fprintf(os.Stderr, "HyperLogLog sum: %d\n", hll.Count()) - } - } else { - // no relays given, will just print the filter - var result string - j, _ := json.Marshal([]any{"COUNT", "nak", filter}) - result = string(j) - stdout(result) } + exitIfLineProcessingError(ctx) return nil }, }