From 8d5653b41e76cdf2f8c33fdd57a473b1b6f0bd0c Mon Sep 17 00:00:00 2001 From: Archi Date: Fri, 23 Dec 2022 22:12:18 +0100 Subject: [PATCH] Add target channel to update command and public API --- ArchiSteamFarm/Core/ASF.cs | 12 ++++-- .../IPC/Controllers/Api/ASFController.cs | 10 ++++- ArchiSteamFarm/IPC/Requests/UpdateRequest.cs | 38 +++++++++++++++++++ ArchiSteamFarm/Steam/Interaction/Actions.cs | 8 +++- ArchiSteamFarm/Steam/Interaction/Commands.cs | 14 ++++++- 5 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 ArchiSteamFarm/IPC/Requests/UpdateRequest.cs diff --git a/ArchiSteamFarm/Core/ASF.cs b/ArchiSteamFarm/Core/ASF.cs index bc6f12b02..b89d2e35e 100644 --- a/ArchiSteamFarm/Core/ASF.cs +++ b/ArchiSteamFarm/Core/ASF.cs @@ -178,7 +178,11 @@ public static class ASF { } } - internal static async Task Update(bool updateOverride = false) { + internal static async Task Update(GlobalConfig.EUpdateChannel? channel = null, bool updateOverride = false) { + if (channel.HasValue && !Enum.IsDefined(channel.Value)) { + throw new InvalidEnumArgumentException(nameof(channel), (int) channel, typeof(GlobalConfig.EUpdateChannel)); + } + if (GlobalConfig == null) { throw new InvalidOperationException(nameof(GlobalConfig)); } @@ -187,7 +191,9 @@ public static class ASF { throw new InvalidOperationException(nameof(WebBrowser)); } - if (!SharedInfo.BuildInfo.CanUpdate || (GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None)) { + channel ??= GlobalConfig.UpdateChannel; + + if (!SharedInfo.BuildInfo.CanUpdate || (channel == GlobalConfig.EUpdateChannel.None)) { return null; } @@ -216,7 +222,7 @@ public static class ASF { ArchiLogger.LogGenericInfo(Strings.UpdateCheckingNewVersion); - GitHub.ReleaseResponse? releaseResponse = await GitHub.GetLatestRelease(GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable).ConfigureAwait(false); + GitHub.ReleaseResponse? releaseResponse = await GitHub.GetLatestRelease(channel == GlobalConfig.EUpdateChannel.Stable).ConfigureAwait(false); if (releaseResponse == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); diff --git a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs index d35b3a281..bb342ce60 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs @@ -173,8 +173,14 @@ public sealed class ASFController : ArchiController { /// [HttpPost("Update")] [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)] - public async Task>> UpdatePost() { - (bool success, string? message, Version? version) = await Actions.Update().ConfigureAwait(false); + public async Task>> UpdatePost([FromBody] UpdateRequest request) { + ArgumentNullException.ThrowIfNull(request); + + if (request.Channel.HasValue && !Enum.IsDefined(request.Channel.Value)) { + return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(request.Channel)))); + } + + (bool success, string? message, Version? version) = await Actions.Update(request.Channel).ConfigureAwait(false); if (string.IsNullOrEmpty(message)) { message = success ? Strings.Success : Strings.WarningFailed; diff --git a/ArchiSteamFarm/IPC/Requests/UpdateRequest.cs b/ArchiSteamFarm/IPC/Requests/UpdateRequest.cs new file mode 100644 index 000000000..c829135b7 --- /dev/null +++ b/ArchiSteamFarm/IPC/Requests/UpdateRequest.cs @@ -0,0 +1,38 @@ +// _ _ _ ____ _ _____ +// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___ +// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \ +// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | | +// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_| +// | +// Copyright 2015-2022 Ɓukasz "JustArchi" Domeradzki +// Contact: JustArchi@JustArchi.net +// | +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// | +// http://www.apache.org/licenses/LICENSE-2.0 +// | +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Diagnostics.CodeAnalysis; +using ArchiSteamFarm.Storage; +using Newtonsoft.Json; + +namespace ArchiSteamFarm.IPC.Requests; + +[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")] +public sealed class UpdateRequest { + /// + /// Target update channel. Not required, will default to UpdateChannel in GlobalConfig if not provided. + /// + [JsonProperty(Required = Required.DisallowNull)] + public GlobalConfig.EUpdateChannel? Channel { get; private set; } + + [JsonConstructor] + private UpdateRequest() { } +} diff --git a/ArchiSteamFarm/Steam/Interaction/Actions.cs b/ArchiSteamFarm/Steam/Interaction/Actions.cs index c291747e3..fd992b7bd 100644 --- a/ArchiSteamFarm/Steam/Interaction/Actions.cs +++ b/ArchiSteamFarm/Steam/Interaction/Actions.cs @@ -431,8 +431,12 @@ public sealed class Actions : IAsyncDisposable, IDisposable { } [PublicAPI] - public static async Task<(bool Success, string? Message, Version? Version)> Update() { - Version? version = await ASF.Update(true).ConfigureAwait(false); + public static async Task<(bool Success, string? Message, Version? Version)> Update(GlobalConfig.EUpdateChannel? channel = null) { + if (channel.HasValue && !Enum.IsDefined(channel.Value)) { + throw new InvalidEnumArgumentException(nameof(channel), (int) channel, typeof(GlobalConfig.EUpdateChannel)); + } + + Version? version = await ASF.Update(channel, true).ConfigureAwait(false); if (version == null) { return (false, null, null); diff --git a/ArchiSteamFarm/Steam/Interaction/Commands.cs b/ArchiSteamFarm/Steam/Interaction/Commands.cs index a4398fa8b..d756f321a 100644 --- a/ArchiSteamFarm/Steam/Interaction/Commands.cs +++ b/ArchiSteamFarm/Steam/Interaction/Commands.cs @@ -329,6 +329,8 @@ public sealed class Commands { return await ResponseTransferByRealAppIDs(access, args[1], args[2], true).ConfigureAwait(false); case "UNPACK": return await ResponseUnpackBoosters(access, Utilities.GetArgsAsText(args, 1, ","), steamID).ConfigureAwait(false); + case "UPDATE": + return await ResponseUpdate(access, args[1]).ConfigureAwait(false); default: string? pluginsResponse = await PluginsCore.OnBotCommand(Bot, access, message, args, steamID).ConfigureAwait(false); @@ -3389,7 +3391,7 @@ public sealed class Commands { return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null; } - private static async Task ResponseUpdate(EAccess access) { + private static async Task ResponseUpdate(EAccess access, string? channelText = null) { if (!Enum.IsDefined(access)) { throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess)); } @@ -3398,7 +3400,15 @@ public sealed class Commands { return null; } - (bool success, string? message, Version? version) = await Actions.Update().ConfigureAwait(false); + GlobalConfig.EUpdateChannel channel = ASF.GlobalConfig?.UpdateChannel ?? GlobalConfig.DefaultUpdateChannel; + + if (!string.IsNullOrEmpty(channelText)) { + if (!Enum.TryParse(channelText, true, out channel) || (channel == GlobalConfig.EUpdateChannel.None)) { + return FormatStaticResponse(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(channelText))); + } + } + + (bool success, string? message, Version? version) = await Actions.Update(channel).ConfigureAwait(false); return FormatStaticResponse($"{(success ? Strings.Success : Strings.WarningFailed)}{(!string.IsNullOrEmpty(message) ? $" {message}" : version != null ? $" {version}" : "")}"); }