diff --git a/Agent/Agent.csproj b/Agent/Agent.csproj index 3f3a9ec4..a500508b 100644 --- a/Agent/Agent.csproj +++ b/Agent/Agent.csproj @@ -24,9 +24,8 @@ + - - diff --git a/Agent/Program.cs b/Agent/Program.cs index 95912a73..ecea3384 100644 --- a/Agent/Program.cs +++ b/Agent/Program.cs @@ -12,6 +12,9 @@ using System.ServiceProcess; using System.Threading; using System.Threading.Tasks; using System.Runtime.Versioning; +using Remotely.Agent.Services.Linux; +using Remotely.Agent.Services.MacOS; +using Remotely.Agent.Services.Windows; namespace Remotely.Agent { @@ -24,6 +27,7 @@ namespace Remotely.Agent { try { + // TODO: Convert to generic host. BuildServices(); await Init(); @@ -45,7 +49,8 @@ namespace Remotely.Agent serviceCollection.AddLogging(builder => { builder.AddConsole().AddDebug(); - builder.AddProvider(new FileLoggerProvider("Remotely_Agent")); + 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. @@ -59,23 +64,23 @@ namespace Remotely.Agent serviceCollection.AddScoped(); serviceCollection.AddScoped(); - if (EnvironmentHelper.IsWindows) + if (OperatingSystem.IsWindows()) { serviceCollection.AddScoped(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); } - else if (EnvironmentHelper.IsLinux) + else if (OperatingSystem.IsLinux()) { serviceCollection.AddScoped(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); } - else if (EnvironmentHelper.IsMac) + else if (OperatingSystem.IsMacOS()) { serviceCollection.AddScoped(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); } else { diff --git a/Agent/Services/AgentHubConnection.cs b/Agent/Services/AgentHubConnection.cs index 8b3b8f38..585ccdb0 100644 --- a/Agent/Services/AgentHubConnection.cs +++ b/Agent/Services/AgentHubConnection.cs @@ -107,6 +107,7 @@ namespace Remotely.Agent.Services _logger.LogInformation("Connected to server."); + // TODO: Move CPU sampler to background service. var device = await _deviceInfoService.CreateDevice(_connectionInfo.DeviceID, _connectionInfo.OrganizationID); var result = await _hubConnection.InvokeAsync("DeviceCameOnline", device); @@ -132,6 +133,7 @@ namespace Remotely.Agent.Services continue; } + // TODO: Move to background service. _heartbeatTimer?.Dispose(); _heartbeatTimer = new Timer(TimeSpan.FromMinutes(5).TotalMilliseconds); _heartbeatTimer.Elapsed += HeartbeatTimer_Elapsed; diff --git a/Agent/Services/CpuUtilizationSampler.cs b/Agent/Services/CpuUtilizationSampler.cs new file mode 100644 index 00000000..a8979cf1 --- /dev/null +++ b/Agent/Services/CpuUtilizationSampler.cs @@ -0,0 +1,88 @@ +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Remotely.Agent.Services; + + +internal interface ICpuUtilizationSampler : IHostedService +{ + double CurrentUtilization { get; } +} + +internal class CpuUtilizationSampler : BackgroundService, ICpuUtilizationSampler +{ + private double _currentUtilization; + + public double CurrentUtilization => _currentUtilization; + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + var currentUtil = await GetCpuUtilization(stoppingToken); + Interlocked.Exchange(ref _currentUtilization, currentUtil); + await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken); + } + } + + private static async Task GetCpuUtilization(CancellationToken cancelToken) + { + double totalUtilization = 0; + var utilizations = new Dictionary>(); + var processes = Process.GetProcesses(); + + foreach (var proc in processes) + { + if (cancelToken.IsCancellationRequested) + { + return 0; + } + + try + { + var startTime = DateTimeOffset.Now; + var startCpuUsage = proc.TotalProcessorTime; + utilizations.Add(proc.Id, new Tuple(startTime, startCpuUsage)); + } + catch + { + continue; + } + } + + await Task.Delay(1_000, cancelToken); + + foreach (var kvp in utilizations) + { + if (cancelToken.IsCancellationRequested) + { + return 0; + } + + var endTime = DateTimeOffset.Now; + try + { + var proc = Process.GetProcessById(kvp.Key); + var startTime = kvp.Value.Item1; + var startCpuUsage = kvp.Value.Item2; + var endCpuUsage = proc.TotalProcessorTime; + var cpuUsedMs = (endCpuUsage - startCpuUsage).TotalMilliseconds; + var totalMsPassed = (endTime - startTime).TotalMilliseconds; + var cpuUsageTotal = cpuUsedMs / (Environment.ProcessorCount * totalMsPassed); + totalUtilization += cpuUsageTotal; + } + catch + { + continue; + } + } + + return totalUtilization; + } +} \ No newline at end of file diff --git a/Agent/Services/DeviceInformationServiceBase.cs b/Agent/Services/DeviceInfoGeneratorBase.cs similarity index 99% rename from Agent/Services/DeviceInformationServiceBase.cs rename to Agent/Services/DeviceInfoGeneratorBase.cs index ac01b042..0330091d 100644 --- a/Agent/Services/DeviceInformationServiceBase.cs +++ b/Agent/Services/DeviceInfoGeneratorBase.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; namespace Remotely.Agent.Services { - public class DeviceInformationServiceBase + public class DeviceInfoGeneratorBase { public Device GetDeviceBase(string deviceID, string orgID) { diff --git a/Agent/Services/AppLauncherLinux.cs b/Agent/Services/Linux/AppLauncherLinux.cs similarity index 98% rename from Agent/Services/AppLauncherLinux.cs rename to Agent/Services/Linux/AppLauncherLinux.cs index e37e43d8..33ed9493 100644 --- a/Agent/Services/AppLauncherLinux.cs +++ b/Agent/Services/Linux/AppLauncherLinux.cs @@ -13,7 +13,7 @@ using System.Security.Cryptography; using System.Threading.Tasks; using System.Web.Services.Description; -namespace Remotely.Agent.Services +namespace Remotely.Agent.Services.Linux { public class AppLauncherLinux : IAppLauncher @@ -24,7 +24,7 @@ namespace Remotely.Agent.Services private readonly ILogger _logger; public AppLauncherLinux( - ConfigService configService, + ConfigService configService, IProcessInvoker processInvoker, ILogger logger) { @@ -157,7 +157,7 @@ namespace Remotely.Agent.Services // Start Desktop app. await hubConnection.SendAsync("DisplayMessage", "Starting remote control.", "Starting remote control.", "bg-success", userConnectionId); - var args = + var args = _rcBinaryPath + $" --mode Unattended" + $" --host {_connectionInfo.Host}" + diff --git a/Agent/Services/DeviceInformationServiceLinux.cs b/Agent/Services/Linux/DeviceInfoGeneratorLinux.cs similarity index 87% rename from Agent/Services/DeviceInformationServiceLinux.cs rename to Agent/Services/Linux/DeviceInfoGeneratorLinux.cs index 33fb0c2f..4d398436 100644 --- a/Agent/Services/DeviceInformationServiceLinux.cs +++ b/Agent/Services/Linux/DeviceInfoGeneratorLinux.cs @@ -8,13 +8,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Remotely.Agent.Services +namespace Remotely.Agent.Services.Linux { - public class DeviceInformationServiceLinux : DeviceInformationServiceBase, IDeviceInformationService + public class DeviceInfoGeneratorLinux : DeviceInfoGeneratorBase, IDeviceInformationService { private readonly IProcessInvoker _processInvoker; - public DeviceInformationServiceLinux(IProcessInvoker processInvoker) + public DeviceInfoGeneratorLinux(IProcessInvoker processInvoker) { _processInvoker = processInvoker; } @@ -75,8 +75,8 @@ namespace Remotely.Agent.Services .Split(' ') .First(); // 16637468 - var freeGB = Math.Round((double.Parse(freeKB) / 1024 / 1024), 2); - var totalGB = Math.Round((double.Parse(totalKB) / 1024 / 1024), 2); + var freeGB = Math.Round(double.Parse(freeKB) / 1024 / 1024, 2); + var totalGB = Math.Round(double.Parse(totalKB) / 1024 / 1024, 2); return (totalGB - freeGB, totalGB); } diff --git a/Agent/Services/UpdaterLinux.cs b/Agent/Services/Linux/UpdaterLinux.cs similarity index 97% rename from Agent/Services/UpdaterLinux.cs rename to Agent/Services/Linux/UpdaterLinux.cs index a8ec45e8..3748fe1b 100644 --- a/Agent/Services/UpdaterLinux.cs +++ b/Agent/Services/Linux/UpdaterLinux.cs @@ -14,9 +14,9 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -namespace Remotely.Agent.Services +namespace Remotely.Agent.Services.Linux { - + public class UpdaterLinux : IUpdater { private readonly SemaphoreSlim _checkForUpdatesLock = new(1, 1); @@ -27,10 +27,10 @@ namespace Remotely.Agent.Services private readonly SemaphoreSlim _installLatestVersionLock = new(1, 1); private readonly System.Timers.Timer _updateTimer = new(TimeSpan.FromHours(6).TotalMilliseconds); private DateTimeOffset _lastUpdateFailure; - + public UpdaterLinux( - ConfigService configService, - IUpdateDownloader updateDownloader, + ConfigService configService, + IUpdateDownloader updateDownloader, IHttpClientFactory httpClientFactory, ILogger logger) { diff --git a/Agent/Services/AppLauncherMac.cs b/Agent/Services/MacOS/AppLauncherMac.cs similarity index 97% rename from Agent/Services/AppLauncherMac.cs rename to Agent/Services/MacOS/AppLauncherMac.cs index a713d310..f2cb070f 100644 --- a/Agent/Services/AppLauncherMac.cs +++ b/Agent/Services/MacOS/AppLauncherMac.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR.Client; using Remotely.Agent.Interfaces; -namespace Remotely.Agent.Services +namespace Remotely.Agent.Services.MacOS { public class AppLauncherMac : IAppLauncher { diff --git a/Agent/Services/DeviceInformationServiceMac.cs b/Agent/Services/MacOS/DeviceInfoGeneratorMac.cs similarity index 94% rename from Agent/Services/DeviceInformationServiceMac.cs rename to Agent/Services/MacOS/DeviceInfoGeneratorMac.cs index 3328d7fb..a2e6adee 100644 --- a/Agent/Services/DeviceInformationServiceMac.cs +++ b/Agent/Services/MacOS/DeviceInfoGeneratorMac.cs @@ -9,13 +9,13 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Remotely.Agent.Services +namespace Remotely.Agent.Services.MacOS { - public class DeviceInformationServiceMac : DeviceInformationServiceBase, IDeviceInformationService + public class DeviceInfoGeneratorMac : DeviceInfoGeneratorBase, IDeviceInformationService { private readonly IProcessInvoker _processInvoker; - public DeviceInformationServiceMac(IProcessInvoker processInvoker) + public DeviceInfoGeneratorMac(IProcessInvoker processInvoker) { _processInvoker = processInvoker; } diff --git a/Agent/Services/UpdaterMac.cs b/Agent/Services/MacOS/UpdaterMac.cs similarity index 97% rename from Agent/Services/UpdaterMac.cs rename to Agent/Services/MacOS/UpdaterMac.cs index 991e5033..1f657495 100644 --- a/Agent/Services/UpdaterMac.cs +++ b/Agent/Services/MacOS/UpdaterMac.cs @@ -15,7 +15,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Remotely.Agent.Services +namespace Remotely.Agent.Services.MacOS { public class UpdaterMac : IUpdater { @@ -30,8 +30,8 @@ namespace Remotely.Agent.Services private readonly System.Timers.Timer _updateTimer = new(TimeSpan.FromHours(6).TotalMilliseconds); public UpdaterMac( - ConfigService configService, - IUpdateDownloader updateDownloader, + ConfigService configService, + IUpdateDownloader updateDownloader, IHttpClientFactory httpClientFactory, ILogger logger) { diff --git a/Agent/Services/AppLauncherWin.cs b/Agent/Services/Windows/AppLauncherWin.cs similarity index 95% rename from Agent/Services/AppLauncherWin.cs rename to Agent/Services/Windows/AppLauncherWin.cs index 90a7231a..adb12fe0 100644 --- a/Agent/Services/AppLauncherWin.cs +++ b/Agent/Services/Windows/AppLauncherWin.cs @@ -13,7 +13,7 @@ using System.Security.Cryptography; using System.Security.Principal; using System.Threading.Tasks; -namespace Remotely.Agent.Services +namespace Remotely.Agent.Services.Windows { [SupportedOSPlatform("windows")] public class AppLauncherWin : IAppLauncher @@ -57,9 +57,9 @@ namespace Remotely.Agent.Services out var procInfo); if (!result) { - await hubConnection.SendAsync("DisplayMessage", - "Chat service failed to start on target device.", - "Failed to start chat service.", + await hubConnection.SendAsync("DisplayMessage", + "Chat service failed to start on target device.", + "Failed to start chat service.", "bg-danger", userConnectionId); } @@ -82,7 +82,7 @@ namespace Remotely.Agent.Services catch (Exception ex) { _logger.LogError(ex, "Error while launching chat."); - await hubConnection.SendAsync("DisplayMessage", + await hubConnection.SendAsync("DisplayMessage", "Chat service failed to start on target device.", "Failed to start chat service.", "bg-danger", @@ -97,9 +97,9 @@ namespace Remotely.Agent.Services { if (!File.Exists(_rcBinaryPath)) { - await hubConnection.SendAsync("DisplayMessage", - "Remote control executable not found on target device.", - "Executable not found on device.", + await hubConnection.SendAsync("DisplayMessage", + "Remote control executable not found on target device.", + "Executable not found on device.", "bg-danger", userConnectionId); return; @@ -107,7 +107,7 @@ namespace Remotely.Agent.Services // Start Desktop app. - await hubConnection.SendAsync("DisplayMessage", + await hubConnection.SendAsync("DisplayMessage", "Starting remote control.", "Starting remote control.", "bg-success", @@ -130,7 +130,7 @@ namespace Remotely.Agent.Services out _); if (!result) { - await hubConnection.SendAsync("DisplayMessage", + await hubConnection.SendAsync("DisplayMessage", "Remote control failed to start on target device.", "Failed to start remote control.", "bg-danger", @@ -152,8 +152,8 @@ namespace Remotely.Agent.Services catch (Exception ex) { _logger.LogError(ex, "Error while launching remote control."); - await hubConnection.SendAsync("DisplayMessage", - "Remote control failed to start on target device.", + await hubConnection.SendAsync("DisplayMessage", + "Remote control failed to start on target device.", "Failed to start remote control.", "bg-danger", userConnectionId); @@ -170,7 +170,7 @@ namespace Remotely.Agent.Services // Give a little time for session changing, etc. await Task.Delay(1000); - var result = Win32Interop.OpenInteractiveProcess(_rcBinaryPath + + var result = Win32Interop.OpenInteractiveProcess(_rcBinaryPath + $" --mode Unattended" + $" --relaunch true" + $" --host {_connectionInfo.Host}" + @@ -191,7 +191,7 @@ namespace Remotely.Agent.Services { _logger.LogWarning("Failed to relaunch screen caster."); await hubConnection.SendAsync("SendConnectionFailedToViewers", viewerIDs); - await hubConnection.SendAsync("DisplayMessage", + await hubConnection.SendAsync("DisplayMessage", "Remote control failed to start on target device.", "Failed to start remote control.", "bg-danger", diff --git a/Agent/Services/DeviceInformationServiceWin.cs b/Agent/Services/Windows/DeviceInfoGeneratorWin.cs similarity index 83% rename from Agent/Services/DeviceInformationServiceWin.cs rename to Agent/Services/Windows/DeviceInfoGeneratorWin.cs index 7e31c82b..c11d96dd 100644 --- a/Agent/Services/DeviceInformationServiceWin.cs +++ b/Agent/Services/Windows/DeviceInfoGeneratorWin.cs @@ -8,9 +8,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Remotely.Agent.Services +namespace Remotely.Agent.Services.Windows { - public class DeviceInformationServiceWin : DeviceInformationServiceBase, IDeviceInformationService + public class DeviceInfoGeneratorWin : DeviceInfoGeneratorBase, IDeviceInformationService { public async Task CreateDevice(string deviceId, string orgId) { @@ -49,8 +49,8 @@ namespace Remotely.Agent.Services if (Kernel32.GlobalMemoryStatusEx(memoryStatus)) { - freeGB = Math.Round(((double)memoryStatus.ullAvailPhys / 1024 / 1024 / 1024), 2); - totalGB = Math.Round(((double)memoryStatus.ullTotalPhys / 1024 / 1024 / 1024), 2); + freeGB = Math.Round((double)memoryStatus.ullAvailPhys / 1024 / 1024 / 1024, 2); + totalGB = Math.Round((double)memoryStatus.ullTotalPhys / 1024 / 1024 / 1024, 2); } return (totalGB - freeGB, totalGB); diff --git a/Agent/Services/UpdaterWin.cs b/Agent/Services/Windows/UpdaterWin.cs similarity index 97% rename from Agent/Services/UpdaterWin.cs rename to Agent/Services/Windows/UpdaterWin.cs index a6a10432..34538a88 100644 --- a/Agent/Services/UpdaterWin.cs +++ b/Agent/Services/Windows/UpdaterWin.cs @@ -10,7 +10,7 @@ using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; -namespace Remotely.Agent.Services +namespace Remotely.Agent.Services.Windows { public class UpdaterWin : IUpdater { @@ -25,8 +25,8 @@ namespace Remotely.Agent.Services public UpdaterWin( - ConfigService configService, - IUpdateDownloader updateDownloader, + ConfigService configService, + IUpdateDownloader updateDownloader, IHttpClientFactory httpClientFactory, ILogger logger) { diff --git a/Desktop.Linux/Program.cs b/Desktop.Linux/Program.cs index 44f6d1d0..83dd8fe0 100644 --- a/Desktop.Linux/Program.cs +++ b/Desktop.Linux/Program.cs @@ -2,19 +2,18 @@ using System.Threading.Tasks; using System.Threading; using System; -using Immense.RemoteControl.Desktop.Linux; using Remotely.Desktop.Shared.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Remotely.Shared.Services; using Immense.RemoteControl.Desktop.Shared.Services; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Immense.RemoteControl.Desktop.Shared.Enums; using Immense.RemoteControl.Desktop.UI.Services; -using Remotely.Shared; using System.Diagnostics; +using Immense.RemoteControl.Desktop.Linux.Startup; +using Remotely.Shared.Utilities; -var logger = new FileLogger("Remotely_Desktop", "Program.cs"); +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 serverUrl = Debugger.IsAttached ? "http://localhost:5000" : string.Empty; var getEmbeddedResult = await EmbeddedServerDataSearcher.Instance.TryGetEmbeddedData(filePath); @@ -27,37 +26,41 @@ else logger.LogWarning(getEmbeddedResult.Exception, "Failed to extract embedded server data."); } -var provider = await Startup.UseRemoteControlClient( - args, +var services = new ServiceCollection(); + +services.AddSingleton(); +services.AddSingleton(); + +services.AddRemoteControlLinux( config => { config.AddBrandingProvider(); - }, - services => - { - services.AddLogging(builder => - { -#if DEBUG - builder.SetMinimumLevel(LogLevel.Debug); -#endif - builder.AddProvider(new FileLoggerProvider("Remotely_Desktop")); - }); + }); - services.AddSingleton(); - services.AddSingleton(); - }, - services => +services.AddLogging(builder => +{ + if (EnvironmentHelper.IsDebug) { - var appState = services.GetRequiredService(); - if (appState.ArgDict.TryGetValue("org-id", out var orgId)) - { - var orgIdProvider = services.GetRequiredService(); - orgIdProvider.OrganizationId = orgId; - } - return Task.CompletedTask; - }, - serverUrl); + builder.SetMinimumLevel(LogLevel.Debug); + } + builder.AddProvider(new FileLoggerProvider("Remotely_Desktop", version)); +}); +var provider = services.BuildServiceProvider(); + +var appState = provider.GetRequiredService(); +var orgIdProvider = provider.GetRequiredService(); + +if (getEmbeddedResult.IsSuccess) +{ + orgIdProvider.OrganizationId = getEmbeddedResult.Value.OrganizationId; + appState.Host = getEmbeddedResult.Value.ServerUrl.AbsoluteUri; +} + +if (appState.ArgDict.TryGetValue("org-id", out var orgId)) +{ + orgIdProvider.OrganizationId = orgId; +} Console.WriteLine("Press Ctrl + C to exit."); diff --git a/Desktop.Shared/Services/BrandingProvider.cs b/Desktop.Shared/Services/BrandingProvider.cs index ab432c18..407fb6d0 100644 --- a/Desktop.Shared/Services/BrandingProvider.cs +++ b/Desktop.Shared/Services/BrandingProvider.cs @@ -1,5 +1,6 @@ using Immense.RemoteControl.Desktop.Shared.Abstractions; using Immense.RemoteControl.Desktop.Shared.Services; +using Immense.RemoteControl.Shared; using Immense.RemoteControl.Shared.Models; using Microsoft.Extensions.Logging; using Remotely.Shared; @@ -89,7 +90,9 @@ namespace Remotely.Desktop.Shared.Services if (!result.IsSuccess) { - return Result.Fail(result.Exception); + return result.HadException ? + Result.Fail(result.Exception) : + Result.Fail(result.Reason); } if (!string.IsNullOrWhiteSpace(result.Value.OrganizationId)) diff --git a/Desktop.Win/Program.cs b/Desktop.Win/Program.cs index fa1f78ab..90a0f616 100644 --- a/Desktop.Win/Program.cs +++ b/Desktop.Win/Program.cs @@ -10,8 +10,11 @@ using Microsoft.Extensions.Logging; using Remotely.Shared.Services; using Immense.RemoteControl.Desktop.Shared.Services; using System.Diagnostics; +using Remotely.Shared.Utilities; +using Immense.RemoteControl.Desktop.Windows.Startup; -var logger = new FileLogger("Remotely_Desktop", "Program.cs"); +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 serverUrl = Debugger.IsAttached ? "https://localhost:5001" : string.Empty; var getEmbeddedResult = await EmbeddedServerDataSearcher.Instance.TryGetEmbeddedData(filePath); @@ -24,45 +27,49 @@ else logger.LogWarning(getEmbeddedResult.Exception, "Failed to extract embedded server data."); } -var provider = await Startup.UseRemoteControlClient( - args, +var services = new ServiceCollection(); + +services.AddSingleton(); +services.AddSingleton(EmbeddedServerDataSearcher.Instance); + +services.AddRemoteControlWindows( config => { config.AddBrandingProvider(); - }, - services => + }); + +services.AddLogging(builder => +{ + if (EnvironmentHelper.IsDebug) { - services.AddLogging(builder => - { -#if DEBUG - builder.SetMinimumLevel(LogLevel.Debug); -#endif - builder.AddProvider(new FileLoggerProvider("Remotely_Desktop")); - }); + builder.SetMinimumLevel(LogLevel.Debug); + } + builder.AddProvider(new FileLoggerProvider("Remotely_Desktop", version)); +}); - services.AddSingleton(); - services.AddSingleton(EmbeddedServerDataSearcher.Instance); - }, - services => - { - var appState = services.GetRequiredService(); - var orgIdProvider = services.GetRequiredService(); +var provider = services.BuildServiceProvider(); - if (getEmbeddedResult.IsSuccess) - { - orgIdProvider.OrganizationId = getEmbeddedResult.Value.OrganizationId; - appState.Host = getEmbeddedResult.Value.ServerUrl.AbsoluteUri; - } +var appState = provider.GetRequiredService(); +var orgIdProvider = provider.GetRequiredService(); - if (appState.ArgDict.TryGetValue("org-id", out var orgId)) - { - orgIdProvider.OrganizationId = orgId; - } +if (getEmbeddedResult.IsSuccess) +{ + orgIdProvider.OrganizationId = getEmbeddedResult.Value.OrganizationId; + appState.Host = getEmbeddedResult.Value.ServerUrl.AbsoluteUri; +} - return Task.CompletedTask; - }, - serverUrl); +if (appState.ArgDict.TryGetValue("org-id", out var orgId)) +{ + orgIdProvider.OrganizationId = orgId; +} +var result = await provider.UseRemoteControlClientWindows(args, serverUrl); + +if (!result.IsSuccess) +{ + logger.LogError(result.Exception, "Failed to remote control client."); + Environment.Exit(1); +} var dispatcher = provider.GetRequiredService(); diff --git a/Server/API/AgentUpdateController.cs b/Server/API/AgentUpdateController.cs index 17d2ef90..16e7b011 100644 --- a/Server/API/AgentUpdateController.cs +++ b/Server/API/AgentUpdateController.cs @@ -26,7 +26,7 @@ namespace Remotely.Server.API { ExpirationScanFrequency = TimeSpan.FromSeconds(10) }); - private readonly IHubContext _agentHubContext; + private readonly IHubContext _agentHubContext; private readonly IApplicationConfig _appConfig; @@ -40,7 +40,7 @@ namespace Remotely.Server.API IDataService dataService, IApplicationConfig appConfig, IServiceHubSessionCache serviceSessionCache, - IHubContext agentHubContext) + IHubContext agentHubContext) { _hostEnv = hostingEnv; _dataService = dataService; diff --git a/Server/API/RemoteControlController.cs b/Server/API/RemoteControlController.cs index e6d4b774..0d10a3a9 100644 --- a/Server/API/RemoteControlController.cs +++ b/Server/API/RemoteControlController.cs @@ -24,7 +24,7 @@ namespace Remotely.Server.API [ApiController] public class RemoteControlController : ControllerBase { - private readonly IHubContext _serviceHub; + private readonly IHubContext _serviceHub; private readonly IDesktopHubSessionCache _desktopSessionCache; private readonly IServiceHubSessionCache _serviceSessionCache; private readonly IApplicationConfig _appConfig; @@ -37,7 +37,7 @@ namespace Remotely.Server.API SignInManager signInManager, IDataService dataService, IDesktopHubSessionCache desktopSessionCache, - IHubContext serviceHub, + IHubContext serviceHub, IServiceHubSessionCache serviceSessionCache, IOtpProvider otpProvider, IHubEventHandlerEx hubEvents, diff --git a/Server/API/ScriptingController.cs b/Server/API/ScriptingController.cs index 5a07b908..c9958ea1 100644 --- a/Server/API/ScriptingController.cs +++ b/Server/API/ScriptingController.cs @@ -22,7 +22,7 @@ namespace Remotely.Server.API [Route("api/[controller]")] public class ScriptingController : ControllerBase { - private readonly IHubContext _agentHubContext; + private readonly IHubContext _agentHubContext; private readonly IDataService _dataService; private readonly IServiceHubSessionCache _serviceSessionCache; @@ -34,7 +34,7 @@ namespace Remotely.Server.API IDataService dataService, IServiceHubSessionCache serviceSessionCache, IExpiringTokenService expiringTokenService, - IHubContext agentHub) + IHubContext agentHub) { _dataService = dataService; _serviceSessionCache = serviceSessionCache; @@ -91,15 +91,16 @@ namespace Remotely.Server.API var requestID = Guid.NewGuid().ToString(); var authToken = _expiringTokenService.GetToken(Time.Now.AddMinutes(AppConstants.ScriptRunExpirationMinutes)); + // TODO: Replace with new invoke capability in .NET 7. await _agentHubContext.Clients.Client(connectionId).SendAsync("ExecuteCommandFromApi", shell, authToken, requestID, command, User?.Identity?.Name); - var success = await WaitHelper.WaitForAsync(() => ServiceHub.ApiScriptResults.TryGetValue(requestID, out _), TimeSpan.FromSeconds(30)); + var success = await WaitHelper.WaitForAsync(() => AgentHub.ApiScriptResults.TryGetValue(requestID, out _), TimeSpan.FromSeconds(30)); if (!success) { return NotFound(); } - ServiceHub.ApiScriptResults.TryGetValue(requestID, out var commandID); - ServiceHub.ApiScriptResults.Remove(requestID); + AgentHub.ApiScriptResults.TryGetValue(requestID, out var commandID); + AgentHub.ApiScriptResults.Remove(requestID); var result = _dataService.GetScriptResult(commandID.ToString(), orgID); return result; } diff --git a/Server/Hubs/ServiceHub.cs b/Server/Hubs/AgentHub.cs similarity index 94% rename from Server/Hubs/ServiceHub.cs rename to Server/Hubs/AgentHub.cs index cace4fa8..5c9a1b3a 100644 --- a/Server/Hubs/ServiceHub.cs +++ b/Server/Hubs/AgentHub.cs @@ -17,16 +17,16 @@ using System.Threading.Tasks; namespace Remotely.Server.Hubs { - public class ServiceHub : Hub + public class AgentHub : Hub { private readonly IApplicationConfig _appConfig; private readonly ICircuitManager _circuitManager; - private readonly IExpiringTokenService _expiringTokenService; private readonly IDataService _dataService; + private readonly IExpiringTokenService _expiringTokenService; private readonly IServiceHubSessionCache _serviceSessionCache; private readonly IHubContext _viewerHubContext; - public ServiceHub(IDataService dataService, + public AgentHub(IDataService dataService, IApplicationConfig appConfig, IServiceHubSessionCache serviceSessionCache, IHubContext viewerHubContext, @@ -41,7 +41,7 @@ namespace Remotely.Server.Hubs _expiringTokenService = expiringTokenService; } - // TODO: Move to service behind interface. + // TODO: Replace with new invoke capability in .NET 7 in ScriptingController. public static IMemoryCache ApiScriptResults { get; } = new MemoryCache(new MemoryCacheOptions()); private Device Device @@ -93,17 +93,6 @@ namespace Remotely.Server.Hubs return Task.FromResult(false); } - //if (_serviceSessionCache.Sessions.Any(x => x.Value == device.ID)) - //{ - // _dataService.WriteEvent(new EventLog() - // { - // EventType = EventType.Info, - // OrganizationID = device.OrganizationID, - // Message = $"Device connection for {device?.DeviceName} was denied because it is already connected." - // }); - // return Task.FromResult(false); - //} - var ip = Context.GetHttpContext()?.Connection?.RemoteIpAddress; if (ip != null && ip.IsIPv4MappedToIPv6) { @@ -209,6 +198,16 @@ namespace Remotely.Server.Hubs return _circuitManager.InvokeOnConnection(requesterID, CircuitEventName.DownloadFileProgress, progressPercent); } + public string GetServerUrl() + { + return _appConfig.ServerUrl; + } + + public string GetServerVerificationToken() + { + return Device.ServerVerificationToken; + } + public override Task OnDisconnectedAsync(Exception exception) { try @@ -266,21 +265,11 @@ namespace Remotely.Server.Hubs { return _circuitManager.InvokeOnConnection(requesterConnectionId, CircuitEventName.RemoteLogsReceived, logChunk); } - - public string GetServerVerificationToken() - { - return Device.ServerVerificationToken; - } - public void SetServerVerificationToken(string verificationToken) { Device.ServerVerificationToken = verificationToken; _dataService.SetServerVerificationToken(Device.ID, verificationToken); } - public string GetServerUrl() - { - return _appConfig.ServerUrl; - } public Task TransferCompleted(string transferID, string requesterID) { return _circuitManager.InvokeOnConnection(requesterID, CircuitEventName.TransferCompleted, transferID); diff --git a/Server/Hubs/CircuitConnection.cs b/Server/Hubs/CircuitConnection.cs index f5c07d44..1f4d8e66 100644 --- a/Server/Hubs/CircuitConnection.cs +++ b/Server/Hubs/CircuitConnection.cs @@ -58,7 +58,7 @@ namespace Remotely.Server.Hubs public class CircuitConnection : CircuitHandler, ICircuitConnection { - private readonly IHubContext _agentHubContext; + private readonly IHubContext _agentHubContext; private readonly IApplicationConfig _appConfig; private readonly IClientAppState _appState; private readonly IAuthService _authService; @@ -74,7 +74,7 @@ namespace Remotely.Server.Hubs IAuthService authService, IDataService dataService, IClientAppState appState, - IHubContext agentHubContext, + IHubContext agentHubContext, IApplicationConfig appConfig, ICircuitManager circuitManager, IToastService toastService, diff --git a/Server/Pages/ServerConfig.razor.cs b/Server/Pages/ServerConfig.razor.cs index 586c9a44..e75cfd6c 100644 --- a/Server/Pages/ServerConfig.razor.cs +++ b/Server/Pages/ServerConfig.razor.cs @@ -142,7 +142,7 @@ namespace Remotely.Server.Pages [Inject] - private IHubContext AgentHubContext { get; set; } + private IHubContext AgentHubContext { get; set; } [Inject] private IConfiguration Configuration { get; set; } diff --git a/Server/Program.cs b/Server/Program.cs index dea1ed8b..791ab4b9 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -257,7 +257,7 @@ app.UseRemoteControlServer(); app.UseEndpoints(endpoints => { - endpoints.MapHub("/hubs/service"); + endpoints.MapHub("/hubs/service"); endpoints.MapControllers(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); diff --git a/Server/Services/RcImplementations/HubEventHandler.cs b/Server/Services/RcImplementations/HubEventHandler.cs index 65103549..efef011c 100644 --- a/Server/Services/RcImplementations/HubEventHandler.cs +++ b/Server/Services/RcImplementations/HubEventHandler.cs @@ -27,12 +27,12 @@ namespace Remotely.Server.Services.RcImplementations private static readonly ConcurrentDictionary _sessionWaitHandlers = new(); private readonly ICircuitManager _circuitManager; - private readonly IHubContext _serviceHub; + private readonly IHubContext _serviceHub; private readonly ILogger _logger; public HubEventHandlerEx( ICircuitManager circuitManager, - IHubContext serviceHub, + IHubContext serviceHub, ILogger logger) { _circuitManager = circuitManager; diff --git a/Server/Services/UpgradeService.cs b/Server/Services/UpgradeService.cs index dcd31c0c..d74757ad 100644 --- a/Server/Services/UpgradeService.cs +++ b/Server/Services/UpgradeService.cs @@ -37,10 +37,10 @@ namespace Remotely.Server.Services return _currentVersion; } - var fileVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo("Remotely_Server.dll").FileVersion; - if (Version.TryParse(fileVersion, out var result)) + var asmVersion = typeof(UpgradeService).Assembly.GetName().Version; + if (asmVersion is not null) { - _currentVersion = result; + _currentVersion = asmVersion; return _currentVersion; } } diff --git a/Shared/Result.cs b/Shared/Result.cs deleted file mode 100644 index 37f96c57..00000000 --- a/Shared/Result.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Remotely.Shared -{ - public class Result - { - public static Result Empty() - { - return new Result(true, default); - } - - public static Result Fail(string error) - { - return new Result(false, error); - } - public static Result Fail(Exception ex) - { - return new Result(false, null, ex); - } - - public static Result Fail(string error) - { - return new Result(false, default, error); - } - - public static Result Fail(Exception ex) - { - return new Result(false, default, exception: ex); - } - - public static Result Ok() - { - return new Result(true); - } - - public static Result Ok(T value) - { - return new Result(true, value, null); - } - - - public Result(bool isSuccess, string error = null, Exception exception = null) - { - IsSuccess = isSuccess; - Error = error; - Exception = exception; - - if (string.IsNullOrWhiteSpace(Error) && !string.IsNullOrWhiteSpace(Exception?.Message)) - { - Error = Exception.Message; - } - - Exception ??= new Exception(Error ?? string.Empty); - } - - public bool IsSuccess { get; init; } - - public string Error { get; init; } = string.Empty; - - public Exception Exception { get; init; } - } - - public class Result - { - public Result(bool isSuccess, T value, string error = null, Exception exception = null) - { - IsSuccess = isSuccess; - Value = value; - Error = error; - Exception = exception; - - if (string.IsNullOrWhiteSpace(Error) && !string.IsNullOrWhiteSpace(Exception?.Message)) - { - Error = Exception.Message; - } - - Exception ??= new Exception(Error ?? string.Empty); - } - - - public bool IsSuccess { get; init; } - - public string Error { get; init; } = string.Empty; - - public Exception Exception { get; init; } - - public T Value { get; init; } - } -} diff --git a/Shared/Services/EmbeddedServerDataSearcher.cs b/Shared/Services/EmbeddedServerDataSearcher.cs index baf8dd04..258ae32c 100644 --- a/Shared/Services/EmbeddedServerDataSearcher.cs +++ b/Shared/Services/EmbeddedServerDataSearcher.cs @@ -1,5 +1,6 @@ #nullable enable +using Immense.RemoteControl.Shared; using Microsoft.Extensions.Logging; using Remotely.Shared.Models; using Remotely.Shared.Utilities; diff --git a/Shared/Services/FileLogger.cs b/Shared/Services/FileLogger.cs index 0f6cff53..c207221d 100644 --- a/Shared/Services/FileLogger.cs +++ b/Shared/Services/FileLogger.cs @@ -1,12 +1,11 @@ -using Microsoft.Extensions.Logging; -using Remotely.Shared.Extensions; +#nullable enable + +using Microsoft.Extensions.Logging; using Remotely.Shared.Utilities; using System; using System.Collections.Concurrent; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -14,42 +13,51 @@ namespace Remotely.Shared.Services { public class FileLogger : ILogger { - private static readonly ConcurrentQueue _logQueue = new(); private static readonly ConcurrentStack _scopeStack = new(); private static readonly SemaphoreSlim _writeLock = new(1, 1); - private static string _logDir; - private readonly string _applicationName; private readonly string _categoryName; - private readonly System.Timers.Timer _sinkTimer = new(5000) { AutoReset = false }; + private readonly string _componentName; + private readonly string _componentVersion; + private DateTimeOffset _lastLogCleanup; - public FileLogger(string applicationName, string categoryName) + public FileLogger(string componentName, string componentVersion, string categoryName) { - _applicationName = applicationName?.SanitizeFileName() ?? string.Empty; + _componentName = componentName; + _componentVersion = componentVersion; _categoryName = categoryName; - _sinkTimer.Elapsed += SinkTimer_Elapsed; } - private string LogDir + private static string LogsFolderPath { get { - if (!string.IsNullOrWhiteSpace(_logDir)) - { - return _logDir; - } - if (OperatingSystem.IsWindows()) { - _logDir = Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Remotely", "Logs")).FullName; + var logsPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), + "Remotely", + "Logs"); + + if (EnvironmentHelper.IsDebug) + { + logsPath += "_Debug"; + } + return logsPath; } - else + + if (OperatingSystem.IsLinux()) { - _logDir = Directory.CreateDirectory("/var/log/remotely").FullName; + if (EnvironmentHelper.IsDebug) + { + return "/var/log/remotely_debug"; + } + return "/var/log/remotely"; } - return _logDir; + + throw new PlatformNotSupportedException(); } } - private string LogPath => Path.Combine(LogDir, $"LogFile_{_applicationName}_{DateTime.Now:yyyy-MM-dd}.log"); + private string LogPath => Path.Combine(LogsFolderPath, _componentName, $"LogFile_{DateTime.Now:yyyy-MM-dd}.log"); public IDisposable BeginScope(TState state) { @@ -85,21 +93,25 @@ namespace Remotely.Shared.Services }; } - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { + _writeLock.Wait(); + try { - var scopeStack = _scopeStack.Any() ? - new string[] { _scopeStack.First(), _scopeStack.Last() } : - Array.Empty(); - var message = FormatLogEntry(logLevel, _categoryName, $"{state}", exception, scopeStack); - _logQueue.Enqueue(message); - _sinkTimer.Start(); + var message = FormatLogEntry(logLevel, _categoryName, $"{state}", exception, _scopeStack.ToArray()); + CheckLogFileExists(); + File.AppendAllText(LogPath, message); + CleanupLogs(); } catch (Exception ex) { - Debug.WriteLine($"Error queueing log entry: {ex.Message}"); + Console.WriteLine($"Error writing log entry: {ex.Message}"); + } + finally + { + _writeLock.Release(); } } @@ -126,42 +138,38 @@ namespace Remotely.Shared.Services private void CheckLogFileExists() { - _ = Directory.CreateDirectory(Path.GetDirectoryName(LogPath)!); - + Directory.CreateDirectory(Path.GetDirectoryName(LogPath)!); if (!File.Exists(LogPath)) { File.Create(LogPath).Close(); + } + } + private void CleanupLogs() + { + if (DateTimeOffset.Now - _lastLogCleanup < TimeSpan.FromDays(1)) + { + return; + } + _lastLogCleanup = DateTimeOffset.Now; + + var logFiles = Directory.GetFiles(Path.GetDirectoryName(LogPath)!) + .Select(x => new FileInfo(x)) + .Where(x => DateTime.Now - x.CreationTime > TimeSpan.FromDays(7)); + + foreach (var file in logFiles) + { try { - if (OperatingSystem.IsWindows()) - { - Process.Start("cmd", $"/c icacls \"{LogPath}\" /grant Users:M").WaitForExit(1_000); - } - else if (OperatingSystem.IsLinux()) - { - Process.Start("sudo", $"chmod 775 {LogPath}").WaitForExit(1_000); - } + file.Delete(); } catch (Exception ex) { - Debug.WriteLine($"Error modifying log file permissions: {ex.Message}"); - } - } - - if (File.Exists(LogPath)) - { - var fi = new FileInfo(LogPath); - while (fi.Length > 1_000_000) - { - var content = File.ReadAllLines(LogPath); - File.WriteAllLines(LogPath, content.Skip(10)); - fi = new FileInfo(LogPath); + Console.WriteLine($"Error while trying to delete log file {file.FullName}. Message: {ex.Message}"); } } } - - private string FormatLogEntry(LogLevel logLevel, string categoryName, string state, Exception exception, string[] scopeStack) + private string FormatLogEntry(LogLevel logLevel, string categoryName, string state, Exception? exception, string[] scopeStack) { var ex = exception; var exMessage = exception?.Message; @@ -174,13 +182,16 @@ namespace Remotely.Shared.Services var entry = $"[{logLevel}]\t" + - $"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff}\t"; + $"[v{_componentVersion}]\t" + + $"[Process ID: {Environment.ProcessId}]\t" + + $"[Thread ID: {Environment.CurrentManagedThreadId}]\t" + + $"[{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff}]\t"; entry += scopeStack.Any() ? - $"[{string.Join(" - ", scopeStack)} - {categoryName}]\t" : + $"[{categoryName} => {string.Join(" => ", scopeStack)}]\t" : $"[{categoryName}]\t"; - entry += $"Message: {state}\t"; + entry += $"{state}\t"; if (!string.IsNullOrWhiteSpace(exMessage)) { @@ -197,32 +208,6 @@ namespace Remotely.Shared.Services return entry; } - private async void SinkTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) - { - try - { - await _writeLock.WaitAsync(); - - CheckLogFileExists(); - - var message = string.Empty; - - while (_logQueue.TryDequeue(out var entry)) - { - message += entry; - } - - File.AppendAllText(LogPath, message); - } - catch (Exception ex) - { - Debug.WriteLine($"Error writing log entry: {ex.Message}"); - } - finally - { - _writeLock.Release(); - } - } private class NoopDisposable : IDisposable { public void Dispose() diff --git a/Shared/Services/FileLoggerProvider.cs b/Shared/Services/FileLoggerProvider.cs index 00633f0b..49a675e1 100644 --- a/Shared/Services/FileLoggerProvider.cs +++ b/Shared/Services/FileLoggerProvider.cs @@ -5,16 +5,18 @@ namespace Remotely.Shared.Services { public class FileLoggerProvider : ILoggerProvider { - private readonly string _applicationName; + private readonly string _componentName; + private readonly string _componentVersion; - public FileLoggerProvider(string applicationName) + public FileLoggerProvider(string componentName, string componentVersion) { - _applicationName = applicationName; + _componentName = componentName; + _componentVersion = componentVersion; } public ILogger CreateLogger(string categoryName) { - return new FileLogger(_applicationName, categoryName); + return new FileLogger(_componentName, _componentVersion, categoryName); } public void Dispose() diff --git a/Shared/Utilities/EnvironmentHelper.cs b/Shared/Utilities/EnvironmentHelper.cs index 66379c02..7d2ba6c7 100644 --- a/Shared/Utilities/EnvironmentHelper.cs +++ b/Shared/Utilities/EnvironmentHelper.cs @@ -4,6 +4,7 @@ using System.Diagnostics; namespace Remotely.Shared.Utilities { + // TODO: Make instanced and put behind interface. public static class EnvironmentHelper { public static string AgentExecutableFileName diff --git a/Tests/LoadTester/Program.cs b/Tests/LoadTester/Program.cs index 60248cbf..49bb899e 100644 --- a/Tests/LoadTester/Program.cs +++ b/Tests/LoadTester/Program.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.SignalR.Client; using Remotely.Agent.Services; +using Remotely.Agent.Services.Windows; using System; using System.Collections.Generic; using System.Threading; @@ -14,11 +15,11 @@ namespace Remotely.Tests.LoadTester private static int _agentCount; private static string _organizationId; private static string _serverurl; - private static DeviceInformationServiceWin _deviceInfo; + private static DeviceInfoGeneratorWin _deviceInfo; private static void Main(string[] args) { - _deviceInfo = new DeviceInformationServiceWin(); + _deviceInfo = new DeviceInfoGeneratorWin(); ConnectAgents(); Console.Write("Press Enter to exit..."); diff --git a/Tests/Server.Tests/AgentHubTests.cs b/Tests/Server.Tests/AgentHubTests.cs index bad8791a..16d0efad 100644 --- a/Tests/Server.Tests/AgentHubTests.cs +++ b/Tests/Server.Tests/AgentHubTests.cs @@ -42,7 +42,7 @@ namespace Remotely.Tests appConfig.Setup(x => x.BannedDevices).Returns(new string[] { _testData.Device1.DeviceName }); - var hub = new ServiceHub(DataService, appConfig.Object, serviceSessionCache.Object, viewerHub.Object, circuitManager.Object, expiringTokenService.Object); + var hub = new AgentHub(DataService, appConfig.Object, serviceSessionCache.Object, viewerHub.Object, circuitManager.Object, expiringTokenService.Object); var hubClients = new Mock(); var caller = new Mock(); @@ -69,7 +69,7 @@ namespace Remotely.Tests appConfig.Setup(x => x.BannedDevices).Returns(new string[] { _testData.Device1.ID }); - var hub = new ServiceHub(DataService, appConfig.Object, serviceSessionCache.Object, viewerHub.Object, circuitManager.Object, expiringTokenService.Object); + var hub = new AgentHub(DataService, appConfig.Object, serviceSessionCache.Object, viewerHub.Object, circuitManager.Object, expiringTokenService.Object); var hubClients = new Mock(); var caller = new Mock(); @@ -100,7 +100,7 @@ namespace Remotely.Tests appConfig.Setup(x => x.BannedDevices).Returns(Array.Empty()); - var hub = new ServiceHub(DataService, appConfig.Object, serviceSessionCache.Object, viewerHub.Object, circuitManager.Object, expiringTokenService.Object) + var hub = new AgentHub(DataService, appConfig.Object, serviceSessionCache.Object, viewerHub.Object, circuitManager.Object, expiringTokenService.Object) { Context = new CallerContext() }; diff --git a/submodules/Immense.RemoteControl b/submodules/Immense.RemoteControl index 345c43e0..283f6656 160000 --- a/submodules/Immense.RemoteControl +++ b/submodules/Immense.RemoteControl @@ -1 +1 @@ -Subproject commit 345c43e03dc8e32cb0d3519a9767dd654ad420ba +Subproject commit 283f66562d90b84132b40116b31694c691a97cc9