Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | // tslint:disable:forin import { ContainerConstants } from '@medjaibot/framework/constants/ContainerConstants'; import { EventManager } from '@medjaibot/framework/event/EventManager'; import { IsNullOrUndefined } from '@medjaibot/framework/Extras'; import { Logger } from '@medjaibot/framework/logger/Logger'; import { IInitializationContext } from '@medjaibot/framework/plugin/IInitializationContext'; import { InitializationSide } from '@medjaibot/framework/plugin/InitializationSide'; import { IPluginDescriptorFile } from '@medjaibot/framework/plugin/IPluginDescriptorFile'; import { existsSync, readdirSync, readFileSync, statSync } from 'fs'; import { Container, inject, injectable } from 'inversify'; import { resolve } from 'path'; import { Plugin } from './Plugin'; declare var __non_webpack_require__: any; /** * The plugin manager manages plugins * The standard implementation is to load plugins * by a given directory * * @export * @class PluginManager * @since 0.0.1 * @version 0.0.1 * @author Yannick Fricke <yannickfricke@googlemail.com> * @license MIT * @copyright MedjaiBot https://github.com/MedjaiBot/server */ @injectable() export class PluginManager { /** * The plugins which will be managed by the plugin manager * * @type {Plugin[]} * @memberof PluginManager */ public plugins: Plugin[]; /** * The event manager which will be used * * @private * @type {EventManager} * @memberof PluginManager */ public eventManager: EventManager; /** * The logger which will be used * Mostly loaded from the dependency injection container * * @private * @type {Logger} * @memberof PluginManager */ private logger: Logger; /** * The container from the application * * @private * @type {Container} * @memberof PluginManager */ private container: Container; /** * Creates an instance of PluginManager. * @param {Logger} logger The logger which should be used from the dependency injection container * @memberof PluginManager */ constructor( @inject(ContainerConstants.LOGGING.LOGGER) logger: Logger, @inject(ContainerConstants.SYSTEMS.EVENT.EVENTMANAGER) eventManager: EventManager, @inject(ContainerConstants.DI.CONTAINER) container: Container, ) { // Sets the plugin property to an empty array this.plugins = []; // Sets the logger property to the given logger this.logger = logger; // Sets the eventManager property to the given event manager this.eventManager = eventManager; // Set the container this.container = container; } /** * Loads all plugins from the given directory * * @param directory The directory where to load the plugins from * @memberof PluginManager */ public loadPlugins = (directory: string) => { // this.eventManager.broadcast(EventsConstants.Plugin.LoadPlugins); // Checks if the given directory exists on the filesystem if (!existsSync(directory)) { throw new Error(`Directory ${directory} does not exists`); } // Loads the contents of the directory const pluginDirectories = readdirSync(directory); // Iterates over the contents of the directory for (const index in pluginDirectories) { // Gets the current entry from the contents const pluginDirectory = pluginDirectories[index]; const pluginPath = resolve( directory, pluginDirectory, ); const fileStats = statSync(pluginPath); // Check if the current entry is a directory if (!fileStats.isDirectory()) { // Current entry is not a directory so we skip it continue; } // Resolves the given parts into a path as string const pluginJsonFile = resolve(pluginPath, 'plugin.json'); // Checks if the plugin.json file exists if (!existsSync(pluginJsonFile)) { this.logger.warn( `Plugin directory ${pluginDirectory} does not contain a plugin.json. Skipping plugin.`, ); continue; } // The loaded plugin.json file contents let pluginFileContents; try { pluginFileContents = readFileSync(pluginJsonFile).toString(); } catch (error) { this.logger.error('Could not read the contents of the plugin.json file', error); continue; } // Parses the the contents of plugin.json file as JSON const parsedPluginFile: IPluginDescriptorFile = JSON.parse(pluginFileContents); // The main entry file of the parsed plugin file const mainEntry = parsedPluginFile.main; // Checks if the main entry is null or undefined if (IsNullOrUndefined(mainEntry)) { this.logger.debug( `The parsed config key "main" for the plugin ${pluginDirectory} is undefined`, ); continue; } // Check if the main entry wants try to include a file outside of the plugin directory if (mainEntry.includes('..')) { this.logger.debug( 'The main entry must be located inside in the plugin directory', ); } // The plugin structure of the file let plugin; try { // Requires the file which is defined in the "main" key plugin = __non_webpack_require__( resolve( directory, pluginDirectory, mainEntry, )); } catch (error) { this.logger.error(`Could not require plugin ${pluginDirectory}`, error); continue; } if (typeof plugin.default !== 'function') { this.logger.warn(`The default export of the plugin ${pluginDirectory} is not a function`); continue; } this.container.bind('test').to(plugin.default); // The plugin instance // const pluginInstance: Plugin = new plugin.default(); const pluginInstance: Plugin = this.container.get('test'); // Get the initialization side from the container const initializationSide = this.container.get<InitializationSide>( ContainerConstants.SYSTEMS.PLUGIN.INITIALIZATIONSIDE, ); // The context for initializing the plugin const initializationContext: IInitializationContext = { initializationSide, container: this.container, }; try { // Trying to call the onInit function of the plugin pluginInstance.onInit(initializationContext); } catch (error) { this.logger.error(`Could not call onInit for plugin "${pluginDirectory}"`, error); continue; } // Add the plugin to the managed plugins this.plugins.push(pluginInstance); } } } |