// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Text.Json.Serialization; using EpicGames.Horde.Agents; using EpicGames.Horde.Agents.Leases; #pragma warning disable CA2227 // Collection properties should be read only namespace EpicGames.Horde.Compute { /// /// Describes port used by a compute task /// public class ConnectionMetadataPort { /// /// Built-in port used for agent and compute task communication /// public const string ComputeId = "_horde_compute"; /// /// Externally visible port that is mapped to agent port /// In direct connection mode, these two are identical. /// public int Port { get; } /// /// Port the local process on the agent is listening on /// public int AgentPort { get; } /// /// Constructor /// /// /// public ConnectionMetadataPort(int port, int agentPort) { Port = port; AgentPort = agentPort; } } /// /// Request a machine to execute compute requests /// public class AssignComputeRequest { /// /// Desired protocol version for the client /// public int Protocol { get; set; } /// /// Condition to identify machines that can execute the request /// public Requirements? Requirements { get; set; } /// /// Arbitrary ID to correlate the same request over multiple calls. /// It's recommended to pick something globally unique, such as a UUID. /// public string? RequestId { get; set; } /// /// Details for making an agent connection /// public ConnectionMetadataRequest? Connection { get; set; } } /// /// Request details for making an agent connection /// public class ConnectionMetadataRequest { /// /// Public IP of client requesting a compute resource (initiator) /// As communication between client and Horde server may be on an internal network, /// the client is responsible for resolving and providing this information. /// public string? ClientPublicIp { get; set; } /// /// TCP/IP ports the compute resource will listen to. /// Key = arbitrary name identifying the port /// Value = actual port number /// Relay connection mode uses this information to set up port forwarding. /// public Dictionary Ports { get; set; } = new(); /// /// Type of connection mode that is preferred by the client. Server can still override. /// public ConnectionMode? ModePreference { get; set; } /// /// Prefer connecting to agent over a public IP even if a more optimal route is available. Server can still override. /// This is useful to avoid sending traffic over VPN tunnels. /// public bool? PreferPublicIp { get; set; } /// /// Encryption mode to request. Server can still override. /// public Encryption? Encryption { get; set; } /// /// Maximum duration (in milliseconds) that communication can be inactive between /// the compute client and task-running agent before the connection is terminated. /// public int? InactivityTimeoutMs { get; set; } } /// /// Response to a cluster lookup request /// public class GetClusterResponse { /// /// Compute cluster ID /// public ClusterId ClusterId { get; set; } } /// /// Response to compute allocation request /// public class AssignComputeResponse { /// /// IP address of the remote agent machine running the compute task /// public string Ip { get; set; } = String.Empty; /// /// How to establish a connection to the remote machine /// public ConnectionMode ConnectionMode { get; set; } /// /// An optional address (host:port) to use when connecting to agent via tunnel or relay mode /// public string? ConnectionAddress { get; set; } /// /// Port number on the remote machine /// public int Port { get; set; } /// /// Assigned ports (externally visible port -> local port on agent) /// Key is an arbitrary name identifying the port (same as was given in ) /// When relay mode is used, ports can mapped to a different externally visible port. /// If compute task uses and listens to port 7000, that port can be externally represented as something else. /// For example, port 32743 can be pointed to port 7000. /// This makes no difference for the compute task process, but the client/initiator making connections must /// pay attention to this mapping. /// public IReadOnlyDictionary Ports { get; set; } = new Dictionary(); /// /// Encryption used /// public Encryption Encryption { get; set; } = Encryption.None; /// /// Cryptographic nonce to identify the request, as a hex string /// public string Nonce { get; set; } = String.Empty; /// /// AES key for the channel, as a hex string /// public string Key { get; set; } = String.Empty; /// /// X.509 certificate used for SSL/TLS encryption /// public string Certificate { get; set; } = String.Empty; /// /// Which cluster this remote machine belongs to /// public ClusterId ClusterId { get; set; } /// /// Identifier for the remote machine /// public AgentId AgentId { get; set; } /// /// Agent version for the remote machine /// public string? AgentVersion { get; set; } /// /// Identifier for the new lease on the remote machine /// public LeaseId LeaseId { get; set; } /// /// Resources assigned to this machine /// public Dictionary AssignedResources { get; set; } = new Dictionary(); /// /// Version number for the compute protocol /// public int Protocol { get; set; } /// /// Properties of the agent assigned to do the work /// public IReadOnlyList Properties { get; set; } = new List(); } /// /// Describe how to connect to the remote machine /// [JsonConverter(typeof(JsonStringEnumConverter))] public enum ConnectionMode { /// /// Connection is established directly to remote machine, behaving like a normal TCP/UDP connection /// Direct, /// /// Connection is tunneled through Horde server. /// When connecting, initiator must send a tunnel handshake request indicating which machine/IP to tunnel to. /// Once handshake is complete, TCP connection behaves as normal (UDP not supported) /// Tunnel, /// /// Connection is established to remote machine via a relay. /// Forwarding is transparent and behaves like a normal TCP/UDP connection. /// Relay } /// /// Describe encryption for the compute resource connection /// [JsonConverter(typeof(JsonStringEnumConverter))] public enum Encryption { /// /// No encryption enabled /// None, /// /// Use custom AES-based encryption transport /// Aes, /// /// Use SSL/TLS encryption with RSA 2048-bits /// Ssl, /// /// Use SSL/TLS encryption with ECDSA P-256 /// SslEcdsaP256 } /// /// Resource needs declaration request /// public class ResourceNeedsMessage { /// /// Unique session ID performing compute resource requests /// public string SessionId { get; set; } = String.Empty; /// /// Pool of agents requesting resources from /// public string Pool { get; set; } = String.Empty; /// /// Key/value of resources needed by session (such as CPU or memory, see KnownPropertyNames in Horde.Server) /// public Dictionary ResourceNeeds { get; set; } = new(); } /// /// Resource needs response /// public class GetResourceNeedsResponse { /// /// List of resource needs /// public List ResourceNeeds { get; set; } = new(); } }