Add relayinfo package and utility modules for NIP-11 support

Introduce the `relayinfo` package with `NIP-11` utilities, including `Fees`, `Limits`, and `NIPs` structures. Add utility modules for handling numbers, timestamps, and kinds. Integrate functionality for fetching and managing relay information.
This commit is contained in:
2025-08-21 15:22:17 +01:00
parent ecaf52b98f
commit 8add32bb78
16 changed files with 1541 additions and 2 deletions

63
app/handleRelayinfo.go Normal file
View File

@@ -0,0 +1,63 @@
package app
import (
"encoding/json"
"net/http"
"sort"
"lol.mleku.dev/chk"
"lol.mleku.dev/log"
"next.orly.dev/pkg/protocol/relayinfo"
"next.orly.dev/pkg/version"
)
// HandleRelayInfo generates and returns a relay information document in JSON
// format based on the server's configuration and supported NIPs.
//
// # Parameters
//
// - w: HTTP response writer used to send the generated document.
//
// - r: HTTP request object containing incoming client request data.
//
// # Expected Behaviour
//
// The function constructs a relay information document using either the
// Informer interface implementation or predefined server configuration. It
// returns this document as a JSON response to the client.
func (l *Listener) HandleRelayInfo(w http.ResponseWriter, r *http.Request) {
r.Header.Set("Content-Type", "application/json")
log.I.Ln("handling relay information document")
var info *relayinfo.T
supportedNIPs := relayinfo.GetList(
relayinfo.BasicProtocol,
// relayinfo.Authentication,
// relayinfo.EncryptedDirectMessage,
// relayinfo.EventDeletion,
relayinfo.RelayInformationDocument,
// relayinfo.GenericTagQueries,
// relayinfo.NostrMarketplace,
// relayinfo.EventTreatment,
// relayinfo.CommandResults,
// relayinfo.ParameterizedReplaceableEvents,
// relayinfo.ExpirationTimestamp,
// relayinfo.ProtectedEvents,
// relayinfo.RelayListMetadata,
)
sort.Sort(supportedNIPs)
log.T.Ln("supported NIPs", supportedNIPs)
info = &relayinfo.T{
Name: l.Config.AppName,
Description: version.Description,
Nips: supportedNIPs,
Software: version.URL,
Version: version.V,
Limitation: relayinfo.Limits{
// AuthRequired: l.C.AuthRequired,
// RestrictedWrites: l.C.AuthRequired,
},
Icon: "https://cdn.satellite.earth/ac9778868fbf23b63c47c769a74e163377e6ea94d3f0f31711931663d035c4f6.png",
}
if err := json.NewEncoder(w).Encode(info); chk.E(err) {
}
}

29
app/listener.go Normal file
View File

@@ -0,0 +1,29 @@
package app
import (
"net/http"
"lol.mleku.dev/log"
"next.orly.dev/app/config"
)
type Listener struct {
mux *http.ServeMux
Config *config.C
}
func (l *Listener) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.I.F("path %v header %v", r.URL, r.Header)
if r.Header.Get("Upgrade") == "websocket" {
l.HandleWebsocket(w, r)
} else if r.Header.Get("Accept") == "application/nostr+json" {
l.HandleRelayInfo(w, r)
} else {
http.Error(w, "Upgrade required", http.StatusUpgradeRequired)
}
}
func (l *Listener) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
log.I.F("websocket")
return
}

View File

@@ -2,6 +2,8 @@ package app
import (
"context"
"fmt"
"net/http"
"lol.mleku.dev/log"
"next.orly.dev/app/config"
@@ -17,7 +19,12 @@ func Run(ctx context.Context, cfg *config.C) (quit chan struct{}) {
}
}()
// start listener
l := &Listener{
Config: cfg,
}
addr := fmt.Sprintf("%s:%d", cfg.Listen, cfg.Port)
log.I.F("starting listener on %s", addr)
go http.ListenAndServe(addr, l)
quit = make(chan struct{})
return
}