relayer

package module
v2.100.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: Unlicense Imports: 33 Imported by: 0

README

Nostr Relay Framework -- use it to implement your own custom relay.

There is an example/reference implementation at basic. Binaries for that are also available under Releases.

GoDoc

Documentation

Index

Constants

View Source
const AUTH_CONTEXT_KEY = iota

Variables

This section is empty.

Functions

func AddEvent

func AddEvent(ctx context.Context, relay Relay, evt *nostr.Event) (accepted bool, message string)

AddEvent has a business rule to add an event to the relayer

func AddEvents

func AddEvents(ctx context.Context, relay Relay, events []nostr.Event) (accepted bool, message string)

AddEvents is a helper function to add multiple events to the relayer It filters out ephemeral events and calls PublishServal on the RelayWrapper

func BroadcastEvent

func BroadcastEvent(evt *nostr.Event)

func GetAuthStatus

func GetAuthStatus(ctx context.Context) (pubkey string, ok bool)

func GetConnPubkey

func GetConnPubkey(ctx context.Context, ws *WebSocket) string

GetConnPubkey returns a pubkey associated with this connection, preferring authenticated pubkey (NIP-42). If not authenticated, it falls back to the optional "pubkey" provided via request header and stored in context.

func GetListeningFilters

func GetListeningFilters() nostr.Filters

func GetUserAgent

func GetUserAgent(ctx context.Context) string

GetUserAgent returns the User-Agent string stored in the context.

Types

type AdminKeyData

type AdminKeyData struct {
	EventID             string `json:"event_id" db:"event_id"`
	GroupID             string `json:"group_id" db:"group_id"`
	OwnerPubkey         string `json:"owner_pubkey" db:"owner_pubkey"`
	UserPubkey          string `json:"user_pubkey" db:"user_pubkey"`
	EncryptedPrivateKey string `json:"encrypted_private_key" db:"encrypted_private_key"`
	Latest              bool   `json:"latest" db:"latest"`
	CreatedAt           int64  `json:"created_at" db:"created_at"`
	InsertedAt          int64  `json:"inserted_at" db:"inserted_at"`
}

AdminKeyData represents the data structure for admin keys based on entgo schema

type AdminKeyUpdateRequest

type AdminKeyUpdateRequest struct {
	GroupID       string     `json:"groupId"`
	EncryptPubkey string     `json:"encryptPubkey,omitempty"`
	Roles         [][]string `json:"roles,omitempty"`
	CreatedAt     int64      `json:"createdAt,omitempty"`
}

AdminKeyUpdateRequest represents the structure for 3046 events (admin-key update)

type AdvancedDeleter

type AdvancedDeleter interface {
	BeforeDelete(ctx context.Context, id string, pubkey string)
	AfterDelete(id string, pubkey string)
}

AdvancedDeleter methods are called before and after [Storage.DeleteEvent].

type AdvancedSaver

type AdvancedSaver interface {
	BeforeSave(context.Context, *nostr.Event)
	AfterSave(*nostr.Event)
}

AdvancedSaver methods are called before and after [Storage.SaveEvent].

type AliasRequest

type AliasRequest struct {
	GroupID string `json:"groupId"`
	Alias   string `json:"alias"`
}

AliasRequest represents the structure for 39304 events

type Auther

type Auther interface {
	ServiceURL() string
}

Auther is the interface for implementing NIP-42. ServiceURL() returns the URL used to verify the "AUTH" event from clients.

type CustomWebSocketHandler

type CustomWebSocketHandler interface {
	HandleUnknownType(ws *WebSocket, typ string, request []json.RawMessage)
}

CustomWebSocketHandler, if implemented, is passed nostr message types unrecognized by the server. The server handles "EVENT", "REQ" and "CLOSE" messages, as described in NIP-01.

type EventBroadcaster

type EventBroadcaster interface {
	BroadcastEvent(*nostr.Event)
}

EventBroadcaster, if implemented by the outer relay, will be invoked whenever an event is accepted so the implementation can propagate the event to other relay instances (e.g., via Redis Pub/Sub).

The relayer core only checks for this interface and calls it; it does not implement any transport itself.

type EventCounter

type EventCounter interface {
	CountEvents(ctx context.Context, filter nostr.Filter) (int64, error)
}

type FilterRequest

type FilterRequest struct {
	Filters nostr.Filters `json:"filters"`
}

type GroupApprovalData

type GroupApprovalData struct {
	GroupID                string    `json:"group_id" db:"group_id"`
	IsJoinApprovalRequired bool      `json:"is_join_approval_required" db:"is_join_approval_required"`
	CreatedAt              time.Time `json:"created_at" db:"created_at"`
	UpdatedAt              time.Time `json:"updated_at" db:"updated_at"`
	IsDissolved            bool      `json:"is_dissolved" db:"is_dissolved"`
}

GroupApprovalData represents the data structure for group approval status

type GroupConfigProvider

type GroupConfigProvider interface {
	GetGroupManagementConfig() interface{} // Use interface{} for flexibility
}

GroupConfigProvider interface for getting group management configuration

type GroupManagementConfig

type GroupManagementConfig struct {
	BotPrivateKey string
}

GroupManagementConfig holds the configuration for group management

type GroupMembershipData

type GroupMembershipData struct {
	EventID             string  `json:"event_id" db:"event_id"`
	GroupID             string  `json:"group_id" db:"group_id"`
	MemberPubkey        string  `json:"member_pubkey" db:"member_pubkey"`
	EncryptedSessionKey string  `json:"encrypted_session_key" db:"encrypted_session_key"`
	AdminPubkey         string  `json:"admin_pubkey" db:"admin_pubkey"`
	GenPubkey           string  `json:"gen_pubkey" db:"gen_pubkey"`
	PreGenPubkey        *string `json:"pre_gen_pubkey" db:"pre_gen_pubkey"`
	Latest              bool    `json:"latest" db:"latest"`
	DecryptType         int     `json:"decrypt_type" db:"decrypt_type"`
	CreatedAt           int64   `json:"created_at" db:"created_at"`
	InsertedAt          int64   `json:"inserted_at" db:"inserted_at"`
}

GroupMembershipData represents the data structure for group membership based on entgo schema

type GroupSchemaProvider

type GroupSchemaProvider interface {
	GetGroupManagementSchema() string
}

optional schema provider interface; if implemented by relay, used to fetch schema

type HTTPQueryLimits

type HTTPQueryLimits struct {
	DefaultFilterLimit int `json:"default_filter_limit"`
	MaxEvents          int `json:"max_events"`
	MaxResponseBytes   int `json:"max_response_bytes"`
	MaxFilters         int `json:"max_filters"` // 0 or negative means unlimited
	RequestTimeoutSecs int `json:"request_timeout_secs"`
}

HTTPQueryLimits is the public shape used to read/update HTTP query caps.

type Informationer

type Informationer interface {
	GetNIP11InformationDocument() nip11.RelayInformationDocument
}

Informationer is called to compose NIP-11 response to an HTTP request with application/nostr+json mime type. See also Relay.Name.

type Injector

type Injector interface {
	InjectEvents() chan nostr.Event
}

type IsShareableRequest

type IsShareableRequest struct {
	GroupID     string `json:"groupId"`
	IsShareable bool   `json:"shareable"`
}

IsShareableRequest represents the structure for 20041 events

type JoinApprovalRequest

type JoinApprovalRequest struct {
	GroupID                string `json:"groupId"`
	IsJoinApprovalRequired bool   `json:"review"`
}

JoinApprovalRequest represents the structure for 20042 events

type Listener

type Listener struct {
	// contains filtered or unexported fields
}

type Logger

type Logger interface {
	Infof(format string, v ...any)
	Warningf(format string, v ...any)
	Errorf(format string, v ...any)
}

Logger is what Server uses to log messages.

type MemberAdditionRequest

type MemberAdditionRequest struct {
	Type          string     `json:"type,omitempty"`
	GroupID       string     `json:"groupId"`
	GenPubkey     string     `json:"genPubkey"`
	PreGenPubkey  string     `json:"preGenPubkey"`
	EncryptPubkey string     `json:"encryptPubkey,omitempty"`
	Members       [][]string `json:"members,omitempty"`
	CreatedAt     int64      `json:"createdAt"`
}

MemberAdditionRequest represents the structure for 3047 events (same as session key rotation)

type MemberAliasData

type MemberAliasData struct {
	GroupID      string    `json:"group_id" db:"group_id"`
	MemberPubkey string    `json:"member_pubkey" db:"member_pubkey"`
	Alias        string    `json:"alias" db:"alias"`
	CreatedAt    time.Time `json:"created_at" db:"created_at"`
}

MemberAliasData represents the data structure for member aliases

type Notice

type Notice struct {
	Kind    string `json:"kind"`
	Message string `json:"message"`
}

type Option

type Option func(*Options)

func WithPerConnectionLimiter

func WithPerConnectionLimiter(rps rate.Limit, burst int) Option

func WithSkipEventFunc

func WithSkipEventFunc(skipEventFunc func(*nostr.Event) bool) Option

type Options

type Options struct {
	// contains filtered or unexported fields
}

func DefaultOptions

func DefaultOptions() *Options

type QueryResponse

type QueryResponse struct {
	Code int            `json:"code"`
	Msg  string         `json:"msg"`
	Data []*nostr.Event `json:"data"`
}

type Relay

type Relay interface {
	// Name is used as the "name" field in NIP-11 and as a prefix in default Server logging.
	// For other NIP-11 fields, see [Informationer].
	Name() string
	// Init is called at the very beginning by [Server.Start], allowing a relay
	// to initialize its internal resources.
	// Also see [eventstore.Store.Init].
	Init() error
	// AcceptEvent is called for every nostr event received by the server.
	// If the returned value is true, the event is passed on to [Storage.SaveEvent].
	// Otherwise, the server responds with a negative and "blocked" message as described
	// in NIP-20.
	AcceptEvent(context.Context, *nostr.Event) (bool, string)
	// Storage returns the relay storage implementation (writer)
	Storage(context.Context) eventstore.Store
	// ReaderStorage returns the relay read-only storage implementation (reader, fallback to writer if nil)
	ReaderStorage(context.Context) eventstore.Store
}

Relay is the main interface for implementing a nostr relay.

type ReqAccepter

type ReqAccepter interface {
	// AcceptReq is called for every nostr request filters received by the
	// server. If the returned value is true, the filtres is passed on to
	// [Storage.QueryEvent].
	AcceptReq(ctx context.Context, id string, filters nostr.Filters, authedPubkey string) bool
}

ReqAccepter is the main interface for implementing a nostr relay.

type Server

type Server struct {
	// Default logger, as set by NewServer, is a stdlib logger prefixed with [Relay.Name],
	// outputting to stderr.
	Log Logger

	// in case you call Server.Start
	Addr string
	// contains filtered or unexported fields
}

Server is a base for package users to implement nostr relays. It can serve HTTP requests and websockets, passing control over to a relay implementation.

To implement a relay, it is enough to satisfy Relay interface. Other interfaces are Informationer, CustomWebSocketHandler, ShutdownAware and AdvancedXxx types. See their respective doc comments.

The basic usage is to call Start or StartConf, which starts serving immediately. For a more fine-grained control, use NewServer. See basic/main.go, whitelisted/main.go, expensive/main.go and rss-bridge/main.go for example implementations.

The following resource is a good starting point for details on what nostr protocol is and how it works: https://github.com/nostr-protocol/nostr

func NewServer

func NewServer(relay Relay, opts ...Option) (*Server, error)

NewServer initializes the relay and its storage using their respective Init methods, returning any non-nil errors, and returns a Server ready to listen for HTTP requests.

func (*Server) HTTPQueryLimits

func (s *Server) HTTPQueryLimits() HTTPQueryLimits

HTTPQueryLimits returns a snapshot of the current HTTP query limits.

func (*Server) HandleHTTPQueryConfig

func (s *Server) HandleHTTPQueryConfig(w http.ResponseWriter, req *http.Request)

HandleHTTPQueryConfig exposes GET/POST to inspect or adjust HTTP query limits dynamically. Mount it on a private path and protect it upstream if needed.

func (*Server) HandleHttpReq

func (s *Server) HandleHttpReq(w http.ResponseWriter, req *http.Request, store eventstore.Store)

func (*Server) HandleNIP11

func (s *Server) HandleNIP11(w http.ResponseWriter, r *http.Request)

func (*Server) HandleWebsocket

func (s *Server) HandleWebsocket(w http.ResponseWriter, r *http.Request)

func (*Server) Router

func (s *Server) Router() *http.ServeMux

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler interface.

func (*Server) SetHTTPQueryLimits

func (s *Server) SetHTTPQueryLimits(limits HTTPQueryLimits)

SetHTTPQueryLimits updates the dynamic HTTP query limits at runtime.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context)

Shutdown sends a websocket close control message to all connected clients.

If the relay is ShutdownAware, Shutdown calls its OnShutdown, passing the context as is. Note that the HTTP server make some time to shutdown and so the context deadline, if any, may have been shortened by the time OnShutdown is called.

func (*Server) Start

func (s *Server) Start(host string, port int, started ...chan bool) error

func (*Server) StartResourceMonitoring

func (s *Server) StartResourceMonitoring()

StartResourceMonitoring 启动简化的资源监控goroutine(导出函数供外部调用)

type SessionKeyRotationRequest

type SessionKeyRotationRequest struct {
	GroupID       string     `json:"groupId"`
	GenPubkey     string     `json:"genPubkey,omitempty"`
	PreGenPubkey  *string    `json:"preGenPubkey,omitempty"`
	EncryptPubkey string     `json:"encryptPubkey,omitempty"`
	Members       [][]string `json:"members,omitempty"`
	CreatedAt     int64      `json:"createdAt,omitempty"`
}

SessionKeyRotationRequest represents the structure for 3046 events (gen-key update)

type ShutdownAware

type ShutdownAware interface {
	OnShutdown(context.Context)
}

ShutdownAware is called during the server shutdown. See Server.Shutdown for details.

type WebSocket

type WebSocket struct {
	// contains filtered or unexported fields
}

func (*WebSocket) WriteJSON

func (ws *WebSocket) WriteJSON(any interface{}) error

func (*WebSocket) WriteMessage

func (ws *WebSocket) WriteMessage(t int, b []byte) error

Directories

Path Synopsis
examples
basic command
expensive command
rss-bridge command
search command
whitelisted command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL