check point
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using NetMQ;
|
||||
using NetMQ.Sockets;
|
||||
|
||||
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
|
||||
|
||||
public class CSharpDataTransferMQ
|
||||
{
|
||||
|
||||
private object _syncObject = new object();
|
||||
private readonly ResponseSocket _server;
|
||||
|
||||
public CSharpDataTransferMQ()
|
||||
{
|
||||
this._server = new ResponseSocket();
|
||||
_server.Bind("tcp://*:5555");
|
||||
|
||||
}
|
||||
|
||||
public byte[] TransferData(string command, byte mode, byte[] data)
|
||||
{
|
||||
lock (_syncObject)
|
||||
{
|
||||
return TransferDataInternal(command,mode,data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private byte[] TransferDataInternal(string command,byte mode,byte[] data)
|
||||
{
|
||||
Console.WriteLine("Waiting for request");
|
||||
_server.ReceiveFrameBytes();
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
var functionBytes=System.Text.Encoding.ASCII.GetBytes(command);
|
||||
bw.Write(functionBytes.Length);
|
||||
bw.Write(functionBytes);
|
||||
bw.Write(mode);
|
||||
bw.Write(data);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Console.WriteLine("Sending response");
|
||||
_server.SendFrame(ms.ToArray());
|
||||
|
||||
Console.WriteLine("Waiting for request");
|
||||
var result= _server.ReceiveFrameBytes();
|
||||
|
||||
_server.SendFrame("OK");
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
using MessagePack;
|
||||
using NetMQ;
|
||||
using NetMQ.Sockets;
|
||||
|
||||
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
|
||||
[MessagePackObject]
|
||||
public class MethodCall
|
||||
{
|
||||
[Key(0)]
|
||||
public string Name { get; set; }
|
||||
[Key(1)]
|
||||
public List<object> Parameters { get; set; }
|
||||
|
||||
public MethodCall()
|
||||
{
|
||||
}
|
||||
|
||||
public MethodCall(string name, params object[] parameters)
|
||||
{
|
||||
Name=name;
|
||||
Parameters=new List<object>(parameters);
|
||||
}
|
||||
}
|
||||
[MessagePackObject]
|
||||
public class TransferData
|
||||
{
|
||||
[Key(0)]
|
||||
public ETransferType DataType { get; set; }
|
||||
[Key(1)]
|
||||
public int Int { get; set; }
|
||||
[Key(2)]
|
||||
public string String { get; set; }
|
||||
[Key(3)]
|
||||
public byte[] Bytes { get; set; }
|
||||
[Key(4)]
|
||||
public float[] Floats { get; set; }
|
||||
|
||||
public static implicit operator TransferData(int value)
|
||||
{
|
||||
return new TransferData()
|
||||
{
|
||||
DataType = ETransferType.Int,
|
||||
Int = value
|
||||
};
|
||||
}
|
||||
|
||||
public static implicit operator TransferData(string value)
|
||||
{
|
||||
return new TransferData()
|
||||
{
|
||||
DataType = ETransferType.String,
|
||||
String = value
|
||||
};
|
||||
}
|
||||
|
||||
public static implicit operator TransferData(byte[] value)
|
||||
{
|
||||
return new TransferData()
|
||||
{
|
||||
DataType = ETransferType.Bytes,
|
||||
Bytes = value
|
||||
};
|
||||
}
|
||||
public static implicit operator TransferData(float[] value)
|
||||
{
|
||||
return new TransferData()
|
||||
{
|
||||
DataType = ETransferType.Floats,
|
||||
Floats = value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum ETransferType
|
||||
{
|
||||
Void=0,
|
||||
Int=1,
|
||||
String=2,
|
||||
Bytes=3,
|
||||
Floats=4
|
||||
}
|
||||
public class CSharpDataTransferMQRPC
|
||||
{
|
||||
private object _syncObject = new object();
|
||||
private readonly ResponseSocket _server;
|
||||
|
||||
public CSharpDataTransferMQRPC()
|
||||
{
|
||||
this._server = new ResponseSocket();
|
||||
_server.Bind("tcp://*:5555");
|
||||
|
||||
|
||||
}
|
||||
|
||||
public T TransferData<T>(MethodCall call)
|
||||
{
|
||||
lock (_syncObject)
|
||||
{
|
||||
return TransferDataInternal<T>(call);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private T TransferDataInternal<T>(MethodCall call)
|
||||
{
|
||||
Console.WriteLine("Waiting for request");
|
||||
_server.ReceiveFrameBytes();
|
||||
|
||||
|
||||
Console.WriteLine("Sending response");
|
||||
|
||||
var serialized = MessagePack.MessagePackSerializer.Serialize(call);
|
||||
|
||||
_server.SendFrame(serialized);
|
||||
|
||||
|
||||
|
||||
Console.WriteLine("Waiting for request");
|
||||
var result = _server.ReceiveFrameBytes();
|
||||
|
||||
var decoded=MessagePackSerializer.Deserialize<object>(result);
|
||||
|
||||
|
||||
|
||||
_server.SendFrame("OK");
|
||||
|
||||
|
||||
return (T)Convert.ChangeType(decoded, typeof(T));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
|
||||
|
||||
public static class ChildProcessTracker
|
||||
{
|
||||
/// <summary>
|
||||
/// Add the process to be tracked. If our current process is killed, the child processes
|
||||
/// that we are tracking will be automatically killed, too. If the child process terminates
|
||||
/// first, that's fine, too.</summary>
|
||||
/// <param name="process"></param>
|
||||
public static void AddProcess(Process process)
|
||||
{
|
||||
if (s_jobHandle != IntPtr.Zero)
|
||||
{
|
||||
bool success = AssignProcessToJobObject(s_jobHandle, process.Handle);
|
||||
if (!success && !process.HasExited)
|
||||
throw new Win32Exception();
|
||||
}
|
||||
}
|
||||
|
||||
static ChildProcessTracker()
|
||||
{
|
||||
// This feature requires Windows 8 or later. To support Windows 7 requires
|
||||
// registry settings to be added if you are using Visual Studio plus an
|
||||
// app.manifest change.
|
||||
// https://stackoverflow.com/a/4232259/386091
|
||||
// https://stackoverflow.com/a/9507862/386091
|
||||
if (Environment.OSVersion.Version < new Version(6, 2))
|
||||
return;
|
||||
|
||||
// The job name is optional (and can be null) but it helps with diagnostics.
|
||||
// If it's not null, it has to be unique. Use SysInternals' Handle command-line
|
||||
// utility: handle -a ChildProcessTracker
|
||||
string jobName = "ChildProcessTracker" + Process.GetCurrentProcess().Id;
|
||||
s_jobHandle = CreateJobObject(IntPtr.Zero, jobName);
|
||||
|
||||
var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION();
|
||||
|
||||
// This is the key flag. When our process is killed, Windows will automatically
|
||||
// close the job handle, and when that happens, we want the child processes to
|
||||
// be killed, too.
|
||||
info.LimitFlags = JOBOBJECTLIMIT.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
|
||||
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
|
||||
extendedInfo.BasicLimitInformation = info;
|
||||
|
||||
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
|
||||
IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
|
||||
|
||||
if (!SetInformationJobObject(s_jobHandle, JobObjectInfoType.ExtendedLimitInformation,
|
||||
extendedInfoPtr, (uint)length))
|
||||
{
|
||||
throw new Win32Exception();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(extendedInfoPtr);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string name);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern bool SetInformationJobObject(IntPtr job, JobObjectInfoType infoType,
|
||||
IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
|
||||
|
||||
// Windows will automatically close any open job handles when our process terminates.
|
||||
// This can be verified by using SysInternals' Handle utility. When the job handle
|
||||
// is closed, the child processes will be killed.
|
||||
private static readonly IntPtr s_jobHandle;
|
||||
}
|
||||
|
||||
public enum JobObjectInfoType
|
||||
{
|
||||
AssociateCompletionPortInformation = 7,
|
||||
BasicLimitInformation = 2,
|
||||
BasicUIRestrictions = 4,
|
||||
EndOfJobTimeInformation = 6,
|
||||
ExtendedLimitInformation = 9,
|
||||
SecurityLimitInformation = 5,
|
||||
GroupInformation = 11
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct JOBOBJECT_BASIC_LIMIT_INFORMATION
|
||||
{
|
||||
public Int64 PerProcessUserTimeLimit;
|
||||
public Int64 PerJobUserTimeLimit;
|
||||
public JOBOBJECTLIMIT LimitFlags;
|
||||
public UIntPtr MinimumWorkingSetSize;
|
||||
public UIntPtr MaximumWorkingSetSize;
|
||||
public UInt32 ActiveProcessLimit;
|
||||
public Int64 Affinity;
|
||||
public UInt32 PriorityClass;
|
||||
public UInt32 SchedulingClass;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum JOBOBJECTLIMIT : uint
|
||||
{
|
||||
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct IO_COUNTERS
|
||||
{
|
||||
public UInt64 ReadOperationCount;
|
||||
public UInt64 WriteOperationCount;
|
||||
public UInt64 OtherOperationCount;
|
||||
public UInt64 ReadTransferCount;
|
||||
public UInt64 WriteTransferCount;
|
||||
public UInt64 OtherTransferCount;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
|
||||
{
|
||||
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
|
||||
public IO_COUNTERS IoInfo;
|
||||
public UIntPtr ProcessMemoryLimit;
|
||||
public UIntPtr JobMemoryLimit;
|
||||
public UIntPtr PeakProcessMemoryUsed;
|
||||
public UIntPtr PeakJobMemoryUsed;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
|
||||
|
||||
public static class PythonModelProxy
|
||||
{
|
||||
|
||||
private static bool _isInitialized = false;
|
||||
private static PythonScriptRunner _pythonScriptRunner;
|
||||
private static CSharpDataTransferMQ _cSharpDataTransfer;
|
||||
|
||||
public static void Initialize(string pythonPath, string scriptFile= "Hawkeye.ModelLoader.py")
|
||||
{
|
||||
if (_isInitialized) return;
|
||||
if (!File.Exists(pythonPath)) return;
|
||||
_isInitialized = true;
|
||||
|
||||
var relativePath = @"..\Data\AI";
|
||||
var absolutePath = Path.GetFullPath(relativePath);
|
||||
_cSharpDataTransfer = new CSharpDataTransferMQ();
|
||||
_pythonScriptRunner = new PythonScriptRunner(pythonPath, scriptFile, absolutePath);
|
||||
_pythonScriptRunner.Start();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static CSharpDataTransferMQ GetInterface()
|
||||
{
|
||||
if (!_isInitialized) return null;
|
||||
return _cSharpDataTransfer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
|
||||
|
||||
public static class PythonModelProxyRPC
|
||||
{
|
||||
private static bool _isInitialized = false;
|
||||
private static PythonScriptRunner _pythonScriptRunner;
|
||||
private static CSharpDataTransferMQRPC _cSharpDataTransferMQRPC;
|
||||
|
||||
public static void Initialize(string scriptFile = @"..\Data\models\Segment128Half.py")
|
||||
{
|
||||
if (_isInitialized) return;
|
||||
|
||||
var pythonPath = Environment.ExpandEnvironmentVariables(@"%userprofile%\miniconda3\envs\ai4\python.exe");
|
||||
//var pythonPath = Environment.ExpandEnvironmentVariables(@"/root/ai3/bin/python3");
|
||||
var scriptRelPath = scriptFile;
|
||||
var scriptAbsPath = Path.GetFullPath(scriptRelPath);
|
||||
var workDirectory = Path.GetDirectoryName(scriptAbsPath);
|
||||
Directory.CreateDirectory(workDirectory);
|
||||
|
||||
|
||||
if (!File.Exists(pythonPath)) return;
|
||||
_isInitialized = true;
|
||||
|
||||
_cSharpDataTransferMQRPC = new CSharpDataTransferMQRPC();
|
||||
_pythonScriptRunner = new PythonScriptRunner(pythonPath, scriptAbsPath, workDirectory);
|
||||
|
||||
_pythonScriptRunner.Start();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static CSharpDataTransferMQRPC GetInterface()
|
||||
{
|
||||
if (!_isInitialized) Initialize();
|
||||
return _cSharpDataTransferMQRPC;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
|
||||
|
||||
public class PythonScriptRunner
|
||||
{
|
||||
private Process process;
|
||||
private readonly string _pythonPath;
|
||||
private string scriptPath;
|
||||
private readonly string _workingDirectory;
|
||||
|
||||
public PythonScriptRunner(string pythonPath, string scriptPath,string workingDirectory)
|
||||
{
|
||||
_pythonPath = pythonPath;
|
||||
this.scriptPath = scriptPath;
|
||||
_workingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo();
|
||||
|
||||
|
||||
startInfo.FileName = _pythonPath; // set the path to the Python executable if not in PATH
|
||||
startInfo.Arguments = "\""+scriptPath+ "\"";
|
||||
startInfo.WorkingDirectory = _workingDirectory;
|
||||
|
||||
// enable running in the background
|
||||
startInfo.UseShellExecute = false;
|
||||
//startInfo.CreateNoWindow = true;
|
||||
// create and start the process
|
||||
process = new Process();
|
||||
|
||||
|
||||
process.StartInfo = startInfo;
|
||||
process.Start();
|
||||
// on windows only
|
||||
if(Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
ChildProcessTracker.AddProcess(process);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (process != null && !process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
process.Dispose();
|
||||
process = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;
|
||||
|
||||
public class WslScriptRunner
|
||||
{
|
||||
private Process process;
|
||||
private readonly string _pythonPath;
|
||||
private string scriptPath;
|
||||
private readonly string _workingDirectory;
|
||||
|
||||
public WslScriptRunner(string pythonPath, string scriptPath,string workingDirectory)
|
||||
{
|
||||
_pythonPath = pythonPath;
|
||||
this.scriptPath = scriptPath;
|
||||
_workingDirectory = workingDirectory;
|
||||
}
|
||||
public static string ConvertToWslPath(string windowsPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(windowsPath))
|
||||
throw new ArgumentException("Path cannot be null or empty.", nameof(windowsPath));
|
||||
|
||||
// Replace backslashes with forward slashes
|
||||
string wslPath = windowsPath.Replace('\\', '/');
|
||||
|
||||
// Extract the drive letter and convert it to WSL format
|
||||
if (wslPath.Length > 1 && wslPath[1] == ':')
|
||||
{
|
||||
char driveLetter = char.ToLower(wslPath[0]);
|
||||
wslPath = $"/mnt/{driveLetter}{wslPath.Substring(2)}";
|
||||
}
|
||||
|
||||
return wslPath;
|
||||
}
|
||||
public void Start()
|
||||
{
|
||||
|
||||
|
||||
|
||||
//startInfo.CreateNoWindow = true;
|
||||
// create and start the process
|
||||
process = new Process();
|
||||
var arg =
|
||||
$@"--distribution ubuntu --user root --cd ""{ConvertToWslPath(_workingDirectory)}"" -- /root/ai3/bin/python3 ""{ConvertToWslPath(scriptPath)}""";
|
||||
process.StartInfo = new ProcessStartInfo("wsl",arg)
|
||||
{
|
||||
UseShellExecute = false
|
||||
};
|
||||
process.Start();
|
||||
// on windows only
|
||||
if(Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||
ChildProcessTracker.AddProcess(process);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (process != null && !process.HasExited)
|
||||
{
|
||||
process.Kill();
|
||||
process.Dispose();
|
||||
process = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user