[Service] Add wrt.setServiceAppId()
[platform/framework/web/wrtjs.git] / wrt_app / service / service_runner.ts
1 import '../common/init';
2 import * as XWalkExtension from '../common/wrt_xwalk_extension';
3 import { DeviceAPIRouter } from './device_api_router';
4 import { isMainThread, parentPort, workerData } from 'worker_threads';
5 import { wrt } from '../browser/wrt';
6
7 Object.defineProperty(global, 'serviceType', {
8   value: wrt.getServiceModel(),
9   writable: false
10 });
11
12 function isServiceApplication() {
13   return global['serviceType'] !== 'UI';
14 }
15
16 function isGlobalService() {
17   return global['serviceType'] === 'GLOBAL';
18 }
19 function printAppControlData(id: string)  {
20   let reqAppControl = global.tizen.application.getCurrentApplication().getRequestedAppControl();
21   if (reqAppControl) {
22     console.log(`id: ${id}, appControlData operation: ${reqAppControl.appControl.operation}`);
23     let appControlData = reqAppControl.appControl.data;
24     for (let dataIndex in appControlData) {
25       for (let valueIndex in appControlData[dataIndex].value)
26         console.log(`data[${dataIndex}][${valueIndex}]: ${appControlData[dataIndex].value[valueIndex]}`);
27     }
28   }
29 }
30
31 function registerExtensionResolver(id: string) {
32   if (wrt.tv) {
33     let extensionResolver = (module: any, file_path: string) => {
34       console.log(`resolved path: ${file_path}`);
35       let content = (wrt.tv as NativeWRTjs.TVExtension).decryptFile(id, file_path);
36       if (content) {
37         // Remove BOM
38         if (content.charCodeAt(0) === 0xFEFF)
39           content = content.slice(1);
40         module._compile(content, file_path);
41       }
42     };
43     require.extensions['.js.spm'] = extensionResolver;
44     require.extensions['.spm'] = extensionResolver;
45   }
46 }
47
48 let requestStopService = (id: string) => {
49   requestStopService = (id: string) => {};
50   setTimeout(() => wrt.stopService(id), 500);
51 }
52
53 let app: any = null;
54 let dummyTimer: any;
55 let periodLauncherAlive = 20; // 2s
56
57 let checkLauncherAlive = (id: string) => {
58   periodLauncherAlive--;
59   if (!periodLauncherAlive) {
60     periodLauncherAlive = 20;
61     if (!wrt.checkLauncherAlive(id)) {
62       console.log(`${id} launcher was killed.`)
63       requestStopService(id);
64       checkLauncherAlive = () => {};
65     }
66   }
67 }
68
69 export function start(id: string, filename: string) {
70   wrt.setServiceAppId(id);
71   XWalkExtension.initialize();
72   XWalkExtension.setRuntimeMessageHandler((type, data) => {
73     if (type === 'tizen://exit') {
74       console.log(`${id} will be closed by ${type}`);
75       requestStopService(id);
76     }
77   });
78
79   console.log(`serviceType : ${global['serviceType']}`)
80   new DeviceAPIRouter(id, isGlobalService());
81
82   // this is workaround solution to make webapis singleton worker
83   // ahead of dropThreadPrivilege()
84   global.tizen.systeminfo.getPropertyValue("CPU", () => { }, () => { });
85
86   // This is for awaking up uv loop.
87   dummyTimer = setInterval(() => {
88     checkLauncherAlive(id);
89   }, 100);
90
91   if (isServiceApplication()) {
92     registerExtensionResolver(id);
93     filename = wrt.getStartServiceFile(id);
94     console.log(`start global service file: ${filename}`);
95   }
96
97   try {
98     let ids = id.split(':');
99     let serviceId = ids[0];
100     let packageId = global.webapis.getPackageId();
101     wrt.security?.dropThreadPrivilege(packageId, serviceId);
102     printAppControlData(id);
103
104     app = require(filename);
105     if (app.onStart !== undefined) {
106       app.onStart();
107     }
108     if (app.onRequest !== undefined) {
109       app.onRequest();
110     }
111     if (isGlobalService()) {
112       wrt.finishStartingService(id);
113     }
114   } catch (e) {
115     console.log(`exception on start: ${e}`);
116     requestStopService(id);
117   }
118 }
119
120 export function stop(id: string) {
121   if (dummyTimer)
122     clearInterval(dummyTimer);
123   try {
124     if (app.onStop !== undefined) {
125       app.onStop();
126     } else if (app.onExit !== undefined) {
127       app.onExit();
128     }
129   } catch (e) {
130     console.log(`exception on stop: ${e}`);
131   }
132 }
133
134 function run() {
135   let id = workerData.id;
136   // FIXME: this should be 'wrt.tv?.serviceMount(id)' after Tizen 6.5 release
137   (wrt.tv as any)?.serviceMount(id);
138
139   let filename = workerData.filename;
140   start(id, filename);
141
142   if (!parentPort)
143     return;
144   parentPort.on('message', (message) => {
145     console.log(`Received message type : ${message.type}`);
146     if (message.type === 'wake') {
147       app?.onRequest();
148     } else if (message.type === 'stop') {
149       stop(id);
150       setTimeout(() => {
151         XWalkExtension.cleanup();
152         parentPort?.postMessage("will-terminate");
153         (wrt.tv as any)?.serviceUmount(id);
154       }, message.delay);
155     }
156   });
157 }
158
159 if (!isMainThread) {
160   run();
161 }