Add Neo4j memory tuning config and query result limits (v0.43.0)
Some checks failed
Go / build-and-release (push) Has been cancelled

- Add Neo4j driver config options for memory management:
  - ORLY_NEO4J_MAX_CONN_POOL (default: 25) - connection pool size
  - ORLY_NEO4J_FETCH_SIZE (default: 1000) - records per batch
  - ORLY_NEO4J_MAX_TX_RETRY_SEC (default: 30) - transaction retry timeout
  - ORLY_NEO4J_QUERY_RESULT_LIMIT (default: 10000) - max results per query
- Apply driver settings when creating Neo4j connection (pool size, fetch size, retry time)
- Enforce query result limit as safety cap on all Cypher queries
- Fix QueryForSerials and QueryForIds to preserve LIMIT clauses
- Add comprehensive memory tuning documentation with sizing guidelines
- Add NIP-46 signer-based authentication for bunker connections
- Update go.mod with new dependencies

Files modified:
- app/config/config.go: Add Neo4j driver tuning config vars
- main.go: Pass new config values to database factory
- pkg/database/factory.go: Add Neo4j tuning fields to DatabaseConfig
- pkg/database/factory_wasm.go: Mirror factory.go changes for WASM
- pkg/neo4j/neo4j.go: Apply driver config, add getter methods
- pkg/neo4j/query-events.go: Enforce query result limit, fix LIMIT preservation
- docs/NEO4J_BACKEND.md: Add Memory Tuning section, update Docker example
- CLAUDE.md: Add Neo4j memory tuning quick reference
- app/handle-req.go: NIP-46 signer authentication
- app/publisher.go: HasActiveNIP46Signer check
- pkg/protocol/publish/publisher.go: NIP46SignerChecker interface
- go.mod: Add dependencies

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-29 02:18:05 +02:00
parent aef9e24e40
commit f22bf3f388
13 changed files with 412 additions and 49 deletions

View File

@@ -320,6 +320,67 @@ func (p *P) removeSubscriber(ws *websocket.Conn) {
delete(p.WriteChans, ws)
}
// HasActiveNIP46Signer checks if there's an active subscription for kind 24133
// where the given pubkey is involved (either as author filter or in #p tag filter).
// This is used to authenticate clients by proving a signer is connected for that pubkey.
func (p *P) HasActiveNIP46Signer(signerPubkey []byte) bool {
const kindNIP46 = 24133
p.Mx.RLock()
defer p.Mx.RUnlock()
for _, subs := range p.Map {
for _, sub := range subs {
if sub.S == nil {
continue
}
for _, f := range *sub.S {
if f == nil || f.Kinds == nil {
continue
}
// Check if filter is for kind 24133
hasNIP46Kind := false
for _, k := range f.Kinds.K {
if k.K == kindNIP46 {
hasNIP46Kind = true
break
}
}
if !hasNIP46Kind {
continue
}
// Check if the signer pubkey matches the #p tag filter
if f.Tags != nil {
pTag := f.Tags.GetFirst([]byte("p"))
if pTag != nil && pTag.Len() >= 2 {
for i := 1; i < pTag.Len(); i++ {
tagValue := pTag.T[i]
// Compare - handle both binary and hex formats
if len(tagValue) == 32 && len(signerPubkey) == 32 {
if utils.FastEqual(tagValue, signerPubkey) {
return true
}
} else if len(tagValue) == 64 && len(signerPubkey) == 32 {
// tagValue is hex, signerPubkey is binary
if string(tagValue) == hex.Enc(signerPubkey) {
return true
}
} else if len(tagValue) == 32 && len(signerPubkey) == 64 {
// tagValue is binary, signerPubkey is hex
if hex.Enc(tagValue) == string(signerPubkey) {
return true
}
} else if utils.FastEqual(tagValue, signerPubkey) {
return true
}
}
}
}
}
}
}
return false
}
// canSeePrivateEvent checks if the authenticated user can see an event with a private tag
func (p *P) canSeePrivateEvent(
authedPubkey, privatePubkey []byte, remote string,