mirror of
https://github.com/Stone-Red-Code/RemoteExec.git
synced 2026-09-04 09:06:20 +02:00
Add infrastructure to support multiple execution environments
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace RemoteExec.Server.Utilities;
|
||||
|
||||
public static class AssemblyUtilities
|
||||
{
|
||||
public static async Task PreLoadReferencedAssembliesAsync(RemoteJobAssemblyLoadContext assemblyLoadContext, Assembly assembly, Func<string, Task<byte[]>> requestAssembly)
|
||||
{
|
||||
AssemblyName[] referencedAssemblies = assembly.GetReferencedAssemblies();
|
||||
|
||||
foreach (AssemblyName referencedAssembly in referencedAssemblies)
|
||||
{
|
||||
// Try to load from the assembly load context first
|
||||
Assembly? loadedAssembly = assemblyLoadContext.Assemblies.FirstOrDefault(a => a.GetName().FullName == referencedAssembly.FullName);
|
||||
|
||||
if (loadedAssembly != null)
|
||||
{
|
||||
continue; // Already loaded in the context
|
||||
}
|
||||
|
||||
// Try to load from default context (BCL assemblies)
|
||||
try
|
||||
{
|
||||
_ = assemblyLoadContext.LoadFromAssemblyName(referencedAssembly);
|
||||
continue; // Successfully loaded from default context
|
||||
}
|
||||
catch
|
||||
{
|
||||
byte[] assemblyBytes = await requestAssembly(referencedAssembly.FullName!);
|
||||
_ = assemblyLoadContext.LoadFromBytes(assemblyBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Assembly LoadFromBytes(this RemoteJobAssemblyLoadContext assemblyLoadContext, byte[] assemblyBytes)
|
||||
{
|
||||
using MemoryStream ms = new(assemblyBytes);
|
||||
return assemblyLoadContext.LoadFromStream(ms);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
namespace RemoteExec.Server.Utilities;
|
||||
|
||||
public class CompletableEventArgs : EventArgs
|
||||
{
|
||||
private readonly TaskCompletionSource<bool> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
public void SetCompleted()
|
||||
{
|
||||
_ = tcs.TrySetResult(true);
|
||||
}
|
||||
|
||||
public Task WaitAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
_ = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken));
|
||||
}
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public class CompletableEventArgs<T> : EventArgs
|
||||
{
|
||||
private readonly TaskCompletionSource<T> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
public void SetCompleted(T result)
|
||||
{
|
||||
_ = tcs.TrySetResult(result);
|
||||
}
|
||||
public Task<T> WaitAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
_ = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken));
|
||||
}
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
|
||||
public class CompletableEventArgs<TValue, TResult>(TValue value)
|
||||
{
|
||||
public TValue Value { get; } = value;
|
||||
|
||||
private readonly TaskCompletionSource<TResult> tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
public void SetCompleted(TResult result)
|
||||
{
|
||||
_ = tcs.TrySetResult(result);
|
||||
}
|
||||
public Task<TResult> WaitAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
_ = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken));
|
||||
}
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user