From 962b4a214149981f3d7c075b7e0262e188b2079b Mon Sep 17 00:00:00 2001 From: JustArchi Date: Thu, 11 Apr 2019 14:04:58 +0200 Subject: [PATCH] Closes #1191 --- .../CatController.cs | 43 +++++++++++++++ .../IPC/Responses/GenericResponse.cs | 10 ++-- ArchiSteamFarm/IPC/Startup.cs | 12 +++++ ArchiSteamFarm/Plugins/Core.cs | 54 +++++++++++-------- 4 files changed, 92 insertions(+), 27 deletions(-) create mode 100644 ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatController.cs diff --git a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatController.cs b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatController.cs new file mode 100644 index 000000000..5fa7a9d56 --- /dev/null +++ b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatController.cs @@ -0,0 +1,43 @@ +// _ _ _ ____ _ _____ +// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___ +// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \ +// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | | +// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_| +// | +// Copyright 2015-2019 Ɓ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.Net; +using System.Threading.Tasks; +using ArchiSteamFarm.IPC.Controllers.Api; +using ArchiSteamFarm.IPC.Responses; +using Microsoft.AspNetCore.Mvc; + +namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin { + // This is an example class which shows you how you can extend ASF's API with your own custom API routes and controllers + // You're free to decide whether you want to integrate with existing ASF concepts (such as ArchiController/GenericResponse), or roll out your own + // All API controllers will be discovered during our Kestrel initialization using attributes mapping, you're also getting usual ASF goodies such as swagger documentation out of the box + [Route("/Api/Cat")] + public sealed class CatController : ArchiController { + [HttpGet] + [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.OK)] + [ProducesResponseType(typeof(GenericResponse), (int) HttpStatusCode.ServiceUnavailable)] + public async Task>> ASFGet() { + string link = await CatAPI.GetRandomCatURL(ASF.WebBrowser).ConfigureAwait(false); + + return !string.IsNullOrEmpty(link) ? Ok(new GenericResponse(link)) : StatusCode((int) HttpStatusCode.ServiceUnavailable, new GenericResponse(false)); + } + } +} diff --git a/ArchiSteamFarm/IPC/Responses/GenericResponse.cs b/ArchiSteamFarm/IPC/Responses/GenericResponse.cs index 36f201ed4..998b1b3e4 100644 --- a/ArchiSteamFarm/IPC/Responses/GenericResponse.cs +++ b/ArchiSteamFarm/IPC/Responses/GenericResponse.cs @@ -34,10 +34,10 @@ namespace ArchiSteamFarm.IPC.Responses { [JsonProperty] public readonly T Result; - internal GenericResponse(T result) : base(result != null) => Result = result; - internal GenericResponse(bool success, string message) : base(success, message) { } - internal GenericResponse(bool success, T result) : base(success) => Result = result; - internal GenericResponse(bool success, string message, T result) : base(success, message) => Result = result; + public GenericResponse(T result) : base(result != null) => Result = result; + public GenericResponse(bool success, string message) : base(success, message) { } + public GenericResponse(bool success, T result) : base(success) => Result = result; + public GenericResponse(bool success, string message, T result) : base(success, message) => Result = result; } public class GenericResponse { @@ -57,7 +57,7 @@ namespace ArchiSteamFarm.IPC.Responses { [Required] public readonly bool Success; - internal GenericResponse(bool success, string message = null) { + public GenericResponse(bool success, string message = null) { Success = success; if (!string.IsNullOrEmpty(message)) { diff --git a/ArchiSteamFarm/IPC/Startup.cs b/ArchiSteamFarm/IPC/Startup.cs index a6f9cb3de..b16c86dec 100644 --- a/ArchiSteamFarm/IPC/Startup.cs +++ b/ArchiSteamFarm/IPC/Startup.cs @@ -20,8 +20,11 @@ // limitations under the License. using System; +using System.Collections.Generic; using System.IO; +using System.Reflection; using ArchiSteamFarm.IPC.Integration; +using ArchiSteamFarm.Plugins; using JetBrains.Annotations; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -159,6 +162,15 @@ namespace ArchiSteamFarm.IPC { // We need MVC for /Api, but we're going to use only a small subset of all available features IMvcCoreBuilder mvc = services.AddMvcCore(); + // Add support for controllers declared in custom plugins + HashSet assemblies = Core.LoadAssemblies(); + + if (assemblies != null) { + foreach (Assembly assembly in assemblies) { + mvc.AddApplicationPart(assembly); + } + } + // Add API explorer for swagger mvc.AddApiExplorer(); diff --git a/ArchiSteamFarm/Plugins/Core.cs b/ArchiSteamFarm/Plugins/Core.cs index 163bb1d34..067638d6e 100644 --- a/ArchiSteamFarm/Plugins/Core.cs +++ b/ArchiSteamFarm/Plugins/Core.cs @@ -86,29 +86,9 @@ namespace ArchiSteamFarm.Plugins { } internal static bool InitPlugins() { - HashSet assemblies = new HashSet(); + HashSet assemblies = LoadAssemblies(); - string pluginsPath = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.PluginsDirectory); - - if (Directory.Exists(pluginsPath)) { - HashSet loadedAssemblies = LoadAssembliesFrom(pluginsPath); - - if ((loadedAssemblies != null) && (loadedAssemblies.Count > 0)) { - assemblies.UnionWith(loadedAssemblies); - } - } - - string customPluginsPath = Path.Combine(Directory.GetCurrentDirectory(), SharedInfo.PluginsDirectory); - - if (Directory.Exists(customPluginsPath)) { - HashSet loadedAssemblies = LoadAssembliesFrom(customPluginsPath); - - if ((loadedAssemblies != null) && (loadedAssemblies.Count > 0)) { - assemblies.UnionWith(loadedAssemblies); - } - } - - if (assemblies.Count == 0) { + if ((assemblies == null) || (assemblies.Count == 0)) { ASF.ArchiLogger.LogGenericTrace(Strings.NothingFound); return true; @@ -166,6 +146,36 @@ namespace ArchiSteamFarm.Plugins { return invalidPlugins.Count == 0; } + internal static HashSet LoadAssemblies() { + HashSet assemblies = null; + + string pluginsPath = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.PluginsDirectory); + + if (Directory.Exists(pluginsPath)) { + HashSet loadedAssemblies = LoadAssembliesFrom(pluginsPath); + + if ((loadedAssemblies != null) && (loadedAssemblies.Count > 0)) { + assemblies = loadedAssemblies; + } + } + + string customPluginsPath = Path.Combine(Directory.GetCurrentDirectory(), SharedInfo.PluginsDirectory); + + if (Directory.Exists(customPluginsPath)) { + HashSet loadedAssemblies = LoadAssembliesFrom(customPluginsPath); + + if ((loadedAssemblies != null) && (loadedAssemblies.Count > 0)) { + if ((assemblies != null) && (assemblies.Count > 0)) { + assemblies.UnionWith(loadedAssemblies); + } else { + assemblies = loadedAssemblies; + } + } + } + + return assemblies; + } + internal static async Task OnASFInitModules(IReadOnlyDictionary additionalConfigProperties = null) { if ((ActivePlugins == null) || (ActivePlugins.Count == 0)) { return;