Refactor Destination struct to enhance request handling and link management; introduce IncomingLinkHandler for improved link processing and update transport interface usage.

This commit is contained in:
2025-12-01 20:30:32 -06:00
parent ad5b6ed83a
commit 52f8e21da0

View File

@@ -14,9 +14,7 @@ import (
"github.com/Sudo-Ivan/reticulum-go/pkg/common" "github.com/Sudo-Ivan/reticulum-go/pkg/common"
"github.com/Sudo-Ivan/reticulum-go/pkg/debug" "github.com/Sudo-Ivan/reticulum-go/pkg/debug"
"github.com/Sudo-Ivan/reticulum-go/pkg/identity" "github.com/Sudo-Ivan/reticulum-go/pkg/identity"
"github.com/Sudo-Ivan/reticulum-go/pkg/link"
"github.com/Sudo-Ivan/reticulum-go/pkg/packet" "github.com/Sudo-Ivan/reticulum-go/pkg/packet"
"github.com/Sudo-Ivan/reticulum-go/pkg/transport"
"github.com/vmihailenco/msgpack/v5" "github.com/vmihailenco/msgpack/v5"
"golang.org/x/crypto/curve25519" "golang.org/x/crypto/curve25519"
) )
@@ -52,12 +50,26 @@ type LinkEstablishedCallback = common.LinkEstablishedCallback
type RequestHandler struct { type RequestHandler struct {
Path string Path string
ResponseGenerator func(pathHash []byte, data []byte, requestID []byte, remoteIdentity *identity.Identity, requestedAt time.Time) interface{} ResponseGenerator func(path string, data []byte, requestID []byte, linkID []byte, remoteIdentity *identity.Identity, requestedAt int64) []byte
AllowMode byte AllowMode byte
AllowedList [][]byte AllowedList [][]byte
AutoCompress bool AutoCompress bool
} }
type Transport interface {
GetConfig() *common.ReticulumConfig
GetInterfaces() map[string]common.NetworkInterface
RegisterDestination(hash []byte, dest interface{})
}
type IncomingLinkHandler func(pkt *packet.Packet, dest *Destination, transport interface{}, networkIface common.NetworkInterface) (interface{}, error)
var incomingLinkHandler IncomingLinkHandler
func RegisterIncomingLinkHandler(handler IncomingLinkHandler) {
incomingLinkHandler = handler
}
type Destination struct { type Destination struct {
identity *identity.Identity identity *identity.Identity
direction byte direction byte
@@ -65,7 +77,7 @@ type Destination struct {
appName string appName string
aspects []string aspects []string
hashValue []byte hashValue []byte
transport *transport.Transport transport Transport
acceptsLinks bool acceptsLinks bool
proofStrategy byte proofStrategy byte
@@ -74,15 +86,15 @@ type Destination struct {
proofCallback ProofRequestedCallback proofCallback ProofRequestedCallback
linkCallback LinkEstablishedCallback linkCallback LinkEstablishedCallback
ratchetsEnabled bool ratchetsEnabled bool
ratchetPath string ratchetPath string
ratchetCount int ratchetCount int
ratchetInterval int ratchetInterval int
enforceRatchets bool enforceRatchets bool
latestRatchetTime time.Time latestRatchetTime time.Time
latestRatchetID []byte latestRatchetID []byte
ratchets [][]byte ratchets [][]byte
ratchetFileLock sync.Mutex ratchetFileLock sync.Mutex
defaultAppData []byte defaultAppData []byte
mutex sync.RWMutex mutex sync.RWMutex
@@ -90,7 +102,7 @@ type Destination struct {
requestHandlers map[string]*RequestHandler requestHandlers map[string]*RequestHandler
} }
func New(id *identity.Identity, direction byte, destType byte, appName string, transport *transport.Transport, aspects ...string) (*Destination, error) { func New(id *identity.Identity, direction byte, destType byte, appName string, transport Transport, aspects ...string) (*Destination, error) {
debug.Log(debug.DEBUG_INFO, "Creating new destination", "app", appName, "type", destType, "direction", direction) debug.Log(debug.DEBUG_INFO, "Creating new destination", "app", appName, "type", destType, "direction", direction)
if id == nil { if id == nil {
@@ -121,7 +133,7 @@ func New(id *identity.Identity, direction byte, destType byte, appName string, t
// FromHash creates a destination from a known hash (e.g., from an announce). // FromHash creates a destination from a known hash (e.g., from an announce).
// This is used by clients to create destination objects for servers they've discovered. // This is used by clients to create destination objects for servers they've discovered.
func FromHash(hash []byte, id *identity.Identity, destType byte, transport *transport.Transport) (*Destination, error) { func FromHash(hash []byte, id *identity.Identity, destType byte, transport Transport) (*Destination, error) {
debug.Log(debug.DEBUG_INFO, "Creating destination from hash", "hash", fmt.Sprintf("%x", hash)) debug.Log(debug.DEBUG_INFO, "Creating destination from hash", "hash", fmt.Sprintf("%x", hash))
if id == nil { if id == nil {
@@ -155,7 +167,7 @@ func (d *Destination) calculateHash() []byte {
// Name hash is the FULL 32-byte SHA256, then we take first 10 bytes for concatenation // Name hash is the FULL 32-byte SHA256, then we take first 10 bytes for concatenation
nameHashFull := sha256.Sum256([]byte(d.ExpandName())) nameHashFull := sha256.Sum256([]byte(d.ExpandName()))
nameHash10 := nameHashFull[:10] // Only use 10 bytes nameHash10 := nameHashFull[:10] // Only use 10 bytes
debug.Log(debug.DEBUG_ALL, "Identity hash", "hash", fmt.Sprintf("%x", identityHash)) debug.Log(debug.DEBUG_ALL, "Identity hash", "hash", fmt.Sprintf("%x", identityHash))
debug.Log(debug.DEBUG_ALL, "Name hash (10 bytes)", "hash", fmt.Sprintf("%x", nameHash10)) debug.Log(debug.DEBUG_ALL, "Name hash (10 bytes)", "hash", fmt.Sprintf("%x", nameHash10))
@@ -180,50 +192,52 @@ func (d *Destination) ExpandName() string {
return name return name
} }
func (d *Destination) Announce(appData []byte) error { func (d *Destination) Announce(pathResponse bool, tag []byte, attachedInterface common.NetworkInterface) error {
d.mutex.Lock() d.mutex.Lock()
defer d.mutex.Unlock() defer d.mutex.Unlock()
debug.Log(debug.DEBUG_VERBOSE, "Announcing destination", "name", d.ExpandName()) debug.Log(debug.DEBUG_VERBOSE, "Announcing destination", "name", d.ExpandName(), "path_response", pathResponse)
if appData == nil { appData := d.defaultAppData
appData = d.defaultAppData
}
// Create announce packet using announce package // Create announce packet using announce package
// Pass the destination hash, name, and app data announceObj, err := announce.New(d.identity, d.hashValue, d.ExpandName(), appData, pathResponse, d.transport.GetConfig())
announce, err := announce.New(d.identity, d.hashValue, d.ExpandName(), appData, false, d.transport.GetConfig())
if err != nil { if err != nil {
return fmt.Errorf("failed to create announce: %w", err) return fmt.Errorf("failed to create announce: %w", err)
} }
packet := announce.GetPacket() packet := announceObj.GetPacket()
if packet == nil { if packet == nil {
return errors.New("failed to create announce packet") return errors.New("failed to create announce packet")
} }
// Send announce packet to all interfaces if pathResponse && tag != nil {
debug.Log(debug.DEBUG_VERBOSE, "Sending announce packet to all interfaces") debug.Log(debug.DEBUG_INFO, "Sending path response announce", "tag", fmt.Sprintf("%x", tag))
}
if d.transport == nil { if d.transport == nil {
return errors.New("transport not initialized") return errors.New("transport not initialized")
} }
interfaces := d.transport.GetInterfaces()
debug.Log(debug.DEBUG_ALL, "Got interfaces from transport", "count", len(interfaces))
var lastErr error var lastErr error
for name, iface := range interfaces { if attachedInterface != nil {
debug.Log(debug.DEBUG_ALL, "Checking interface", "name", name, "enabled", iface.IsEnabled(), "online", iface.IsOnline()) if attachedInterface.IsEnabled() && attachedInterface.IsOnline() {
if iface.IsEnabled() && iface.IsOnline() { debug.Log(debug.DEBUG_VERBOSE, "Sending announce to attached interface", "name", attachedInterface.GetName())
debug.Log(debug.DEBUG_ALL, "Sending announce to interface", "name", name, "bytes", len(packet)) if err := attachedInterface.Send(packet, ""); err != nil {
if err := iface.Send(packet, ""); err != nil { debug.Log(debug.DEBUG_ERROR, "Failed to send announce on attached interface", "error", err)
debug.Log(debug.DEBUG_ERROR, "Failed to send announce on interface", "name", name, "error", err)
lastErr = err lastErr = err
} else {
debug.Log(debug.DEBUG_ALL, "Successfully sent announce to interface", "name", name)
} }
} else { }
debug.Log(debug.DEBUG_ALL, "Skipping interface", "name", name, "reason", "not enabled or not online") } else {
interfaces := d.transport.GetInterfaces()
for name, iface := range interfaces {
if iface.IsEnabled() && iface.IsOnline() {
debug.Log(debug.DEBUG_VERBOSE, "Sending announce to interface", "name", name)
if err := iface.Send(packet, ""); err != nil {
debug.Log(debug.DEBUG_ERROR, "Failed to send announce on interface", "name", name, "error", err)
lastErr = err
}
}
} }
} }
@@ -262,19 +276,18 @@ func (d *Destination) HandleIncomingLinkRequest(pkt interface{}, transport inter
return errors.New("invalid packet type") return errors.New("invalid packet type")
} }
transportObj, ok := transport.(*transport.Transport) if incomingLinkHandler == nil {
if !ok { return errors.New("no incoming link handler registered")
return errors.New("invalid transport type")
} }
link, err := link.HandleIncomingLinkRequest(pktObj, d, transportObj, networkIface) linkIface, err := incomingLinkHandler(pktObj, d, transport, networkIface)
if err != nil { if err != nil {
return fmt.Errorf("failed to handle link request: %w", err) return fmt.Errorf("failed to handle link request: %w", err)
} }
if d.linkCallback != nil && link != nil { if d.linkCallback != nil && linkIface != nil {
debug.Log(debug.DEBUG_INFO, "Calling link established callback") debug.Log(debug.DEBUG_INFO, "Calling link established callback")
d.linkCallback(link) d.linkCallback(linkIface)
} }
return nil return nil
@@ -415,7 +428,7 @@ func (d *Destination) GetRequestHandler(pathHash []byte) func([]byte, []byte, []
if handler.AllowMode == ALLOW_ALL { if handler.AllowMode == ALLOW_ALL {
allowed = true allowed = true
} else if handler.AllowMode == ALLOW_LIST && remoteIdentity != nil { } else if handler.AllowMode == ALLOW_LIST && remoteIdentity != nil {
remoteHash := remoteIdentity.GetHash() remoteHash := remoteIdentity.Hash()
for _, allowedHash := range handler.AllowedList { for _, allowedHash := range handler.AllowedList {
if string(remoteHash) == string(allowedHash) { if string(remoteHash) == string(allowedHash) {
allowed = true allowed = true
@@ -428,7 +441,11 @@ func (d *Destination) GetRequestHandler(pathHash []byte) func([]byte, []byte, []
return nil return nil
} }
return handler.ResponseGenerator(pathHash, data, requestID, remoteIdentity, requestedAt) result := handler.ResponseGenerator(handler.Path, data, requestID, nil, remoteIdentity, requestedAt.Unix())
if result == nil {
return nil
}
return result
} }
} }
} }
@@ -446,7 +463,11 @@ func (d *Destination) HandleRequest(path string, data []byte, requestID []byte,
} }
debug.Log(debug.DEBUG_VERBOSE, "Calling request handler", "path", path) debug.Log(debug.DEBUG_VERBOSE, "Calling request handler", "path", path)
return handler.ResponseGenerator(path, data, requestID, linkID, remoteIdentity, requestedAt) result := handler.ResponseGenerator(path, data, requestID, linkID, remoteIdentity, requestedAt)
if result == nil {
return []byte(">Not Found\n\nThe requested resource was not found.")
}
return result
} }
func (d *Destination) Encrypt(plaintext []byte) ([]byte, error) { func (d *Destination) Encrypt(plaintext []byte) ([]byte, error) {