Skip to content

Commit 0df0505

Browse files
committed
Begin building Mac services in Agent project.
1 parent 1b4ba49 commit 0df0505

11 files changed

+249
-59
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,4 @@ Server/wwwroot/Content/Win-x86/*
291291
Server/.config/dotnet-tools.json
292292
/Server/Properties/ServiceDependencies/*
293293
Server.Installer/Properties/launchSettings.json
294+
.DS_Store

Agent/Program.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Remotely.Agent.Services;
55
using Remotely.Shared.Enums;
66
using Remotely.Shared.Utilities;
7+
using Remotely.Shared.Services;
78
using System;
89
using System.Diagnostics;
910
using System.IO;
@@ -52,6 +53,7 @@ private static void BuildServices()
5253
serviceCollection.AddScoped<ConfigService>();
5354
serviceCollection.AddScoped<Uninstaller>();
5455
serviceCollection.AddScoped<ScriptExecutor>();
56+
serviceCollection.AddScoped<IProcessInvoker, ProcessLauncher>();
5557

5658
if (EnvironmentHelper.IsWindows)
5759
{
@@ -67,7 +69,9 @@ private static void BuildServices()
6769
}
6870
else if (EnvironmentHelper.IsMac)
6971
{
70-
// TODO: Mac.
72+
serviceCollection.AddScoped<IAppLauncher, AppLauncherMac>();
73+
serviceCollection.AddSingleton<IUpdater, UpdaterMac>();
74+
serviceCollection.AddSingleton<IDeviceInformationService, DeviceInformationServiceMac>();
7175
}
7276
else
7377
{

Agent/Services/AppLauncherLinux.cs

+16-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Microsoft.AspNetCore.SignalR.Client;
22
using Remotely.Agent.Interfaces;
33
using Remotely.Shared.Models;
4+
using Remotely.Shared.Services;
45
using Remotely.Shared.Utilities;
56
using System;
67
using System.Collections.Generic;
@@ -15,13 +16,15 @@ namespace Remotely.Agent.Services
1516
public class AppLauncherLinux : IAppLauncher
1617
{
1718
private readonly string _rcBinaryPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Desktop", EnvironmentHelper.DesktopExecutableFileName);
19+
private readonly IProcessInvoker _processInvoker;
20+
private readonly ConnectionInfo _connectionInfo;
1821

19-
public AppLauncherLinux(ConfigService configService)
22+
public AppLauncherLinux(ConfigService configService, IProcessInvoker processInvoker)
2023
{
21-
ConnectionInfo = configService.GetConnectionInfo();
24+
_processInvoker = processInvoker;
25+
_connectionInfo = configService.GetConnectionInfo();
2226
}
2327

24-
private ConnectionInfo ConnectionInfo { get; }
2528

2629
public async Task<int> LaunchChatService(string orgName, string requesterID, HubConnection hubConnection)
2730
{
@@ -43,8 +46,8 @@ await hubConnection.SendAsync("DisplayMessage",
4346
$"-mode Chat " +
4447
$"-requester \"{requesterID}\" " +
4548
$"-organization \"{orgName}\" " +
46-
$"-host \"{ConnectionInfo.Host}\" " +
47-
$"-orgid \"{ConnectionInfo.OrganizationID}\"";
49+
$"-host \"{_connectionInfo.Host}\" " +
50+
$"-orgid \"{_connectionInfo.OrganizationID}\"";
4851
return StartLinuxDesktopApp(args);
4952
}
5053
catch (Exception ex)
@@ -76,9 +79,9 @@ await hubConnection.SendAsync("DisplayMessage",
7679
$"-mode Unattended " +
7780
$"-requester \"{requesterID}\" " +
7881
$"-serviceid \"{serviceID}\" " +
79-
$"-deviceid {ConnectionInfo.DeviceID} " +
80-
$"-host \"{ConnectionInfo.Host}\" " +
81-
$"-orgid \"{ConnectionInfo.OrganizationID}\"";
82+
$"-deviceid {_connectionInfo.DeviceID} " +
83+
$"-host \"{_connectionInfo.Host}\" " +
84+
$"-orgid \"{_connectionInfo.OrganizationID}\"";
8285
StartLinuxDesktopApp(args);
8386
}
8487
catch (Exception ex)
@@ -96,9 +99,9 @@ public async Task RestartScreenCaster(List<string> viewerIDs, string serviceID,
9699
$"-mode Unattended " +
97100
$"-requester \"{requesterID}\" " +
98101
$"-serviceid \"{serviceID}\" " +
99-
$"-deviceid {ConnectionInfo.DeviceID} " +
100-
$"-host \"{ConnectionInfo.Host}\" " +
101-
$"-orgid \"{ConnectionInfo.OrganizationID}\" " +
102+
$"-deviceid {_connectionInfo.DeviceID} " +
103+
$"-host \"{_connectionInfo.Host}\" " +
104+
$"-orgid \"{_connectionInfo.OrganizationID}\" " +
102105
$"-relaunch true " +
103106
$"-viewers {string.Join(",", viewerIDs)}";
104107
StartLinuxDesktopApp(args);
@@ -116,7 +119,7 @@ private int StartLinuxDesktopApp(string args)
116119
var xauthority = GetXorgAuth();
117120

118121
var display = ":0";
119-
var whoString = EnvironmentHelper.StartProcessWithResults("who", "")?.Trim();
122+
var whoString = _processInvoker.InvokeProcessOutput("who", "")?.Trim();
120123
var username = "";
121124

122125
if (!string.IsNullOrWhiteSpace(whoString))
@@ -155,7 +158,7 @@ private string GetXorgAuth()
155158
{
156159
try
157160
{
158-
var processes = EnvironmentHelper.StartProcessWithResults("ps", "-eaf")?.Split(Environment.NewLine);
161+
var processes = _processInvoker.InvokeProcessOutput("ps", "-eaf")?.Split(Environment.NewLine);
159162
if (processes?.Length > 0)
160163
{
161164
var xorgLine = processes.FirstOrDefault(x => x.Contains("xorg", StringComparison.OrdinalIgnoreCase));

Agent/Services/AppLauncherMac.cs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using Microsoft.AspNetCore.SignalR.Client;
4+
using Remotely.Agent.Interfaces;
5+
6+
namespace Remotely.Agent.Services
7+
{
8+
public class AppLauncherMac : IAppLauncher
9+
{
10+
public async Task<int> LaunchChatService(string orgName, string requesterID, HubConnection hubConnection)
11+
{
12+
return 0;
13+
}
14+
15+
public async Task LaunchRemoteControl(int targetSessionId, string requesterID, string serviceID, HubConnection hubConnection)
16+
{
17+
18+
}
19+
20+
public async Task RestartScreenCaster(List<string> viewerIDs, string serviceID, string requesterID, HubConnection hubConnection, int targetSessionID = -1)
21+
{
22+
23+
}
24+
}
25+
}

Agent/Services/ConfigService.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public ConnectionInfo GetConnectionInfo()
6262
return new ConnectionInfo()
6363
{
6464
DeviceID = _debugGuid,
65-
Host = "https://localhost:5001",
65+
Host = "http://localhost:5000",
6666
OrganizationID = orgID
6767
};
6868
}

Agent/Services/DeviceInformationServiceBase.cs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Remotely.Shared.Models;
2+
using Remotely.Shared.Services;
23
using Remotely.Shared.Utilities;
34
using System;
45
using System.Collections.Generic;

Agent/Services/DeviceInformationServiceLinux.cs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Remotely.Agent.Interfaces;
22
using Remotely.Shared.Models;
3+
using Remotely.Shared.Services;
34
using Remotely.Shared.Utilities;
45
using System;
56
using System.Collections.Generic;
@@ -11,6 +12,12 @@ namespace Remotely.Agent.Services
1112
{
1213
public class DeviceInformationServiceLinux : DeviceInformationServiceBase, IDeviceInformationService
1314
{
15+
private readonly IProcessInvoker _processInvoker;
16+
17+
public DeviceInformationServiceLinux(IProcessInvoker processInvoker)
18+
{
19+
_processInvoker = processInvoker;
20+
}
1421
public async Task<Device> CreateDevice(string deviceId, string orgId)
1522
{
1623
var device = GetDeviceBase(deviceId, orgId);
@@ -40,15 +47,15 @@ public async Task<Device> CreateDevice(string deviceId, string orgId)
4047

4148
private string GetCurrentUser()
4249
{
43-
var users = EnvironmentHelper.StartProcessWithResults("users", "");
50+
var users = _processInvoker.InvokeProcessOutput("users", "");
4451
return users?.Split()?.FirstOrDefault()?.Trim();
4552
}
4653

4754
public (double usedGB, double totalGB) GetMemoryInGB()
4855
{
4956
try
5057
{
51-
var results = EnvironmentHelper.StartProcessWithResults("cat", "/proc/meminfo");
58+
var results = _processInvoker.InvokeProcessOutput("cat", "/proc/meminfo");
5259
var resultsArr = results.Split("\n".ToCharArray());
5360
var freeKB = resultsArr
5461
.FirstOrDefault(x => x.Trim().StartsWith("MemAvailable"))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using Remotely.Agent.Interfaces;
2+
using Remotely.Shared.Models;
3+
using Remotely.Shared.Services;
4+
using Remotely.Shared.Utilities;
5+
using Remotely.Shared.Win32;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Text;
10+
using System.Threading.Tasks;
11+
12+
namespace Remotely.Agent.Services
13+
{
14+
public class DeviceInformationServiceMac : DeviceInformationServiceBase, IDeviceInformationService
15+
{
16+
private readonly IProcessInvoker _processInvoker;
17+
18+
public DeviceInformationServiceMac(IProcessInvoker processInvoker)
19+
{
20+
_processInvoker = processInvoker;
21+
}
22+
public async Task<Device> CreateDevice(string deviceId, string orgId)
23+
{
24+
var device = GetDeviceBase(deviceId, orgId);
25+
26+
try
27+
{
28+
29+
var (usedStorage, totalStorage) = GetSystemDriveInfo();
30+
var (usedMemory, totalMemory) = GetMemoryInGB();
31+
32+
device.CurrentUser = Environment.UserName;
33+
device.Drives = GetAllDrives();
34+
device.UsedStorage = usedStorage;
35+
device.TotalStorage = totalStorage;
36+
device.UsedMemory = usedMemory;
37+
device.TotalMemory = totalMemory;
38+
device.CpuUtilization = await GetCpuUtilization();
39+
device.AgentVersion = GetAgentVersion();
40+
}
41+
catch (Exception ex)
42+
{
43+
Logger.Write(ex, "Error getting device info.");
44+
}
45+
46+
return device;
47+
}
48+
49+
public new Task<double> GetCpuUtilization()
50+
{
51+
try
52+
{
53+
var cpuPercentStrings = _processInvoker.InvokeProcessOutput("zsh", "-c \"ps -A -o %cpu\"");
54+
55+
double cpuPercent = 0;
56+
cpuPercentStrings
57+
.Split(Environment.NewLine)
58+
.ToList()
59+
.ForEach(x => {
60+
if (double.TryParse(x, out var result))
61+
{
62+
cpuPercent += result;
63+
}
64+
});
65+
66+
return Task.FromResult(cpuPercent / Environment.ProcessorCount / 100);
67+
}
68+
catch (Exception ex)
69+
{
70+
Logger.Write(ex, "Error while getting CPU utilization.");
71+
}
72+
73+
return Task.FromResult((double)0);
74+
}
75+
76+
public (double usedGB, double totalGB) GetMemoryInGB()
77+
{
78+
try
79+
{
80+
double totalGB = default;
81+
82+
var totalMemoryString = _processInvoker.InvokeProcessOutput("zsh", "-c \"sysctl -n hw.memsize\"");
83+
if (double.TryParse(totalMemoryString, out var totalMemory))
84+
{
85+
totalGB = (double)Math.Round(totalMemory / 1024 / 1024 / 1024, 2);
86+
}
87+
88+
89+
double usedGB = default;
90+
91+
var memPercentStrings = _processInvoker.InvokeProcessOutput("zsh", $"-c \"ps -A -o %mem\"");
92+
93+
double usedMemPercent = 0;
94+
memPercentStrings
95+
.Split(Environment.NewLine)
96+
.ToList()
97+
.ForEach(x => {
98+
if (double.TryParse(x, out var result))
99+
{
100+
usedMemPercent += result;
101+
}
102+
});
103+
104+
usedMemPercent = usedMemPercent / 4 / 100;
105+
usedGB = usedMemPercent * totalGB;
106+
107+
return (usedGB,totalGB);
108+
}
109+
catch
110+
{
111+
return (0, 0);
112+
}
113+
}
114+
}
115+
}

Agent/Services/UpdaterMac.cs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Threading.Tasks;
2+
using Remotely.Agent.Interfaces;
3+
4+
namespace Remotely.Agent.Services
5+
{
6+
public class UpdaterMac : IUpdater
7+
{
8+
public async Task BeginChecking()
9+
{
10+
11+
}
12+
13+
public async Task CheckForUpdates()
14+
{
15+
16+
}
17+
18+
public async Task InstallLatestVersion()
19+
{
20+
21+
}
22+
}
23+
}

Shared/Services/ProcessLauncher.cs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Diagnostics;
3+
using Remotely.Shared.Utilities;
4+
5+
namespace Remotely.Shared.Services
6+
{
7+
public interface IProcessInvoker
8+
{
9+
string InvokeProcessOutput(string command, string arguments);
10+
}
11+
public class ProcessLauncher : IProcessInvoker
12+
{
13+
public string InvokeProcessOutput(string command, string arguments)
14+
{
15+
try
16+
{
17+
var psi = new ProcessStartInfo(command, arguments)
18+
{
19+
WindowStyle = ProcessWindowStyle.Hidden,
20+
Verb = "RunAs",
21+
UseShellExecute = false,
22+
RedirectStandardOutput = true
23+
};
24+
25+
var proc = Process.Start(psi);
26+
proc.WaitForExit();
27+
28+
return proc.StandardOutput.ReadToEnd();
29+
}
30+
catch (Exception ex)
31+
{
32+
Logger.Write(ex, "Failed to start process.");
33+
return string.Empty;
34+
}
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)