the main motivation for this change is to be able to run tests.
before this commit, Start, Router and Log operated on global variables,
making automated testing unreasonably hard.
this commit puts all that a server needs in a new Server type,
which also made it possible for a Server.Shutdown - see ShutdownAware
doc comments.
BREAKING CHANGES:
- Relay.OnInitialized takes one argument now, *relayer.Server.
- relayer.Router is now replaced by relayer.Server.Router().
package users can still hook into the router from OnInitialized
for custom HTTP routing.
- relayer.Log is gone. apart from another global var, imho this was
a too opinionated choice for a framework to build a custom relay upon.
this commit introduces a Logger interface which package users can implement
for zerolog to make it log like before. see Server.Log for details.
other notable changes: finally added a couple basic tests, for start up
and shutdown. doc comments now explain most of the essentials,
hopefully making it more approachable for newcomers and easier to understand
the relayer package.
the changes in handlers.go are minimal, although git diff goes crazy.
this is because most of the lines are simply shifted indentation back by one
due to go fmt.
before this commit:
func handleWebsocket(relay Relay) func(http.ResponseWriter, *http.Request)
func handleNIP11(relay Relay) func(http.ResponseWriter, *http.Request)
after:
func (s *Server) handleWebsocket(w http.ResponseWriter, r *http.Request)
func (s *Server) handleNIP11(w http.ResponseWriter, r *http.Request)
94 lines
3.1 KiB
Go
94 lines
3.1 KiB
Go
package relayer
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/nbd-wtf/go-nostr"
|
|
"github.com/nbd-wtf/go-nostr/nip11"
|
|
)
|
|
|
|
// Relay is the main interface for implementing a nostr 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 [Storage.Init].
|
|
Init() error
|
|
// OnInitialized is called by [Server.Start] right before starting to serve HTTP requests.
|
|
// It is passed the server to allow callers make final adjustments, such as custom routing.
|
|
OnInitialized(*Server)
|
|
// 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(*nostr.Event) bool
|
|
// Storage returns the relay storage implementation.
|
|
Storage() Storage
|
|
}
|
|
|
|
type Injector interface {
|
|
InjectEvents() chan nostr.Event
|
|
}
|
|
|
|
// Informationer is called to compose NIP-11 response to an HTTP request
|
|
// with application/nostr+json mime type.
|
|
// See also [Relay.Name].
|
|
type Informationer interface {
|
|
GetNIP11InformationDocument() nip11.RelayInformationDocument
|
|
}
|
|
|
|
// 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 CustomWebSocketHandler interface {
|
|
HandleUnknownType(ws *WebSocket, typ string, request []json.RawMessage)
|
|
}
|
|
|
|
// ShutdownAware is called during the server shutdown.
|
|
// See [Server.Shutdown] for details.
|
|
type ShutdownAware interface {
|
|
OnShutdown(context.Context)
|
|
}
|
|
|
|
// Logger is what [Server] uses to log messages.
|
|
type Logger interface {
|
|
Infof(format string, v ...any)
|
|
Warningf(format string, v ...any)
|
|
Errorf(format string, v ...any)
|
|
}
|
|
|
|
// Storage is a persistence layer for nostr events handled by a relay.
|
|
type Storage interface {
|
|
// Init is called at the very beginning by [Server.Start], after [Relay.Init],
|
|
// allowing a storage to initialize its internal resources.
|
|
Init() error
|
|
|
|
// QueryEvents is invoked upon a client's REQ as described in NIP-01.
|
|
QueryEvents(filter *nostr.Filter) (events []nostr.Event, err error)
|
|
// DeleteEvent is used to handle deletion events, as per NIP-09.
|
|
DeleteEvent(id string, pubkey string) error
|
|
// SaveEvent is called once Relay.AcceptEvent reports true.
|
|
SaveEvent(event *nostr.Event) error
|
|
}
|
|
|
|
// AdvancedQuerier methods are called before and after [Storage.QueryEvents].
|
|
type AdvancedQuerier interface {
|
|
BeforeQuery(*nostr.Filter)
|
|
AfterQuery([]nostr.Event, *nostr.Filter)
|
|
}
|
|
|
|
// AdvancedDeleter methods are called before and after [Storage.DeleteEvent].
|
|
type AdvancedDeleter interface {
|
|
BeforeDelete(id string, pubkey string)
|
|
AfterDelete(id string, pubkey string)
|
|
}
|
|
|
|
// AdvancedSaver methods are called before and after [Storage.SaveEvent].
|
|
type AdvancedSaver interface {
|
|
BeforeSave(*nostr.Event)
|
|
AfterSave(*nostr.Event)
|
|
}
|