Skip to content

Commit

Permalink
Add plugin framework [wip]
Browse files Browse the repository at this point in the history
-Added volume plugin
-Added weather plugin
  • Loading branch information
habibrehmansg committed Dec 18, 2024
1 parent ca3f7d1 commit b40156b
Show file tree
Hide file tree
Showing 22 changed files with 574 additions and 62 deletions.
7 changes: 0 additions & 7 deletions InfoPanel.Contract/IPanelData.cs

This file was deleted.

22 changes: 0 additions & 22 deletions InfoPanel.Contract/PanelData.cs

This file was deleted.

13 changes: 13 additions & 0 deletions InfoPanel.Plugins.Loader/InfoPanel.Plugins.Loader.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\InfoPanel.Plugins\InfoPanel.Plugins.csproj" />
</ItemGroup>

</Project>
17 changes: 17 additions & 0 deletions InfoPanel.Plugins.Loader/PluginExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace InfoPanel.Plugins.Loader
{
public static class PluginExtensions
{
public static string Id(this IPlugin panelData)
{
return panelData.ToString();

Check warning on line 14 in InfoPanel.Plugins.Loader/PluginExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference return.

Check warning on line 14 in InfoPanel.Plugins.Loader/PluginExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference return.
}
}
}
42 changes: 42 additions & 0 deletions InfoPanel.Plugins.Loader/PluginLoadContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;

namespace InfoPanel.Plugins.Loader
{
public class PluginLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;

public PluginLoadContext(string pluginPath)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}

protected override Assembly Load(AssemblyName assemblyName)
{
string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);

Check warning on line 22 in InfoPanel.Plugins.Loader/PluginLoadContext.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.

Check warning on line 22 in InfoPanel.Plugins.Loader/PluginLoadContext.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.
if (assemblyPath != null)
{
return LoadFromAssemblyPath(assemblyPath);
}

return null;

Check warning on line 28 in InfoPanel.Plugins.Loader/PluginLoadContext.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference return.

Check warning on line 28 in InfoPanel.Plugins.Loader/PluginLoadContext.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference return.
}

protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);

Check warning on line 33 in InfoPanel.Plugins.Loader/PluginLoadContext.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.

Check warning on line 33 in InfoPanel.Plugins.Loader/PluginLoadContext.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.
if (libraryPath != null)
{
return LoadUnmanagedDllFromPath(libraryPath);
}

return IntPtr.Zero;
}
}
}
78 changes: 78 additions & 0 deletions InfoPanel.Plugins.Loader/PluginLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace InfoPanel.Plugins.Loader
{
public class PluginLoader
{
public void test(string folder)
{
var plugins= Directory.GetFiles(folder, "InfoPanel.*.dll");
IEnumerable<IPlugin> commands = plugins.SelectMany(pluginPath =>
{
Assembly pluginAssembly = LoadPlugin(pluginPath);
return CreateCommands(pluginAssembly);
}).ToList();

//foreach (var command in commands)
//{
// Trace.WriteLine(command);
// var panelDatas = command.GetData();
// foreach(var panelData in panelDatas)
// {
// Trace.WriteLine(panelData.CollectionName);
// foreach(var item in panelData.EntryList)
// {
// Trace.WriteLine($"{item.Name}: {item.Value} {item.Unit}");
// }
// }
//}
}

public IEnumerable<IPlugin> InitializePlugin(string pluginPath)
{
Assembly pluginAssembly = LoadPlugin(pluginPath);
return CreateCommands(pluginAssembly);
}


static Assembly LoadPlugin(string pluginPath)
{
PluginLoadContext loadContext = new(pluginPath);
return loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginPath)));
}

static IEnumerable<IPlugin> CreateCommands(Assembly assembly)
{
int count = 0;

foreach (Type type in assembly.GetTypes())
{
if (typeof(IPlugin).IsAssignableFrom(type))
{
if (Activator.CreateInstance(type) is IPlugin result)
{
count++;
yield return result;
}
}
}

if (count == 0)
{
string availableTypes = string.Join(",", assembly.GetTypes().Select(t => t.FullName));
throw new ApplicationException(
$"Can't find any type which implements ICommand in {assembly} from {assembly.Location}.\n" +
$"Available types: {availableTypes}");
}
}


}
}
16 changes: 16 additions & 0 deletions InfoPanel.Plugins.Simulator/InfoPanel.Plugins.Simulator.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\InfoPanel.Plugins.Loader\InfoPanel.Plugins.Loader.csproj" />
<ProjectReference Include="..\InfoPanel.Plugins\InfoPanel.Plugins.csproj" />
<ProjectReference Include="..\InfoPanel.VolumePlugin\InfoPanel.Extras.csproj" />
</ItemGroup>

</Project>
50 changes: 50 additions & 0 deletions InfoPanel.Plugins.Simulator/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using InfoPanel.Plugins;
using InfoPanel.Plugins.Loader;

PluginLoader pluginLoader = new();

//\InfoPanel\InfoPanel.Plugins.Simulator\bin\Debug\net8.0-windows
var plugins = pluginLoader.InitializePlugin("..\\..\\..\\..\\InfoPanel.VolumePlugin\\bin\\x64\\Debug\\net8.0-windows\\InfoPanel.Extras.dll");

List<IPlugin> loadedPlugins = [];

foreach (var plugin in plugins)
{
loadedPlugins.Add(plugin);
plugin.Initialize();
}

new Task(async () =>
{
while (true)
{
foreach (var plugin in loadedPlugins)
{
await plugin.UpdateAsync();
}
await Task.Delay(300);
}
}).Start();

while (true)
{
Console.Clear();

foreach (var plugin in loadedPlugins)
{
Console.Write("-");
Console.WriteLine($"{plugin.Name} ({plugin.GetType().FullName})");
var panelDatas = plugin.GetData();

foreach (var panelData in panelDatas)
{
Console.Write("--");
Console.WriteLine($"{panelData.Name}: {panelData.Value}{panelData.Unit}");
}

Console.WriteLine();
}

Thread.Sleep(10);
}

11 changes: 11 additions & 0 deletions InfoPanel.Plugins/IPlugin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace InfoPanel.Plugins
{
public interface IPlugin
{
string Name { get; }
void Initialize();
List<IPluginSensor> GetData();
Task UpdateAsync();
void Close();
}
}
23 changes: 23 additions & 0 deletions InfoPanel.Plugins/IPluginSensor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InfoPanel.Plugins
{
public enum IPluginSensorValueType
{
Double,
String
}

public interface IPluginSensor
{
string Id { get; }
string Name { get; }
IPluginSensorValueType ValueType { get; }
object Value { get; set; }
string? Unit { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>

</Project>
28 changes: 28 additions & 0 deletions InfoPanel.VolumePlugin/InfoPanel.Extras.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnableDynamicLoading>true</EnableDynamicLoading>
<Platforms>x64</Platforms>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ini-parser" Version="2.5.2" />
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
<PackageReference Include="OpenWeatherMap.Standard" Version="3.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\InfoPanel.Plugins\InfoPanel.Plugins.csproj">
<Private>false</Private>
<ExcludeAssets>runtime</ExcludeAssets>
</ProjectReference>
</ItemGroup>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="if not exist &quot;$(SolutionDir)InfoPanel\bin\$(Platform)\$(ConfigurationName)\$(TargetFramework)\plugins&quot; mkdir &quot;$(SolutionDir)InfoPanel\bin\$(Platform)\$(ConfigurationName)\$(TargetFramework)\plugins&quot;&#xD;&#xA;xcopy &quot;$(TargetDir)$(TargetFileName)&quot; &quot;$(SolutionDir)InfoPanel\bin\$(Platform)\$(ConfigurationName)\$(TargetFramework)\plugins&quot; /Y /I&#xD;&#xA;" />
</Target>

</Project>
35 changes: 35 additions & 0 deletions InfoPanel.VolumePlugin/VolumePlugin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using InfoPanel.Plugins;
using NAudio.CoreAudioApi;

namespace InfoPanel.Extras
{
public class VolumePlugin : IPlugin
{
private MMDeviceEnumerator? _deviceEnumerator;
private readonly VolumeSensor _volumeSensor = new();

string IPlugin.Name => "Volume Plugin";

void IPlugin.Initialize()
{
_deviceEnumerator = new MMDeviceEnumerator();
}

void IPlugin.Close()
{
_deviceEnumerator?.Dispose();
}

List<IPluginSensor> IPlugin.GetData()
{
return [_volumeSensor];
}

Task IPlugin.UpdateAsync()
{
using var defaultDevice = _deviceEnumerator?.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
_volumeSensor.Value = Math.Round((defaultDevice?.AudioEndpointVolume.MasterVolumeLevelScalar ?? 0) * 100);
return Task.CompletedTask;
}
}
}
19 changes: 19 additions & 0 deletions InfoPanel.VolumePlugin/VolumeSensor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using InfoPanel.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InfoPanel.Extras
{
internal class VolumeSensor() : IPluginSensor
{
public string Id => "volume";
public string Name => "Master Volume";
public IPluginSensorValueType ValueType => IPluginSensorValueType.Double;
public object Value { get; set; } = 0;
public string? Unit => "%";

}
}
Loading

0 comments on commit b40156b

Please sign in to comment.