- Timestamp:
- 06/17/19 10:40:41 (5 years ago)
- Location:
- branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3
- Files:
-
- 1 added
- 1 deleted
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/ApplicationBase.cs
r16993 r17013 21 21 22 22 23 using System;23 using HEAL.Attic; 24 24 25 25 namespace HeuristicLab.PluginInfrastructure { … … 27 27 /// Abstract base implementation for the IApplication interface. 28 28 /// </summary> 29 [S erializable]29 [StorableType("FB13839C-2EEC-4C6F-BEF3-A1CAE4467362")] 30 30 public abstract class ApplicationBase : IApplication { 31 31 /// <summary> -
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/HeuristicLab.PluginInfrastructure-3.3.csproj
r16993 r17013 17 17 </PropertyGroup> 18 18 <ItemGroup> 19 <PackageReference Include="System.CodeDom" Version="4.5.0" />20 <PackageReference Include="System.Drawing.Common" Version="4.5.1" />21 19 <PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> 22 <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.5.0" /> 23 <PackageReference Include="System.Configuration.ConfigurationManager" Version="4.5.0" /> 24 <PackageReference Include="System.Security.Cryptography.Primitives" Version="4.3.0" /> 20 </ItemGroup> 21 <ItemGroup> 22 <Reference Include="HEAL.Attic"> 23 <HintPath>..\..\bin\HEAL.Attic.dll</HintPath> 24 <Private>true</Private> 25 </Reference> 25 26 </ItemGroup> 26 27 </Project> -
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/Interfaces/IRunner.cs
r16993 r17013 3 3 namespace HeuristicLab.PluginInfrastructure { 4 4 public interface IRunner { 5 /// <summary>6 /// Set this to true, if console output should be disabled.7 /// </summary>8 bool QuietMode { get; set; }9 10 5 /// <summary> 11 6 /// Assemblies which the child process needs to load. … … 17 12 /// </summary> 18 13 void Run(); 14 15 void Pause(); 16 void Resume(); 17 void Cancel(); 19 18 } 20 19 } -
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/Interfaces/IRunnerHost.cs
r16993 r17013 12 12 /// </summary> 13 13 RunnerState State { get; } 14 15 /// <summary> 16 /// Set this to true, if console output should be disabled. 17 /// </summary> 18 bool QuietMode { get; set; } 14 19 15 20 /// <summary> … … 28 33 29 34 /// <summary> 30 /// Method to pause the runner and the isolated IApplication.35 /// Method to send messages to the runner, which runs in child process. 31 36 /// </summary> 32 void Pause(); 33 34 /// <summary> 35 /// Method to resume a paused runner and the isolated IApplication. 36 /// </summary> 37 void Resume(); 37 /// <param name="runnerMessage">A object from a derived class of RunnerMessage.</param> 38 void Send(RunnerMessage runnerMessage); 38 39 } 39 40 } -
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/Isolation/ApplicationRunner.cs
r16993 r17013 1 using System; 2 using System.IO; 1 using HEAL.Attic; 3 2 4 3 namespace HeuristicLab.PluginInfrastructure { 5 [S erializable]4 [StorableType("612F98AF-E254-4C5E-BD41-75B4F1D9B96D")] 6 5 public class ApplicationRunner : Runner { 7 6 /// <summary> 8 7 /// Arguments for the StartApplication. 9 8 /// </summary> 9 [Storable] 10 10 public ICommandLineArgument[] Args { get; set; } 11 11 … … 15 15 public IApplication StartApplication { 16 16 get { 17 if (application == null) {18 using (var memStream = new MemoryStream(serializedStartApplication)) {19 application = (IApplication) formatter.Deserialize(memStream);20 }17 lock (locker) { 18 if (application == null) 19 application = (IApplication)new ProtoBufSerializer().Deserialize(serializedStartApplication); 20 return application; 21 21 } 22 return application;23 22 } 24 23 set { 25 using (var ms = new MemoryStream()) {26 formatter.Serialize(ms,value);27 serializedStartApplication = ms.ToArray();24 lock (locker) { 25 serializedStartApplication = new ProtoBufSerializer().Serialize(value); 26 application = value; 28 27 } 29 28 } … … 31 30 // Encapsulated application is necessary, because it is not possible to 32 31 // instantly deserialize the application, before all assemblies are loaded. 32 [Storable] 33 33 private byte[] serializedStartApplication = new byte[0]; 34 34 35 // cache application to prevent new instances every get call of StartApplication 35 36 private IApplication application; 37 private object locker = new object(); 36 38 37 39 protected override void Execute() { … … 39 41 } 40 42 41 protected override void OnRunnerJob(RunnerJob runnerJob) { 42 switch (runnerJob) { 43 case RunnerJob.Cancel: StartApplication.OnCancel(); break; 44 case RunnerJob.Pause: StartApplication.OnPause(); break; 45 case RunnerJob.Resume: StartApplication.OnResume(); break; 46 } 43 protected override void OnRunnerMessage(RunnerMessage message) { 44 if (message is PauseRunnerMessage) 45 StartApplication.OnPause(); 46 else if (message is ResumeRunnerMessage) 47 StartApplication.OnResume(); 48 else if (message is CancelRunnerMessage) 49 StartApplication.OnCancel(); 47 50 } 48 51 } -
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/Isolation/AssemblyInfo.cs
r16984 r17013 1 using System;1 using HEAL.Attic; 2 2 3 3 namespace HeuristicLab.PluginInfrastructure { 4 [S erializable]4 [StorableType(StorableMemberSelection.AllProperties, "D1DC9C3E-16B7-464E-A377-35FA614195AD")] 5 5 public class AssemblyInfo { 6 6 /// <summary> -
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/Isolation/DockerRunnerHost.cs
r16993 r17013 1 1 using System.Diagnostics; 2 using System.IO; 3 using System.Threading.Tasks; 2 4 using HeuristicLab.PluginInfrastructure.Exceptions; 3 5 … … 8 10 public class DockerRunnerHost : RunnerHost { 9 11 #region Constants 10 private const string Docker = "docker"; 11 private const string ContainerStartup = "container run -i --rm "; 12 private const string Mounting = @"--mount type=bind,source=/c/Users/,target=/Users "; 13 private const string Image = "heuristiclab33:latest"; 14 private const string DockerExceptionMessage = "Docker is not running or image '" + Image + "' does not exists!"; 12 private readonly static string Docker = "docker"; 13 private readonly static string ContainerStartup = "container run -i --rm "; 14 private readonly static string MountingLinux = @"--mount type=bind,source=/c/Users/,target=/Users "; 15 private readonly static string MountingWindows = @"--mount type=bind,source=C:\Users\,target=C:\Users\ "; 16 private readonly static string LinuxImage = "." + Path.DirectorySeparatorChar + "DockerLinuxBuild" + Path.DirectorySeparatorChar + "Dockerfile"; 17 private readonly static string WindowsImage = "." + Path.DirectorySeparatorChar + "DockerWindowsBuild" + Path.DirectorySeparatorChar + "Dockerfile"; 18 private readonly static string Image = "heuristiclab33:latest"; 19 private readonly static string DockerExceptionMessage = "Docker is not running!"; 15 20 #endregion 16 21 17 22 #region Constructors 18 public DockerRunnerHost(bool doDockerAvailableCheck = true) 19 : base(Docker, ContainerStartup + Mounting + Image, null, null, null) { 20 if (doDockerAvailableCheck && !IsDockerAvailable()) 21 throw new DockerException(DockerExceptionMessage); 23 public DockerRunnerHost() 24 : base(Docker, ContainerStartup + GetTargetOSMounting() + Image, null, null, null) { 22 25 } 23 26 #endregion 24 27 25 28 #region Helper 26 private bool IsDockerAvailable() { 29 30 private static string GetTargetOSMounting() { 31 Task<bool> win = Task.Run(() => BuildImage(WindowsImage)); 32 Task<bool> lin = Task.Run(() => BuildImage(LinuxImage)); 33 if (win.Result) return MountingWindows; 34 else if (lin.Result) return MountingLinux; 35 else throw new DockerException(DockerExceptionMessage); 36 } 37 38 private static bool BuildImage(string pathToDockerfile) { 27 39 var process = new Process { 28 40 StartInfo = new ProcessStartInfo { 29 41 FileName = Docker, 30 Arguments = "image inspect " + Image, 42 Arguments = "image build -t " + Image + 43 " -f " + Path.GetFullPath(pathToDockerfile) + 44 " .", 31 45 UseShellExecute = false, 32 46 RedirectStandardOutput = true, … … 37 51 EnableRaisingEvents = false 38 52 }; 39 40 53 process.Start(); 41 54 process.BeginOutputReadLine(); -
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/Isolation/Runner.cs
r16993 r17013 2 2 using System.Collections.Generic; 3 3 using System.IO; 4 using System.Runtime.Serialization;5 using System.Runtime.Serialization.Formatters.Binary;6 4 using System.Threading; 5 using System.Threading.Tasks; 6 using HEAL.Attic; 7 7 8 8 namespace HeuristicLab.PluginInfrastructure { 9 [S erializable]9 [StorableType(StorableMemberSelection.MarkedOnly, "D93CBE04-9847-417A-AAB5-7FBCA6A32247")] 10 10 public abstract class Runner : IRunner { 11 11 12 12 #region Vars 13 [NonSerialized]14 13 private Thread listener; 15 16 [NonSerialized]17 private Thread executor;18 19 [NonSerialized]20 protected static IFormatter formatter = new BinaryFormatter();21 14 #endregion 22 15 23 16 #region Properties 24 public bool QuietMode { get; set; } 17 [Storable] 18 public IEnumerable<AssemblyInfo> AssembliesToLoad { get; set; } 25 19 26 public IEnumerable<AssemblyInfo> AssembliesToLoad{ get; set; }20 internal RunnerHost Host { get; set; } 27 21 #endregion 28 22 23 public void Pause() { 24 var message = new PauseRunnerMessage(); 25 if (Host != null) Host.Send(message); 26 else OnRunnerMessage(message); 27 } 29 28 30 public static void Serialize(IRunner runner, Stream stream) => formatter.Serialize(stream, runner); 31 public static IRunner Deserialize(Stream stream = null) => (IRunner)formatter.Deserialize(stream); 32 public static void Pause(Stream stream) => formatter.Serialize(stream, RunnerJob.Pause); 33 public static void Resume(Stream stream) => formatter.Serialize(stream, RunnerJob.Resume); 34 public static void Cancel(Stream stream) => formatter.Serialize(stream, RunnerJob.Cancel); 29 public void Resume() { 30 var message = new ResumeRunnerMessage(); 31 if (Host != null) Host.Send(message); 32 else OnRunnerMessage(message); 33 } 34 35 public void Cancel() { 36 var message = new CancelRunnerMessage(); 37 if (Host != null) Host.Send(message); 38 else OnRunnerMessage(message); 39 } 35 40 36 41 public void Run() { 37 42 IPluginLoader loader = PluginLoaderFactory.Create(); 38 43 loader.LoadPlugins(AssembliesToLoad); 39 StartExecutor();44 Task t = Task.Run(Execute); 40 45 StartListener(); 41 executor.Join();46 t.Wait(); 42 47 } 43 48 44 49 protected abstract void Execute(); 45 protected abstract void OnRunner Job(RunnerJob runnerJob);50 protected abstract void OnRunnerMessage(RunnerMessage message); 46 51 47 52 #region Helper 48 private void StartExecutor() {49 executor = new Thread(Execute);50 executor.IsBackground = false;51 executor.Start();52 }53 53 54 54 private void StartListener() { 55 55 listener = new Thread(() => { 56 56 Stream stdin = Console.OpenStandardInput(); 57 while (executor.IsAlive) 58 OnRunnerJob((RunnerJob)formatter.Deserialize(stdin)); 57 DateTime lastMessageRecieved = DateTime.MinValue; 58 while (true) { 59 RunnerMessage message = RunnerMessage.ReadMessageFromStream(stdin); 60 if (DateTime.Compare(lastMessageRecieved, message.SendTime) < 0) { 61 OnRunnerMessage(message); 62 lastMessageRecieved = message.SendTime; 63 } 64 } 59 65 }); 60 66 listener.IsBackground = true; -
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/Isolation/RunnerHost.cs
r16993 r17013 4 4 using System.Threading; 5 5 using System.Threading.Tasks; 6 using HEAL.Attic; 6 7 7 8 namespace HeuristicLab.PluginInfrastructure { … … 14 15 Starting, 15 16 Running, 16 Paused,17 Stopping,18 17 Stopped 19 18 } … … 27 26 #region Vars 28 27 protected Process process; 28 private ProtoBufSerializer serializer = new ProtoBufSerializer(); 29 29 #endregion 30 30 31 31 #region Properties 32 /// <summary> 33 /// Set this to true, if console output should be disabled. 34 /// </summary> 35 public bool QuietMode { get; set; } 36 37 32 38 /// <summary> 33 39 /// The programm, which should be used. For example 'docker'. … … 41 47 protected string Password { get; private set; } 42 48 protected string Domain { get; private set; } 49 protected IRunner Runner { get; set; } 43 50 44 /// <summary>45 /// The runner state.46 /// </summary>47 51 public RunnerState State { get; protected set; } = RunnerState.Created; 48 52 #endregion 49 53 50 54 #region Constructors 55 51 56 protected RunnerHost(string program, string startArgument, string userName, string password, string domain) { 52 57 Program = program; … … 63 68 throw new InvalidOperationException("Runner must be in state 'Created'."); 64 69 State = RunnerState.Starting; 70 Runner = runner; 65 71 process = new Process { 66 72 StartInfo = new ProcessStartInfo { … … 72 78 RedirectStandardError = true, 73 79 CreateNoWindow = false, 74 UserName = string.IsNullOrEmpty(UserName) ? null : UserName, 80 UserName = string.IsNullOrEmpty(UserName) ? null : UserName, // TODO: accounts testen: https://docs.microsoft.com/en-us/windows/security/identity-protection/access-control/local-accounts#sec-localsystem 75 81 PasswordInClearText = string.IsNullOrEmpty(Password) ? null : Password, 76 82 Domain = string.IsNullOrEmpty(Domain) ? null : Domain, … … 80 86 }; 81 87 process.Start(); 88 82 89 // registers a task for cancellation, prevents the use of polling (while-loop) 83 90 var task = RegisterCancellation(token.HasValue ? token.Value : CancellationToken.None); 84 91 85 // write config to standardinput, runner listens on this and deserializes the config 86 Runner.Serialize(runner, process.StandardInput.BaseStream); 92 // set runnerhost in runner 93 Runner r = Runner as Runner; 94 if (r != null) r.Host = this; 87 95 88 96 process.BeginOutputReadLine(); 89 97 process.BeginErrorReadLine(); 90 98 91 if (! runner.QuietMode) {99 if (!QuietMode) { 92 100 process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data); 93 101 process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data); 94 102 } 103 104 // write config to standardinput, runner listens on this and deserializes the config 105 SendMessage(new TransportRunnerMessage(Runner)); 106 95 107 State = RunnerState.Running; 96 108 if (await task) State = RunnerState.Cancelled; 97 109 else State = RunnerState.Stopped; 98 99 110 } 100 111 101 /// <summary> 102 /// Pauses the runners. The childprocess gets notified with the help of the standard input and a serialized RunnerJob. 103 /// To pause the runner, the state must be "Running". 104 /// </summary> 105 public void Pause() { 112 113 public void Send(RunnerMessage runnerMessage) { 106 114 if (State != RunnerState.Running) throw new InvalidOperationException("Runner must be in state 'Running'!"); 107 Runner.Pause(process.StandardInput.BaseStream); 108 State = RunnerState.Paused; 115 SendMessage(runnerMessage); 109 116 } 110 117 111 /// <summary> 112 /// Resumes a paused runner. The childprocess gets notified with the help of the standard input and a serialized RunnerJob. 113 /// To resume the runner, the state must be "Paused". 114 /// </summary> 115 public void Resume() { 116 if (State != RunnerState.Paused) throw new InvalidOperationException("Runner must be in state 'Paused'!"); 117 Runner.Resume(process.StandardInput.BaseStream); 118 State = RunnerState.Running; 118 // because we need to transfer the runner with a TransportRunnerMessage in the starting state and the 119 // original send method should not be available until running state 120 protected virtual void SendMessage(RunnerMessage runnerMessage) { 121 runnerMessage.SendTime = DateTime.Now; 122 byte[] bytes = serializer.Serialize(runnerMessage); 123 byte[] size = BitConverter.GetBytes(bytes.Length); 124 process.StandardInput.BaseStream.Write(size, 0, size.Length); 125 process.StandardInput.BaseStream.Flush(); 126 process.StandardInput.BaseStream.Write(bytes, 0, bytes.Length); 127 process.StandardInput.BaseStream.Flush(); 119 128 } 120 129 … … 125 134 /// When the child process gets finished without requested cancellation, the linked token gets cancelled and a result set. 126 135 /// </summary> 127 pr ivateTask<bool> RegisterCancellation(CancellationToken token) {136 protected Task<bool> RegisterCancellation(CancellationToken token) { 128 137 if (process != null && State == RunnerState.Starting) { 129 138 var cts = CancellationTokenSource.CreateLinkedTokenSource(token); … … 133 142 cts.Token.Register(() => { 134 143 if (!process.HasExited) { 135 Runner.Cancel( process.StandardInput.BaseStream);144 Runner.Cancel(); 136 145 process.WaitForExit(); 137 146 } -
branches/2924_DotNetCoreMigration/HeuristicLab.PluginInfrastructure/3.3/Utils/UniPath.cs
r16984 r17013 1 using System; 2 using System.Collections.Generic; 3 using System.IO; 1 using System.IO; 4 2 using System.Runtime.InteropServices; 5 using System.Text;6 3 using System.Text.RegularExpressions; 4 using HEAL.Attic; 7 5 8 6 namespace HeuristicLab.PluginInfrastructure { 9 [S erializable]7 [StorableType("8911C8DC-FDA0-4CF6-A0CD-C67E72094D62")] 10 8 public class UniPath { 11 9 12 10 #region Vars 11 [Storable] 13 12 private string fullPath = ""; 14 13 #endregion 15 14 16 15 #region Constructors 16 [StorableConstructor] 17 private UniPath(StorableConstructorFlag _) { } 17 18 public UniPath(string path) { 18 19 fullPath = Path.GetFullPath(path); 19 20 } 20 21 #endregion 21 22 22 23 private bool IsWindowsAbsolutePath(string path) => Regex.IsMatch(path, @"^[A-Z]:"); 23 24 24 25 private string Rebuild(char split, string startStr, string seperator) { 25 26 string[] splits = fullPath.Split(split); 26 27 string tmp = startStr; 27 28 int i = 1; 28 while (i < splits.Length - 1) {29 while (i < (splits.Length - 1)) { 29 30 tmp += splits[i] + seperator; 30 31 ++i;
Note: See TracChangeset
for help on using the changeset viewer.