Skip to content

Commit

Permalink
Fix session info state after reconnects. Use hosting for agent. Fix s…
Browse files Browse the repository at this point in the history
…hutdown process. Fix idle timer when disconnected.
  • Loading branch information
bitbound committed Apr 26, 2023
1 parent bb2126b commit e3cf287
Show file tree
Hide file tree
Showing 14 changed files with 138 additions and 131 deletions.
23 changes: 13 additions & 10 deletions Agent/Agent.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,19 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="6.0.9" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.9" />
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.6" />
<PackageReference Include="Microsoft.WSMan.Management" Version="7.2.6" />
<PackageReference Include="Microsoft.WSMan.Runtime" Version="7.2.6" />
<PackageReference Include="System.Management.Automation" Version="7.2.6" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.WindowsServices" Version="7.0.5" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="7.0.5" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.EventLog" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.5" />
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.3.4" />
<PackageReference Include="Microsoft.WSMan.Management" Version="7.3.4" />
<PackageReference Include="Microsoft.WSMan.Runtime" Version="7.3.4" />
<PackageReference Include="System.Management.Automation" Version="7.3.4" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="7.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
190 changes: 87 additions & 103 deletions Agent/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,131 +14,115 @@
using Remotely.Agent.Services.Linux;
using Remotely.Agent.Services.MacOS;
using Remotely.Agent.Services.Windows;
using Microsoft.Extensions.Hosting;
using System.Linq;

namespace Remotely.Agent
{
public class Program
{
namespace Remotely.Agent;

public static IServiceProvider Services { get; set; }
public class Program
{
[Obsolete("Remove this when all services are in DI behind interfaces.")]
public static IServiceProvider Services { get; set; }

public static async Task Main(string[] args)
public static async Task Main(string[] args)
{
try
{
try
{
// TODO: Convert to generic host.
BuildServices();
var host = Host
.CreateDefaultBuilder(args)
.UseWindowsService()
.UseSystemd()
.ConfigureServices(RegisterServices)
.Build();

await Init();
await host.StartAsync();

await Task.Delay(-1);
await Init(host.Services);

}
catch (Exception ex)
{
Logger.Write(ex);
throw;
}
await host.WaitForShutdownAsync();
}

private static void BuildServices()
catch (Exception ex)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddHttpClient();
serviceCollection.AddLogging(builder =>
{
builder.AddConsole().AddDebug();
var version = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0";
builder.AddProvider(new FileLoggerProvider("Remotely_Agent", version));
});

// TODO: All these should be registered as interfaces.
serviceCollection.AddSingleton<IAgentHubConnection, AgentHubConnection>();
serviceCollection.AddSingleton<ICpuUtilizationSampler, CpuUtilizationSampler>();
serviceCollection.AddHostedService(services => services.GetRequiredService<ICpuUtilizationSampler>());
serviceCollection.AddScoped<ChatClientService>();
serviceCollection.AddTransient<PSCore>();
serviceCollection.AddTransient<ExternalScriptingShell>();
serviceCollection.AddScoped<ConfigService>();
serviceCollection.AddScoped<Uninstaller>();
serviceCollection.AddScoped<ScriptExecutor>();
serviceCollection.AddScoped<IProcessInvoker, ProcessInvoker>();
serviceCollection.AddScoped<IUpdateDownloader, UpdateDownloader>();

if (OperatingSystem.IsWindows())
{
serviceCollection.AddScoped<IAppLauncher, AppLauncherWin>();
serviceCollection.AddSingleton<IUpdater, UpdaterWin>();
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInfoGeneratorWin>();
}
else if (OperatingSystem.IsLinux())
{
serviceCollection.AddScoped<IAppLauncher, AppLauncherLinux>();
serviceCollection.AddSingleton<IUpdater, UpdaterLinux>();
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInfoGeneratorLinux>();
}
else if (OperatingSystem.IsMacOS())
{
serviceCollection.AddScoped<IAppLauncher, AppLauncherMac>();
serviceCollection.AddSingleton<IUpdater, UpdaterMac>();
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInfoGeneratorMac>();
}
else
{
throw new NotSupportedException("Operating system not supported.");
}

Services = serviceCollection.BuildServiceProvider();
var version = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0";
var logger = new FileLogger("Remotely_Agent", version, "Main");
logger.LogError(ex, "Error during agent startup.");
throw;
}
}

private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
private static void RegisterServices(IServiceCollection services)
{
services.AddHttpClient();
services.AddLogging(builder =>
{
Logger.Write(e.ExceptionObject as Exception);
builder.AddConsole().AddDebug();
var version = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0";
builder.AddProvider(new FileLoggerProvider("Remotely_Agent", version));
});

// TODO: All these should be registered as interfaces.
services.AddSingleton<IAgentHubConnection, AgentHubConnection>();
services.AddSingleton<ICpuUtilizationSampler, CpuUtilizationSampler>();
services.AddHostedService(services => services.GetRequiredService<ICpuUtilizationSampler>());
services.AddScoped<ChatClientService>();
services.AddTransient<PSCore>();
services.AddTransient<ExternalScriptingShell>();
services.AddScoped<ConfigService>();
services.AddScoped<Uninstaller>();
services.AddScoped<ScriptExecutor>();
services.AddScoped<IProcessInvoker, ProcessInvoker>();
services.AddScoped<IUpdateDownloader, UpdateDownloader>();

if (OperatingSystem.IsWindows())
{
services.AddScoped<IAppLauncher, AppLauncherWin>();
services.AddSingleton<IUpdater, UpdaterWin>();
services.AddSingleton<IDeviceInformationService, DeviceInfoGeneratorWin>();
}

private static async Task Init()
else if (OperatingSystem.IsLinux())
{
try
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

SetWorkingDirectory();


if (OperatingSystem.IsWindows() &&
Process.GetCurrentProcess().SessionId == 0)
{
_ = Task.Run(StartService);
}

await Services.GetRequiredService<IUpdater>().BeginChecking();

await Services.GetRequiredService<IAgentHubConnection>().Connect();
}
catch (Exception ex)
{
Logger.Write(ex);
}
services.AddScoped<IAppLauncher, AppLauncherLinux>();
services.AddSingleton<IUpdater, UpdaterLinux>();
services.AddSingleton<IDeviceInformationService, DeviceInfoGeneratorLinux>();
}

private static void SetWorkingDirectory()
else if (OperatingSystem.IsMacOS())
{
var assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
var assemblyDir = Path.GetDirectoryName(assemblyPath);
Directory.SetCurrentDirectory(assemblyDir);
services.AddScoped<IAppLauncher, AppLauncherMac>();
services.AddSingleton<IUpdater, UpdaterMac>();
services.AddSingleton<IDeviceInformationService, DeviceInfoGeneratorMac>();
}
else
{
throw new NotSupportedException("Operating system not supported.");
}
}

[SupportedOSPlatform("windows")]
private static void StartService()
private static async Task Init(IServiceProvider services)
{
AppDomain.CurrentDomain.UnhandledException += (sender, ex) =>
{
try
var logger = services.GetRequiredService<ILogger<AppDomain>>();
if (ex.ExceptionObject is Exception exception)
{
ServiceBase.Run(new WindowsService());
logger.LogError(exception, "Unhandled exception in AppDomain.");
}
catch (Exception ex)
else
{
Logger.Write(ex, "Failed to start service.", EventType.Warning);
logger.LogError("Unhandled exception in AppDomain.");
}
}
};

SetWorkingDirectory();

await services.GetRequiredService<IUpdater>().BeginChecking();

await services.GetRequiredService<IAgentHubConnection>().Connect();
}

private static void SetWorkingDirectory()
{
var exePath = Environment.ProcessPath ?? Environment.GetCommandLineArgs().First();
var exeDir = Path.GetDirectoryName(exePath);
Directory.SetCurrentDirectory(exeDir);
}
}
12 changes: 10 additions & 2 deletions Agent/Services/AgentHubConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public async Task Connect()

_hubConnection = new HubConnectionBuilder()
.WithUrl(_connectionInfo.Host + "/hubs/service")
.WithAutomaticReconnect(new RetryPolicy())
.WithAutomaticReconnect(new RetryPolicy(_logger))
.AddMessagePackProtocol()
.Build();

Expand Down Expand Up @@ -521,14 +521,22 @@ private async Task<bool> VerifyServer()

private class RetryPolicy : IRetryPolicy
{
private readonly ILogger<AgentHubConnection> _logger;

public RetryPolicy(ILogger<AgentHubConnection> logger)
{
_logger = logger;
}

public TimeSpan? NextRetryDelay(RetryContext retryContext)
{
if (retryContext.PreviousRetryCount == 0)
{
return TimeSpan.FromSeconds(3);
}

var waitSeconds = Math.Min(30, retryContext.PreviousRetryCount * 5);
var waitSeconds = Random.Shared.Next(3, 10);
_logger.LogDebug("Attempting to reconnect in {seconds} seconds.", waitSeconds);
return TimeSpan.FromSeconds(waitSeconds);
}
}
Expand Down
3 changes: 3 additions & 0 deletions Agent/Services/CpuUtilizationSampler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public CpuUtilizationSampler(ILogger<CpuUtilizationSampler> logger)

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// Allow host startup to continue immediately.
await Task.Yield();

while (!stoppingToken.IsCancellationRequested)
{
try
Expand Down
1 change: 0 additions & 1 deletion Agent/Services/Windows/DeviceInfoGeneratorWin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public Task<Device> CreateDevice(string deviceId, string orgId)

try
{

var (usedStorage, totalStorage) = GetSystemDriveInfo();
var (usedMemory, totalMemory) = GetMemoryInGB();

Expand Down
3 changes: 2 additions & 1 deletion Desktop.Linux/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
using Immense.RemoteControl.Desktop.Startup;
using Remotely.Shared.Utilities;
using Immense.RemoteControl.Desktop.Shared.Startup;
using System.Linq;

var version = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0";
var logger = new FileLogger("Remotely_Desktop", version, "Program.cs");
var filePath = Process.GetCurrentProcess()?.MainModule?.FileName;
var filePath = Environment.ProcessPath ?? Environment.GetCommandLineArgs().First();
var serverUrl = Debugger.IsAttached ? "http://localhost:5000" : string.Empty;
var getEmbeddedResult = await EmbeddedServerDataSearcher.Instance.TryGetEmbeddedData(filePath);
if (getEmbeddedResult.IsSuccess)
Expand Down
3 changes: 2 additions & 1 deletion Desktop.Win/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
using Remotely.Shared.Utilities;
using Immense.RemoteControl.Desktop.Windows.Startup;
using Immense.RemoteControl.Desktop.Shared.Startup;
using System.Linq;

var version = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0";
var logger = new FileLogger("Remotely_Desktop", version, "Program.cs");
var filePath = Process.GetCurrentProcess()?.MainModule?.FileName;
var filePath = Environment.ProcessPath ?? Environment.GetCommandLineArgs().First();
var serverUrl = Debugger.IsAttached ? "https://localhost:5001" : string.Empty;
var getEmbeddedResult = await EmbeddedServerDataSearcher.Instance.TryGetEmbeddedData(filePath);
if (getEmbeddedResult.IsSuccess)
Expand Down
10 changes: 10 additions & 0 deletions Remotely.sln.startup.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@
"ProfileName": "Desktop.Win"
}
}
},
"Server+Agent": {
"Projects": {
"Server\\Server.csproj": {
"ProfileName": "Server"
},
"Agent": {
"ProfileName": "Agent"
}
}
}
}
}
4 changes: 2 additions & 2 deletions Server/API/RemoteControlController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private async Task<IActionResult> InitiateRemoteControl(string deviceID, string
{
UnattendedSessionId = sessionId,
UserConnectionId = HttpContext.Connection.Id,
ServiceConnectionId = serviceConnectionId,
AgentConnectionId = serviceConnectionId,
DeviceId = deviceID,
OrganizationId = orgID
};
Expand All @@ -137,7 +137,7 @@ private async Task<IActionResult> InitiateRemoteControl(string deviceID, string
{
if (v is RemoteControlSessionEx ex)
{
ex.ServiceConnectionId = HttpContext.Connection.Id;
ex.AgentConnectionId = HttpContext.Connection.Id;
return ex;
}
v.Dispose();
Expand Down
2 changes: 1 addition & 1 deletion Server/Hubs/CircuitConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public async Task<Result<RemoteControlSessionEx>> RemoteControl(string deviceId,
{
UnattendedSessionId = sessionId,
UserConnectionId = ConnectionId,
ServiceConnectionId = serviceConnectionId,
AgentConnectionId = serviceConnectionId,
DeviceId = deviceId,
ViewOnly = viewOnly,
OrganizationId = User.OrganizationID
Expand Down
3 changes: 0 additions & 3 deletions Server/Models/RemoteControlSessionEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ namespace Remotely.Server.Models
{
public class RemoteControlSessionEx : RemoteControlSession
{
public string ServiceConnectionId { get; set; } = string.Empty;
public string UserConnectionId { get; set; } = string.Empty;
public string DeviceId { get; set; } = string.Empty;
public bool ViewOnly { get; set; }
public string OrganizationId { get; set; } = string.Empty;
}
}
Loading

0 comments on commit e3cf287

Please sign in to comment.