diff options
| author | bndw <ben@bdw.to> | 2026-02-13 17:52:42 -0800 |
|---|---|---|
| committer | bndw <ben@bdw.to> | 2026-02-13 17:52:42 -0800 |
| commit | fcba12d7ae3cdb361c6321519fdaf5a537a6a871 (patch) | |
| tree | 81131f5d8c96879d78688affa9c35f2cf6f83835 | |
| parent | d1a6b2ed2cc3e1f21d214ae54a14f6553d1b17b7 (diff) | |
feat: testclient can accept JSON events from stdin
Usage:
- Standalone: ./bin/testclient (generates event)
- With nak: nak event "hello" | ./bin/testclient
Compatible with nak CLI for easy event generation
| -rw-r--r-- | README.md | 18 | ||||
| -rw-r--r-- | cmd/testclient/main.go | 57 |
2 files changed, 57 insertions, 18 deletions
| @@ -31,8 +31,8 @@ The relay will start listening on `:50051` (gRPC). | |||
| 31 | 31 | ||
| 32 | ### Test with Client | 32 | ### Test with Client |
| 33 | 33 | ||
| 34 | **Standalone mode:** | ||
| 34 | ```bash | 35 | ```bash |
| 35 | # In another terminal: | ||
| 36 | ./bin/testclient | 36 | ./bin/testclient |
| 37 | 37 | ||
| 38 | # Output: | 38 | # Output: |
| @@ -40,10 +40,24 @@ The relay will start listening on `:50051` (gRPC). | |||
| 40 | # Publishing event... | 40 | # Publishing event... |
| 41 | # ✓ Event published successfully: abc123... | 41 | # ✓ Event published successfully: abc123... |
| 42 | # Querying events... | 42 | # Querying events... |
| 43 | # Found 1 events | 43 | # Found 1 events from author abc123... |
| 44 | # - abc123...: Hello from gRPC client! | 44 | # - abc123...: Hello from gRPC client! |
| 45 | ``` | 45 | ``` |
| 46 | 46 | ||
| 47 | **With nak CLI:** | ||
| 48 | ```bash | ||
| 49 | # Pipe events from nak | ||
| 50 | nak event "Hello from nak!" | ./bin/testclient | ||
| 51 | |||
| 52 | # Or generate a signed event | ||
| 53 | nak event --sec <nsec> --kind 1 "My message" | ./bin/testclient | ||
| 54 | |||
| 55 | # Output: | ||
| 56 | # Read event from stdin: abc123... | ||
| 57 | # Publishing event... | ||
| 58 | # ✓ Event published successfully: abc123... | ||
| 59 | ``` | ||
| 60 | |||
| 47 | ## gRPC API | 61 | ## gRPC API |
| 48 | 62 | ||
| 49 | See [proto/nostr/v1/nostr.proto](proto/nostr/v1/nostr.proto) for the full API. | 63 | See [proto/nostr/v1/nostr.proto](proto/nostr/v1/nostr.proto) for the full API. |
diff --git a/cmd/testclient/main.go b/cmd/testclient/main.go index 571751e..224d9d9 100644 --- a/cmd/testclient/main.go +++ b/cmd/testclient/main.go | |||
| @@ -2,8 +2,11 @@ package main | |||
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "context" | 4 | "context" |
| 5 | "encoding/json" | ||
| 5 | "flag" | 6 | "flag" |
| 7 | "io" | ||
| 6 | "log" | 8 | "log" |
| 9 | "os" | ||
| 7 | "time" | 10 | "time" |
| 8 | 11 | ||
| 9 | "google.golang.org/grpc" | 12 | "google.golang.org/grpc" |
| @@ -26,23 +29,45 @@ func main() { | |||
| 26 | client := pb.NewNostrRelayClient(conn) | 29 | client := pb.NewNostrRelayClient(conn) |
| 27 | ctx := context.Background() | 30 | ctx := context.Background() |
| 28 | 31 | ||
| 29 | key, err := nostr.GenerateKey() | 32 | var event *nostr.Event |
| 30 | if err != nil { | 33 | |
| 31 | log.Fatalf("failed to generate key: %v", err) | 34 | stat, _ := os.Stdin.Stat() |
| 32 | } | 35 | if (stat.Mode() & os.ModeCharDevice) == 0 { |
| 36 | data, err := io.ReadAll(os.Stdin) | ||
| 37 | if err != nil { | ||
| 38 | log.Fatalf("failed to read stdin: %v", err) | ||
| 39 | } | ||
| 40 | |||
| 41 | event = &nostr.Event{} | ||
| 42 | if err := json.Unmarshal(data, event); err != nil { | ||
| 43 | log.Fatalf("failed to parse JSON event: %v", err) | ||
| 44 | } | ||
| 45 | |||
| 46 | log.Printf("Read event from stdin: %s", event.ID[:16]) | ||
| 47 | } else { | ||
| 48 | key, err := nostr.GenerateKey() | ||
| 49 | if err != nil { | ||
| 50 | log.Fatalf("failed to generate key: %v", err) | ||
| 51 | } | ||
| 52 | |||
| 53 | log.Printf("Generated key: %s", key.Npub()) | ||
| 33 | 54 | ||
| 34 | log.Printf("Generated key: %s", key.Npub()) | 55 | event = &nostr.Event{ |
| 56 | PubKey: key.Public(), | ||
| 57 | CreatedAt: time.Now().Unix(), | ||
| 58 | Kind: 1, | ||
| 59 | Tags: nostr.Tags{}, | ||
| 60 | Content: "Hello from gRPC client!", | ||
| 61 | } | ||
| 35 | 62 | ||
| 36 | event := &nostr.Event{ | 63 | if err := key.Sign(event); err != nil { |
| 37 | PubKey: key.Public(), | 64 | log.Fatalf("failed to sign event: %v", err) |
| 38 | CreatedAt: time.Now().Unix(), | 65 | } |
| 39 | Kind: 1, | ||
| 40 | Tags: nostr.Tags{}, | ||
| 41 | Content: "Hello from gRPC client!", | ||
| 42 | } | 66 | } |
| 43 | 67 | ||
| 44 | if err := key.Sign(event); err != nil { | 68 | tags := make([]*pb.Tag, len(event.Tags)) |
| 45 | log.Fatalf("failed to sign event: %v", err) | 69 | for i, tag := range event.Tags { |
| 70 | tags[i] = &pb.Tag{Values: tag} | ||
| 46 | } | 71 | } |
| 47 | 72 | ||
| 48 | pbEvent := &pb.Event{ | 73 | pbEvent := &pb.Event{ |
| @@ -50,7 +75,7 @@ func main() { | |||
| 50 | Pubkey: event.PubKey, | 75 | Pubkey: event.PubKey, |
| 51 | CreatedAt: event.CreatedAt, | 76 | CreatedAt: event.CreatedAt, |
| 52 | Kind: int32(event.Kind), | 77 | Kind: int32(event.Kind), |
| 53 | Tags: []*pb.Tag{}, | 78 | Tags: tags, |
| 54 | Content: event.Content, | 79 | Content: event.Content, |
| 55 | Sig: event.Sig, | 80 | Sig: event.Sig, |
| 56 | } | 81 | } |
| @@ -71,14 +96,14 @@ func main() { | |||
| 71 | log.Println("Querying events...") | 96 | log.Println("Querying events...") |
| 72 | queryResp, err := client.QueryEvents(ctx, &pb.QueryRequest{ | 97 | queryResp, err := client.QueryEvents(ctx, &pb.QueryRequest{ |
| 73 | Filters: []*pb.Filter{ | 98 | Filters: []*pb.Filter{ |
| 74 | {Authors: []string{key.Public()}}, | 99 | {Authors: []string{event.PubKey}}, |
| 75 | }, | 100 | }, |
| 76 | }) | 101 | }) |
| 77 | if err != nil { | 102 | if err != nil { |
| 78 | log.Fatalf("failed to query: %v", err) | 103 | log.Fatalf("failed to query: %v", err) |
| 79 | } | 104 | } |
| 80 | 105 | ||
| 81 | log.Printf("Found %d events", len(queryResp.Events)) | 106 | log.Printf("Found %d events from author %s", len(queryResp.Events), event.PubKey[:16]) |
| 82 | for _, e := range queryResp.Events { | 107 | for _, e := range queryResp.Events { |
| 83 | log.Printf(" - %s: %s", e.Id[:16], e.Content) | 108 | log.Printf(" - %s: %s", e.Id[:16], e.Content) |
| 84 | } | 109 | } |
