Initial commit

This commit is contained in:
xx-TheDoctor-xx
2020-04-19 17:48:58 +01:00
commit faddda7dbc
15 changed files with 818 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

353
.gitignore vendored Normal file
View File

@ -0,0 +1,353 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/

24
LICENSE Normal file
View File

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PluginManager\PluginManager.csproj" />
<ProjectReference Include="..\TestPlugin\TestPlugin.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,38 @@
using System;
using Xunit;
using PluginManager.Manager;
using TestPlugin;
namespace PluginManager.Test
{
public class PDM : PluginDataManager
{
public override PluginData LoadData(string pluginDataFolder)
{
return null;
}
public override void SaveData(string yes, PluginData data)
{
}
}
class PPD : PluginProcessData
{
}
public class PluginManagerTest
{
[Fact]
public void Test1()
{
PluginManager<Class1, PDM> pluginManager = new PluginManager<Class1, PDM>();
PluginManagerConfig.PluginFolderPath = "Plugins";
pluginManager.Load();
pluginManager.DoProcessing(new PPD());
pluginManager.Unload();
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PluginManager
{
/// <summary>
/// This class implements all the plugin data information handling
/// </summary>
public abstract class PluginDataManager
{
public PluginDataManager()
{
// Need a constructor to use Activator.CreateInstance()
}
/// <summary>
/// Loads the data for a specific plugin
/// </summary>
/// <param name="pluginName">The path to the plugin data file</param>
/// <returns>Plugin data object if found, else return null, the plugin must handle this</returns>
public abstract PluginData LoadData(string pluginDataFileName);
/// <summary>
/// Saves the data to the plugin data file
/// </summary>
/// <param name="pluginName">The path to the plugin data file</param>
/// <param name="data">Data object to save</param>
public abstract void SaveData(string pluginDataFileName, PluginData data);
}
}

View File

@ -0,0 +1,162 @@
using Crayon;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace PluginManager.Manager
{
/// <summary>
/// Class that handles all plugin handling
/// </summary>
/// <typeparam name="T">Type of the Plugin that is going to get loaded</typeparam>
/// <typeparam name="M">Type of PluginDataManager that is going to get used to load data</typeparam>
public class PluginManager<T, M> where T : Plugin where M : PluginDataManager
{
/// <summary>
/// A list of plugins based on their name
/// </summary>
public List<T> Plugins { get; private set; }
private int pluginsSize;
private PluginDataManager dataManager;
/// <summary>
/// Specifies if you are using the plugin system or not
/// </summary>
public bool Enabled { get; set; }
public PluginManager()
{
Plugins = new List<T>();
dataManager = (PluginDataManager)Activator.CreateInstance(typeof(M), null);
Enabled = true; // By default it's true
}
/// <summary>
/// Loads all plugins and their data from the plugin folder
/// </summary>
public void Load()
{
if (Enabled)
{
if (string.IsNullOrEmpty(PluginManagerConfig.PluginFolderPath))
throw new ArgumentNullException("Plugins folder path", "You need to set a path for your plugins folder");
// First run
if (!Directory.Exists(PluginManagerConfig.PluginFolderPath))
{
Directory.CreateDirectory(PluginManagerConfig.PluginFolderPath);
return; // Let's return here, no plugins available
}
// Ignores files in this folder
var pluginDirectories = Directory.GetDirectories(PluginManagerConfig.PluginFolderPath);
foreach (var pluginPath in pluginDirectories)
{
// Should contain the plugin file
var files = Directory.GetFiles(pluginPath, "*.dll");
foreach (var dll in files)
{
try
{
// We try to load them if they have at least one class that inherits Plugin
var assembly = Assembly.LoadFrom(dll);
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(typeof(T)))
addPlugin(type);
}
}
catch (ReflectionTypeLoadException ex)
{
Console.Error.WriteLine(Output.Red($"Failed to load {Path.GetFileName(dll)}. We will continue to load more assemblies"), ex);
}
catch (Exception ex)
{
Console.Error.WriteLine(Output.Red($"Failed to load {Path.GetFileName(dll)}. We will continue to load more assemblies"), ex);
}
}
}
pluginsSize = Plugins.Count;
}
else
{
// Throw here?
}
}
/// <summary>
/// Saves plugin information to their data files
/// </summary>
public void Unload()
{
foreach (var plugin in Plugins)
{
try
{
var dataFilePath = plugin.DataFilePath();
// If it's null it means it's not using a file
if (!string.IsNullOrEmpty(dataFilePath))
dataManager.SaveData(dataFilePath, plugin.Data);
}
catch (Exception)
{
Console.Error.WriteLine(Output.Red($"Couldn't save data for {plugin.Name()}"));
}
}
}
/// <summary>
/// Internal function that handles plugin instancing
/// </summary>
/// <param name="plugin"></param>
internal void addPlugin(Type plugin)
{
Plugin pluginInstance = (T)Activator.CreateInstance(plugin);
try
{
Plugins.Add((T)pluginInstance);
var pluginDataFilePath = pluginInstance.DataFilePath();
// If it's null we are not using plugin data
if (!string.IsNullOrEmpty(PluginManagerConfig.PluginDataFolderPath) && !string.IsNullOrEmpty(pluginDataFilePath))
{
var pluginData = dataManager.LoadData(Path.Combine(PluginManagerConfig.PluginDataFolderPath, pluginDataFilePath));
// This one shouldn't throw, loadData() will always exist
pluginInstance.loadData(pluginData);
}
Console.WriteLine($"Loaded {pluginInstance.Name()}");
}
catch (ArgumentException)
{
Console.Error.WriteLine(Output.Red($"{pluginInstance.Name()} is already loaded"));
}
}
/// <summary>
/// Executes DoProcessing on all plugins
/// </summary>
/// <param name="processData"></param>
public void DoProcessing(PluginProcessData processData)
{
for (int i = 0; i < pluginsSize; i++)
{
Plugins[i].DoProcessing(processData);
}
}
}
}

View File

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PluginManager
{
public delegate void OnLoadedEvent(PluginData data);
/// <summary>
/// Base class to create plugins
/// </summary>
public abstract class Plugin
{
/// <summary>
/// Event executed when the plugin manager finishes loading this plugin
/// </summary>
public event OnLoadedEvent OnLoaded;
/// <summary>
/// The plugin data object
/// </summary>
public PluginData Data { get; private set; }
public Plugin()
{
// Need a constructor to use Activator.CreateInstance()
}
/// <summary>
/// Internal function that handles data loading
/// </summary>
/// <param name="data">Data object that is going to get loaded</param>
internal void loadData(PluginData data)
{
if (data == null)
BuildDataFile();
this.Data = data;
OnLoaded?.Invoke(data);
}
/// <summary>
/// Builds the default plugin file for when the plugin is first instanciated
/// </summary>
public abstract void BuildDataFile();
/// <summary>
/// The version of the plugin
/// </summary>
/// <returns>The version of the plugin</returns>
public abstract Version Version();
/// <summary>
/// The version of the plugin
/// </summary>
/// <returns>The name of the plugin</returns>
public abstract string Name();
/// <summary>
/// The path to the plugin data file
/// </summary>
/// <returns>The path to the plugin data file</returns>
public abstract string DataFilePath();
/// <summary>
/// Base function that should get called everytime this plugin needs to process data
/// </summary>
/// <param name="data"></param>
public abstract void DoProcessing(PluginProcessData data);
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PluginManager
{
public abstract class PluginData
{
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PluginManager
{
/// <summary>
/// Base class for plugin process data that gets passes to Plugin.DoProcessing()
/// </summary>
public abstract class PluginProcessData
{
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace PluginManager
{
public static class PluginManagerConfig
{
public static string PluginDataFolderPath { get; set; }
public static string PluginFolderPath { get; set; }
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Crayon" Version="1.2.48" />
</ItemGroup>
</Project>

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# PluginManager
C# PluginManager

50
TestPlugin/Class1.cs Normal file
View File

@ -0,0 +1,50 @@
using PluginManager;
using System;
namespace TestPlugin
{
public abstract class Class1 : Plugin
{
public Class1()
{
}
}
public class asd : Class1
{
public asd()
{
base.OnLoaded += Asd_OnLoaded;
}
private void Asd_OnLoaded(PluginData data)
{
Console.Out.WriteLine("I'm loaded man");
}
public override void DoProcessing(PluginProcessData data)
{
//Console.WriteLine("working");
}
public override string Name()
{
return "asd";
}
public override Version Version()
{
return new Version("1.0.0.0");
}
public override void BuildDataFile()
{
// Leave this empty if you are not using a data file
}
public override string DataFilePath()
{
return null;
}
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\PluginManager.Test\bin\Debug\Plugins\Yep\</OutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PluginManager\PluginManager.csproj" />
</ItemGroup>
</Project>