1 /** 2 Copyright 2018 Mark Fisher 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy of 5 this software and associated documentation files (the "Software"), to deal in 6 the Software without restriction, including without limitation the rights to 7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 8 of the Software, and to permit persons to whom the Software is furnished to do 9 so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in all 12 copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 SOFTWARE. 21 **/ 22 module dxx.app.plugin; 23 24 private import std.experimental.logger; 25 private import std.exception; 26 27 private import dxx.util; 28 private import dxx.sys.loader; 29 30 private import dxx.app.component; 31 private import dxx.app.extension; 32 private import dxx.app.platform; 33 34 struct PluginDependency { 35 string id; 36 string verRange; 37 bool optional; 38 } 39 40 struct PluginDescriptor { 41 string id; 42 string pluginVersion; 43 string name; 44 string pluginDoc; 45 uint runLevel; 46 string[string] attr; 47 48 PluginDependency[] dependencies; 49 ExtensionPointDesc[]* extensionPoints; 50 ExtensionDesc[]* extensions; 51 } 52 53 struct PluginContext { 54 PluginDescriptor* desc; 55 void* delegate(string id) shared pluginCreateInstance; 56 void delegate(void*) shared pluginDestroyInstance; 57 } 58 59 class PluginLoader { 60 PluginContext ctx; 61 Loader loader; 62 alias loader this; 63 64 static auto pluginFileName(string name,string path) { 65 version(Windows) { 66 return path ~ "/" ~ name ~ ".dll"; 67 } else { 68 return path ~ "/lib" ~ name ~ ".so"; 69 } 70 71 } 72 void load(string path) { 73 debug(Plugin) { 74 MsgLog.info("PluginLoader load " ~ path); 75 } 76 loader = Loader.loadModule(path,&ctx); 77 enforce(loader); 78 } 79 void load(string name,string path) { 80 auto p = pluginFileName(name,path); 81 this.load(p); 82 } 83 inout ref 84 auto desc() { 85 return ctx.desc; 86 } 87 inout ref 88 auto pluginContext() { 89 return ctx; 90 } 91 } 92 93 class PluginRuntime(PluginType : Plugin,Param...) : PlatformRuntime!(Param) { 94 void registerPluginComponents(InjectionContainer injector) { 95 injector.register!(Plugin,PluginType); 96 new PluginDefault.ModuleListener().register; 97 } 98 override void registerAppDependencies(InjectionContainer injector) { 99 debug(Plugin) { 100 import std.experimental.logger; 101 sharedLog.info("registerAppDependencies()"); 102 } 103 super.registerAppDependencies(injector); 104 registerPluginComponents(injector); 105 } 106 } 107 108 mixin template registerPlugin(P : Plugin,Param ...) { 109 version(DXX_Plugin) { 110 mixin registerComponent!(PluginRuntime!(P,Param)); 111 } 112 } 113 114 interface PluginActivator { 115 void activate(PluginContext* ctx); 116 void deactivate(PluginContext* ctx); 117 } 118 119 interface Plugin { 120 // void init(PluginDescriptor* pluginData); 121 enum State { 122 UNINSTALLED,INSTALLED,LOADED,INITIALIZED,STARTED,STOPPED,DEINITIALIZED 123 } 124 const(PluginDescriptor)* descr(); 125 void init(); 126 void deinit(); 127 PluginActivator activator(); 128 } 129 130 abstract class PluginDefault : Plugin { 131 static __gshared Plugin INSTANCE; 132 static __gshared PluginDescriptor DESCR; 133 static bool instantiated = false; 134 135 PluginActivator _activator; 136 137 ExtensionDesc[] extensions; 138 ExtensionPointDesc[] extensionPoints; 139 140 static void setDescr(PluginDescriptor desc) { 141 DESCR = desc; 142 } 143 static auto getInstance() { 144 if(!instantiated) { 145 synchronized(PluginDefault.classinfo) { 146 if(!INSTANCE) { 147 INSTANCE = resolveInjector!Plugin; 148 } 149 } 150 instantiated = true; 151 } 152 return INSTANCE; 153 } 154 //static Plugin getInstance() { 155 // if(INSTANCE is null) { 156 // INSTANCE = resolveInjector!Plugin; 157 // } 158 // return INSTANCE; 159 //} 160 static class ModuleListener : ModuleNotificationListener { 161 override shared void onInit(Module.ModuleEvent* event) { 162 debug(Plugin) { 163 info("onInit"); 164 } 165 event.mod.data!(PluginContext).desc = &DESCR; 166 //event.mod.data!(PluginContext).desc.extensionPoints = &extensionPoints; 167 //event.mod.data!(PluginContext).desc.extensions = &extensions; 168 event.mod.data!(PluginContext).pluginCreateInstance = &createInstance; 169 event.mod.data!(PluginContext).pluginDestroyInstance = &destroyInstance; 170 getInstance.init; 171 } 172 override shared void onDeinit(Module.ModuleEvent* event) { 173 debug(Plugin) { 174 info("onDeinit"); 175 } 176 unregister; 177 } 178 override shared void onLoad(Module.ModuleEvent* event) { 179 debug(Plugin) { 180 info("onLoad"); 181 } 182 } 183 override shared void onUnload(Module.ModuleEvent* event) { 184 debug(Plugin) { 185 info("onUnload"); 186 } 187 if(getInstance.activator !is null) { 188 getInstance.activator.deactivate(event.mod.data!PluginContext); 189 } 190 } 191 override shared void onUpdate(Module.ModuleEvent* event) { 192 debug(Plugin) { 193 info("onUpdate"); 194 } 195 if(getInstance.activator !is null) { 196 getInstance.activator.activate(event.mod.data!PluginContext); 197 } 198 } 199 shared void* createInstance(string id) { 200 auto a = TypeInfo_Class.find(id).create; 201 // TODO use injector 202 return cast(void*)a; 203 } 204 shared void destroyInstance(void* t) { 205 destroy(t); 206 } 207 } 208 209 //shared static this() { 210 // new ModuleListener().register; 211 //} 212 this() { 213 DESCR.extensionPoints = &extensionPoints; 214 DESCR.extensions = &extensions; 215 } 216 override void init() { 217 debug(Pugin) { 218 MsgLog.info("init"); 219 MsgLog.info(descr.id); 220 } 221 } 222 override void deinit() { 223 debug(Pugin) { 224 MsgLog.info("deinit"); 225 MsgLog.info(descr.id); 226 } 227 } 228 override PluginActivator activator() { 229 debug(Pugin) { 230 MsgLog.info("activator"); 231 MsgLog.info(descr.id); 232 } 233 return _activator; 234 } 235 void activator(PluginActivator a) { 236 _activator = a; 237 } 238 239 override const(PluginDescriptor)* descr() { 240 return &DESCR; 241 } 242 243 } 244 245 mixin template pluginMain() { 246 version(unittest) { 247 } else { 248 version(Windows) { 249 private import core.sys.windows.dll; 250 mixin SimpleDllMain; 251 } else { 252 } 253 } 254 }