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.extension; 23 24 private import std.algorithm; 25 private import std.variant; 26 import std.typecons : Proxy; 27 28 private import hunt.cache; 29 private import witchcraft; 30 31 private import dxx.util; 32 private import dxx.app.plugin; 33 34 struct ExtensionPointDesc { 35 string id; 36 string symbolicName; 37 string description; 38 string url; 39 //void*[string] executableExtensions; 40 ConfigurationElement[string] configuration; 41 } 42 43 interface ExtensionPoint { 44 //const(string) id(); 45 inout(ExtensionPointDesc) desc() inout; 46 } 47 48 struct ConfigurationElement { 49 enum ElementType { 50 STRING_VAL, 51 INT_VAL, 52 FLOAT_VAL, 53 ARRAY_VAL, 54 // the xp parameter is an instance of a given type 55 // hosted by the plugin exposing the extension point. 56 TYPE_VAL, 57 // the xp parameter represents a static method in the exposing plugin. 58 METHOD_VAL 59 } 60 @property 61 ElementType elementType; 62 @property 63 string id; 64 @property 65 Variant[string] attr; 66 @property 67 ConfigurationElement[] children; 68 @property 69 ConfigurationElement* parent; 70 @property 71 ExtensionPointDesc* extensionPoint; 72 } 73 74 struct ExtensionDesc { 75 string id; 76 string symbolicName; 77 string extensionPoint; 78 string description; 79 string url; 80 //void* delegate(string id) createExecutableExtension; 81 //ConfigurationElement[string] configuration; 82 //void* createExecutableExtension(string id){ 83 // return null; 84 //} 85 //void*[string] executableExtensions; 86 ConfigurationSetting[] settings; 87 } 88 89 struct ConfigurationSetting { 90 ExtensionDesc* extension; 91 ConfigurationElement* element; 92 Variant value; 93 } 94 95 interface Extension { 96 inout(ExtensionDesc) desc() inout; 97 } 98 99 struct ExtensionEvent { 100 enum Type { 101 Register,Unregister 102 }; 103 @property 104 Type eventType; 105 @property 106 string pluginId; 107 @property 108 ExtensionDesc* extension; 109 } 110 111 interface ExecutableExtensionType { 112 string executableType(); 113 //Variant executable(); 114 //Variant methods(); 115 Method[] methods(); 116 Variant create(); 117 } 118 119 interface ExecutableExtension { 120 ExecutableExtensionType executableType(); 121 Variant object(); 122 } 123 124 mixin template exportExecutableExtension(T) { 125 void exportExecutableExtension(string id,string pluginId) { 126 // register the export with the injector 127 } 128 } 129 130 mixin template importExecutableExtension(alias T) { 131 void importExecutableExtension(string id,string pluginId) { 132 // register the import with the injector 133 } 134 } 135 136 interface ExtensionsManager : NotificationSource { 137 void registerExtensionPoint(ExtensionPointDesc* xp,string pluginId); 138 void registerExecutableExtensionType(ExtensionPointDesc* xp,string pluginId,string id,ConfigurationElement elem); 139 ExecutableExtensionType findExecutableExtensionType(string type,string pluginId); 140 Variant createExecutableExtension(string stype,string pluginId,string id); 141 void unregisterExtensionPoint(ExtensionPointDesc* xp,string pluginId); 142 void registerExtension(ExtensionDesc* x,string pluginId); 143 void unregisterExtension(ExtensionDesc* x,string pluginId); 144 } 145 146 final class _ExtensionsManager : SyncNotificationSource,ExtensionsManager { 147 static class _Event { 148 ExtensionEvent ev; 149 this(ExtensionEvent.Type evType,string pluginId,ExtensionDesc* x) { 150 ev=ExtensionEvent(evType,pluginId,x); 151 } 152 }; 153 class _ExecutableExtension(T) : T,ExecutableExtension { 154 T ext; 155 mixin Witchcraft; 156 157 string executableType() { 158 return typeid(T); 159 } 160 void* executable() { 161 return &this; 162 } 163 this(T* t,string pluginId) { 164 ext=t; 165 // executableExtensionTypes[pluginId][typeid(T)] = this; 166 } 167 } 168 class _ExecutableExtensionType(T) : ExecutableExtensionType { 169 string executableType() { 170 return typeid(T); 171 } 172 this(string pluginId) { 173 executableExtensionTypes[pluginId][typeid(T)] = this; 174 } 175 } 176 ExecutableExtensionType[string][string] executableExtensionTypes; 177 Cache xpCache; 178 Cache xCache; 179 180 void enumerateExtensions(alias T)(string xp) { 181 //extensions.filter!(a => a.desc.extensionPoint == xp).each!(a => T(a)); 182 } 183 void enumerateExtensionPoints(alias T)(string xp) { 184 } 185 this() { 186 xpCache = CacheFactory.create(); 187 xCache = CacheFactory.create(); 188 } 189 void sendExtensionEvent(ExtensionEvent.Type type,string pluginId,ExtensionDesc* x) { 190 auto e = new _Event(type,pluginId,x); 191 //_send!ExtensionEvent(&e.ev); 192 throw new Exception("NYI"); 193 } 194 // 195 void registerExtensionPoint(ExtensionPointDesc* xp,string pluginId) { 196 //xpCache.put(pluginId ~ "." ~ xp.id,xp); 197 foreach(k,v;xp.configuration) { 198 switch(v.elementType) { 199 case ConfigurationElement.ElementType.TYPE_VAL: 200 registerExecutableExtensionType(xp,pluginId,k,v); 201 break; 202 default: 203 break; 204 } 205 } 206 } 207 void registerExecutableExtensionType(ExtensionPointDesc* xp,string pluginId,string id,ConfigurationElement elem) { 208 auto elemType = elem.attr["type"]; 209 210 } 211 ExecutableExtensionType findExecutableExtensionType(string type,string pluginId) { 212 return null; 213 } 214 void unregisterExtensionPoint(ExtensionPointDesc* xp,string pluginId) { 215 //xpCache.remove(pluginId ~ "." ~ xp.id); 216 } 217 void registerExtension(ExtensionDesc* x,string pluginId) { 218 //xCache.put(pluginId ~ "." ~ x.id,x); 219 sendExtensionEvent(ExtensionEvent.Type.Register,pluginId,x); 220 } 221 void unregisterExtension(ExtensionDesc* x,string pluginId) { 222 //xCache.remove(pluginId ~ "." ~ x.id); 223 sendExtensionEvent(ExtensionEvent.Type.Unregister,pluginId,x); 224 } 225 Variant createExecutableExtension(string type,string pluginId,string id) { 226 auto n = pluginId in executableExtensionTypes; 227 if(n) { 228 auto m = type in executableExtensionTypes[pluginId]; 229 if(m) { 230 return createLocalExexcutable(id,executableExtensionTypes[pluginId][type]); 231 } 232 } 233 return Variant(null); 234 } 235 Variant createLocalExexcutable(string id,ExecutableExtensionType extType) { 236 //executableType 237 return Variant(null); 238 } 239 240 version(DXX_Plugin) { 241 // The plugin version of the manager is just a stub that reflects to 242 // the host. However it exposes the notification interface to the plugin 243 // and registration events are sent only to the container plugin. 244 // The host receiver gets a notification signal on all registration events. 245 auto getPlugin() { 246 return PluginDefault.getInstance; 247 } 248 } else { 249 250 } 251 252 }