|
|
|
|
|
|
public class PyrceptionInstaller : EditorWindow |
|
|
|
{ |
|
|
|
|
|
|
|
private static string fileNameStreamlitInstances= "streamlit_instances.csv"; |
|
|
|
private static readonly string _filename_streamlit_instances = "streamlit_instances.csv"; |
|
|
|
private static string pathToStreamlitInstances |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
#if UNITY_EDITOR_WIN
|
|
|
|
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), _filename_streamlit_instances); |
|
|
|
#elif UNITY_EDITOR_OSX
|
|
|
|
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _filename_streamlit_instances); |
|
|
|
#endif
|
|
|
|
} |
|
|
|
} |
|
|
|
private static readonly string nameOfPyrceptionProcess |
|
|
|
#if UNITY_EDITOR_WIN
|
|
|
|
= "pyrception"; |
|
|
|
#elif UNITY_EDITOR_OSX
|
|
|
|
= "bash"; |
|
|
|
#else
|
|
|
|
= ""; |
|
|
|
#endif
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Runs pyrception instance in default browser
|
|
|
|
|
|
|
[MenuItem("Window/Pyrception/Run")] |
|
|
|
private static void RunPyrception() |
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
string project = Application.dataPath; |
|
|
|
(int pythonPID, int port, int pyrceptionPID) = ReadEntry(project); |
|
|
|
if(pythonPID != -1 && ProcessAlive(pythonPID, port, pyrceptionPID)) |
|
|
|
|
|
|
{ |
|
|
|
DeleteEntry(project); |
|
|
|
Process[] before = Process.GetProcesses(); |
|
|
|
|
|
|
|
int errorCode = LaunchPyrception(); |
|
|
|
if(errorCode == -1) |
|
|
|
{ |
|
|
|
|
|
|
{ |
|
|
|
Thread.Sleep(1000); |
|
|
|
after = Process.GetProcesses(); |
|
|
|
newPyrceptionPID = GetNewProcessID(before, after, "pyrception"); |
|
|
|
newPyrceptionPID = GetNewProcessID(before, after, nameOfPyrceptionProcess); |
|
|
|
} |
|
|
|
|
|
|
|
int newPythonPID = -1; |
|
|
|
|
|
|
Thread.Sleep(1000); |
|
|
|
newPort = GetPortForPID(newPythonPID); |
|
|
|
} |
|
|
|
|
|
|
|
"Manually Open")) |
|
|
|
"Manually Open", |
|
|
|
"Cancel")) |
|
|
|
{ |
|
|
|
LaunchBrowser(newPort); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
private static (int pythonPID, int port, int pyrceptionPID) ReadEntry(string project) |
|
|
|
{ |
|
|
|
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),fileNameStreamlitInstances); |
|
|
|
string path = pathToStreamlitInstances; |
|
|
|
if (!File.Exists(path)) |
|
|
|
return (-1,-1,-1); |
|
|
|
using (StreamReader sr = File.OpenText(path)) |
|
|
|
|
|
|
|
|
|
|
private static void WriteEntry(string project, int pythonId, int port, int pyrceptionId) |
|
|
|
{ |
|
|
|
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),fileNameStreamlitInstances); |
|
|
|
string path = pathToStreamlitInstances; |
|
|
|
using (StreamWriter sw = File.AppendText(path)) |
|
|
|
{ |
|
|
|
sw.WriteLine($"{project},{pythonId},{port},{pyrceptionId}"); |
|
|
|
|
|
|
private static void DeleteEntry(string project) |
|
|
|
{ |
|
|
|
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),fileNameStreamlitInstances); |
|
|
|
string path = pathToStreamlitInstances; |
|
|
|
if (!File.Exists(path)) |
|
|
|
return; |
|
|
|
List<string> entries = new List<string>(File.ReadAllLines(path)); |
|
|
|
|
|
|
foreach(Process p in after) |
|
|
|
{ |
|
|
|
bool isNew = true; |
|
|
|
if (p.ProcessName.ToLower().Contains(name)) |
|
|
|
// try/catch to skip any process that may not exist anymore
|
|
|
|
try |
|
|
|
foreach(Process q in before) |
|
|
|
if (p.ProcessName.ToLower().Contains(name)) |
|
|
|
if(p.Id == q.Id) |
|
|
|
foreach (Process q in before) |
|
|
|
isNew = false; |
|
|
|
break; |
|
|
|
if (p.Id == q.Id) |
|
|
|
{ |
|
|
|
isNew = false; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (isNew) |
|
|
|
{ |
|
|
|
return p.Id; |
|
|
|
if (isNew) |
|
|
|
{ |
|
|
|
return p.Id; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
foreach(ProcessPort p in ProcessPorts.ProcessPortMap) |
|
|
|
{ |
|
|
|
//UnityEngine.Debug.Log($"PID: {p.ProcessId} PORT: {p.PortNumber}");
|
|
|
|
if(p.ProcessId == PID) |
|
|
|
{ |
|
|
|
return p.PortNumber; |
|
|
|
|
|
|
checkProcessName(pythonPID, "python") && |
|
|
|
ProcessListensToPort(pythonPID, port) && |
|
|
|
PIDExists(pyrceptionPID) && |
|
|
|
checkProcessName(pyrceptionPID, "pyrception"); |
|
|
|
checkProcessName(pyrceptionPID, nameOfPyrceptionProcess); |
|
|
|
} |
|
|
|
|
|
|
|
private static bool PIDExists(int PID) |
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ProcessStartInfo StartInfo = new ProcessStartInfo(); |
|
|
|
#if UNITY_EDITOR_WIN
|
|
|
|
#elif UNITY_EDITOR_OSX
|
|
|
|
StartInfo.FileName = "netstat"; |
|
|
|
StartInfo.Arguments = "-v -a"; |
|
|
|
#endif
|
|
|
|
StartInfo.WindowStyle = ProcessWindowStyle.Hidden; |
|
|
|
StartInfo.UseShellExecute = false; |
|
|
|
StartInfo.RedirectStandardInput = true; |
|
|
|
|
|
|
Proc.StartInfo = StartInfo; |
|
|
|
Proc.Start(); |
|
|
|
Proc.WaitForExit(); |
|
|
|
|
|
|
|
StreamReader StandardOutput = Proc.StandardOutput; |
|
|
|
StreamReader StandardError = Proc.StandardError; |
|
|
|
|
|
|
|
|
|
|
if (NetStatExitStatus != "0") |
|
|
|
{ |
|
|
|
Console.WriteLine("NetStat command failed. This may require elevated permissions."); |
|
|
|
UnityEngine.Debug.LogError("NetStat command failed. This may require elevated permissions."); |
|
|
|
string[] NetStatRows = Regex.Split(NetStatContent, "\r\n"); |
|
|
|
string[] NetStatRows = null; |
|
|
|
#if UNITY_EDITOR_WIN
|
|
|
|
NetStatRows = Regex.Split(NetStatContent, "\r\n"); |
|
|
|
#elif UNITY_EDITOR_OSX
|
|
|
|
NetStatRows = Regex.Split(NetStatContent, "\n"); |
|
|
|
#endif
|
|
|
|
#if UNITY_EDITOR_WIN
|
|
|
|
if (Tokens.Length > 4 && (Tokens[1].Equals("UDP") || Tokens[1].Equals("TCP"))) |
|
|
|
{ |
|
|
|
string IpAddress = Regex.Replace(Tokens[2], @"\[(.*?)\]", "1.1.1.1"); |
|
|
|
|
|
|
} |
|
|
|
catch |
|
|
|
{ |
|
|
|
Console.WriteLine("Could not convert the following NetStat row to a Process to Port mapping."); |
|
|
|
Console.WriteLine(NetStatRow); |
|
|
|
UnityEngine.Debug.LogError("Could not convert the following NetStat row to a Process to Port mapping."); |
|
|
|
UnityEngine.Debug.LogError(NetStatRow); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
|
|
|
Console.WriteLine("Unrecognized NetStat row to a Process to Port mapping."); |
|
|
|
Console.WriteLine(NetStatRow); |
|
|
|
UnityEngine.Debug.LogError("Unrecognized NetStat row to a Process to Port mapping."); |
|
|
|
UnityEngine.Debug.LogError(NetStatRow); |
|
|
|
#elif UNITY_EDITOR_OSX
|
|
|
|
if (Tokens.Length == 12 && Tokens[0].Equals("tcp4") & (Tokens[3].Contains("localhost") || Tokens[3].Contains("*."))) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
ProcessPorts.Add(new ProcessPort( |
|
|
|
GetProcessName(Convert.ToInt32(Tokens[8])), |
|
|
|
Convert.ToInt32(Tokens[8]), |
|
|
|
"tcp4", |
|
|
|
Convert.ToInt32(Tokens[3].Split('.')[1]) |
|
|
|
)); |
|
|
|
} |
|
|
|
catch |
|
|
|
{ |
|
|
|
UnityEngine.Debug.LogError("Could not convert the following NetStat row to a Process to Port mapping."); |
|
|
|
UnityEngine.Debug.LogError(NetStatRow); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif
|
|
|
|
Console.WriteLine(ex.Message); |
|
|
|
UnityEngine.Debug.LogError(ex.Message); |
|
|
|
} |
|
|
|
return ProcessPorts; |
|
|
|
} |
|
|
|