[Service] Fix memory leak with worker isolation
[platform/framework/web/wrtjs.git] / wrt_app / common / service_runner.ts
1 import './init';
2 import * as XWalkExtension from './wrt_xwalk_extension';
3 import { DeviceAPIRouter } from '../service/device_api_router';
4 import { isMainThread, parentPort, workerData } from 'worker_threads';
5 import { wrt } from '../browser/wrt';
6
7 let serviceType: string = wrt.getServiceModel();
8
9 function isServiceApplication() {
10   return serviceType !== 'UI';
11 }
12
13 function isGloablService() {
14   return serviceType === 'DAEMON';
15 }
16
17 function registerExtensionResolver(id: string) {
18   if (wrt.tv) {
19     let extensionResolver = (module: any, file_path: string) => {
20       console.log(`resolved path: ${file_path}`);
21       let content = (wrt.tv as NativeWRTjs.TVExtension).decryptFile(id, file_path);
22       if (content) {
23         // Remove BOM
24         if (content.charCodeAt(0) === 0xFEFF)
25           content = content.slice(1);
26         module._compile(content, file_path);
27       }
28     };
29     require.extensions['.js.spm'] = extensionResolver;
30     require.extensions['.spm'] = extensionResolver;
31   }
32 }
33
34 let app: any = null;
35 export function start(id: string, filename: string) {
36   XWalkExtension.initialize();
37   XWalkExtension.setRuntimeMessageHandler((type, data) => {
38     if (type === 'tizen://exit') {
39       console.log(`${id} will be closed by ${type}`);
40       setTimeout(() => wrt.stopService(id), 500);
41     }
42   });
43
44   console.log('serviceType : '+serviceType)
45   new DeviceAPIRouter(id, isGloablService());
46
47   if (isServiceApplication()) {
48     registerExtensionResolver(id);
49     filename = wrt.getStartServiceFile(id);
50     console.log(`start global service file: ${filename}`);
51   }
52
53   // FIXME: this is for awaking up uv loop.
54   // uv loop is sleeping for a few second with tizen webapis's aync callback
55   setInterval(() => {}, 100);
56   try {
57     app = require(filename);
58     if (app.onStart !== undefined) {
59       app.onStart();
60     }
61     if (app.onRequest !== undefined) {
62       app.onRequest();
63     }
64     if (isGloablService()) {
65       wrt.finishStartingService(id);
66     }
67   } catch (e) {
68     console.log(`exception on start: ${e}`);
69     setTimeout(() => wrt.stopService(id), 500);
70   }
71 }
72
73 export function stop(id: string) {
74   try {
75     if (app.onStop !== undefined) {
76       app.onStop();
77     } else if (app.onExit !== undefined) {
78       app.onExit();
79     }
80   } catch (e) {
81     console.log(`exception on stop: ${e}`);
82   }
83 }
84
85 function run() {
86   let id = workerData.id;
87   let filename = workerData.filename;
88   start(id, filename);
89
90   if (!parentPort)
91     return;
92   parentPort.on('message', (msg) => {
93     console.log(`message received : ${msg}`);
94     if (msg === 'stopService') {
95       stop(id);
96       XWalkExtension.cleanup();
97     }
98   });
99 }
100
101 if (!isMainThread) {
102   run();
103 }