--- /dev/null
+[
+ {
+ "name":"tizen.filesystem",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_filesystem.so",
+ "entry_points": []
+ },
+ {
+ "name":"tizen.messageport",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_messageport.so",
+ "entry_points": []
+ },
+ {
+ "name":"tizen",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen.so",
+ "entry_points": []
+ },
+ {
+ "name":"tizen.datacontrol",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_datacontrol.so",
+ "entry_points": []
+ },
+ {
+ "name":"tizen.application",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_application.so",
+ "entry_points": ["tizen.ApplicationControl","tizen.ApplicationControlData"]
+ },
+ {
+ "name":"tizen.time",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_time.so",
+ "entry_points": ["tizen.TZDate","tizen.TimeDuration"]
+ },
+ {
+ "name":"xwalk",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_utils.so",
+ "entry_points": []
+ },
+ {
+ "name":"tizen.systeminfo",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_systeminfo.so",
+ "entry_points": []
+ },
+ {
+ "name":"tizen.package",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_package.so",
+ "entry_points": []
+ },
+ {
+ "name":"tizen.alarm",
+ "lib":"/usr/lib/tizen-extensions-crosswalk/libtizen_alarm.so",
+ "entry_points": ["tizen.AlarmRelative","tizen.AlarmAbsolute"]
+ }
+]
--- /dev/null
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function() {
+const extension = require('./wrt_service_extension');
+const wrt = require('../browser/wrt');
+var window = global;
+var api_ = {};
+var extensions_ = {};
+var runtime_variables_ = {'runtime_name': 'wrt-service'};
+
+var ExtensionLoader = function() {
+ let plugins = require('./plugins.json');
+ extension.initialize(runtime_variables_);
+
+ var extensions = extension.getExtensions();
+ for (var i = 0; i < extensions.length; i++) {
+ extensions[i].loaded = false;
+ for (var idx in plugins) {
+ if (extensions[i].name === plugins[idx].name) {
+ console.log("ExtensionLoader name " + extensions[i].name);
+ extensions_[extensions[i].name] = extensions[i];
+ }
+ }
+ }
+ for (var name in extensions_) {
+ if (!extensions_[name].use_trampoline) {
+ this.load(extensions_[name]);
+ }
+ }
+ for (var name in extensions_) {
+ if (extensions_[name].use_trampoline) {
+ this.installTrampoline(extensions_[name]);
+ }
+ }
+};
+
+ExtensionLoader.prototype = {
+ /**
+ * Creates namespace for 'name' in given object.
+ * Eg. this.createNamespace(GLOBAL, 'tizen.contact') will create:
+ * GLOBAL.tizen.contact = {}
+ *
+ * @param {Object} object
+ * @param {String} name
+ */
+ createNamespace: function(object, name) {
+ var obj = object;
+ var arr = name.split('.');
+ for (var i = 0; i < arr.length; i++) {
+ obj[arr[i]] = obj[arr[i]] || {};
+ obj = obj[arr[i]];
+ }
+ },
+ exposeApi: function (ext) {
+ var i, entry_points, entry_point, tmp, parent_name, base_name;
+
+ // additional entry points are installed in GLOBAL context by eval()
+ // so we need to move it to protected api_ object first
+ entry_points = [...new Set(ext.entry_points)];
+ for (i = 0; i < entry_points.length; i++) {
+ entry_point = entry_points[i];
+ tmp = entry_point.split('.');
+ parent_name = tmp[0];
+ base_name = tmp[tmp.length - 1];
+
+ api_[parent_name][base_name] = GLOBAL[parent_name][base_name];
+ delete GLOBAL[parent_name][base_name];
+ }
+
+ entry_points.push(ext.name);
+
+ for (i = 0; i < entry_points.length; i++) {
+ entry_point = entry_points[i];
+ tmp = entry_point.split('.');
+ parent_name = tmp[0];
+ base_name = tmp[tmp.length - 1];
+
+ Object.defineProperty(GLOBAL[parent_name], base_name, {
+ get: function (parent_name, base_name) {
+ return function () {
+ return api_[parent_name][base_name];
+ }
+ }(parent_name, base_name),
+ configurable: false,
+ enumerable: true
+ });
+ }
+ },
+
+ /**
+ * @param {Object} ext
+ */
+ load: function(ext) {
+ if (ext.loaded) {
+ return;
+ }
+ ext.loadInstance();
+
+ ext.loaded = true;
+
+ this.createNamespace(api_, ext.name);
+ this.createNamespace(GLOBAL, ext.name);
+
+ var api = (ext.use_trampoline) ? api_ : GLOBAL;
+
+ var jscode =
+ '(function(extension) {' +
+ ' extension.internal = {};' +
+ ' extension.internal.sendSyncMessage = extension.sendSyncMessage;' +
+ ' delete extension.sendSyncMessage;' +
+ ' var exports = {}; ' +
+ ' (function() {\'use strict\'; ' + ext.jsapi + '})();' +
+ ' api.' + ext.name + ' = exports; ' +
+ '});';
+
+ try {
+ var func = eval(jscode);
+ func({
+ postMessage: function(msg) {
+ return ext.postMessage(msg);
+ },
+ sendSyncMessage: function(msg) {
+ return ext.sendSyncMessage(msg);
+ },
+ setMessageListener: function(fn) {
+ return ext.setMessageListener(fn);
+ },
+ sendRuntimeMessage: function(type, data) {
+ return runtimeMessageHandler(type, data);
+ },
+ sendRuntimeSyncMessage: function(type, data) {
+ return runtimeMessageHandler(type, data);
+ },
+ sendRuntimeAsyncMessage: function(type, data, callback) {
+ return runtimeMessageHandler(type, data, callback);
+ },
+ postData: function(msg, chunk) {
+ return ext.postData(msg, chunk);
+ },
+ sendSyncData: function(msg, chunk) {
+ return ext.sendSyncData(msg, chunk);
+ },
+ setDataListener: function(fn) {
+ return ext.setDataListener(fn);
+ },
+ receiveChunkData: function(id, type) {
+ return ext.receiveChunkData(id, type);
+ }
+ });
+
+ if (ext.use_trampoline) {
+ this.exposeApi(ext);
+ }
+ } catch (err) {
+ console.log('Error loading extension "' + ext.name + '": ' + err.message);
+ }
+ },
+
+ /**
+ * This is used to defer extension loading to it's first usage.
+ * Eg. First access to tizen.contact will load extension's 'jsapi' through eval().
+ *
+ * @param {Object} ext
+ */
+ installTrampoline: function(ext) {
+ var entry_points = [...new Set(ext.entry_points)];
+ entry_points.push(ext.name);
+ for (var i = 0; i < entry_points.length; i++) {
+ var tmp = entry_points[i].split('.');
+ var parent_name = tmp[0];
+ var base_name = tmp[tmp.length - 1];
+
+ this.createNamespace(GLOBAL, entry_points[i]);
+
+ Object.defineProperty(GLOBAL[parent_name], base_name, {
+ get: function (parent_name, base_name) {
+ return function() {
+ try {
+ this.deleteTrampoline(ext);
+ this.load(ext);
+ return api_[parent_name][base_name];
+ } catch (e) {
+ console.log(e.stack);
+ }
+ }.bind(this);
+ }.call(this, parent_name, base_name),
+ enumerable: true
+ });
+ }
+ },
+
+ deleteTrampoline: function(ext) {
+ var entry_points = [...new Set(ext.entry_points)];
+ entry_points.push(ext.name);
+
+ for (var i = 0; i < entry_points.length; i++) {
+ var tmp = entry_points[i].split('.');
+ var parent_name = tmp[0];
+ var base_name = tmp[tmp.length - 1];
+ delete GLOBAL[parent_name][base_name];
+ }
+ }
+};
+
+new ExtensionLoader();
+})();