complete the marshal/unmarshal of events using the new pool enabled tag codecs
This commit is contained in:
5
app/handle-message.go
Normal file
5
app/handle-message.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package app
|
||||
|
||||
func (s *Server) HandleMessage() {
|
||||
|
||||
}
|
||||
@@ -25,9 +25,9 @@ import (
|
||||
// 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) {
|
||||
func (s *Server) HandleRelayInfo(w http.ResponseWriter, r *http.Request) {
|
||||
r.Header.Set("Content-Type", "application/json")
|
||||
log.I.Ln("handling relay information document")
|
||||
log.D.Ln("handling relay information document")
|
||||
var info *relayinfo.T
|
||||
supportedNIPs := relayinfo.GetList(
|
||||
relayinfo.BasicProtocol,
|
||||
@@ -47,14 +47,14 @@ func (l *Listener) HandleRelayInfo(w http.ResponseWriter, r *http.Request) {
|
||||
sort.Sort(supportedNIPs)
|
||||
log.T.Ln("supported NIPs", supportedNIPs)
|
||||
info = &relayinfo.T{
|
||||
Name: l.Config.AppName,
|
||||
Name: s.Config.AppName,
|
||||
Description: version.Description,
|
||||
Nips: supportedNIPs,
|
||||
Software: version.URL,
|
||||
Version: version.V,
|
||||
Limitation: relayinfo.Limits{
|
||||
// AuthRequired: l.C.AuthRequired,
|
||||
// RestrictedWrites: l.C.AuthRequired,
|
||||
// AuthRequired: s.C.AuthRequired,
|
||||
// RestrictedWrites: s.C.AuthRequired,
|
||||
},
|
||||
Icon: "https://cdn.satellite.earth/ac9778868fbf23b63c47c769a74e163377e6ea94d3f0f31711931663d035c4f6.png",
|
||||
}
|
||||
100
app/handle-websocket.go
Normal file
100
app/handle-websocket.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
"lol.mleku.dev/chk"
|
||||
"lol.mleku.dev/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// CloseMessage denotes a close control message. The optional message
|
||||
// payload contains a numeric code and text. Use the FormatCloseMessage
|
||||
// function to format a close message payload.
|
||||
CloseMessage = 8
|
||||
|
||||
// PingMessage denotes a ping control message. The optional message payload
|
||||
// is UTF-8 encoded text.
|
||||
PingMessage = 9
|
||||
|
||||
// PongMessage denotes a pong control message. The optional message payload
|
||||
// is UTF-8 encoded text.
|
||||
PongMessage = 10
|
||||
)
|
||||
|
||||
func (s *Server) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||
remote := GetRemoteFromReq(r)
|
||||
var cancel context.CancelFunc
|
||||
s.Ctx, cancel = context.WithCancel(s.Ctx)
|
||||
defer cancel()
|
||||
var err error
|
||||
var conn *websocket.Conn
|
||||
if conn, err = websocket.Accept(
|
||||
w, r, &websocket.AcceptOptions{},
|
||||
); chk.E(err) {
|
||||
return
|
||||
}
|
||||
defer conn.CloseNow()
|
||||
|
||||
go s.Pinger(s.Ctx, conn, time.NewTicker(time.Second*10), cancel)
|
||||
for {
|
||||
select {
|
||||
case <-s.Ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
var typ websocket.MessageType
|
||||
var message []byte
|
||||
if typ, message, err = conn.Read(s.Ctx); err != nil {
|
||||
if strings.Contains(
|
||||
err.Error(), "use of closed network connection",
|
||||
) {
|
||||
return
|
||||
}
|
||||
status := websocket.CloseStatus(err)
|
||||
switch status {
|
||||
case websocket.StatusNormalClosure,
|
||||
websocket.StatusGoingAway,
|
||||
websocket.StatusNoStatusRcvd,
|
||||
websocket.StatusAbnormalClosure,
|
||||
websocket.StatusProtocolError:
|
||||
default:
|
||||
log.E.F("unexpected close error from %s: %v", remote, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if typ == PingMessage {
|
||||
if err = conn.Write(s.Ctx, PongMessage, message); chk.E(err) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
go s.HandleMessage()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Pinger(
|
||||
ctx context.Context, conn *websocket.Conn, ticker *time.Ticker,
|
||||
cancel context.CancelFunc,
|
||||
) {
|
||||
defer func() {
|
||||
cancel()
|
||||
ticker.Stop()
|
||||
}()
|
||||
var err error
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
if err = conn.Write(ctx, PingMessage, nil); err != nil {
|
||||
log.E.F("error writing ping: %v; closing websocket", err)
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
69
app/helpers.go
Normal file
69
app/helpers.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetRemoteFromReq retrieves the originating IP address of the client from
|
||||
// an HTTP request, considering standard and non-standard proxy headers.
|
||||
//
|
||||
// # Parameters
|
||||
//
|
||||
// - r: The HTTP request object containing details of the client and
|
||||
// routing information.
|
||||
//
|
||||
// # Return Values
|
||||
//
|
||||
// - rr: A string value representing the IP address of the originating
|
||||
// remote client.
|
||||
//
|
||||
// # Expected behaviour
|
||||
//
|
||||
// The function first checks for the standardized "Forwarded" header (RFC 7239)
|
||||
// to identify the original client IP. If that isn't available, it falls back to
|
||||
// the "X-Forwarded-For" header. If both headers are absent, it defaults to
|
||||
// using the request's RemoteAddr.
|
||||
//
|
||||
// For the "Forwarded" header, it extracts the client IP from the "for"
|
||||
// parameter. For the "X-Forwarded-For" header, if it contains one IP, it
|
||||
// returns that. If it contains two IPs, it returns the second.
|
||||
func GetRemoteFromReq(r *http.Request) (rr string) {
|
||||
// First check for the standardized Forwarded header (RFC 7239)
|
||||
forwarded := r.Header.Get("Forwarded")
|
||||
if forwarded != "" {
|
||||
// Parse the Forwarded header which can contain multiple parameters
|
||||
//
|
||||
// Format:
|
||||
//
|
||||
// Forwarded: by=<identifier>;for=<identifier>;host=<host>;proto=<http|https>
|
||||
parts := strings.Split(forwarded, ";")
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if strings.HasPrefix(part, "for=") {
|
||||
// Extract the client IP from the "for" parameter
|
||||
forValue := strings.TrimPrefix(part, "for=")
|
||||
// Remove quotes if present
|
||||
forValue = strings.Trim(forValue, "\"")
|
||||
// Handle IPv6 addresses which are enclosed in square brackets
|
||||
forValue = strings.Trim(forValue, "[]")
|
||||
return forValue
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the Forwarded header is not available or doesn't contain "for"
|
||||
// parameter, fall back to X-Forwarded-For
|
||||
rem := r.Header.Get("X-Forwarded-For")
|
||||
if rem == "" {
|
||||
rr = r.RemoteAddr
|
||||
} else {
|
||||
splitted := strings.Split(rem, " ")
|
||||
if len(splitted) == 1 {
|
||||
rr = splitted[0]
|
||||
}
|
||||
if len(splitted) == 2 {
|
||||
rr = splitted[1]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,29 +1,9 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"lol.mleku.dev/log"
|
||||
"next.orly.dev/app/config"
|
||||
"github.com/coder/websocket"
|
||||
)
|
||||
|
||||
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
|
||||
conn *websocket.Conn
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func Run(ctx context.Context, cfg *config.C) (quit chan struct{}) {
|
||||
}
|
||||
}()
|
||||
// start listener
|
||||
l := &Listener{
|
||||
l := &Server{
|
||||
Config: cfg,
|
||||
}
|
||||
addr := fmt.Sprintf("%s:%d", cfg.Listen, cfg.Port)
|
||||
|
||||
26
app/server.go
Normal file
26
app/server.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"lol.mleku.dev/log"
|
||||
"next.orly.dev/app/config"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
mux *http.ServeMux
|
||||
Config *config.C
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
log.T.F("path %v header %v", r.URL, r.Header)
|
||||
if r.Header.Get("Upgrade") == "websocket" {
|
||||
s.HandleWebsocket(w, r)
|
||||
} else if r.Header.Get("Accept") == "application/nostr+json" {
|
||||
s.HandleRelayInfo(w, r)
|
||||
} else {
|
||||
http.Error(w, "Upgrade required", http.StatusUpgradeRequired)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user