This commit is contained in:
2026-05-18 21:33:39 +03:00
parent 5096155d83
commit 469fa0e860
94 changed files with 8761 additions and 8003 deletions
@@ -0,0 +1,94 @@
package mesh
import (
"context"
"encoding/json"
"fmt"
"strings"
"sync/atomic"
"time"
"github.com/example/remote-access-platform/agents/rap-node-agent/internal/fabricproto"
)
var fabricControlForwardSequence atomic.Uint64
type FabricControlForwardResult struct {
Payload json.RawMessage `json:"payload,omitempty"`
LatencyMs int64 `json:"latency_ms"`
Endpoint string `json:"endpoint,omitempty"`
}
func FabricTransportTargetFromRegistryEndpoint(endpoint FabricRegistryEndpoint) FabricTransportTarget {
return FabricTransportTarget{
EndpointID: strings.TrimSpace(endpoint.EndpointID),
PeerID: strings.TrimSpace(endpoint.EndpointID),
Endpoint: strings.TrimSpace(endpoint.Address),
Transport: strings.TrimSpace(endpoint.Transport),
PeerCertSHA256: strings.TrimSpace(endpoint.PeerCertSHA256),
Timeout: 5 * time.Second,
InboundBuffer: 4,
ErrorBuffer: 4,
}
}
func SendFabricControlForward(ctx context.Context, transport FabricTransport, endpoint FabricRegistryEndpoint, payload []byte, timeout time.Duration) (FabricControlForwardResult, error) {
if transport == nil {
return FabricControlForwardResult{}, fmt.Errorf("fabric control transport is unavailable")
}
if len(payload) == 0 {
return FabricControlForwardResult{}, fmt.Errorf("fabric control payload is empty")
}
if timeout <= 0 {
timeout = 5 * time.Second
}
target := FabricTransportTargetFromRegistryEndpoint(endpoint)
target.Timeout = timeout
session, err := transport.Connect(ctx, target)
if err != nil {
return FabricControlForwardResult{}, err
}
defer session.Close()
sequence := fabricControlForwardSequence.Add(1)
if err := session.Send(ctx, fabricproto.Frame{
Type: fabricproto.FrameData,
TrafficClass: fabricproto.TrafficClassReliable,
StreamID: FabricControlForwardQUICStreamID,
Sequence: sequence,
Payload: append([]byte(nil), payload...),
}); err != nil {
return FabricControlForwardResult{}, err
}
waitCtx := ctx
var cancel context.CancelFunc
if timeout > 0 {
waitCtx, cancel = context.WithTimeout(ctx, timeout)
defer cancel()
}
startedAt := time.Now()
for {
select {
case <-waitCtx.Done():
return FabricControlForwardResult{}, waitCtx.Err()
case err, ok := <-session.Errors():
if !ok {
return FabricControlForwardResult{}, fmt.Errorf("fabric control session closed")
}
if err != nil {
return FabricControlForwardResult{}, err
}
case frame, ok := <-session.Frames():
if !ok {
return FabricControlForwardResult{}, fmt.Errorf("fabric control session closed")
}
if frame.Type != fabricproto.FrameData || frame.StreamID != FabricControlForwardQUICStreamID || frame.Sequence != sequence {
continue
}
return FabricControlForwardResult{
Payload: append(json.RawMessage(nil), frame.Payload...),
LatencyMs: time.Since(startedAt).Milliseconds(),
Endpoint: endpoint.Address,
}, nil
}
}
}