-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathPluginManagerBase.cs
193 lines (185 loc) · 6.22 KB
/
PluginManagerBase.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;
namespace FSClient {
[XmlRoot("SettingsPluginDataCollection")]
public class SettingsPluginDataCollection {
public SettingsPluginData[] data { get; set; }
[XmlRoot("SettingsPluginData")]
public class SettingsPluginData {
public string dll { get; set; }
public bool enabled { get; set; }
public SettingsPluginData() { }
public SettingsPluginData(PluginManagerBase.PluginData data) {
dll = data.dll;
enabled = data.enabled;
}
public PluginManagerBase.PluginData GetPluginData() {
return new PluginManagerBase.PluginData() { dll = dll, enabled = enabled };
}
}
public SettingsPluginDataCollection() {
}
public SettingsPluginDataCollection(IEnumerable<PluginManagerBase.PluginData> plugins) {
data = (from p in plugins select new SettingsPluginData(p)).ToArray();
}
}
public abstract class PluginManagerBase : IDisposable {
public class PluginData {
public string dll { get; set; }
public bool enabled { get; set; }
public enum PluginDataState { MISSING, SKIPPED, ERROR_LOADING, LOADED, DISABLED_ERROR };
public PluginDataState state;
public string last_error;
[System.Xml.Serialization.XmlIgnoreAttribute]
public virtual IPlugin plugin { get; set; }
public PluginData() {
enabled = true;
state = PluginDataState.MISSING;
}
public PluginData(PluginData data) {
dll = data.dll;
enabled = data.enabled;
state = data.state;
plugin = data.plugin;
last_error = data.last_error;
}
}
protected virtual void LoadSettings(SettingsPluginDataCollection settings) {
SetPlugins(settings.data.Select(settings_data => settings_data.GetPluginData()).ToArray());
}
public abstract void LoadPlugins();
private static List<PossiblePlugin> possible_plugins;
private class PossiblePlugin {
private IEnumerable<Type> _types;
public IEnumerable<Type> types {
get {
if (!loaded_types)
LoadTypes();
return _types;
}
}
public PossiblePlugin(String full_dll) {
this.full_dll = full_dll;
file_info = new FileInfo(full_dll);
}
private string full_dll { get; set; }
public FileInfo file_info;
private Assembly _asm;
private bool loaded_types = false;
public Assembly asm {
get {
if (!loaded_types)
LoadTypes();
return _asm;
}
}
private void LoadTypes() {
loaded_types = true;
_asm = Assembly.LoadFrom(full_dll);
if (asm == null)
return;
_types = asm.GetTypes();
}
}
private static void PluginScan() {
if (possible_plugins != null)
return;
possible_plugins = new List<PossiblePlugin>();
String plugin_dir = Utils.plugins_dir();
string[] dlls;
try {
if (Directory.Exists(plugin_dir)) {
dlls = Directory.GetFileSystemEntries(plugin_dir, "*Plugin.dll");
foreach (String full_dll in dlls)
possible_plugins.Add(new PossiblePlugin(full_dll));
}
}
catch (DirectoryNotFoundException) {
return;
}
}
protected void LoadActualPlugins(String file_end, Type plugin_type, IEnumerable<PluginData> plugins) {
PluginScan();
file_end += "Plugin.dll";
foreach (PossiblePlugin pos_plug in possible_plugins) {
String dll = pos_plug.file_info.Name;
if (!dll.EndsWith(file_end, StringComparison.CurrentCultureIgnoreCase))
continue;
PluginData data = (from p in plugins where p.dll == dll select p).SingleOrDefault();
bool add_to_list = false;
if (data == null) {
add_to_list = true;
data = NewPluginData(dll);
data.dll = dll;
}
if (data.enabled == false && !add_to_list) { //if not yet on the list we have to continue to see if we should be on the list
data.state = PluginData.PluginDataState.SKIPPED;
continue;
}
try {
Assembly asm = pos_plug.asm;
if (asm == null || pos_plug.types == null)
continue;
foreach (Type type in pos_plug.types) {
if (type.IsAbstract)
continue;
if (!IsTypeOf(type, plugin_type))
continue;
if (add_to_list)
PluginLoadAddPlugin(data);
if (data.enabled == false) {
data.state = PluginData.PluginDataState.SKIPPED;
continue;
}
data.plugin = asm.CreateInstance(type.FullName) as IPlugin;
PluginLoadRegisterPlugin(data);
}
}
catch (ReflectionTypeLoadException ex) {
HandlePluginLoadReflectionException(data, ex);
}
catch (Exception e) {
HandlePluginLoadException(data, e);
}
}
}
public abstract string PluginManagerName();
protected abstract void PluginLoadAddPlugin(PluginData plugin);
protected abstract void PluginLoadRegisterPlugin(PluginData plugin);
protected abstract PluginData NewPluginData(String dll);
protected virtual void HandlePluginLoadReflectionException(PluginData data, ReflectionTypeLoadException ex) {
String err = "Error creating plugin from dll \"" + data.dll + "\" due to a loader exception error was:\n";
foreach (Exception e in ex.LoaderExceptions)
err += e.Message + "\n";
data.last_error = err;
data.state = PluginData.PluginDataState.ERROR_LOADING;
Utils.PluginLog(PluginManagerName(), err);
}
protected virtual void HandlePluginLoadException(PluginData data, Exception e) {
String err = "Error creating plugin from dll \"" + data.dll + "\" of: " + e.Message;
data.last_error = err;
data.state = PluginData.PluginDataState.ERROR_LOADING;
Utils.PluginLog(PluginManagerName(), err);
}
protected bool IsTypeOf(Type to_check, Type of) {
if (to_check == null)
return false;
if (to_check == of)
return true;
return IsTypeOf(to_check.BaseType, of);
}
public virtual SettingsPluginDataCollection GetSettings() {
return new SettingsPluginDataCollection(GetPlugins());
}
public abstract IEnumerable<PluginData> GetPlugins();
protected abstract void SetPlugins(IEnumerable<PluginData> plugins);
public virtual void SetPluginEnabled(bool enabled, PluginData plugin) {
plugin.enabled = enabled;
}
public abstract void Dispose();
}
}