Пример #1
0
        public override Task <RevisionDescription?> RunUpdateAsync(string?currentVersion, string binPath,
                                                                   CancellationToken cancel = default)
        {
            if (currentVersion == _specificConfiguration.CurrentVersion)
            {
                return(Task.FromResult <RevisionDescription?>(null));
            }

            var binariesPath = Path.Combine(_serverInstance.InstanceDir, "binaries");

            if (!Directory.Exists(binariesPath))
            {
                throw new InvalidOperationException(
                          "Expected binaries/ directory containing all client binaries in the instance folder.");
            }

            var binariesRoot = new Uri(new Uri(_configuration["BaseUrl"]),
                                       $"instances/{_serverInstance.Key}/binaries/");

            DownloadInfoPair?GetInfoPair(string platform)
            {
                var fileName     = GetBuildFilename(platform);
                var diskFileName = Path.Combine(binariesPath, fileName);

                if (!File.Exists(diskFileName))
                {
                    return(null);
                }

                var download = new Uri(binariesRoot, fileName);
                var hash     = GetFileHash(diskFileName);

                _logger.LogTrace("SHA256 hash for {fileName} is {hash}", fileName, hash);

                return(new DownloadInfoPair(download.ToString(), hash));
            }

            var revisionDescription = new RevisionDescription(
                _specificConfiguration.CurrentVersion,
                GetInfoPair(PlatformNameWindows),
                GetInfoPair(PlatformNameLinux),
                GetInfoPair(PlatformNameMacOS));

            // ReSharper disable once RedundantTypeArgumentsOfMethod
            return(Task.FromResult <RevisionDescription?>(revisionDescription));
        }
        public override async Task <RevisionDescription?> RunUpdateAsync(string?currentVersion,
                                                                         string binPath,
                                                                         CancellationToken cancel = default)
        {
            try
            {
                _logger.LogTrace("Updating...");

                var buildRef = await GetLastSuccessfulBuildAsync(cancel);

                if (buildRef == null)
                {
                    _logger.LogTrace("No last build?");
                    return(null);
                }

                if (buildRef.Number.ToString(CultureInfo.InvariantCulture) == currentVersion)
                {
                    _logger.LogTrace("Update not necessary!");
                    return(null);
                }

                _logger.LogTrace("New version is {newVersion} from {oldVersion}", buildRef.Number,
                                 currentVersion ?? "<none>");


                var downloadRootUri = new Uri($"{_baseUrl}/job/{_jobName}/{buildRef.Number}/artifact/release/");

                async Task <string> GetHash(string platform)
                {
                    var url  = new Uri(downloadRootUri, $"{GetBuildFilename(platform)}.sha256");
                    var resp = await _httpClient.GetAsync(url, cancel);

                    resp.EnsureSuccessStatusCode();

                    return((await resp.Content.ReadAsStringAsync()).Trim());
                }

                Uri PlatformUrl(string platform)
                {
                    return(new Uri(downloadRootUri, Uri.EscapeUriString(GetBuildFilename(platform))));
                }

                async Task <DownloadInfoPair> PlatformInfo(string platform)
                {
                    var download = PlatformUrl(platform).ToString();
                    var hash     = await GetHash(platform);

                    return(new DownloadInfoPair(download, hash));
                }

                _logger.LogTrace("Fetching revision information from Jenkins...");

                // Get revision information that the server instance needs.
                var revision = new RevisionDescription(buildRef.Number.ToString(CultureInfo.InvariantCulture),
                                                       await PlatformInfo(PlatformNameWindows),
                                                       await PlatformInfo(PlatformNameLinux),
                                                       await PlatformInfo(PlatformNameMacOS));

                // Create temporary file to download binary into (not doing this in memory).
                await using var tempFile = File.Open(Path.GetTempFileName(), FileMode.Open, FileAccess.ReadWrite);
                // Download URI for server binary.
                var serverDownload = new Uri(downloadRootUri, $"SS14.Server_{GetHostPlatformName()}_x64.zip");

                _logger.LogTrace("Downloading server binary from {download} to {tempFile}", serverDownload,
                                 tempFile.Name);

                // Download to file...
                var resp = await _httpClient.GetAsync(serverDownload, cancel);

                await resp.Content.CopyToAsync(tempFile);

                _logger.LogTrace("Deleting old bin directory ({binPath})", binPath);
                if (Directory.Exists(binPath))
                {
                    Directory.Delete(binPath, true);
                }

                Directory.CreateDirectory(binPath);

                _logger.LogTrace("Extracting zip file");
                // Reset file position so we can extract.
                tempFile.Seek(0, SeekOrigin.Begin);

                // Actually extract.
                using var archive = new ZipArchive(tempFile, ZipArchiveMode.Read);
                archive.ExtractToDirectory(binPath);

                if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ||
                    RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    // chmod +x Robust.Server

                    var rsPath = Path.Combine(binPath, "Robust.Server");
                    if (File.Exists(rsPath))
                    {
                        var proc = Process.Start(new ProcessStartInfo("chmod")
                        {
                            ArgumentList = { "+x", rsPath }
                        });

                        await proc.WaitForExitAsync(cancel);
                    }
                }

                return(revision);
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Failed to run update!");

                return(null);
            }
        }