mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 22:20:52 +00:00
Add GlobalConfig to /Api/ASF, and POST /Api/ASF, #750
This commit is contained in:
@@ -201,9 +201,17 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
internal async Task MakeReadOnly() {
|
||||
if (ReadOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
await FileSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
if (ReadOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReadOnly = true;
|
||||
} finally {
|
||||
FileSemaphore.Release();
|
||||
|
||||
@@ -23,6 +23,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using Newtonsoft.Json;
|
||||
using SteamKit2;
|
||||
@@ -36,6 +38,8 @@ namespace ArchiSteamFarm {
|
||||
|
||||
internal static readonly HashSet<uint> SalesBlacklist = new HashSet<uint> { 267420, 303700, 335590, 368020, 425280, 480730, 566020, 639900, 762800 }; // Steam Summer/Winter sales
|
||||
|
||||
private static readonly SemaphoreSlim WriteSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
internal readonly bool AutoRestart = true;
|
||||
|
||||
@@ -170,6 +174,35 @@ namespace ArchiSteamFarm {
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static async Task<bool> Write(string filePath, GlobalConfig globalConfig) {
|
||||
if (string.IsNullOrEmpty(filePath) || (globalConfig == null)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(filePath) + " || " + nameof(globalConfig));
|
||||
return false;
|
||||
}
|
||||
|
||||
string json = JsonConvert.SerializeObject(globalConfig, Formatting.Indented);
|
||||
string newFilePath = filePath + ".new";
|
||||
|
||||
await WriteSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false);
|
||||
|
||||
if (File.Exists(filePath)) {
|
||||
File.Replace(newFilePath, filePath, null);
|
||||
} else {
|
||||
File.Move(newFilePath, filePath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
return false;
|
||||
} finally {
|
||||
WriteSemaphore.Release();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal enum EOptimizationMode : byte {
|
||||
MaxPerformance,
|
||||
MinMemoryUsage
|
||||
|
||||
@@ -43,9 +43,9 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private static readonly HashSet<string> CompressableContentTypes = new HashSet<string> {
|
||||
"application/javascript",
|
||||
"application/json",
|
||||
"text/css",
|
||||
"text/html",
|
||||
"text/json",
|
||||
"text/plain"
|
||||
};
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace ArchiSteamFarm {
|
||||
{ ".ico", "image/x-icon" },
|
||||
{ ".jpg", "image/jpeg" },
|
||||
{ ".js", "application/javascript" },
|
||||
{ ".json", "text/json" },
|
||||
{ ".json", "application/json" },
|
||||
{ ".png", "image/png" },
|
||||
{ ".txt", "text/plain" }
|
||||
};
|
||||
@@ -174,6 +174,8 @@ namespace ArchiSteamFarm {
|
||||
switch (request.HttpMethod) {
|
||||
case HttpMethods.Get:
|
||||
return await HandleApiASFGet(request, response, arguments, argumentsIndex).ConfigureAwait(false);
|
||||
case HttpMethods.Post:
|
||||
return await HandleApiASFPost(request, response, arguments, argumentsIndex).ConfigureAwait(false);
|
||||
default:
|
||||
await ResponseStatusCode(request, response, HttpStatusCode.MethodNotAllowed).ConfigureAwait(false);
|
||||
return true;
|
||||
@@ -194,12 +196,60 @@ namespace ArchiSteamFarm {
|
||||
processStartTime = process.StartTime;
|
||||
}
|
||||
|
||||
ASFResponse asfResponse = new ASFResponse(memoryUsage, processStartTime, SharedInfo.Version);
|
||||
ASFResponse asfResponse = new ASFResponse(Program.GlobalConfig, memoryUsage, processStartTime, SharedInfo.Version);
|
||||
|
||||
await ResponseJsonObject(request, response, new GenericResponse(true, "OK", asfResponse)).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<bool> HandleApiASFPost(HttpListenerRequest request, HttpListenerResponse response, string[] arguments, byte argumentsIndex) {
|
||||
if ((request == null) || (response == null) || (arguments == null) || (argumentsIndex == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(request) + " || " + nameof(response) + " || " + nameof(arguments) + " || " + nameof(argumentsIndex));
|
||||
return false;
|
||||
}
|
||||
|
||||
const string requiredContentType = "application/json";
|
||||
|
||||
if (request.ContentType != requiredContentType) {
|
||||
await ResponseJsonObject(request, response, new GenericResponse(false, nameof(request.ContentType) + " must be declared as " + requiredContentType), HttpStatusCode.NotAcceptable).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
string body;
|
||||
using (StreamReader reader = new StreamReader(request.InputStream)) {
|
||||
body = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(body)) {
|
||||
await ResponseJsonObject(request, response, new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(body))), HttpStatusCode.BadRequest).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
ASFRequest jsonRequest;
|
||||
|
||||
try {
|
||||
jsonRequest = JsonConvert.DeserializeObject<ASFRequest>(body);
|
||||
} catch (Exception e) {
|
||||
await ResponseJsonObject(request, response, new GenericResponse(false, string.Format(Strings.ErrorParsingObject, nameof(jsonRequest)) + Environment.NewLine + e), HttpStatusCode.BadRequest).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (jsonRequest == null) {
|
||||
await ResponseJsonObject(request, response, new GenericResponse(false, string.Format(Strings.ErrorObjectIsNull, nameof(jsonRequest))), HttpStatusCode.BadRequest).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
string filePath = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName);
|
||||
|
||||
if (!await GlobalConfig.Write(filePath, jsonRequest.GlobalConfig).ConfigureAwait(false)) {
|
||||
await ResponseJsonObject(request, response, new GenericResponse(false, "Writing global config failed, check ASF log for details"), HttpStatusCode.BadRequest).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
await ResponseJsonObject(request, response, new GenericResponse(true, "OK")).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<bool> HandleApiBot(HttpListenerRequest request, HttpListenerResponse response, string[] arguments, byte argumentsIndex) {
|
||||
if ((request == null) || (response == null) || (arguments == null) || (argumentsIndex == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(request) + " || " + nameof(response) + " || " + nameof(arguments) + " || " + nameof(argumentsIndex));
|
||||
@@ -320,6 +370,11 @@ namespace ArchiSteamFarm {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (jsonRequest == null) {
|
||||
await ResponseJsonObject(request, response, new GenericResponse(false, string.Format(Strings.ErrorObjectIsNull, nameof(jsonRequest))), HttpStatusCode.BadRequest).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
string botName = WebUtility.UrlDecode(arguments[argumentsIndex]);
|
||||
|
||||
if (jsonRequest.KeepSensitiveDetails && Bot.Bots.TryGetValue(botName, out Bot bot)) {
|
||||
@@ -459,6 +514,11 @@ namespace ArchiSteamFarm {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (jsonRequest == null) {
|
||||
await ResponseJsonObject(request, response, new GenericResponse(false, string.Format(Strings.ErrorObjectIsNull, nameof(jsonRequest))), HttpStatusCode.BadRequest).ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (jsonRequest.GamesToRedeemInBackground.Count == 0) {
|
||||
await ResponseJsonObject(request, response, new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(jsonRequest.GamesToRedeemInBackground))), HttpStatusCode.BadRequest).ConfigureAwait(false);
|
||||
return true;
|
||||
@@ -932,7 +992,21 @@ namespace ArchiSteamFarm {
|
||||
await ResponseString(request, response, text, "text/plain", statusCode).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
private sealed class ASFRequest {
|
||||
#pragma warning disable 649
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal readonly GlobalConfig GlobalConfig;
|
||||
#pragma warning restore 649
|
||||
|
||||
// Deserialized from JSON
|
||||
private ASFRequest() { }
|
||||
}
|
||||
|
||||
private sealed class ASFResponse {
|
||||
[JsonProperty]
|
||||
private readonly GlobalConfig GlobalConfig;
|
||||
|
||||
[JsonProperty]
|
||||
private readonly uint MemoryUsage;
|
||||
|
||||
@@ -942,11 +1016,12 @@ namespace ArchiSteamFarm {
|
||||
[JsonProperty]
|
||||
private readonly Version Version;
|
||||
|
||||
internal ASFResponse(uint memoryUsage, DateTime processStartTime, Version version) {
|
||||
if ((memoryUsage == 0) || (processStartTime == DateTime.MinValue) || (version == null)) {
|
||||
internal ASFResponse(GlobalConfig globalConfig, uint memoryUsage, DateTime processStartTime, Version version) {
|
||||
if ((globalConfig == null) || (memoryUsage == 0) || (processStartTime == DateTime.MinValue) || (version == null)) {
|
||||
throw new ArgumentNullException(nameof(memoryUsage) + " || " + nameof(processStartTime) + " || " + nameof(version));
|
||||
}
|
||||
|
||||
GlobalConfig = globalConfig;
|
||||
MemoryUsage = memoryUsage;
|
||||
ProcessStartTime = processStartTime;
|
||||
Version = version;
|
||||
|
||||
Reference in New Issue
Block a user