Documentation
¶
Index ¶
- Variables
- func BroadcastEvent(evt nostr.Event)
- func ClientHandler(ws *websocket.Conn)
- func DeleteEvents(ids []string) error
- func HandleArgs() bool
- func ImportEvents(filename string) error
- func InitStatsMonitoring()
- func PrintStats()
- func ReadDeleteFile(path string) ([]string, error)
- func Run() error
- func SetVersionInfo(version, buildTime, gitCommit string)
- type Client
- func (c *Client) AllowEvent(kind int, category string) (bool, string)
- func (c *Client) AllowReq() (bool, string)
- func (c *Client) ClientInfo() string
- func (c *Client) CloseClient()
- func (c *Client) DeleteSubscription(subID string)
- func (c *Client) ForEachSubscription(fn func(subID string, filters []nostr.Filter))
- func (c *Client) GetSubscriptions() map[string][]nostr.Filter
- func (c *Client) GetWS() *websocket.Conn
- func (c *Client) IsConnected() bool
- func (c *Client) SendMessage(msg interface{})
- func (c *Client) SetSubscription(subID string, filters []nostr.Filter)
- func (c *Client) SubscriptionCount() int
- type ConnectionManager
Constants ¶
This section is empty.
Variables ¶
var ( Version = "dev" BuildTime = "unknown" GitCommit = "unknown" )
Version information - these will be set during build via main package
Functions ¶
func BroadcastEvent ¶ added in v0.5.0
BroadcastEvent sends an event to all connected clients whose active subscriptions match the event. This is the real-time delivery mechanism required by NIP-01: after EOSE, new matching events are pushed to subscribers.
func ClientHandler ¶
func DeleteEvents ¶ added in v0.5.0
DeleteEvents is the admin-takedown entry point invoked from `grain --delete <id>` / `grain --delete-file <path>`. It opens nostrdb with the same settings as normal startup, enqueues a physical delete for every supplied hex event id, and waits for the writer queue to drain on Close.
Authorization model: there is none. Shell access to the grain binary and data directory is the authorization boundary — identical to the existing `--import` flow. This is the moderator / legal-takedown path, not a protocol-level feature, and deliberately has no signature check.
Each call logs one line per id: "deleted <id>" on success, "not found" isn't observable from the Go side (the C delete is a no-op on missing ids and returns success), so every well-formed id that enqueues cleanly is reported as deleted. Malformed ids report an error and continue.
func HandleArgs ¶ added in v0.4.1
func HandleArgs() bool
HandleArgs processes command-line arguments and returns true if the program should exit
func ImportEvents ¶ added in v0.5.0
ImportEvents reads a JSONL file of Nostr events and stores them in nostrdb. It processes the entire file in a single run with an in-place progress bar.
func PrintStats ¶
func PrintStats()
PrintStats periodically logs messaging and connection statistics
func ReadDeleteFile ¶ added in v0.5.0
ReadDeleteFile loads a newline-delimited file of hex event ids, stripping blank lines and comments (lines beginning with '#'). Used by `grain --delete-file <path>`.
func Run ¶ added in v0.4.1
func Run() error
Run starts the GRAIN relay server with configuration management and graceful shutdown
func SetVersionInfo ¶ added in v0.4.1
func SetVersionInfo(version, buildTime, gitCommit string)
SetVersionInfo allows main package to set version information. The version is also forwarded to server/utils so the NIP-11 relay info document always advertises the running binary's version.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client implements ClientInterface
func (*Client) AllowEvent ¶ added in v0.5.0
AllowEvent checks this client's per-connection event rate limiter.
func (*Client) AllowReq ¶ added in v0.5.0
AllowReq checks this client's per-connection REQ rate limiter.
func (*Client) ClientInfo ¶
func (*Client) CloseClient ¶
func (c *Client) CloseClient()
CloseClient closes the client connection and cleans up resources
func (*Client) DeleteSubscription ¶ added in v0.5.0
func (*Client) ForEachSubscription ¶ added in v0.5.0
func (*Client) IsConnected ¶
IsConnected returns true if the client connection is still active
func (*Client) SendMessage ¶
func (c *Client) SendMessage(msg interface{})
SendMessage marshals and enqueues a message for delivery to the client. It NEVER blocks on the network — the dedicated writeLoop goroutine drains the queue. If the per-client buffer is full, the consumer is treated as slow/dead: the message is dropped and the connection is closed. This is the load-bearing fix for the broadcaster lockup: a single stuck peer can no longer freeze BroadcastEvent for every other client.
func (*Client) SetSubscription ¶ added in v0.5.0
func (*Client) SubscriptionCount ¶ added in v0.5.0
type ConnectionManager ¶
type ConnectionManager struct {
// contains filtered or unexported fields
}
ConnectionManager tracks connections and memory usage
func (*ConnectionManager) GetConnectionCount ¶
func (cm *ConnectionManager) GetConnectionCount() int
GetConnectionCount returns the current number of connections
func (*ConnectionManager) GetMemoryStats ¶
func (cm *ConnectionManager) GetMemoryStats() map[string]interface{}
GetMemoryStats returns memory statistics for monitoring
func (*ConnectionManager) RegisterConnection ¶
func (cm *ConnectionManager) RegisterConnection(client *Client)
RegisterConnection adds a connection to the manager. If the memory threshold is exceeded, the oldest connection is selected for eviction and closed AFTER releasing cm.mu — the close path re-enters this manager via RemoveConnection, which would self-deadlock the goroutine if we were still holding the lock here. That self-deadlock was the production WebSocket lockup symptom: the holding goroutine blocked forever on its own mutex, every subsequent new connection then blocked on cm.mu, and the relay went silent on WebSockets while HTTP kept serving (it never touches cm).
func (*ConnectionManager) RemoveConnection ¶
func (cm *ConnectionManager) RemoveConnection(client *Client)
RemoveConnection removes a connection from tracking