using System; using Newtonsoft.Json; using UnityEngine; using Unity.Pipeline.Config; using System.IO; using Unity.Pipeline.Security; namespace Unity.Pipeline.Models { /// /// Instance descriptor for runtime Unity Player builds with Pipeline server. /// Different from Editor InstanceDescriptor to reflect runtime context and security. /// [Serializable] public class RuntimeInstanceDescriptor { private const string RuntimeDescriptorFileName = ".unity-pipeline-runtime-port"; /// /// Process ID of the Unity Player application /// [JsonProperty("pid")] public int Pid { get; set; } /// /// HTTP port the pipeline server is listening on (7900-7999 range) /// [JsonProperty("port")] public int Port { get; set; } /// /// Unity runtime platform (Windows, macOS, Linux, etc.) /// [JsonProperty("platform")] public string Platform { get; set; } /// /// Unity Player version string /// [JsonProperty("unityVersion")] public string UnityVersion { get; set; } /// /// Unique build identifier /// [JsonProperty("buildGuid")] public string BuildGuid { get; set; } /// /// When the runtime instance was started /// [JsonProperty("startedAt")] public DateTime StartedAt { get; set; } /// /// Last heartbeat timestamp /// [JsonProperty("lastHeartbeat")] public DateTime LastHeartbeat { get; set; } /// /// Working directory where the application is running /// [JsonProperty("workingDirectory")] public string WorkingDirectory { get; set; } /// /// Security token used to authorize requests to this runtime server. /// [JsonProperty("evalToken")] public string EvalToken { get; set; } /// /// Create runtime instance descriptor for current Player application. /// public static RuntimeInstanceDescriptor CreateCurrent(int port, RuntimePipelineConfig config) { try { var pid = System.Diagnostics.Process.GetCurrentProcess().Id; var unityVersion = Application.unityVersion; var platform = Application.platform.ToString(); var buildGuid = Application.buildGUID; var workingDir = Directory.GetCurrentDirectory(); var token = SecurityTokenManager.GetOrCreateToken(); return new RuntimeInstanceDescriptor { Pid = pid, Port = port, Platform = platform, UnityVersion = unityVersion, BuildGuid = buildGuid, StartedAt = DateTime.UtcNow, LastHeartbeat = DateTime.UtcNow, WorkingDirectory = workingDir, EvalToken = token }; } catch (Exception ex) { UnityEngine.Debug.LogError($"Pipeline: CreateCurrent failed: {ex.Message}"); throw; } } /// /// Write runtime instance descriptor to working directory. /// public static void WriteToWorkingDirectory(RuntimeInstanceDescriptor descriptor) { try { var filePath = GetDescriptorFilePath(); var isNewFile = !File.Exists(filePath); var json = JsonConvert.SerializeObject(descriptor, Formatting.Indented); File.WriteAllText(filePath, json); // The descriptor carries the auth token; keep it readable only by the current user. // Applied once on creation (heartbeat rewrites preserve the existing permissions). if (isNewFile) FilePermissions.RestrictToCurrentUser(filePath); System.Console.WriteLine($"Pipeline: Runtime descriptor written to {filePath}"); } catch (Exception ex) { UnityEngine.Debug.LogError($"Pipeline: Failed to write runtime descriptor: {ex.Message}"); throw; } } /// /// Read runtime instance descriptor from working directory. /// public static RuntimeInstanceDescriptor ReadFromWorkingDirectory() { var filePath = GetDescriptorFilePath(); if (!File.Exists(filePath)) return null; try { var json = File.ReadAllText(filePath); return JsonConvert.DeserializeObject(json); } catch (Exception ex) { UnityEngine.Debug.LogWarning($"Pipeline: Failed to read runtime descriptor: {ex.Message}"); return null; } } /// /// Remove runtime instance descriptor from working directory. /// public static void RemoveFromWorkingDirectory() { var filePath = GetDescriptorFilePath(); if (File.Exists(filePath)) { try { File.Delete(filePath); } catch (Exception ex) { UnityEngine.Debug.LogWarning($"Pipeline: Failed to remove runtime descriptor: {ex.Message}"); } } } /// /// Update heartbeat timestamp in existing descriptor file. /// public static void UpdateHeartbeat() { try { var descriptor = ReadFromWorkingDirectory(); if (descriptor != null) { descriptor.LastHeartbeat = DateTime.UtcNow; WriteToWorkingDirectory(descriptor); } } catch (Exception ex) { UnityEngine.Debug.LogWarning($"Pipeline: Failed to update runtime heartbeat: {ex.Message}"); } } private static string GetDescriptorFilePath() { var workingDir = new FileInfo($"{Application.dataPath}/..").FullName; return Path.Combine(workingDir, RuntimeDescriptorFileName); } } }