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:
@@ -14,9 +14,7 @@ import (
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/common"
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/debug"
|
||||
"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/transport"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
@@ -52,12 +50,26 @@ type LinkEstablishedCallback = common.LinkEstablishedCallback
|
||||
|
||||
type RequestHandler struct {
|
||||
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
|
||||
AllowedList [][]byte
|
||||
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 {
|
||||
identity *identity.Identity
|
||||
direction byte
|
||||
@@ -65,7 +77,7 @@ type Destination struct {
|
||||
appName string
|
||||
aspects []string
|
||||
hashValue []byte
|
||||
transport *transport.Transport
|
||||
transport Transport
|
||||
|
||||
acceptsLinks bool
|
||||
proofStrategy byte
|
||||
@@ -74,15 +86,15 @@ type Destination struct {
|
||||
proofCallback ProofRequestedCallback
|
||||
linkCallback LinkEstablishedCallback
|
||||
|
||||
ratchetsEnabled bool
|
||||
ratchetPath string
|
||||
ratchetCount int
|
||||
ratchetInterval int
|
||||
enforceRatchets bool
|
||||
latestRatchetTime time.Time
|
||||
latestRatchetID []byte
|
||||
ratchets [][]byte
|
||||
ratchetFileLock sync.Mutex
|
||||
ratchetsEnabled bool
|
||||
ratchetPath string
|
||||
ratchetCount int
|
||||
ratchetInterval int
|
||||
enforceRatchets bool
|
||||
latestRatchetTime time.Time
|
||||
latestRatchetID []byte
|
||||
ratchets [][]byte
|
||||
ratchetFileLock sync.Mutex
|
||||
|
||||
defaultAppData []byte
|
||||
mutex sync.RWMutex
|
||||
@@ -90,7 +102,7 @@ type Destination struct {
|
||||
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)
|
||||
|
||||
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).
|
||||
// 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))
|
||||
|
||||
if id == nil {
|
||||
@@ -152,17 +164,17 @@ func (d *Destination) calculateHash() []byte {
|
||||
// destination_hash = SHA256(name_hash_10bytes + identity_hash_16bytes)[:16]
|
||||
// Identity hash is the truncated hash of the public key (16 bytes)
|
||||
identityHash := identity.TruncatedHash(d.identity.GetPublicKey())
|
||||
|
||||
|
||||
// Name hash is the FULL 32-byte SHA256, then we take first 10 bytes for concatenation
|
||||
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, "Name hash (10 bytes)", "hash", fmt.Sprintf("%x", nameHash10))
|
||||
|
||||
// Concatenate name_hash (10 bytes) + identity_hash (16 bytes) = 26 bytes
|
||||
combined := append(nameHash10, identityHash...)
|
||||
|
||||
|
||||
// Then hash again and truncate to 16 bytes
|
||||
finalHashFull := sha256.Sum256(combined)
|
||||
finalHash := finalHashFull[:16]
|
||||
@@ -180,50 +192,52 @@ func (d *Destination) ExpandName() string {
|
||||
return name
|
||||
}
|
||||
|
||||
func (d *Destination) Announce(appData []byte) error {
|
||||
func (d *Destination) Announce(pathResponse bool, tag []byte, attachedInterface common.NetworkInterface) error {
|
||||
d.mutex.Lock()
|
||||
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
|
||||
// Pass the destination hash, name, and app data
|
||||
announce, err := announce.New(d.identity, d.hashValue, d.ExpandName(), appData, false, d.transport.GetConfig())
|
||||
announceObj, err := announce.New(d.identity, d.hashValue, d.ExpandName(), appData, pathResponse, d.transport.GetConfig())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create announce: %w", err)
|
||||
}
|
||||
|
||||
packet := announce.GetPacket()
|
||||
packet := announceObj.GetPacket()
|
||||
if packet == nil {
|
||||
return errors.New("failed to create announce packet")
|
||||
}
|
||||
|
||||
// Send announce packet to all interfaces
|
||||
debug.Log(debug.DEBUG_VERBOSE, "Sending announce packet to all interfaces")
|
||||
if pathResponse && tag != nil {
|
||||
debug.Log(debug.DEBUG_INFO, "Sending path response announce", "tag", fmt.Sprintf("%x", tag))
|
||||
}
|
||||
|
||||
if d.transport == nil {
|
||||
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
|
||||
for name, iface := range interfaces {
|
||||
debug.Log(debug.DEBUG_ALL, "Checking interface", "name", name, "enabled", iface.IsEnabled(), "online", iface.IsOnline())
|
||||
if iface.IsEnabled() && iface.IsOnline() {
|
||||
debug.Log(debug.DEBUG_ALL, "Sending announce to interface", "name", name, "bytes", len(packet))
|
||||
if err := iface.Send(packet, ""); err != nil {
|
||||
debug.Log(debug.DEBUG_ERROR, "Failed to send announce on interface", "name", name, "error", err)
|
||||
if attachedInterface != nil {
|
||||
if attachedInterface.IsEnabled() && attachedInterface.IsOnline() {
|
||||
debug.Log(debug.DEBUG_VERBOSE, "Sending announce to attached interface", "name", attachedInterface.GetName())
|
||||
if err := attachedInterface.Send(packet, ""); err != nil {
|
||||
debug.Log(debug.DEBUG_ERROR, "Failed to send announce on attached interface", "error", 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +248,7 @@ func (d *Destination) AcceptsLinks(accepts bool) {
|
||||
d.mutex.Lock()
|
||||
defer d.mutex.Unlock()
|
||||
d.acceptsLinks = accepts
|
||||
|
||||
|
||||
// Register with transport if accepting links
|
||||
if accepts && d.transport != nil {
|
||||
d.transport.RegisterDestination(d.hashValue, d)
|
||||
@@ -256,27 +270,26 @@ func (d *Destination) GetLinkCallback() common.LinkEstablishedCallback {
|
||||
|
||||
func (d *Destination) HandleIncomingLinkRequest(pkt interface{}, transport interface{}, networkIface common.NetworkInterface) error {
|
||||
debug.Log(debug.DEBUG_INFO, "Handling incoming link request for destination", "hash", fmt.Sprintf("%x", d.GetHash()))
|
||||
|
||||
|
||||
pktObj, ok := pkt.(*packet.Packet)
|
||||
if !ok {
|
||||
return errors.New("invalid packet type")
|
||||
}
|
||||
|
||||
transportObj, ok := transport.(*transport.Transport)
|
||||
if !ok {
|
||||
return errors.New("invalid transport type")
|
||||
|
||||
if incomingLinkHandler == nil {
|
||||
return errors.New("no incoming link handler registered")
|
||||
}
|
||||
|
||||
link, err := link.HandleIncomingLinkRequest(pktObj, d, transportObj, networkIface)
|
||||
|
||||
linkIface, err := incomingLinkHandler(pktObj, d, transport, networkIface)
|
||||
if err != nil {
|
||||
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")
|
||||
d.linkCallback(link)
|
||||
d.linkCallback(linkIface)
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -415,7 +428,7 @@ func (d *Destination) GetRequestHandler(pathHash []byte) func([]byte, []byte, []
|
||||
if handler.AllowMode == ALLOW_ALL {
|
||||
allowed = true
|
||||
} else if handler.AllowMode == ALLOW_LIST && remoteIdentity != nil {
|
||||
remoteHash := remoteIdentity.GetHash()
|
||||
remoteHash := remoteIdentity.Hash()
|
||||
for _, allowedHash := range handler.AllowedList {
|
||||
if string(remoteHash) == string(allowedHash) {
|
||||
allowed = true
|
||||
@@ -428,7 +441,11 @@ func (d *Destination) GetRequestHandler(pathHash []byte) func([]byte, []byte, []
|
||||
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)
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user