mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Implement DI container into Agent.
This commit is contained in:
parent
3b82261f9e
commit
a9c52851f3
@ -25,6 +25,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="3.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="3.1.1" />
|
||||
<PackageReference Include="Microsoft.Management.Infrastructure" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="3.1.1" />
|
||||
<PackageReference Include="Microsoft.PowerShell.Commands.Diagnostics" Version="6.2.3" />
|
||||
|
||||
@ -11,6 +11,7 @@ using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Remotely.Agent
|
||||
{
|
||||
@ -24,9 +25,7 @@ namespace Remotely.Agent
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: Replace static services with scoped instances in IoC container.
|
||||
var serviceCollection = new ServiceCollection();
|
||||
Services = serviceCollection.BuildServiceProvider();
|
||||
BuildServices();
|
||||
|
||||
Task.Run(() => { Init(args); });
|
||||
|
||||
@ -39,6 +38,27 @@ namespace Remotely.Agent
|
||||
}
|
||||
}
|
||||
|
||||
private static void BuildServices()
|
||||
{
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddLogging(builder =>
|
||||
{
|
||||
builder.AddConsole()
|
||||
.AddEventLog();
|
||||
});
|
||||
serviceCollection.AddSingleton<DeviceSocket>();
|
||||
serviceCollection.AddScoped<Bash>();
|
||||
serviceCollection.AddScoped<CMD>();
|
||||
serviceCollection.AddScoped<PSCore>();
|
||||
serviceCollection.AddScoped<WindowsPS>();
|
||||
serviceCollection.AddScoped<ConfigService>();
|
||||
serviceCollection.AddScoped<Logger>();
|
||||
serviceCollection.AddScoped<Updater>();
|
||||
serviceCollection.AddScoped<Uninstaller>();
|
||||
|
||||
Services = serviceCollection.BuildServiceProvider();
|
||||
}
|
||||
|
||||
private static async void Init(string[] args)
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
@ -52,9 +72,9 @@ namespace Remotely.Agent
|
||||
|
||||
if (argDict.ContainsKey("update"))
|
||||
{
|
||||
Updater.CoreUpdate();
|
||||
Services.GetRequiredService<Updater>().CoreUpdate();
|
||||
}
|
||||
|
||||
|
||||
if (!IsDebug && OSUtils.IsWindows)
|
||||
{
|
||||
_ = Task.Run(() =>
|
||||
@ -65,7 +85,7 @@ namespace Remotely.Agent
|
||||
|
||||
try
|
||||
{
|
||||
await DeviceSocket.Connect();
|
||||
await Services.GetRequiredService<DeviceSocket>().Connect();
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -79,12 +99,12 @@ namespace Remotely.Agent
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!DeviceSocket.IsConnected)
|
||||
if (!Services.GetRequiredService<DeviceSocket>().IsConnected)
|
||||
{
|
||||
var waitTime = new Random().Next(1000, 30000);
|
||||
Logger.Write($"Websocket closed. Reconnecting in {waitTime / 1000} seconds...");
|
||||
await Task.Delay(waitTime);
|
||||
await DeviceSocket.Connect();
|
||||
await Services.GetRequiredService<DeviceSocket>().Connect();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@ -5,52 +5,15 @@ using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Remotely.Agent.Services
|
||||
{
|
||||
public class Bash
|
||||
{
|
||||
private static ConcurrentDictionary<string, Bash> Sessions { get; set; } = new ConcurrentDictionary<string, Bash>();
|
||||
private Process BashProc { get; }
|
||||
private System.Timers.Timer ProcessIdleTimeout { get; set; }
|
||||
private string ConnectionID { get; set; }
|
||||
private string LastInputID { get; set; }
|
||||
private bool OutputDone { get; set; }
|
||||
private string StandardOut { get; set; }
|
||||
private string ErrorOut { get; set; }
|
||||
|
||||
public static Bash GetCurrent(string connectionID)
|
||||
{
|
||||
if (Sessions.ContainsKey(connectionID))
|
||||
{
|
||||
var bash = Sessions[connectionID];
|
||||
bash.ProcessIdleTimeout.Stop();
|
||||
bash.ProcessIdleTimeout.Start();
|
||||
return bash;
|
||||
}
|
||||
else
|
||||
{
|
||||
var bash = new Bash();
|
||||
bash.ConnectionID = connectionID;
|
||||
bash.ProcessIdleTimeout = new System.Timers.Timer(600000); // 10 minutes.
|
||||
bash.ProcessIdleTimeout.AutoReset = false;
|
||||
bash.ProcessIdleTimeout.Elapsed += bash.ProcessIdleTimeout_Elapsed;
|
||||
Sessions.AddOrUpdate(connectionID, bash, (id, b) => bash);
|
||||
bash.ProcessIdleTimeout.Start();
|
||||
return bash;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessIdleTimeout_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
Sessions.Remove(ConnectionID, out var outResult);
|
||||
outResult.BashProc.Kill();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Bash()
|
||||
public Bash(ConfigService configService)
|
||||
{
|
||||
ConfigService = configService;
|
||||
var psi = new ProcessStartInfo("bash");
|
||||
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
psi.Verb = "RunAs";
|
||||
@ -68,26 +31,37 @@ namespace Remotely.Agent.Services
|
||||
|
||||
BashProc.BeginErrorReadLine();
|
||||
BashProc.BeginOutputReadLine();
|
||||
|
||||
ProcessIdleTimeout = new System.Timers.Timer(600_000); // 10 minutes.
|
||||
ProcessIdleTimeout.AutoReset = false;
|
||||
ProcessIdleTimeout.Elapsed += ProcessIdleTimeout_Elapsed;
|
||||
ProcessIdleTimeout.Start();
|
||||
}
|
||||
|
||||
private void CMDProc_OutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
private static ConcurrentDictionary<string, Bash> Sessions { get; set; } = new ConcurrentDictionary<string, Bash>();
|
||||
private Process BashProc { get; }
|
||||
private ConfigService ConfigService { get; set; }
|
||||
private string ConnectionID { get; set; }
|
||||
private string ErrorOut { get; set; }
|
||||
private string LastInputID { get; set; }
|
||||
private bool OutputDone { get; set; }
|
||||
private System.Timers.Timer ProcessIdleTimeout { get; set; }
|
||||
private string StandardOut { get; set; }
|
||||
public static Bash GetCurrent(string connectionID)
|
||||
{
|
||||
if (e?.Data?.Contains(LastInputID) == true)
|
||||
if (Sessions.ContainsKey(connectionID))
|
||||
{
|
||||
OutputDone = true;
|
||||
var bash = Sessions[connectionID];
|
||||
bash.ProcessIdleTimeout.Stop();
|
||||
bash.ProcessIdleTimeout.Start();
|
||||
return bash;
|
||||
}
|
||||
else if (!OutputDone)
|
||||
else
|
||||
{
|
||||
StandardOut += e.Data + Environment.NewLine;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void CMDProc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e?.Data != null)
|
||||
{
|
||||
ErrorOut += e.Data + Environment.NewLine;
|
||||
var bash = Program.Services.GetRequiredService<Bash>();
|
||||
bash.ConnectionID = connectionID;
|
||||
Sessions.AddOrUpdate(connectionID, bash, (id, b) => bash);
|
||||
return bash;
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,21 +88,25 @@ namespace Remotely.Agent.Services
|
||||
return GenerateCompletedResult();
|
||||
}
|
||||
|
||||
private GenericCommandResult GeneratePartialResult()
|
||||
private void CMDProc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
OutputDone = true;
|
||||
var partialResult = new GenericCommandResult()
|
||||
if (e?.Data != null)
|
||||
{
|
||||
CommandContextID = LastInputID,
|
||||
DeviceID = ConfigService.GetConnectionInfo().DeviceID,
|
||||
CommandType = "Bash",
|
||||
StandardOutput = StandardOut,
|
||||
ErrorOutput = "WARNING: The command execution froze and was forced to return before finishing. " +
|
||||
"The results may be partial, and the console process has been reset. " +
|
||||
"Please note that interactive commands aren't supported." + Environment.NewLine + ErrorOut
|
||||
};
|
||||
ProcessIdleTimeout_Elapsed(this, null);
|
||||
return partialResult;
|
||||
ErrorOut += e.Data + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
|
||||
private void CMDProc_OutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e?.Data?.Contains(LastInputID) == true)
|
||||
{
|
||||
OutputDone = true;
|
||||
}
|
||||
else if (!OutputDone)
|
||||
{
|
||||
StandardOut += e.Data + Environment.NewLine;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private GenericCommandResult GenerateCompletedResult()
|
||||
@ -143,5 +121,27 @@ namespace Remotely.Agent.Services
|
||||
};
|
||||
}
|
||||
|
||||
private GenericCommandResult GeneratePartialResult()
|
||||
{
|
||||
OutputDone = true;
|
||||
var partialResult = new GenericCommandResult()
|
||||
{
|
||||
CommandContextID = LastInputID,
|
||||
DeviceID = ConfigService.GetConnectionInfo().DeviceID,
|
||||
CommandType = "Bash",
|
||||
StandardOutput = StandardOut,
|
||||
ErrorOutput = "WARNING: The command execution froze and was forced to return before finishing. " +
|
||||
"The results may be partial, and the console process has been reset. " +
|
||||
"Please note that interactive commands aren't supported." + Environment.NewLine + ErrorOut
|
||||
};
|
||||
ProcessIdleTimeout_Elapsed(this, null);
|
||||
return partialResult;
|
||||
}
|
||||
|
||||
private void ProcessIdleTimeout_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
BashProc?.Kill();
|
||||
Sessions.TryRemove(ConnectionID, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,13 +6,15 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Remotely.Agent.Services
|
||||
{
|
||||
public class CMD
|
||||
{
|
||||
private CMD()
|
||||
public CMD(ConfigService configService)
|
||||
{
|
||||
ConfigService = configService;
|
||||
var psi = new ProcessStartInfo("cmd.exe");
|
||||
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
psi.Verb = "RunAs";
|
||||
@ -30,10 +32,16 @@ namespace Remotely.Agent.Services
|
||||
|
||||
CMDProc.BeginErrorReadLine();
|
||||
CMDProc.BeginOutputReadLine();
|
||||
|
||||
ProcessIdleTimeout = new System.Timers.Timer(600_000); // 10 minutes.
|
||||
ProcessIdleTimeout.AutoReset = false;
|
||||
ProcessIdleTimeout.Elapsed += ProcessIdleTimeout_Elapsed;
|
||||
ProcessIdleTimeout.Start();
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<string, CMD> Sessions { get; set; } = new ConcurrentDictionary<string, CMD>();
|
||||
private Process CMDProc { get; }
|
||||
private ConfigService ConfigService { get; }
|
||||
private string ConnectionID { get; set; }
|
||||
|
||||
private string ErrorOut { get; set; }
|
||||
@ -52,13 +60,9 @@ namespace Remotely.Agent.Services
|
||||
}
|
||||
else
|
||||
{
|
||||
var cmd = new CMD();
|
||||
var cmd = Program.Services.GetRequiredService<CMD>();
|
||||
cmd.ConnectionID = connectionID;
|
||||
cmd.ProcessIdleTimeout = new System.Timers.Timer(600000); // 10 minutes.
|
||||
cmd.ProcessIdleTimeout.AutoReset = false;
|
||||
cmd.ProcessIdleTimeout.Elapsed += cmd.ProcessIdleTimeout_Elapsed;
|
||||
Sessions.AddOrUpdate(connectionID, cmd, (id, c) => cmd);
|
||||
cmd.ProcessIdleTimeout.Start();
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
@ -139,8 +143,8 @@ namespace Remotely.Agent.Services
|
||||
|
||||
private void ProcessIdleTimeout_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
Sessions.Remove(ConnectionID, out var outResult);
|
||||
outResult.CMDProc.Kill();
|
||||
CMDProc?.Kill();
|
||||
Sessions.TryRemove(ConnectionID, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,28 +8,36 @@ using System.Linq;
|
||||
|
||||
namespace Remotely.Agent.Services
|
||||
{
|
||||
public static class ConfigService
|
||||
public class ConfigService
|
||||
{
|
||||
private static ConnectionInfo connectionInfo;
|
||||
public static ConnectionInfo GetConnectionInfo()
|
||||
private static object fileLock = new object();
|
||||
private ConnectionInfo connectionInfo;
|
||||
|
||||
public ConnectionInfo GetConnectionInfo()
|
||||
{
|
||||
if (connectionInfo == null)
|
||||
{
|
||||
if (!File.Exists("ConnectionInfo.json"))
|
||||
lock (fileLock)
|
||||
{
|
||||
Logger.Write(new Exception("No connection info available. Please create ConnectionInfo.json file with appropriate values."));
|
||||
return null;
|
||||
if (!File.Exists("ConnectionInfo.json"))
|
||||
{
|
||||
Logger.Write(new Exception("No connection info available. Please create ConnectionInfo.json file with appropriate values."));
|
||||
return null;
|
||||
}
|
||||
connectionInfo = JsonConvert.DeserializeObject<ConnectionInfo>(File.ReadAllText("ConnectionInfo.json"));
|
||||
}
|
||||
connectionInfo = JsonConvert.DeserializeObject<ConnectionInfo>(File.ReadAllText("ConnectionInfo.json"));
|
||||
}
|
||||
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
|
||||
public static void SaveConnectionInfo(ConnectionInfo connectionInfo)
|
||||
public void SaveConnectionInfo(ConnectionInfo connectionInfo)
|
||||
{
|
||||
File.WriteAllText("ConnectionInfo.json", JsonConvert.SerializeObject(connectionInfo));
|
||||
lock (fileLock)
|
||||
{
|
||||
File.WriteAllText("ConnectionInfo.json", JsonConvert.SerializeObject(connectionInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,15 +17,24 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Remotely.Agent.Services
|
||||
{
|
||||
public static class DeviceSocket
|
||||
public class DeviceSocket
|
||||
{
|
||||
public static Timer HeartbeatTimer { get; private set; }
|
||||
public static bool IsServerVerified { get; set; }
|
||||
private static ConnectionInfo ConnectionInfo { get; set; }
|
||||
public DeviceSocket(Updater updater, ConfigService configService, Uninstaller uninstaller)
|
||||
{
|
||||
Updater = updater;
|
||||
ConfigService = configService;
|
||||
Uninstaller = uninstaller;
|
||||
}
|
||||
public Timer HeartbeatTimer { get; private set; }
|
||||
public bool IsConnected => HubConnection?.State == HubConnectionState.Connected;
|
||||
public bool IsServerVerified { get; set; }
|
||||
public Uninstaller Uninstaller { get; }
|
||||
private ConfigService ConfigService { get; }
|
||||
private ConnectionInfo ConnectionInfo { get; set; }
|
||||
|
||||
private static HubConnection HubConnection { get; set; }
|
||||
|
||||
public static async Task Connect()
|
||||
private HubConnection HubConnection { get; set; }
|
||||
private Updater Updater { get; }
|
||||
public async Task Connect()
|
||||
{
|
||||
ConnectionInfo = ConfigService.GetConnectionInfo();
|
||||
|
||||
@ -59,16 +68,13 @@ namespace Remotely.Agent.Services
|
||||
HeartbeatTimer.Elapsed += HeartbeatTimer_Elapsed;
|
||||
HeartbeatTimer.Start();
|
||||
}
|
||||
|
||||
public static bool IsConnected => HubConnection?.State == HubConnectionState.Connected;
|
||||
|
||||
public static void SendHeartbeat()
|
||||
public void SendHeartbeat()
|
||||
{
|
||||
var currentInfo = Device.Create(ConnectionInfo);
|
||||
HubConnection.InvokeAsync("DeviceHeartbeat", currentInfo);
|
||||
}
|
||||
|
||||
private static async Task ExecuteCommand(string mode, string command, string commandID, string senderConnectionID)
|
||||
private async Task ExecuteCommand(string mode, string command, string commandID, string senderConnectionID)
|
||||
{
|
||||
if (!IsServerVerified)
|
||||
{
|
||||
@ -150,16 +156,16 @@ namespace Remotely.Agent.Services
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
await HubConnection.InvokeAsync("DisplayMessage", $"There was an error executing the command. It has been logged on the client device.", "Error executing command.", senderConnectionID);
|
||||
await HubConnection.InvokeAsync("DisplayMessage", "There was an error executing the command. It has been logged on the client device.", "Error executing command.", senderConnectionID);
|
||||
}
|
||||
}
|
||||
|
||||
private static void HeartbeatTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
private void HeartbeatTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
SendHeartbeat();
|
||||
}
|
||||
|
||||
private static void RegisterMessageHandlers(HubConnection hubConnection)
|
||||
private void RegisterMessageHandlers(HubConnection hubConnection)
|
||||
{
|
||||
hubConnection.On("ExecuteCommand", (async (string mode, string command, string commandID, string senderConnectionID) =>
|
||||
{
|
||||
@ -263,8 +269,6 @@ namespace Remotely.Agent.Services
|
||||
}
|
||||
else if (OSUtils.IsLinux)
|
||||
{
|
||||
//var users = OSUtils.StartProcessWithResults("users", "");
|
||||
//var username = users?.Split()?.FirstOrDefault()?.Trim();
|
||||
var xauthority = OSUtils.StartProcessWithResults("find", $"/ -name Xauthority").Split('\n', StringSplitOptions.RemoveEmptyEntries).First();
|
||||
var display = ":0";
|
||||
var whoString = OSUtils.StartProcessWithResults("who", "")?.Trim();
|
||||
@ -387,7 +391,7 @@ namespace Remotely.Agent.Services
|
||||
});
|
||||
}
|
||||
|
||||
private static void SendResultsViaAjax(string resultType, object result)
|
||||
private void SendResultsViaAjax(string resultType, object result)
|
||||
{
|
||||
var targetURL = ConfigService.GetConnectionInfo().Host + $"/API/Commands/{resultType}";
|
||||
var webRequest = WebRequest.CreateHttp(targetURL);
|
||||
|
||||
@ -10,7 +10,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Remotely.Agent.Services
|
||||
{
|
||||
public static class Logger
|
||||
public class Logger
|
||||
{
|
||||
private static string LogPath => Path.Combine(Path.GetTempPath(), "Remotely_Logs.log");
|
||||
private static object WriteLock { get; } = new object();
|
||||
|
||||
@ -7,13 +7,38 @@ using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Text;
|
||||
using System.Timers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Remotely.Agent.Services
|
||||
{
|
||||
public class PSCore
|
||||
{
|
||||
public PSCore(ConfigService configService)
|
||||
{
|
||||
ConfigService = configService;
|
||||
PS = PowerShell.Create();
|
||||
PS.AddScript(@"$VerbosePreference = ""Continue"";
|
||||
$DebugPreference = ""Continue"";
|
||||
$InformationPreference = ""Continue"";
|
||||
$WarningPreference = ""Continue"";");
|
||||
PS.Invoke();
|
||||
|
||||
ProcessIdleTimeout = new Timer(600_000); // 10 minutes.
|
||||
ProcessIdleTimeout.AutoReset = false;
|
||||
ProcessIdleTimeout.Elapsed += ProcessIdleTimeout_Elapsed;
|
||||
ProcessIdleTimeout.Start();
|
||||
}
|
||||
|
||||
public string ConnectionID { get; private set; }
|
||||
|
||||
private static ConcurrentDictionary<string, PSCore> Sessions { get; set; } = new ConcurrentDictionary<string, PSCore>();
|
||||
|
||||
private ConfigService ConfigService { get; }
|
||||
|
||||
private Timer ProcessIdleTimeout { get; set; }
|
||||
|
||||
private PowerShell PS { get; set; }
|
||||
|
||||
public static PSCore GetCurrent(string connectionID)
|
||||
{
|
||||
if (Sessions.ContainsKey(connectionID))
|
||||
@ -25,36 +50,19 @@ namespace Remotely.Agent.Services
|
||||
}
|
||||
else
|
||||
{
|
||||
var psCore = new PSCore();
|
||||
psCore.ProcessIdleTimeout = new Timer(600000); // 10 minutes.
|
||||
psCore.ProcessIdleTimeout.AutoReset = false;
|
||||
psCore.ProcessIdleTimeout.Elapsed += (sender, args) =>
|
||||
{
|
||||
Sessions.Remove(connectionID, out var pSCore);
|
||||
};
|
||||
var psCore = Program.Services.GetRequiredService<PSCore>();
|
||||
psCore.ConnectionID = connectionID;
|
||||
Sessions.AddOrUpdate(connectionID, psCore, (id, p) => psCore);
|
||||
psCore.ProcessIdleTimeout.Start();
|
||||
return psCore;
|
||||
}
|
||||
}
|
||||
private PowerShell PS { get; set; }
|
||||
|
||||
private PSCore()
|
||||
{
|
||||
PS = PowerShell.Create();
|
||||
PS.AddScript(@"$VerbosePreference = ""Continue"";
|
||||
$DebugPreference = ""Continue"";
|
||||
$InformationPreference = ""Continue"";
|
||||
$WarningPreference = ""Continue"";");
|
||||
PS.Invoke();
|
||||
}
|
||||
|
||||
public PSCoreCommandResult WriteInput(string input, string commandID)
|
||||
{
|
||||
PS.Commands.Clear();
|
||||
PS.AddScript(input);
|
||||
var results = PS.Invoke();
|
||||
|
||||
|
||||
var ps = PowerShell.Create();
|
||||
ps.AddScript("$args[0] | Out-String");
|
||||
ps.AddArgument(results);
|
||||
@ -68,7 +76,7 @@ namespace Remotely.Agent.Services
|
||||
|
||||
PS.Streams.ClearStreams();
|
||||
PS.Commands.Clear();
|
||||
|
||||
|
||||
return new PSCoreCommandResult()
|
||||
{
|
||||
CommandContextID = commandID,
|
||||
@ -82,5 +90,10 @@ namespace Remotely.Agent.Services
|
||||
};
|
||||
}
|
||||
|
||||
private void ProcessIdleTimeout_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
PS?.Dispose();
|
||||
Sessions.TryRemove(ConnectionID, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Remotely.Agent.Services
|
||||
{
|
||||
public class Uninstaller
|
||||
{
|
||||
public static void UninstallAgent()
|
||||
public void UninstallAgent()
|
||||
{
|
||||
if (OSUtils.IsWindows)
|
||||
{
|
||||
|
||||
@ -15,7 +15,14 @@ namespace Remotely.Agent.Services
|
||||
{
|
||||
public class Updater
|
||||
{
|
||||
internal static void CheckForCoreUpdates()
|
||||
public Updater(ConfigService configService)
|
||||
{
|
||||
ConfigService = configService;
|
||||
}
|
||||
|
||||
private ConfigService ConfigService { get; }
|
||||
|
||||
public void CheckForCoreUpdates()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -69,7 +76,7 @@ namespace Remotely.Agent.Services
|
||||
Logger.Write(ex);
|
||||
}
|
||||
}
|
||||
internal static void CoreUpdate()
|
||||
public void CoreUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -172,23 +179,5 @@ namespace Remotely.Agent.Services
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
internal static async Task<string> GetLatestScreenCastVersion()
|
||||
{
|
||||
var platform = "";
|
||||
if (OSUtils.IsWindows)
|
||||
{
|
||||
platform = "Windows";
|
||||
}
|
||||
else if (OSUtils.IsLinux)
|
||||
{
|
||||
platform = "Linux";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unsupported operating system.");
|
||||
}
|
||||
var response = await new HttpClient().GetAsync(ConfigService.GetConnectionInfo().Host + $"/API/ScreenCastVersion/{platform}");
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Remotely.Shared.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Remotely.Shared.Models;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@ -10,45 +11,9 @@ namespace Remotely.Agent.Services
|
||||
{
|
||||
public class WindowsPS
|
||||
{
|
||||
private static ConcurrentDictionary<string, WindowsPS> Sessions { get; set; } = new ConcurrentDictionary<string, WindowsPS>();
|
||||
private string ConnectionID { get; set; }
|
||||
private System.Timers.Timer ProcessIdleTimeout { get; set; }
|
||||
private string LastInputID { get; set; }
|
||||
private bool OutputDone { get; set; }
|
||||
private string StandardOut { get; set; }
|
||||
private string ErrorOut { get; set; }
|
||||
public static WindowsPS GetCurrent(string connectionID)
|
||||
{
|
||||
if (Sessions.ContainsKey(connectionID))
|
||||
{
|
||||
var winPS = Sessions[connectionID];
|
||||
winPS.ProcessIdleTimeout.Stop();
|
||||
winPS.ProcessIdleTimeout.Start();
|
||||
return winPS;
|
||||
}
|
||||
else
|
||||
{
|
||||
var winPS = new WindowsPS();
|
||||
winPS.ConnectionID = connectionID;
|
||||
winPS.ProcessIdleTimeout = new System.Timers.Timer(600000); // 10 minutes.
|
||||
winPS.ProcessIdleTimeout.AutoReset = false;
|
||||
winPS.ProcessIdleTimeout.Elapsed += winPS.ProcessIdleTimeout_Elapsed;
|
||||
Sessions.AddOrUpdate(connectionID, winPS, (id, w) => winPS);
|
||||
winPS.ProcessIdleTimeout.Start();
|
||||
return winPS;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessIdleTimeout_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
Sessions.Remove(ConnectionID, out var outResult);
|
||||
outResult.PSProc.Kill();
|
||||
}
|
||||
|
||||
private Process PSProc { get; }
|
||||
|
||||
private WindowsPS()
|
||||
public WindowsPS(ConfigService configService)
|
||||
{
|
||||
ConfigService = configService;
|
||||
var psi = new ProcessStartInfo("powershell.exe");
|
||||
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
psi.Verb = "RunAs";
|
||||
@ -66,25 +31,38 @@ namespace Remotely.Agent.Services
|
||||
|
||||
PSProc.BeginErrorReadLine();
|
||||
PSProc.BeginOutputReadLine();
|
||||
|
||||
ProcessIdleTimeout = new System.Timers.Timer(600_000); // 10 minutes.
|
||||
ProcessIdleTimeout.AutoReset = false;
|
||||
ProcessIdleTimeout.Elapsed += ProcessIdleTimeout_Elapsed;
|
||||
ProcessIdleTimeout.Start();
|
||||
}
|
||||
|
||||
private void CMDProc_OutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
private static ConcurrentDictionary<string, WindowsPS> Sessions { get; set; } = new ConcurrentDictionary<string, WindowsPS>();
|
||||
private ConfigService ConfigService { get; }
|
||||
private string ConnectionID { get; set; }
|
||||
private string ErrorOut { get; set; }
|
||||
private string LastInputID { get; set; }
|
||||
private bool OutputDone { get; set; }
|
||||
private System.Timers.Timer ProcessIdleTimeout { get; set; }
|
||||
private Process PSProc { get; }
|
||||
private string StandardOut { get; set; }
|
||||
public static WindowsPS GetCurrent(string connectionID)
|
||||
{
|
||||
if (e?.Data?.Contains(LastInputID) == true)
|
||||
if (Sessions.ContainsKey(connectionID))
|
||||
{
|
||||
OutputDone = true;
|
||||
var winPS = Sessions[connectionID];
|
||||
winPS.ProcessIdleTimeout.Stop();
|
||||
winPS.ProcessIdleTimeout.Start();
|
||||
return winPS;
|
||||
}
|
||||
else if (!OutputDone)
|
||||
else
|
||||
{
|
||||
StandardOut += e.Data + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
var winPS = Program.Services.GetRequiredService<WindowsPS>();
|
||||
|
||||
private void CMDProc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e?.Data != null)
|
||||
{
|
||||
ErrorOut += e.Data + Environment.NewLine;
|
||||
winPS.ConnectionID = connectionID;
|
||||
Sessions.AddOrUpdate(connectionID, winPS, (id, w) => winPS);
|
||||
return winPS;
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,6 +90,38 @@ namespace Remotely.Agent.Services
|
||||
return GenerateCompletedResult();
|
||||
}
|
||||
|
||||
private void CMDProc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e?.Data != null)
|
||||
{
|
||||
ErrorOut += e.Data + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
|
||||
private void CMDProc_OutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (e?.Data?.Contains(LastInputID) == true)
|
||||
{
|
||||
OutputDone = true;
|
||||
}
|
||||
else if (!OutputDone)
|
||||
{
|
||||
StandardOut += e.Data + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
|
||||
private GenericCommandResult GenerateCompletedResult()
|
||||
{
|
||||
return new GenericCommandResult()
|
||||
{
|
||||
CommandContextID = LastInputID,
|
||||
DeviceID = ConfigService.GetConnectionInfo().DeviceID,
|
||||
CommandType = "WinPS",
|
||||
StandardOutput = StandardOut,
|
||||
ErrorOutput = ErrorOut
|
||||
};
|
||||
}
|
||||
|
||||
private GenericCommandResult GeneratePartialResult()
|
||||
{
|
||||
OutputDone = true;
|
||||
@ -129,16 +139,10 @@ namespace Remotely.Agent.Services
|
||||
return partialResult;
|
||||
}
|
||||
|
||||
private GenericCommandResult GenerateCompletedResult()
|
||||
private void ProcessIdleTimeout_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
return new GenericCommandResult()
|
||||
{
|
||||
CommandContextID = LastInputID,
|
||||
DeviceID = ConfigService.GetConnectionInfo().DeviceID,
|
||||
CommandType = "WinPS",
|
||||
StandardOutput = StandardOut,
|
||||
ErrorOutput = ErrorOut
|
||||
};
|
||||
PSProc?.Kill();
|
||||
Sessions.TryRemove(ConnectionID, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,9 +35,9 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="0.9.1" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.9.1" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.9.1" />
|
||||
<PackageReference Include="Avalonia" Version="0.9.2" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.9.2" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.9.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ScreenCast.Core\ScreenCast.Core.csproj" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user