messages.go raw
1 package net
2
3 import (
4 "strconv"
5
6 "git.smesh.lol/torly/pkg/nostr"
7 )
8
9 func eventMsg(sub string, data []byte) []byte {
10 buf := make([]byte, 0, len(data)+len(sub)+16)
11 buf = append(buf, `["EVENT",`...)
12 buf = nostr.AppendJSONString(buf, sub)
13 buf = append(buf, ',')
14 buf = append(buf, data...)
15 return append(buf, ']')
16 }
17
18 func okMsg(id string, good bool, msg string) []byte {
19 buf := make([]byte, 0, len(id)+len(msg)+16)
20 buf = append(buf, `["OK","`...)
21 buf = append(buf, id...)
22 buf = append(buf, `",`...)
23 if good {
24 buf = append(buf, "true"...)
25 } else {
26 buf = append(buf, "false"...)
27 }
28 buf = append(buf, ',')
29 buf = nostr.AppendJSONString(buf, msg)
30 return append(buf, ']')
31 }
32
33 func eoseMsg(sub string) []byte {
34 buf := make([]byte, 0, len(sub)+12)
35 buf = append(buf, `["EOSE",`...)
36 buf = nostr.AppendJSONString(buf, sub)
37 return append(buf, ']')
38 }
39
40 func noticeMsg(msg string) []byte {
41 buf := make([]byte, 0, len(msg)+12)
42 buf = append(buf, `["NOTICE",`...)
43 buf = nostr.AppendJSONString(buf, msg)
44 return append(buf, ']')
45 }
46
47 func closedMsg(sub, msg string) []byte {
48 buf := make([]byte, 0, len(sub)+len(msg)+14)
49 buf = append(buf, `["CLOSED",`...)
50 buf = nostr.AppendJSONString(buf, sub)
51 buf = append(buf, ',')
52 buf = nostr.AppendJSONString(buf, msg)
53 return append(buf, ']')
54 }
55
56 func authMsg(challenge string) []byte {
57 buf := make([]byte, 0, len(challenge)+12)
58 buf = append(buf, `["AUTH",`...)
59 buf = nostr.AppendJSONString(buf, challenge)
60 return append(buf, ']')
61 }
62
63 func countMsg(sub string, n int, approximate bool) []byte {
64 buf := make([]byte, 0, len(sub)+48)
65 buf = append(buf, `["COUNT",`...)
66 buf = nostr.AppendJSONString(buf, sub)
67 buf = append(buf, `,{"count":`...)
68 buf = strconv.AppendInt(buf, int64(n), 10)
69 buf = append(buf, `,"approximate":`...)
70 if approximate {
71 buf = append(buf, "true"...)
72 } else {
73 buf = append(buf, "false"...)
74 }
75 return append(buf, `}]`...)
76 }
77
78 func filterMatches(ev *nostr.Event, f *nostr.Filter) bool {
79 if !f.Matches(ev) {
80 return false
81 }
82 if f.Search == "" {
83 return true
84 }
85 want := tokenize(f.Search)
86 if len(want) == 0 {
87 return true
88 }
89 have := make(map[string]struct{})
90 for w := range tokenize(ev.Content) {
91 have[w] = struct{}{}
92 }
93 for w := range want {
94 if _, ok := have[w]; !ok {
95 return false
96 }
97 }
98 return true
99 }
100
101 func tokenize(s string) map[string]struct{} {
102 out := make(map[string]struct{})
103 var buf []byte
104 flush := func() {
105 if len(buf) >= 3 {
106 out[string(buf)] = struct{}{}
107 }
108 buf = buf[:0]
109 }
110 for i := 0; i < len(s); i++ {
111 c := s[i]
112 switch {
113 case c >= 'a' && c <= 'z', c >= '0' && c <= '9':
114 buf = append(buf, c)
115 case c >= 'A' && c <= 'Z':
116 buf = append(buf, c+32)
117 default:
118 flush()
119 }
120 }
121 flush()
122 return out
123 }
124