summaryrefslogtreecommitdiffstats
path: root/internal/handler/websocket/convert.go
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-13 18:17:37 -0800
committerbndw <ben@bdw.to>2026-02-13 18:17:37 -0800
commit3481c3273f8764bd0a0ab51183dc57f592fb616c (patch)
tree8bef805f5f18420198a04bf87578bbc80b76ea40 /internal/handler/websocket/convert.go
parentecd4a2240dd443fd6949e6e1120a7ec971a024ca (diff)
feat: add WebSocket server with full NIP-01 support
WebSocket handler: - NIP-01 protocol (EVENT, REQ, CLOSE, OK, EOSE, NOTICE) - JSON envelope parsing - Shares subscription manager with gRPC (unified event fan-out) - Standard Nostr client compatibility Relay now serves dual protocols: - gRPC on :50051 (binary, high performance) - WebSocket on :8080 (JSON, Nostr standard) Both protocols share: - Same storage layer - Same subscription manager - Same validation logic Compatible with all Nostr clients!
Diffstat (limited to 'internal/handler/websocket/convert.go')
-rw-r--r--internal/handler/websocket/convert.go76
1 files changed, 76 insertions, 0 deletions
diff --git a/internal/handler/websocket/convert.go b/internal/handler/websocket/convert.go
new file mode 100644
index 0000000..0458ee4
--- /dev/null
+++ b/internal/handler/websocket/convert.go
@@ -0,0 +1,76 @@
1package websocket
2
3import (
4 pb "northwest.io/nostr-grpc/api/nostr/v1"
5 "northwest.io/nostr-grpc/internal/nostr"
6)
7
8func NostrToPB(n *nostr.Event) *pb.Event {
9 tags := make([]*pb.Tag, len(n.Tags))
10 for i, tag := range n.Tags {
11 tags[i] = &pb.Tag{Values: tag}
12 }
13
14 return &pb.Event{
15 Id: n.ID,
16 Pubkey: n.PubKey,
17 CreatedAt: n.CreatedAt,
18 Kind: int32(n.Kind),
19 Tags: tags,
20 Content: n.Content,
21 Sig: n.Sig,
22 }
23}
24
25func PBToNostr(e *pb.Event) *nostr.Event {
26 tags := make(nostr.Tags, len(e.Tags))
27 for i, tag := range e.Tags {
28 tags[i] = tag.Values
29 }
30
31 return &nostr.Event{
32 ID: e.Id,
33 PubKey: e.Pubkey,
34 CreatedAt: e.CreatedAt,
35 Kind: int(e.Kind),
36 Tags: tags,
37 Content: e.Content,
38 Sig: e.Sig,
39 }
40}
41
42func NostrFilterToPB(f *nostr.Filter) *pb.Filter {
43 pbFilter := &pb.Filter{
44 Ids: f.IDs,
45 Authors: f.Authors,
46 Kinds: make([]int32, len(f.Kinds)),
47 }
48
49 for i, kind := range f.Kinds {
50 pbFilter.Kinds[i] = int32(kind)
51 }
52
53 if f.Since != nil {
54 since := int64(*f.Since)
55 pbFilter.Since = &since
56 }
57
58 if f.Until != nil {
59 until := int64(*f.Until)
60 pbFilter.Until = &until
61 }
62
63 if f.Limit > 0 {
64 limit := int32(f.Limit)
65 pbFilter.Limit = &limit
66 }
67
68 if len(f.Tags) > 0 {
69 pbFilter.TagFilters = make(map[string]*pb.TagFilter)
70 for tagName, values := range f.Tags {
71 pbFilter.TagFilters[tagName] = &pb.TagFilter{Values: values}
72 }
73 }
74
75 return pbFilter
76}