Remotely/Agent/Services/UpdaterLinux.cs
2021-07-29 07:58:06 -07:00

184 lines
6.1 KiB
C#

using Remotely.Agent.Interfaces;
using Remotely.Shared.Utilities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Remotely.Agent.Services
{
public class UpdaterLinux : IUpdater
{
private readonly SemaphoreSlim _checkForUpdatesLock = new SemaphoreSlim(1, 1);
private readonly ConfigService _configService;
private readonly IWebClientEx _webClientEx;
private readonly SemaphoreSlim _installLatestVersionLock = new SemaphoreSlim(1, 1);
private DateTimeOffset _lastUpdateFailure;
private readonly System.Timers.Timer _updateTimer = new System.Timers.Timer(TimeSpan.FromHours(6).TotalMilliseconds);
public UpdaterLinux(ConfigService configService, IWebClientEx webClientEx)
{
_configService = configService;
_webClientEx = webClientEx;
_webClientEx.SetRequestTimeout((int)_updateTimer.Interval);
}
public async Task BeginChecking()
{
if (EnvironmentHelper.IsDebug)
{
return;
}
await CheckForUpdates();
_updateTimer.Elapsed += UpdateTimer_Elapsed;
_updateTimer.Start();
}
public async Task CheckForUpdates()
{
try
{
await _checkForUpdatesLock.WaitAsync();
if (EnvironmentHelper.IsDebug)
{
return;
}
if (_lastUpdateFailure.AddDays(1) > DateTimeOffset.Now)
{
Logger.Write("Skipping update check due to previous failure. Restart the service to try again, or manually install the update.");
return;
}
var connectionInfo = _configService.GetConnectionInfo();
var serverUrl = _configService.GetConnectionInfo().Host;
var fileUrl = serverUrl + $"/Content/Remotely-Linux.zip";
var lastEtag = string.Empty;
if (File.Exists("etag.txt"))
{
lastEtag = await File.ReadAllTextAsync("etag.txt");
}
try
{
var wr = WebRequest.CreateHttp(fileUrl);
wr.Method = "Head";
wr.Headers.Add("If-None-Match", lastEtag);
using var response = (HttpWebResponse)await wr.GetResponseAsync();
if (response.StatusCode == HttpStatusCode.NotModified)
{
Logger.Write("Service Updater: Version is current.");
return;
}
}
catch (WebException ex) when ((ex.Response as HttpWebResponse).StatusCode == HttpStatusCode.NotModified)
{
Logger.Write("Service Updater: Version is current.");
return;
}
Logger.Write("Service Updater: Update found.");
await InstallLatestVersion();
}
catch (Exception ex)
{
Logger.Write(ex);
}
finally
{
_checkForUpdatesLock.Release();
}
}
public void Dispose()
{
_webClientEx?.Dispose();
}
public async Task InstallLatestVersion()
{
try
{
await _installLatestVersionLock.WaitAsync();
var connectionInfo = _configService.GetConnectionInfo();
var serverUrl = connectionInfo.Host;
Logger.Write("Service Updater: Downloading install package.");
var downloadId = Guid.NewGuid().ToString();
var zipPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.zip");
var installerPath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.sh");
string platform;
if (RuntimeInformation.OSDescription.Contains("Ubuntu", StringComparison.OrdinalIgnoreCase))
{
platform = "UbuntuInstaller-x64";
}
else if (RuntimeInformation.OSDescription.Contains("Manjaro", StringComparison.OrdinalIgnoreCase))
{
platform = "ManjaroInstaller-x64";
}
else
{
throw new PlatformNotSupportedException();
}
await _webClientEx.DownloadFileTaskAsync(
serverUrl + $"/API/ClientDownloads/{connectionInfo.OrganizationID}/{platform}",
installerPath);
await _webClientEx.DownloadFileTaskAsync(
serverUrl + $"/API/AgentUpdate/DownloadPackage/linux/{downloadId}",
zipPath);
(await WebRequest.CreateHttp(serverUrl + $"/api/AgentUpdate/ClearDownload/{downloadId}").GetResponseAsync()).Dispose();
Logger.Write("Launching installer to perform update.");
Process.Start("sudo", $"chmod +x {installerPath}").WaitForExit();
Process.Start("sudo", $"{installerPath} --path {zipPath}");
}
catch (WebException ex) when (ex.Status == WebExceptionStatus.Timeout)
{
Logger.Write("Timed out while waiting to download update.", Shared.Enums.EventType.Warning);
_lastUpdateFailure = DateTimeOffset.Now;
}
catch (Exception ex)
{
Logger.Write(ex);
_lastUpdateFailure = DateTimeOffset.Now;
}
finally
{
_installLatestVersionLock.Release();
}
}
private async void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
await CheckForUpdates();
}
}
}