package nostr import ( "net/url" "strings" "sync" "github.com/dgraph-io/ristretto/z" "golang.org/x/exp/constraints" ) const MAX_LOCKS = 50 var namedMutexPool = make([]sync.Mutex, MAX_LOCKS) func namedLock(name string) (unlock func()) { idx := z.MemHashString(name) % MAX_LOCKS namedMutexPool[idx].Lock() return namedMutexPool[idx].Unlock } func similar[E constraints.Ordered](as, bs []E) bool { if len(as) != len(bs) { return false } for _, a := range as { for _, b := range bs { if b == a { goto next } } // didn't find a B that corresponded to the current A return false next: continue } return true } // Escaping strings for JSON encoding according to RFC8259. // Also encloses result in quotation marks "". func escapeString(dst []byte, s string) []byte { dst = append(dst, '"') for i := 0; i < len(s); i++ { c := s[i] switch { case c == '"': // quotation mark dst = append(dst, []byte{'\\', '"'}...) case c == '\\': // reverse solidus dst = append(dst, []byte{'\\', '\\'}...) case c >= 0x20: // default, rest below are control chars dst = append(dst, c) case c == 0x08: dst = append(dst, []byte{'\\', 'b'}...) case c < 0x09: dst = append(dst, []byte{'\\', 'u', '0', '0', '0', '0' + c}...) case c == 0x09: dst = append(dst, []byte{'\\', 't'}...) case c == 0x0a: dst = append(dst, []byte{'\\', 'n'}...) case c == 0x0c: dst = append(dst, []byte{'\\', 'f'}...) case c == 0x0d: dst = append(dst, []byte{'\\', 'r'}...) case c < 0x10: dst = append(dst, []byte{'\\', 'u', '0', '0', '0', 0x57 + c}...) case c < 0x1a: dst = append(dst, []byte{'\\', 'u', '0', '0', '1', 0x20 + c}...) case c < 0x20: dst = append(dst, []byte{'\\', 'u', '0', '0', '1', 0x47 + c}...) } } dst = append(dst, '"') return dst } func IsValidRelayURL(u string) bool { parsed, err := url.Parse(u) if err != nil { return false } if parsed.Scheme != "wss" && parsed.Scheme != "ws" { return false } if len(strings.Split(parsed.Host, ".")) < 2 { return false } return true }