mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Agents auto-update via downloaded script. Pauses for random seconds based on total device count before downloading (to even out the bandwidth).
This commit is contained in:
parent
372f1e18a0
commit
d82da3dea9
@ -108,11 +108,6 @@ namespace Remotely.Agent
|
||||
SetWorkingDirectory();
|
||||
var argDict = ProcessArgs(args);
|
||||
|
||||
if (argDict.ContainsKey("update"))
|
||||
{
|
||||
Services.GetRequiredService<Updater>().CoreUpdate();
|
||||
}
|
||||
|
||||
if (!IsDebug && OSUtils.IsWindows)
|
||||
{
|
||||
_ = Task.Run(() =>
|
||||
|
||||
@ -181,7 +181,7 @@ namespace Remotely.Agent.Services
|
||||
IsServerVerified = true;
|
||||
if (!Program.IsDebug)
|
||||
{
|
||||
Updater.CheckForCoreUpdates();
|
||||
Task.Run(Updater.CheckForUpdates);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@ -22,52 +22,46 @@ namespace Remotely.Agent.Services
|
||||
|
||||
private ConfigService ConfigService { get; }
|
||||
|
||||
public void CheckForCoreUpdates()
|
||||
public async Task CheckForUpdates()
|
||||
{
|
||||
try
|
||||
{
|
||||
var wc = new WebClient();
|
||||
var response = new HttpClient().GetAsync(ConfigService.GetConnectionInfo().Host + $"/API/CoreVersion/").Result;
|
||||
var connectionInfo = ConfigService.GetConnectionInfo();
|
||||
var response = new HttpClient().GetAsync(connectionInfo.Host + $"/API/AgentUpdate/CurrentVersion").Result;
|
||||
var latestVersion = response.Content.ReadAsStringAsync().Result;
|
||||
var thisVersion = FileVersionInfo.GetVersionInfo("Remotely_Agent.dll").FileVersion.ToString().Trim();
|
||||
if (thisVersion != latestVersion)
|
||||
{
|
||||
Logger.Write($"Service Updater: Downloading update. Current Version: {thisVersion}. Latest Version: {latestVersion}.");
|
||||
var fileName = OSUtils.CoreZipFileName;
|
||||
var tempFile = Path.Combine(Path.GetTempPath(), fileName);
|
||||
var tempFolder = Path.Combine(Path.GetTempPath(), "Remotely_Update");
|
||||
if (File.Exists(tempFile))
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
}
|
||||
if (Directory.Exists(tempFolder))
|
||||
{
|
||||
Directory.Delete(tempFolder, true);
|
||||
}
|
||||
wc.DownloadFile(new Uri(ConfigService.GetConnectionInfo().Host + $"/Downloads/{fileName}"), tempFile);
|
||||
Logger.Write($"Service Updater: Update found. Current Version: {thisVersion}. Latest Version: {latestVersion}.");
|
||||
|
||||
Logger.Write($"Service Updater: Extracting files.");
|
||||
var updateWindow = int.Parse(wc.DownloadString(connectionInfo.Host + $"/API/AgentUpdate/UpdateWindow"));
|
||||
var waitTime = new Random().Next(1, updateWindow);
|
||||
Logger.Write($"Waiting {waitTime} seconds before updating.");
|
||||
await Task.Delay(TimeSpan.FromSeconds(waitTime));
|
||||
|
||||
Logger.Write($"Service Updater: Downloading installer.");
|
||||
if (OSUtils.IsWindows)
|
||||
{
|
||||
ZipFile.ExtractToDirectory(tempFile, tempFolder, true);
|
||||
Logger.Write($"Service Updater: Launching extracted process to perform update.");
|
||||
var psi = new ProcessStartInfo()
|
||||
{
|
||||
FileName = Path.Combine(Path.GetTempPath(), "Remotely_Update", OSUtils.ClientExecutableFileName),
|
||||
Arguments = "-update true",
|
||||
Verb = "RunAs"
|
||||
};
|
||||
Process.Start(psi);
|
||||
var filePath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.ps1");
|
||||
|
||||
wc.DownloadFile(
|
||||
ConfigService.GetConnectionInfo().Host + $"/API/ClientDownloads/{connectionInfo.OrganizationID}/{OSUtils.PlatformString}",
|
||||
filePath);
|
||||
|
||||
Process.Start("powershell.exe", $"-f \"{filePath}\"");
|
||||
}
|
||||
else if (OSUtils.IsLinux)
|
||||
{
|
||||
Process.Start("sudo", "apt-get install unzip").WaitForExit();
|
||||
Process.Start("sudo", $"unzip -o {tempFile} -d /usr/local/bin/Remotely/").WaitForExit();
|
||||
Process.Start("sudo", "chmod +x /usr/local/bin/Remotely/Remotely_Agent").WaitForExit();
|
||||
Process.Start("sudo", "chmod +x /usr/local/bin/Remotely/ScreenCast/Remotely_ScreenCast.Linux").WaitForExit();
|
||||
Logger.Write($"Service Updater: Update complete. Restarting service.");
|
||||
Process.Start("sudo", "systemctl restart remotely-agent");
|
||||
var filePath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.sh");
|
||||
|
||||
wc.DownloadFile(
|
||||
ConfigService.GetConnectionInfo().Host + $"/API/ClientDownloads/{connectionInfo.OrganizationID}/{OSUtils.PlatformString}",
|
||||
filePath);
|
||||
|
||||
Process.Start("sudo", $"chmod +x {filePath}").WaitForExit();
|
||||
|
||||
Process.Start("sudo", $"{filePath} & disown");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,108 +70,5 @@ namespace Remotely.Agent.Services
|
||||
Logger.Write(ex);
|
||||
}
|
||||
}
|
||||
public void CoreUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Write("Service Updater: Starting update.");
|
||||
var ps = PowerShell.Create();
|
||||
if (OSUtils.IsWindows)
|
||||
{
|
||||
ps.AddScript(@"Get-Service | Where-Object {$_.Name -like ""Remotely_Service""} | Stop-Service -Force");
|
||||
ps.Invoke();
|
||||
ps.Commands.Clear();
|
||||
}
|
||||
else if (OSUtils.IsLinux)
|
||||
{
|
||||
Process.Start("sudo", "systemctl stop remotely-agent");
|
||||
}
|
||||
|
||||
|
||||
foreach (var proc in Process.GetProcesses().Where(x =>
|
||||
(x.ProcessName.Contains("Remotely_Agent") ||
|
||||
x.ProcessName.Contains("Remotely_ScreenCast") ||
|
||||
x.ProcessName.Contains("Remotely_Desktop"))
|
||||
&& x.Id != Process.GetCurrentProcess().Id))
|
||||
{
|
||||
proc.Kill();
|
||||
}
|
||||
|
||||
string targetDir = "";
|
||||
|
||||
if (OSUtils.IsWindows)
|
||||
{
|
||||
targetDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Remotely");
|
||||
}
|
||||
else if (OSUtils.IsLinux)
|
||||
{
|
||||
targetDir = "/usr/local/bin/Remotely";
|
||||
}
|
||||
|
||||
Logger.Write("Service Updater: Copying new files.");
|
||||
|
||||
|
||||
var fileList = Directory.GetFiles(Path.Combine(Path.GetTempPath(), "Remotely_Update"));
|
||||
foreach (var file in fileList)
|
||||
{
|
||||
try
|
||||
{
|
||||
var targetPath = Path.Combine(targetDir, Path.GetFileName(file));
|
||||
File.Copy(file, targetPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var subdirList = Directory.GetDirectories(Path.Combine(Path.GetTempPath(), "Remotely_Update"));
|
||||
|
||||
foreach (var subdir in subdirList)
|
||||
{
|
||||
try
|
||||
{
|
||||
var targetPath = Path.Combine(targetDir, Path.GetFileName(subdir.TrimEnd(Path.DirectorySeparatorChar)));
|
||||
if (Directory.Exists(targetPath))
|
||||
{
|
||||
Directory.Delete(targetPath, true);
|
||||
while (Directory.Exists(targetPath))
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
Directory.Move(subdir, targetPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
Logger.Write("Service Updater: Update completed.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Logger.Write("Service Updater: Starting service.");
|
||||
if (OSUtils.IsWindows)
|
||||
{
|
||||
var ps = PowerShell.Create();
|
||||
ps.AddScript("Start-Service -Name \"Remotely_Service\"");
|
||||
ps.Invoke();
|
||||
}
|
||||
else if (OSUtils.IsLinux)
|
||||
{
|
||||
Process.Start("sudo", "systemctl restart remotely-agent").WaitForExit();
|
||||
}
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
41
Server/API/AgentUpdateController.cs
Normal file
41
Server/API/AgentUpdateController.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Remotely.Server.Services;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace Remotely.Server.API
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
public class AgentUpdateController : Controller
|
||||
{
|
||||
public AgentUpdateController(IWebHostEnvironment hostingEnv, DataService dataService)
|
||||
{
|
||||
this.HostingEnv = hostingEnv;
|
||||
DataService = dataService;
|
||||
}
|
||||
|
||||
private IWebHostEnvironment HostingEnv { get; }
|
||||
private DataService DataService { get; }
|
||||
|
||||
// GET: api/<controller>
|
||||
[HttpGet("[action]")]
|
||||
public string CurrentVersion()
|
||||
{
|
||||
var filePath = Path.Combine(HostingEnv.ContentRootPath, "CurrentVersion.txt");
|
||||
if (!System.IO.File.Exists(filePath))
|
||||
{
|
||||
return "0.0.0.0";
|
||||
}
|
||||
return System.IO.File.ReadAllText(filePath).Trim();
|
||||
}
|
||||
|
||||
[HttpGet("[action]")]
|
||||
public int UpdateWindow()
|
||||
{
|
||||
return DataService.GetDeviceCount() * 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -28,9 +28,20 @@ namespace Remotely.Server.API
|
||||
|
||||
[Authorize]
|
||||
[HttpGet("{platformID}")]
|
||||
public ActionResult Get(string platformID)
|
||||
public async Task<ActionResult> Get(string platformID)
|
||||
{
|
||||
var user = DataService.GetUserByName(User.Identity.Name);
|
||||
return await GetInstallFile(user.OrganizationID, platformID);
|
||||
}
|
||||
|
||||
[HttpGet("{organizationID}/{platformID}")]
|
||||
public async Task<ActionResult> Get(string organizationID, string platformID)
|
||||
{
|
||||
return await GetInstallFile(organizationID, platformID);
|
||||
}
|
||||
|
||||
private async Task<ActionResult> GetInstallFile(string organizationID, string platformID)
|
||||
{
|
||||
var fileContents = new List<string>();
|
||||
string fileName;
|
||||
byte[] fileBytes;
|
||||
@ -41,32 +52,32 @@ namespace Remotely.Server.API
|
||||
{
|
||||
fileName = $"Install-{platformID}.ps1";
|
||||
|
||||
fileContents.AddRange(System.IO.File.ReadAllLines(Path.Combine(HostEnv.WebRootPath, "Downloads", $"{fileName}")));
|
||||
fileContents.AddRange(await System.IO.File.ReadAllLinesAsync(Path.Combine(HostEnv.WebRootPath, "Downloads", $"{fileName}")));
|
||||
|
||||
var hostIndex = fileContents.IndexOf("[string]$HostName = $null");
|
||||
var orgIndex = fileContents.IndexOf("[string]$Organization = $null");
|
||||
|
||||
fileContents[hostIndex] = $"[string]$HostName = \"{Request.Scheme}://{Request.Host}\"";
|
||||
fileContents[orgIndex] = $"[string]$Organization = \"{user.Organization.ID}\"";
|
||||
fileContents[orgIndex] = $"[string]$Organization = \"{organizationID}\"";
|
||||
fileBytes = System.Text.Encoding.UTF8.GetBytes(string.Join(Environment.NewLine, fileContents));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case "Linux-x64":
|
||||
{
|
||||
fileName = "Install-Linux-x64.sh";
|
||||
|
||||
fileContents.AddRange(System.IO.File.ReadAllLines(Path.Combine(HostEnv.WebRootPath, "Downloads", $"{fileName}")));
|
||||
fileContents.AddRange(await System.IO.File.ReadAllLinesAsync(Path.Combine(HostEnv.WebRootPath, "Downloads", $"{fileName}")));
|
||||
|
||||
var hostIndex = fileContents.IndexOf("HostName=");
|
||||
var orgIndex = fileContents.IndexOf("Organization=");
|
||||
|
||||
fileContents[hostIndex] = $"HostName=\"{Request.Scheme}://{Request.Host}\"";
|
||||
fileContents[orgIndex] = $"Organization=\"{user.Organization.ID}\"";
|
||||
fileContents[orgIndex] = $"Organization=\"{organizationID}\"";
|
||||
fileBytes = System.Text.Encoding.UTF8.GetBytes(string.Join("\n", fileContents));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ using System.IO.Compression;
|
||||
|
||||
namespace Remotely.Server.API
|
||||
{
|
||||
// TODO: Delete after a few versions.
|
||||
[Route("api/[controller]")]
|
||||
public class CoreVersionController : Controller
|
||||
{
|
||||
|
||||
@ -114,7 +114,7 @@
|
||||
<strong>Local Install:</strong>
|
||||
<span data-toggle="modal" data-target="#localInstallInfo" class="fas fa-question-circle pointer"></span>
|
||||
<br />
|
||||
<span class="label label-default code">sudo [path]/Install-Linux-x64.sh --path [path]/Remotely-Win10-x86.zip</span>
|
||||
<span class="label label-default code">sudo [path]/Install-Linux-x64.sh --path [path]/Remotely-Linux.zip</span>
|
||||
</p>
|
||||
<p>
|
||||
<strong>Uninstall:</strong>
|
||||
|
||||
@ -129,6 +129,7 @@ namespace Remotely.Server.Services
|
||||
RemotelyContext.SaveChanges();
|
||||
return true;
|
||||
}
|
||||
|
||||
public string AddSharedFile(IFormFile file, string organizationID)
|
||||
{
|
||||
var expirationDate = DateTime.Now.AddDays(-AppConfig.DataRetentionInDays);
|
||||
@ -209,6 +210,7 @@ namespace Remotely.Server.Services
|
||||
RemotelyContext.DeviceGroups.Remove(deviceGroup);
|
||||
RemotelyContext.SaveChanges();
|
||||
}
|
||||
|
||||
public void DeleteInvite(string requesterUserName, string inviteID)
|
||||
{
|
||||
var requester = RemotelyContext.Users
|
||||
@ -277,6 +279,7 @@ namespace Remotely.Server.Services
|
||||
.Where(x => x.OrganizationID == orgID)
|
||||
.OrderByDescending(x => x.TimeStamp);
|
||||
}
|
||||
|
||||
public IEnumerable<Device> GetAllDevicesForUser(string userID)
|
||||
{
|
||||
var user = RemotelyContext.Users.FirstOrDefault(x => x.Id == userID);
|
||||
@ -294,6 +297,7 @@ namespace Remotely.Server.Services
|
||||
.Where(x => x.OrganizationID == orgID)
|
||||
.OrderByDescending(x => x.TimeStamp);
|
||||
}
|
||||
|
||||
public ICollection<InviteLink> GetAllInviteLinks(string userName)
|
||||
{
|
||||
return RemotelyContext.Users
|
||||
@ -336,6 +340,10 @@ namespace Remotely.Server.Services
|
||||
return AppConfig.DefaultPrompt;
|
||||
}
|
||||
|
||||
public int GetDeviceCount()
|
||||
{
|
||||
return RemotelyContext.Devices.Count();
|
||||
}
|
||||
public Device GetDeviceForUser(string userID, string deviceID)
|
||||
{
|
||||
var user = RemotelyContext.Users.FirstOrDefault(x => x.Id == userID);
|
||||
|
||||
@ -4,8 +4,6 @@ Organization=
|
||||
GUID=$(cat /proc/sys/kernel/random/uuid)
|
||||
|
||||
systemctl stop remotely-agent
|
||||
rm -r -f /usr/local/bin/Remotely
|
||||
rm -f /etc/systemd/system/remotely-agent.service
|
||||
systemctl daemon-reload
|
||||
|
||||
if [ "$1" = "--uninstall" ]; then
|
||||
@ -27,6 +25,14 @@ apt-get -y install libc6-dev
|
||||
apt-get -y install libgdiplus
|
||||
apt-get -y install libxtst-dev
|
||||
apt-get -y install xclip
|
||||
apt-get -y install jq
|
||||
|
||||
if [ -f "/usr/local/bin/Remotely/ConnectionInfo.json" ]; then
|
||||
GUID=`cat "/usr/local/bin/Remotely/ConnectionInfo.json" | jq -r '.DeviceID'`
|
||||
fi
|
||||
|
||||
rm -r -f /usr/local/bin/Remotely
|
||||
rm -f /etc/systemd/system/remotely-agent.service
|
||||
|
||||
mkdir -p /usr/local/bin/Remotely/
|
||||
cd /usr/local/bin/Remotely/
|
||||
|
||||
@ -56,7 +56,7 @@ namespace Remotely.Shared.Services
|
||||
}
|
||||
}
|
||||
|
||||
public static string CoreZipFileName
|
||||
public static string PlatformString
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -64,17 +64,17 @@ namespace Remotely.Shared.Services
|
||||
{
|
||||
if (Environment.Is64BitOperatingSystem)
|
||||
{
|
||||
return "Remotely-Win10-x64.zip";
|
||||
return "Win10-x64";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Remotely-Win10-x86.zip";
|
||||
return "Win10-x86";
|
||||
}
|
||||
|
||||
}
|
||||
else if (OSUtils.IsLinux)
|
||||
else if (IsLinux)
|
||||
{
|
||||
return "Remotely-Linux.zip";
|
||||
return "Linux-x64";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user