using System;
using Unity.Pipeline.Config;
using Unity.Pipeline.Models;
using UnityEngine;
namespace Unity.Pipeline
{
/// The Player-side , owned by a .
public class RuntimePipelineServer : BasePipelineServer
{
private RuntimePipelineConfig m_Config;
private RuntimeInstanceDescriptor m_InstanceDescriptor;
///
/// Guards mutate-then-write of m_InstanceDescriptor: concurrent /api/status probes both
/// reach UpdateHeartBeat now, and RuntimeInstanceDescriptor.WriteToWorkingDirectory's own
/// lock only covers the write, not the field mutation feeding it.
///
private readonly object m_HeartbeatLock = new object();
/// UTC time this server instance started listening.
public override DateTime StartedAt => m_InstanceDescriptor == null ? new DateTime() : m_InstanceDescriptor.StartedAt;
/// Create a server bound to the given configuration.
/// The runtime pipeline configuration.
public RuntimePipelineServer(RuntimePipelineConfig config)
{
m_Config = config;
}
/// Runtime servers use ports 7900-7949 (test runtime servers use 7950-7999).
/// The inclusive port range to try when binding the listener.
protected override (int basePort, int maxPort) GetPortRange()
{
return (7900, 7949); // Runtime production (test runtime servers use 7950-7999)
}
/// Write the runtime instance descriptor to the working directory for CLI discovery.
protected override void CreateInstanceDescriptor()
{
// Create and write instance descriptor for CLI discovery
m_InstanceDescriptor = RuntimeInstanceDescriptor.CreateCurrent(Port, m_Config);
RuntimeInstanceDescriptor.WriteToWorkingDirectory(m_InstanceDescriptor);
}
/// Remove the runtime instance descriptor on shutdown.
protected override void DeleteInstanceDescriptor()
{
// Clean up instance descriptor file
if (m_InstanceDescriptor != null)
{
RuntimeInstanceDescriptor.RemoveFromWorkingDirectory();
}
m_InstanceDescriptor = null;
}
/// Refresh the descriptor's heartbeat timestamp.
protected override void UpdateHeartBeat()
{
// Update heartbeat in instance descriptor
if (m_InstanceDescriptor == null)
return;
lock (m_HeartbeatLock)
{
m_InstanceDescriptor.LastHeartbeat = DateTime.UtcNow;
try
{
RuntimeInstanceDescriptor.WriteToWorkingDirectory(m_InstanceDescriptor);
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to update instance descriptor: {ex.Message}");
}
}
}
/// Build the Player-specific status/heartbeat payload for /api/status.
/// The status payload.
protected override object GetServerStatus()
{
UpdateHeartBeat();
return new
{
status = m_InstanceDescriptor == null ? "error" : "ready",
lastHeartbeat = m_InstanceDescriptor?.LastHeartbeat,
capabilities = Capabilities
};
}
/// The bearer token clients must present to authenticate requests.
/// The current token.
protected override string GetToken()
{
return m_InstanceDescriptor.EvalToken;
}
}
}