[Service][UI] Add startService handler
[platform/framework/web/wrtjs.git] / wrt_app / src / runtime.js
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 'use strict';
18
19 const wrt = require('../browser/wrt');  // Load first for log
20 const AddonManager = require('./addon_manager');
21 const {app, ipcMain} = require('electron');
22 const IPC_MESSAGE = require('./ipc_message');
23 const WAS_EVENT = require('./was_event');
24 const WebApplication = require('./web_application');
25
26 class Runtime {
27     constructor(options) {
28         this.webApplication = null;
29         this.handleIpcMessages();
30         this.addonManager = null;
31         this.isLaunched = false;
32         this.inspectorEnabledByVconf = false;
33         this.webContents = null;
34
35         var _this = this;
36         app.on('before-quit', function(event) {
37             console.log('before-quit');
38             if (!wrt.isElectronApp()) {
39                 _this.webApplication.quit(_this.addonManager.evt_emitter_);
40                 _this.webApplication.finalize();
41                 _this.webApplication = null;
42             }
43         });
44         app.on('will-quit', function(event) {
45             console.log('will-quit');
46             _this.addonManager.deactivateAll(app);
47         });
48         app.on('quit', function(event) {
49             console.log('quit');
50             wrt.exit();
51         });
52         app.on('browser-window-blur', function() {
53             console.log('browser-window-blur');
54         });
55         app.on('browser-window-focus', function() {
56             console.log('browser-window-focus');
57         });
58         app.on('browser-window-created', function() {
59             console.log('browser-window-created');
60             if (!_this.isLaunched) {
61                 _this.addonManager.activateAll(app);
62                 _this.isLaunched = true;
63             }
64         });
65         app.on('gpu-process-crashed', function() {
66             console.error('gpu-process-crashed');
67         });
68         app.on('window-all-closed', function(event) {
69             console.log('window-all-closed');
70             app.quit();
71         });
72         app.on('will-finish-launching', function(event) {
73             console.log('will-finish-launching');
74         });
75         app.on('web-contents-created', function(event, webContents) {
76             console.log('web-contents-created');
77             _this.webContents = webContents;
78             _this.webContents.on('before-input-event', function(event, input) {
79                 if (_this.isLaunched && _this.webApplication) {
80                     _this.handleKeyEvents(input.key);
81                 }
82             });
83         });
84         app.once('ready', function(event) {
85             console.log('ready');
86             _this.addonManager = new AddonManager();
87             if (!options.noAddons) {
88                 _this.addonManager.build();
89             }
90             wrt.importCertificate('');
91         });
92         wrt.on('app-control', function(event, appControl) {
93             console.log('app-control');
94             let loadInfo = appControl.getLoadInfo();
95             let src = loadInfo.getSrc();
96
97             if (wrt.isElectronApp()) {
98                 console.log('Electron App launch');
99                 const Module = require('module');
100                 Module.globalPaths.push(wrt.getAppPath());
101                 let filePath = src[7] === '/' ? src.substr(8) : src.substr(7); // strip "file://"
102                 let pkgJson = require(filePath);
103                 let pos = filePath.lastIndexOf('/');
104
105                 let mainJsPath = (pos !== -1 ? filePath.substr(0, pos + 1) : '') +
106                                  (pkgJson.main || 'index.js');
107                 console.log('loading path:', mainJsPath);
108                 Module._load(mainJsPath, Module, true);
109                 app.emit('ready');
110             } else {
111                 console.log('Tizen Web App launch');
112                 let launchMode = appControl.getData('http://samsung.com/appcontrol/data/launch_mode');
113                 if (!_this.webApplication) {
114                     console.log('Creating WebApplication');
115                     options.isAddonAvailable = !options.noAddons &&
116                             _this.addonManager.isAddonAvailable();
117                     options.launchMode = launchMode;
118                     _this.webApplication = new WebApplication(options);
119                     _this.inspectorEnabledByVconf = wrt.needUseInspector();
120                     if (_this.inspectorEnabledByVconf && launchMode != 'backgroundExecution') {
121                         _this.webApplication.inspectorSrc = src;
122                         src = "about:blank";
123                     }
124                     _this.webApplication.mainWindow.loadURL(src);
125                     _this.webApplication.prelaunch(_this.addonManager.evt_emitter_, src);
126                 } else {
127                     console.log('Handling app-control event');
128                     if (_this.webApplication.preloadStatus == 'readyToShow') {
129                         _this.webApplication.show();
130                     } else {
131                         if (launchMode != 'backgroundAtStartup') {
132                             _this.webApplication.preloadStatus = 'none';
133                         }
134                     }
135
136                     let skipReload = appControl.getData('SkipReload');
137                     if (skipReload == 'Yes') {
138                         console.log('skipping reload');
139                         // TODO : Need to care this situation and decide to pass the addon event emitter to resume()
140                         _this.webApplication.resume();
141                         return;
142                     }
143
144                     let reload = loadInfo.getReload() || _this.webApplication.isAlwaysReload;
145                     if (!reload) {
146                         if (src != _this.webApplication.mainWindow.getURL())
147                             reload = true;
148                     }
149                     // handle http://tizen.org/appcontrol/operation/main operation specially.
150                     // only menu-screen app can send launch request with main operation.
151                     // in this case, web app should have to resume web app not reset.
152                     if (reload && appControl.getOperation() == 'http://tizen.org/appcontrol/operation/main')
153                         reload = false;
154                     if (reload) {
155                         _this.webApplication.closeWindows();
156                         _this.webApplication.mainWindow.loadURL(src);
157                     } else {
158                         _this.webApplication.sendAppControlEvent();
159                     }
160                 }
161             }
162             _this.configureRuntime(appControl);
163         });
164         wrt.on('suspend', function() {
165             console.log('suspend');
166             if (_this.webApplication)
167                 _this.webApplication.suspend(_this.addonManager.evt_emitter_);
168         });
169         wrt.on('resume', function() {
170             console.log('resume');
171             if (_this.webApplication)
172                 _this.webApplication.resume(_this.addonManager.evt_emitter_);
173         });
174         wrt.on('low-memory', function() {
175             console.log('low-memory');
176             if (_this.webApplication)
177                 _this.webApplication.lowMemory();
178         });
179         wrt.on('message', function(event, type, params) {
180             console.log('message type(' + type + ') params : ' + params);
181             if (type === 'startService') {
182                 const vm = require('vm');
183                 const fs = require('fs');
184                 let sandbox = {
185                     console: console,
186                     module: module,
187                     require: require,
188                 };
189                 let options = {};
190                 let code = fs.readFileSync(params[1]);
191                 vm.runInNewContext(code, sandbox, options);
192                 event.preventDefault();
193             }
194         });
195         wrt.on('wgt-installed', function(event, path) {
196             console.log('wgt-installed at ' + path);
197             if (AddonManager.isAddon(path)) {
198                 console.log('Addon is updated on DB');
199             }
200         });
201         wrt.on('addon-uninstalled', function(event, id) {
202             console.log('addon-unistalled named ' + id);
203         });
204         /* FIXME: will uncheck after chromium-efl released */
205         if (wrt.getPlatformType() !== "product_tv") {
206             wrt.getInstalledPkg();
207         }
208     }
209     handleIpcMessages() {
210         var _this = this;
211         ipcMain.on(IPC_MESSAGE.ADDONS.INSTALLED, (sender, name) => {
212             console.log('handleIpcMessages: INSTALLED ' + name);
213             _this.addonManager.build();
214             return _this.addonManager.activate(app, name);
215         });
216         ipcMain.on(IPC_MESSAGE.ADDONS.UNINSTALLED, (sender, name, pkg) => {
217             console.log('handleIpcMessages: UNINSTALLED ' + name);
218             _this.addonManager.deactivate(app, name);
219             /* FIXME: will uncheck after chromium-efl released */
220             if (wrt.getPlatformType() !== "product_tv") {
221                wrt.reqUninstallPkg(pkg);
222             }
223             return true;
224         });
225         ipcMain.on(IPC_MESSAGE.ADDONS.ACTIVATE, (sender, name) => {
226             console.log('handleIpcMessages: ACTIVATE ' + name);
227             return _this.addonManager.activate(app, name);
228         });
229         ipcMain.on(IPC_MESSAGE.ADDONS.DEACTIVATE, (sender, name) => {
230             console.log('handleIpcMessages: DEACTIVATE ' + name);
231             return _this.addonManager.deactivate(app, name);
232         });
233     }
234     checkInspectorCondition(appControl) {
235         let bundleDebug = (appControl.getData('__AUL_DEBUG__') === "1");
236         return (bundleDebug || this.inspectorEnabledByVconf);
237     }
238     launchInspector(appControl) {
239         var portnum = wrt.getDebuggingPort();
240         var data    = { "port" :  [ portnum.toString() ] };
241         if (this.webApplication)
242             this.webApplication.debugPort = portnum;
243         appControl.reply(data);
244     }
245     configureRuntime(appControl) {
246         this.configureRuntime = (param) => {}; // call once
247
248         // FIX ME : It must be supplemented to set a specific path
249         wrt.setCookiePath();
250
251         // AUL public key/Vconf - To support inspector
252         if (this.checkInspectorCondition(appControl)) {
253             this.launchInspector(appControl);
254         }
255     }
256     handleKeyEvents(key) {
257         let valid = false;
258         let _this = this;
259
260         console.log(key + ' is pressed');
261         switch(key) {
262             case "ArrowUp":
263             case "Up":
264             case "ArrowDown":
265             case "Down":
266                 valid = true;
267                 break;
268             default:
269                 console.log('No handler for the key ' + key);
270                 break;
271         }
272
273         if (valid) {
274             _this.webApplication.keyEvent(_this.addonManager.evt_emitter_, key);
275         }
276     }
277 }
278 module.exports = Runtime;