2 const fs = require('fs');
3 const path = require('path');
4 const extension_debug = require('debug')('EXTENSION');
5 const MANIFEST_FILE = 'manifest.json';
6 const PRELOAD_JS_FILE = 'preload.js';
7 const EXTENSIONS_DB_FILE = 'extensions_db.json';
11 const {BrowserWindow} = require('electron');
13 var EXTENSIONS_PATH = process.env.WAS_EXTENSIONS_PATH;
14 if (!EXTENSIONS_PATH) {
15 var resourcePath = __dirname.split('app.asar')[0];
16 extension_debug('WARNING! WAS_EXTENSIONS_PATH not set - extensions cannot be loaded');
17 EXTENSIONS_PATH = path.join(resourcePath, 'runtime_addon');
18 extension_debug('Temporarily set WAS_EXTENSIONS_PATH=' + EXTENSIONS_PATH);
21 class ExtensionManager {
23 constructor(ext_path) {
24 if (!ext_path) ext_path = EXTENSIONS_PATH;
25 this.ext_path_ = ext_path;
26 this.extensions_list_ = null;
27 this.extensions_ = null;
28 this.extensions_API_ = null;
32 extension_debug('==========printAPIs==========');
33 for (var namespace in this.extensions_API_) {
34 extension_debug('namespace: ' + namespace);
35 for (var entry_symbol in this.extensions_API_[namespace]) {
36 extension_debug('extensions_API[' + namespace + '][' + entry_symbol + '] = ' + this.extensions_API_[namespace][entry_symbol]);
39 extension_debug('==========printAPIs==========');
42 loadExtensionsListFromPath() {
43 var extensions_list = [],
46 filenames = fs.readdirSync(this.ext_path_);
48 extension_debug('LoadExtensionsListFromPath - fs.readdirSync error : ' + e);
52 for (var i in filenames) {
53 var filename = filenames[i],
54 filepath = path.join(this.ext_path_, filename),
55 stats = fs.statSync(filepath);
57 if (stats.isDirectory()) {
59 manifest_path = path.join(filepath, MANIFEST_FILE);
62 manifest_obj = JSON.parse(fs.readFileSync(manifest_path));
64 extension_debug('LoadExtensionsListFromPath - error : ' + e);
67 var extension = new Object();
69 extension.name = manifest_obj.name;
70 extension.path = filepath;
71 if (manifest_obj.type) {
72 extension.type = manifest_obj.type;
74 extension.type = 'WRT';
76 extension.activate = true; // activate by default
77 extensions_list.push(extension);
81 this.extensions_list_ = extensions_list;
82 extension_debug('LoadExtensionsListFromPath ; ' + JSON.stringify(this.extensions_list_));
88 db_path = path.join(this.ext_path_, EXTENSIONS_DB_FILE);
92 extensions_list = JSON.parse(fs.readFileSync(db_path));
94 extension_debug('LoadJsonDB - open error : ' + e);
96 // For DEBUG purpose (load extensions from PATH, not via INSTALLER)
97 //return this.loadExtensionsListFromExtPath();
99 this.extensions_list_ = extensions_list;
103 saveJsonDB(db_path) {
105 db_path = path.join(this.ext_path_, EXTENSIONS_DB_FILE);
109 fd = fs.openSync(db_path, 'w');
111 extension_debug('SaveJsonDB - open error : ' + e);
114 fs.writeSync(fd, JSON.stringify(this.extensions_list_));
119 generateJsFromAPIs(js_path) {
121 js_path = path.join(this.ext_path_, PRELOAD_JS_FILE);
123 extension_debug('preload.js : ' + js_path);
126 fd = fs.openSync(js_path, 'w');
128 extension_debug('GenerateJsFromAPIs - open error : ' + e);
131 // Introduction Comments & preset
132 var comments = '// Auto-generated code by extensions_installer\n// Generated from “entry_points” field in package.json\n// var <entry_points_symbol> = <entry_points_class>;\n';
133 var preset = '\nvar EXTENSIONS_PATH = process.env.WAS_EXTENSIONS_PATH;\n';
134 fs.writeSync(fd, comments + preset);
136 for (var namespace in this.extensions_API_) {
137 if (namespace != '_default_') {
138 fs.writeSync(fd, '\n//namespace\n');
139 fs.writeSync(fd, 'var ' + namespace + ' = new Object();\n');
140 // namespace.entry_points
141 fs.writeSync(fd, '\n//namespace.entry_points\n');
142 for (var entry_symbol in this.extensions_API_[namespace]) {
143 fs.writeSync(fd, namespace + '.' + entry_symbol + ' = require("' + this.extensions_API_[namespace][entry_symbol] + '");\n');
146 fs.writeSync(fd, '\n//attach to window\n');
147 fs.writeSync(fd, 'window.' + namespace + ' = ' + namespace + ';\n');
148 } else { // '_default_'
149 // entry_points and attach to root
150 fs.writeSync(fd, '\n//default namespace - entry_points and attach to window\n');
151 /*eslint no-redeclare: 1*/
152 for (var entry_symbol in this.extensions_API_[namespace]) {
153 fs.writeSync(fd, 'window.' + entry_symbol + ' = require("' + this.extensions_API_[namespace][entry_symbol] + '");\n');
162 // 0. load extensions_list_ from JSON DB
165 var extensions_API = [];
166 // 1. load extensions from extension_list_
167 if (this.extensions_list_) {
168 for (var i in this.extensions_list_) {
169 var extension = this.extensions_list_[i];
170 if (extension.activate == false) {
174 var manifest_obj, manifest_path = path.join(extension.path, MANIFEST_FILE);
175 manifest_obj = JSON.parse(fs.readFileSync(manifest_path));
176 extension_debug('manifest_obj : ' + JSON.stringify(manifest_obj));
177 if (manifest_obj.type && manifest_obj.type.toUpperCase() === 'INSTALLER') {
178 // do nothing for installer extension
179 extension_debug('ExtensionManager.build ' + manifest_obj.name + ' is for installer - SKIP');
181 } else if (manifest_obj.type && manifest_obj.type.toUpperCase() === 'API') {
182 var namespace = manifest_obj.namespace;
184 namespace = '_default_';
186 if (!extensions_API[namespace]) {
187 extensions_API[namespace] = [];
189 for (var entry_it in manifest_obj.entry_points) {
190 for (var entry_symbol in manifest_obj.entry_points[entry_it]) {
191 var module_path = manifest_obj.entry_points[entry_it][entry_symbol];
192 if (extensions_API[namespace][entry_symbol]) {
193 extension_debug('extensions_API[' + namespace + '][' + entry_symbol + '] already registered :' + extensions_API[namespace][entry_symbol]);
196 extensions_API[namespace][entry_symbol] = path.join(extension.path, module_path);
197 extension_debug('extensions_API[' + namespace + '][' + entry_symbol + '] registered :' + extensions_API[namespace][entry_symbol]);
202 if (manifest_obj.main) {
207 if (!extensions[type]) {
208 extensions[type] = [];
210 if (extensions[type][manifest_obj.name]) {
211 extension_debug('extensions[' + type + '][' + manifest_obj.name + '] already registered : ' + extensions[type][manifest_obj.name]);
214 if (manifest_obj.main) {
215 extensions[type][manifest_obj.name] = path.join(extension.path, manifest_obj.main);
217 extensions[type][manifest_obj.name] = extension.path;
220 extension_debug('extensions[' + type + '][' + manifest_obj.name + '] = ' + extensions[type][manifest_obj.name] + ' registered');
222 extension_debug('ExtensionManager.build error - ' + e);
226 if (this.extensions_ != null) {
227 delete this.extensions_;
228 this.extensions_ = null;
230 if (this.extensions_API_ != null) {
231 delete this.extensions_API_;
232 this.extensions_API_ = null;
234 this.extensions_ = extensions;
235 this.extensions_API_ = extensions_API;
236 return this.extensions_;
239 activate(event_emitter, name) {
240 if (!this.extensions_) {
243 var extension, extension_path = null;
244 if (this.extensions_[T_WRT] !== undefined && this.extensions_[T_WRT][name] !== undefined) {
245 extension_path = this.extensions_[T_WRT][name];
246 extension_debug('activate: ' + extension_path + ' name:' + name);
248 extension = require(extension_path);
250 extension_debug('activate - error on require() : ' + e);
253 if (extension && extension.activate) {
254 extension.activate(event_emitter);
256 else extension_debug('extension.activate not defined!');
257 } else if (this.extensions_[T_CRX] !== undefined && this.extensions_[T_CRX][name] !== undefined) {
258 extension_path = this.extensions_[T_CRX][name];
259 extension_debug('activate 22: ' + extension_path + ' name:' + name);
261 BrowserWindow.addExtension(extension_path);
263 extension_debug('activate - error on addExtension() : ' + e);
269 deactivate(event_emitter, name) {
270 if (!this.extensions_) {
273 extension_debug('deactivate: name:' + name);
274 var extension, extension_path = null;
275 if (this.extensions_[T_WRT] !== undefined && this.extensions_[T_WRT][name] !== undefined) {
277 extension_path = this.extensions_[T_WRT][name];
279 extension_debug('deactivate - error : ' + e);
282 extension_debug('deactivate: path:' + extension_path);
284 extension = require(extension_path);
286 extension_debug('deactivate - error on require() : ' + e);
288 if (extension && extension.deactivate) {
289 extension.deactivate(event_emitter);
291 extension_debug('extension.deactivate not defined!');
293 } else if (this.extensions_[T_CRX] !== undefined && this.extensions_[T_CRX][name] !== undefined) {
294 extension_path = this.extensions_[T_CRX][name];
296 BrowserWindow.removeExtension(name);
298 extension_debug('activate - error on removeExtension() : ' + e);
303 activateAll(event_emitter) {
304 if (!this.extensions_) {
305 extension_debug('activateAll - extensions not built');
308 for (var name in this.extensions_[T_WRT]) {
309 this.activate(event_emitter, name);
311 for (var name in this.extensions_[T_CRX]) {
312 this.activate(event_emitter, name);
316 deactivateAll(event_emitter) {
317 if (!this.extensions_) {
318 extension_debug('deactivateAll - extensions not built');
321 for (var name in this.extensions_[T_WRT]) {
322 this.deactivate(event_emitter, name);
324 for (var name in this.extensions_[T_CRX]) {
325 this.deactivate(event_emitter, name);
329 static getManifestFile() {
330 return MANIFEST_FILE;
333 static getPreloadJsFile() {
334 return PRELOAD_JS_FILE;
337 static getExtensionsPath() {
338 return EXTENSIONS_PATH;
342 module.exports = ExtensionManager;