Skip to content

Commit

Permalink
Closes #3343
Browse files Browse the repository at this point in the history
  • Loading branch information
JustArchi committed Jan 5, 2025
1 parent 8c9cf69 commit 3f98337
Show file tree
Hide file tree
Showing 62 changed files with 342 additions and 588 deletions.
5 changes: 2 additions & 3 deletions ArchiSteamFarm.CustomPlugins.ExamplePlugin/ExamplePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,16 @@ internal sealed class ExamplePlugin : IASF, IBot, IBotCommand2, IBotConnection,
// This is used for identification purposes, typically you want to use a friendly name of your plugin here, such as the name of your main class
// Please note that this property can have direct dependencies only on structures that were initialized by the constructor, as it's possible to be called before OnLoaded() takes place
[JsonInclude]
[Required]
public string Name => nameof(ExamplePlugin);

// This will be displayed to the user and written in the log file, typically you should point it to the version of your library, but alternatively you can do some more advanced logic if you'd like to
// Please note that this property can have direct dependencies only on structures that were initialized by the constructor, as it's possible to be called before OnLoaded() takes place
[JsonInclude]
[Required]
public Version Version => typeof(ExamplePlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));

// Plugins can expose custom properties for our GET /Api/Plugins API call, simply annotate them with [JsonProperty] (or keep public)
// Plugins can expose custom properties for our GET /Api/Plugins API call, simply annotate them with [JsonInclude] (or keep public)
[JsonInclude]
[JsonRequired]
[Required]
public bool CustomIsEnabledField { get; private init; } = true;

Expand Down
3 changes: 0 additions & 3 deletions ArchiSteamFarm.CustomPlugins.PeriodicGC/PeriodicGCPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
// limitations under the License.

using System;
using System.ComponentModel.DataAnnotations;
using System.Composition;
using System.Runtime;
using System.Text.Json.Serialization;
Expand All @@ -43,11 +42,9 @@ internal sealed class PeriodicGCPlugin : IPlugin {
private static readonly Timer PeriodicGCTimer = new(PerformGC);

[JsonInclude]
[Required]
public string Name => nameof(PeriodicGCPlugin);

[JsonInclude]
[Required]
public Version Version => typeof(PeriodicGCPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));

public Task OnLoaded() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
// limitations under the License.

using System;
using System.ComponentModel.DataAnnotations;
using System.Composition;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
Expand All @@ -36,11 +35,9 @@ namespace ArchiSteamFarm.CustomPlugins.SignInWithSteam;
[UsedImplicitly]
internal sealed class SignInWithSteamPlugin : IPlugin {
[JsonInclude]
[Required]
public string Name => nameof(SignInWithSteamPlugin);

[JsonInclude]
[Required]
public Version Version => typeof(SignInWithSteamPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));

public Task OnLoaded() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
<PackageReference Include="System.Linq.Async" IncludeAssets="compile" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Composition;
using System.Linq;
using System.Text.Json;
Expand All @@ -47,11 +46,9 @@ internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotCommand2, I
internal static readonly ConcurrentDictionary<Bot, RemoteCommunication> RemoteCommunications = new();

[JsonInclude]
[Required]
public override string Name => nameof(ItemsMatcherPlugin);

[JsonInclude]
[Required]
public override Version Version => typeof(ItemsMatcherPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));

public async Task<string?> OnBotCommand(Bot bot, EAccess access, string message, string[] args, ulong steamID = 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Composition;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
Expand All @@ -42,11 +41,9 @@ namespace ArchiSteamFarm.OfficialPlugins.MobileAuthenticator;
[SuppressMessage("ReSharper", "MemberCanBeFileLocal")]
internal sealed class MobileAuthenticatorPlugin : OfficialPlugin, IBotCommand2, IBotSteamClient {
[JsonInclude]
[Required]
public override string Name => nameof(MobileAuthenticatorPlugin);

[JsonInclude]
[Required]
public override Version Version => typeof(MobileAuthenticatorPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));

public async Task<string?> OnBotCommand(Bot bot, EAccess access, string message, string[] args, ulong steamID = 0) {
Expand Down
3 changes: 0 additions & 3 deletions ArchiSteamFarm.OfficialPlugins.Monitoring/MonitoringPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Composition;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Metrics;
Expand Down Expand Up @@ -73,13 +72,11 @@ internal sealed class MonitoringPlugin : OfficialPlugin, IDisposable, IOfficialG
private static FrozenSet<Measurement<int>>? PluginMeasurements;

[JsonInclude]
[Required]
public override string Name => nameof(MonitoringPlugin);

public string RepositoryName => SharedInfo.GithubRepo;

[JsonInclude]
[Required]
public override Version Version => typeof(MonitoringPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));

private readonly ConcurrentDictionary<Bot, TradeStatistics> TradeStatistics = new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
<PackageReference Include="SteamKit2" IncludeAssets="compile" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" IncludeAssets="compile" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@

using System.Net;
using ArchiSteamFarm.IPC.Controllers.Api;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;

namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper;

[Route("Api/SteamTokenDumperPlugin")]
public sealed class SteamTokenDumperController : ArchiController {
[HttpGet(nameof(GlobalConfigExtension))]
[ProducesResponseType<GlobalConfigExtension>((int) HttpStatusCode.OK)]
[SwaggerOperation(Tags = [nameof(GlobalConfigExtension)])]
[Tags(nameof(GlobalConfigExtension))]
public ActionResult<GlobalConfigExtension> Get() => Ok(new GlobalConfigExtension());
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
using System.Collections.Frozen;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Composition;
using System.Linq;
using System.Net;
Expand Down Expand Up @@ -65,11 +64,9 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotC
private static DateTimeOffset LastUploadAt = DateTimeOffset.MinValue;

[JsonInclude]
[Required]
public override string Name => nameof(SteamTokenDumperPlugin);

[JsonInclude]
[Required]
public override Version Version => typeof(SteamTokenDumperPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));

public Task<uint> GetPreferredChangeNumberToStartFrom() => Task.FromResult(GlobalCache?.LastChangeNumber ?? 0);
Expand Down
5 changes: 2 additions & 3 deletions ArchiSteamFarm/ArchiSteamFarm.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);config/**;debug/**;logs/**;overlay/**</DefaultItemExcludes>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<OutputType>Exe</OutputType>
</PropertyGroup>

Expand All @@ -11,13 +10,13 @@
<PackageReference Include="Humanizer" />
<PackageReference Include="JetBrains.Annotations" PrivateAssets="all" />
<PackageReference Include="Markdig.Signed" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
<PackageReference Include="Microsoft.CodeAnalysis.ResxSourceGenerator" PrivateAssets="all" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" />
<PackageReference Include="Nito.AsyncEx.Coordination" />
<PackageReference Include="NLog.Web.AspNetCore" />
<PackageReference Include="SteamKit2" />
<PackageReference Include="Swashbuckle.AspNetCore" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" />
<PackageReference Include="System.Composition" />
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
Expand Down
86 changes: 21 additions & 65 deletions ArchiSteamFarm/IPC/ArchiKestrel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
using ArchiSteamFarm.Helpers.Json;
using ArchiSteamFarm.IPC.Controllers.Api;
using ArchiSteamFarm.IPC.Integration;
using ArchiSteamFarm.IPC.OpenApi;
using ArchiSteamFarm.Localization;
using ArchiSteamFarm.NLog;
using ArchiSteamFarm.NLog.Targets;
Expand All @@ -52,7 +53,6 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Microsoft.OpenApi.Models;
using NLog.Web;
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;

Expand Down Expand Up @@ -118,7 +118,7 @@ internal static async Task Stop() {

[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL2026:RequiresUnreferencedCode", Justification = "PathString is a primitive, it's unlikely to be trimmed to the best of our knowledge")]
[UnconditionalSuppressMessage("AssemblyLoadTrimming", "IL3000", Justification = "We don't care about trimmed assemblies, as we need it to work only with the known (used) ones")]
private static void ConfigureApp([SuppressMessage("ReSharper", "SuggestBaseTypeForParameter")] ConfigurationManager configuration, IApplicationBuilder app) {
private static void ConfigureApp([SuppressMessage("ReSharper", "SuggestBaseTypeForParameter")] ConfigurationManager configuration, WebApplication app) {
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(app);

Expand Down Expand Up @@ -252,10 +252,10 @@ private static void ConfigureApp([SuppressMessage("ReSharper", "SuggestBaseTypeF
}

// Finally register proper API endpoints once we're done with routing
app.UseEndpoints(static endpoints => endpoints.MapControllers());
app.MapControllers();

// Add support for swagger, responsible for automatic API documentation generation, this should be on the end, once we're done with API
app.UseSwagger();
// Add support for OpenAPI, responsible for automatic API documentation generation, this should be on the end, once we're done with API
app.MapOpenApi("/swagger/{documentName}/swagger.json");

// Add support for swagger UI, this should be after swagger, obviously
app.UseSwaggerUI(
Expand Down Expand Up @@ -331,66 +331,12 @@ private static void ConfigureServices([SuppressMessage("ReSharper", "SuggestBase
services.AddCors(static options => options.AddDefaultPolicy(static policyBuilder => policyBuilder.AllowAnyOrigin()));
}

// Add support for swagger, responsible for automatic API documentation generation
services.AddSwaggerGen(
static options => {
options.AddSecurityDefinition(
nameof(GlobalConfig.IPCPassword), new OpenApiSecurityScheme {
Description = $"{nameof(GlobalConfig.IPCPassword)} authentication using request headers. Check {SharedInfo.ProjectURL}/wiki/IPC#authentication for more info.",
In = ParameterLocation.Header,
Name = ApiAuthenticationMiddleware.HeadersField,
Type = SecuritySchemeType.ApiKey
}
);

options.AddSecurityRequirement(
new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme {
Reference = new OpenApiReference {
Id = nameof(GlobalConfig.IPCPassword),
Type = ReferenceType.SecurityScheme
}
},

[]
}
}
);

// We require custom schema IDs due to conflicting type names, choosing the proper one is tricky as there is no good answer and any kind of convention has a potential to create conflict
// FullName and Name both do, ToString() for unknown to me reason doesn't, and I don't have courage to call our WebUtilities.GetUnifiedName() better than what .NET ships with (because it isn't)
// Let's use ToString() until we find a good enough reason to change it, also, the name must pass ^[a-zA-Z0-9.-_]+$ regex
options.CustomSchemaIds(static type => type.ToString().Replace('+', '-'));

options.EnableAnnotations(true, true);

options.SchemaFilter<CustomAttributesSchemaFilter>();
options.SchemaFilter<EnumSchemaFilter>();
options.SchemaFilter<ReadOnlyFixesSchemaFilter>();

options.SwaggerDoc(
SharedInfo.ASF, new OpenApiInfo {
Contact = new OpenApiContact {
Name = SharedInfo.GithubRepo,
Url = new Uri(SharedInfo.ProjectURL)
},

License = new OpenApiLicense {
Name = SharedInfo.LicenseName,
Url = new Uri(SharedInfo.LicenseURL)
},

Title = $"{SharedInfo.AssemblyName} API",
Version = SharedInfo.Version.ToString()
}
);

string xmlDocumentationFile = Path.Combine(AppContext.BaseDirectory, SharedInfo.AssemblyDocumentation);

if (File.Exists(xmlDocumentationFile)) {
options.IncludeXmlComments(xmlDocumentationFile);
}
// Add support for OpenAPI, responsible for automatic API documentation generation
services.AddOpenApi(
SharedInfo.ASF, static options => {
options.AddDocumentTransformer<DocumentTransformer>();
options.AddOperationTransformer<OperationTransformer>();
options.AddSchemaTransformer<SchemaTransformer>();
}
);

Expand All @@ -406,6 +352,16 @@ private static void ConfigureServices([SuppressMessage("ReSharper", "SuggestBase
}
}

services.ConfigureHttpJsonOptions(
static options => {
JsonSerializerOptions jsonSerializerOptions = Debugging.IsUserDebugging ? JsonUtilities.IndentedJsonSerialierOptions : JsonUtilities.DefaultJsonSerialierOptions;

options.SerializerOptions.PropertyNamingPolicy = jsonSerializerOptions.PropertyNamingPolicy;
options.SerializerOptions.TypeInfoResolver = jsonSerializerOptions.TypeInfoResolver;
options.SerializerOptions.WriteIndented = jsonSerializerOptions.WriteIndented;
}
);

// We need MVC for /Api, but we're going to use only a small subset of all available features
IMvcBuilder mvc = services.AddControllers();

Expand Down
Loading

0 comments on commit 3f98337

Please sign in to comment.