mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Refactor to align with changes in submodule.
This commit is contained in:
parent
19805a81b1
commit
c0b10ef93d
@ -24,9 +24,8 @@
|
||||
|
||||
<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.Console" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" 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" />
|
||||
|
||||
@ -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<IProcessInvoker, ProcessInvoker>();
|
||||
serviceCollection.AddScoped<IUpdateDownloader, UpdateDownloader>();
|
||||
|
||||
if (EnvironmentHelper.IsWindows)
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
serviceCollection.AddScoped<IAppLauncher, AppLauncherWin>();
|
||||
serviceCollection.AddSingleton<IUpdater, UpdaterWin>();
|
||||
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInformationServiceWin>();
|
||||
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInfoGeneratorWin>();
|
||||
}
|
||||
else if (EnvironmentHelper.IsLinux)
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
serviceCollection.AddScoped<IAppLauncher, AppLauncherLinux>();
|
||||
serviceCollection.AddSingleton<IUpdater, UpdaterLinux>();
|
||||
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInformationServiceLinux>();
|
||||
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInfoGeneratorLinux>();
|
||||
}
|
||||
else if (EnvironmentHelper.IsMac)
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
serviceCollection.AddScoped<IAppLauncher, AppLauncherMac>();
|
||||
serviceCollection.AddSingleton<IUpdater, UpdaterMac>();
|
||||
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInformationServiceMac>();
|
||||
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInfoGeneratorMac>();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -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<bool>("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;
|
||||
|
||||
88
Agent/Services/CpuUtilizationSampler.cs
Normal file
88
Agent/Services/CpuUtilizationSampler.cs
Normal file
@ -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<double> GetCpuUtilization(CancellationToken cancelToken)
|
||||
{
|
||||
double totalUtilization = 0;
|
||||
var utilizations = new Dictionary<int, Tuple<DateTimeOffset, TimeSpan>>();
|
||||
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<DateTimeOffset, TimeSpan>(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;
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
@ -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<AppLauncherLinux> _logger;
|
||||
|
||||
public AppLauncherLinux(
|
||||
ConfigService configService,
|
||||
ConfigService configService,
|
||||
IProcessInvoker processInvoker,
|
||||
ILogger<AppLauncherLinux> 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}" +
|
||||
@ -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);
|
||||
}
|
||||
@ -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<UpdaterLinux> logger)
|
||||
{
|
||||
@ -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
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
@ -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<UpdaterMac> logger)
|
||||
{
|
||||
@ -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",
|
||||
@ -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<Device> 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);
|
||||
@ -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<UpdaterWin> logger)
|
||||
{
|
||||
@ -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<IOrganizationIdProvider, OrganizationIdProvider>();
|
||||
services.AddSingleton<IEmbeddedServerDataSearcher, EmbeddedServerDataSearcher>();
|
||||
|
||||
services.AddRemoteControlLinux(
|
||||
config =>
|
||||
{
|
||||
config.AddBrandingProvider<BrandingProvider>();
|
||||
},
|
||||
services =>
|
||||
{
|
||||
services.AddLogging(builder =>
|
||||
{
|
||||
#if DEBUG
|
||||
builder.SetMinimumLevel(LogLevel.Debug);
|
||||
#endif
|
||||
builder.AddProvider(new FileLoggerProvider("Remotely_Desktop"));
|
||||
});
|
||||
});
|
||||
|
||||
services.AddSingleton<IOrganizationIdProvider, OrganizationIdProvider>();
|
||||
services.AddSingleton<IEmbeddedServerDataSearcher, EmbeddedServerDataSearcher>();
|
||||
},
|
||||
services =>
|
||||
services.AddLogging(builder =>
|
||||
{
|
||||
if (EnvironmentHelper.IsDebug)
|
||||
{
|
||||
var appState = services.GetRequiredService<IAppState>();
|
||||
if (appState.ArgDict.TryGetValue("org-id", out var orgId))
|
||||
{
|
||||
var orgIdProvider = services.GetRequiredService<IOrganizationIdProvider>();
|
||||
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<IAppState>();
|
||||
var orgIdProvider = provider.GetRequiredService<IOrganizationIdProvider>();
|
||||
|
||||
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.");
|
||||
|
||||
|
||||
@ -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<BrandingInfo>(result.Exception);
|
||||
return result.HadException ?
|
||||
Result.Fail<BrandingInfo>(result.Exception) :
|
||||
Result.Fail<BrandingInfo>(result.Reason);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(result.Value.OrganizationId))
|
||||
|
||||
@ -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<IOrganizationIdProvider, OrganizationIdProvider>();
|
||||
services.AddSingleton<IEmbeddedServerDataSearcher>(EmbeddedServerDataSearcher.Instance);
|
||||
|
||||
services.AddRemoteControlWindows(
|
||||
config =>
|
||||
{
|
||||
config.AddBrandingProvider<BrandingProvider>();
|
||||
},
|
||||
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<IOrganizationIdProvider, OrganizationIdProvider>();
|
||||
services.AddSingleton<IEmbeddedServerDataSearcher>(EmbeddedServerDataSearcher.Instance);
|
||||
},
|
||||
services =>
|
||||
{
|
||||
var appState = services.GetRequiredService<IAppState>();
|
||||
var orgIdProvider = services.GetRequiredService<IOrganizationIdProvider>();
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
if (getEmbeddedResult.IsSuccess)
|
||||
{
|
||||
orgIdProvider.OrganizationId = getEmbeddedResult.Value.OrganizationId;
|
||||
appState.Host = getEmbeddedResult.Value.ServerUrl.AbsoluteUri;
|
||||
}
|
||||
var appState = provider.GetRequiredService<IAppState>();
|
||||
var orgIdProvider = provider.GetRequiredService<IOrganizationIdProvider>();
|
||||
|
||||
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<IWindowsUiDispatcher>();
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ namespace Remotely.Server.API
|
||||
{ ExpirationScanFrequency = TimeSpan.FromSeconds(10) });
|
||||
|
||||
|
||||
private readonly IHubContext<ServiceHub> _agentHubContext;
|
||||
private readonly IHubContext<AgentHub> _agentHubContext;
|
||||
|
||||
private readonly IApplicationConfig _appConfig;
|
||||
|
||||
@ -40,7 +40,7 @@ namespace Remotely.Server.API
|
||||
IDataService dataService,
|
||||
IApplicationConfig appConfig,
|
||||
IServiceHubSessionCache serviceSessionCache,
|
||||
IHubContext<ServiceHub> agentHubContext)
|
||||
IHubContext<AgentHub> agentHubContext)
|
||||
{
|
||||
_hostEnv = hostingEnv;
|
||||
_dataService = dataService;
|
||||
|
||||
@ -24,7 +24,7 @@ namespace Remotely.Server.API
|
||||
[ApiController]
|
||||
public class RemoteControlController : ControllerBase
|
||||
{
|
||||
private readonly IHubContext<ServiceHub> _serviceHub;
|
||||
private readonly IHubContext<AgentHub> _serviceHub;
|
||||
private readonly IDesktopHubSessionCache _desktopSessionCache;
|
||||
private readonly IServiceHubSessionCache _serviceSessionCache;
|
||||
private readonly IApplicationConfig _appConfig;
|
||||
@ -37,7 +37,7 @@ namespace Remotely.Server.API
|
||||
SignInManager<RemotelyUser> signInManager,
|
||||
IDataService dataService,
|
||||
IDesktopHubSessionCache desktopSessionCache,
|
||||
IHubContext<ServiceHub> serviceHub,
|
||||
IHubContext<AgentHub> serviceHub,
|
||||
IServiceHubSessionCache serviceSessionCache,
|
||||
IOtpProvider otpProvider,
|
||||
IHubEventHandlerEx hubEvents,
|
||||
|
||||
@ -22,7 +22,7 @@ namespace Remotely.Server.API
|
||||
[Route("api/[controller]")]
|
||||
public class ScriptingController : ControllerBase
|
||||
{
|
||||
private readonly IHubContext<ServiceHub> _agentHubContext;
|
||||
private readonly IHubContext<AgentHub> _agentHubContext;
|
||||
|
||||
private readonly IDataService _dataService;
|
||||
private readonly IServiceHubSessionCache _serviceSessionCache;
|
||||
@ -34,7 +34,7 @@ namespace Remotely.Server.API
|
||||
IDataService dataService,
|
||||
IServiceHubSessionCache serviceSessionCache,
|
||||
IExpiringTokenService expiringTokenService,
|
||||
IHubContext<ServiceHub> agentHub)
|
||||
IHubContext<AgentHub> 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;
|
||||
}
|
||||
|
||||
@ -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<ViewerHub> _viewerHubContext;
|
||||
|
||||
public ServiceHub(IDataService dataService,
|
||||
public AgentHub(IDataService dataService,
|
||||
IApplicationConfig appConfig,
|
||||
IServiceHubSessionCache serviceSessionCache,
|
||||
IHubContext<ViewerHub> 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);
|
||||
@ -58,7 +58,7 @@ namespace Remotely.Server.Hubs
|
||||
|
||||
public class CircuitConnection : CircuitHandler, ICircuitConnection
|
||||
{
|
||||
private readonly IHubContext<ServiceHub> _agentHubContext;
|
||||
private readonly IHubContext<AgentHub> _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<ServiceHub> agentHubContext,
|
||||
IHubContext<AgentHub> agentHubContext,
|
||||
IApplicationConfig appConfig,
|
||||
ICircuitManager circuitManager,
|
||||
IToastService toastService,
|
||||
|
||||
@ -142,7 +142,7 @@ namespace Remotely.Server.Pages
|
||||
|
||||
|
||||
[Inject]
|
||||
private IHubContext<ServiceHub> AgentHubContext { get; set; }
|
||||
private IHubContext<AgentHub> AgentHubContext { get; set; }
|
||||
|
||||
[Inject]
|
||||
private IConfiguration Configuration { get; set; }
|
||||
|
||||
@ -257,7 +257,7 @@ app.UseRemoteControlServer();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapHub<ServiceHub>("/hubs/service");
|
||||
endpoints.MapHub<AgentHub>("/hubs/service");
|
||||
endpoints.MapControllers();
|
||||
endpoints.MapBlazorHub();
|
||||
endpoints.MapFallbackToPage("/_Host");
|
||||
|
||||
@ -27,12 +27,12 @@ namespace Remotely.Server.Services.RcImplementations
|
||||
private static readonly ConcurrentDictionary<string, SemaphoreSlim> _sessionWaitHandlers = new();
|
||||
|
||||
private readonly ICircuitManager _circuitManager;
|
||||
private readonly IHubContext<ServiceHub> _serviceHub;
|
||||
private readonly IHubContext<AgentHub> _serviceHub;
|
||||
private readonly ILogger<HubEventHandlerEx> _logger;
|
||||
|
||||
public HubEventHandlerEx(
|
||||
ICircuitManager circuitManager,
|
||||
IHubContext<ServiceHub> serviceHub,
|
||||
IHubContext<AgentHub> serviceHub,
|
||||
ILogger<HubEventHandlerEx> logger)
|
||||
{
|
||||
_circuitManager = circuitManager;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<T> Empty<T>()
|
||||
{
|
||||
return new Result<T>(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<T> Fail<T>(string error)
|
||||
{
|
||||
return new Result<T>(false, default, error);
|
||||
}
|
||||
|
||||
public static Result<T> Fail<T>(Exception ex)
|
||||
{
|
||||
return new Result<T>(false, default, exception: ex);
|
||||
}
|
||||
|
||||
public static Result Ok()
|
||||
{
|
||||
return new Result(true);
|
||||
}
|
||||
|
||||
public static Result<T> Ok<T>(T value)
|
||||
{
|
||||
return new Result<T>(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<T>
|
||||
{
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
|
||||
using Immense.RemoteControl.Shared;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Remotely.Shared.Models;
|
||||
using Remotely.Shared.Utilities;
|
||||
|
||||
@ -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<string> _logQueue = new();
|
||||
private static readonly ConcurrentStack<string> _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>(TState state)
|
||||
{
|
||||
@ -85,21 +93,25 @@ namespace Remotely.Shared.Services
|
||||
};
|
||||
}
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
||||
{
|
||||
_writeLock.Wait();
|
||||
|
||||
try
|
||||
{
|
||||
var scopeStack = _scopeStack.Any() ?
|
||||
new string[] { _scopeStack.First(), _scopeStack.Last() } :
|
||||
Array.Empty<string>();
|
||||
|
||||
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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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...");
|
||||
|
||||
@ -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<IHubCallerClients>();
|
||||
var caller = new Mock<IClientProxy>();
|
||||
@ -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<IHubCallerClients>();
|
||||
var caller = new Mock<IClientProxy>();
|
||||
@ -100,7 +100,7 @@ namespace Remotely.Tests
|
||||
|
||||
appConfig.Setup(x => x.BannedDevices).Returns(Array.Empty<string>());
|
||||
|
||||
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()
|
||||
};
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 345c43e03dc8e32cb0d3519a9767dd654ad420ba
|
||||
Subproject commit 283f66562d90b84132b40116b31694c691a97cc9
|
||||
Loading…
Reference in New Issue
Block a user