Browse Source

Démarrage des applications en mode daemon

Les applications sont désormais lancées en mode "détachées".
Une limite "dure" de 2 secondes est appliquées pour l'animation de lancement sur les tuiles.

Fixes #5
William Petit 1 year ago
parent
commit
ef57e28dab
3 changed files with 73 additions and 11 deletions
  1. 8
    2
      src/components/launcher/launcher-view.js
  2. 9
    2
      src/store/actions/launcher.js
  3. 56
    7
      src/util/system.js

+ 8
- 2
src/components/launcher/launcher-view.js View File

@@ -104,10 +104,16 @@ var LauncherView = React.createClass({
104 104
 
105 105
       var el = evt.currentTarget;
106 106
       el.classList.add('pulse');
107
-
107
+      let startAnim = Date.now();
108
+      let endAnim = startAnim + 2000;
108 109
       this.props.dispatch(actions.launcher.runApp(item.exec))
109 110
         .then(function() {
110
-          el.classList.remove('pulse');
111
+          let now = Date.now();
112
+          if(endAnim > now) {
113
+            setTimeout(() => el.classList.remove('pulse'), endAnim - now)
114
+          } else {
115
+            el.classList.remove('pulse')
116
+          }
111 117
         })
112 118
         .catch(function() {
113 119
           el.classList.remove('pulse');

+ 9
- 2
src/store/actions/launcher.js View File

@@ -1,6 +1,7 @@
1 1
 var Util = require('../../util');
2 2
 var logger = Util.Logger;
3
-var remote = require('electron').Remote;
3
+var LoggerStream = Util.LoggerStream;
4
+var remote = require('electron').remote;
4 5
 
5 6
 var RUN_APP = exports.RUN_APP = 'RUN_APP';
6 7
 var RUN_APP_SUCCESS = exports.RUN_APP_SUCCESS = 'RUN_APP_SUCCESS';
@@ -14,7 +15,13 @@ exports.runApp = function(execPath) {
14 15
 
15 16
     dispatch({ type: RUN_APP, execPath: execPath });
16 17
 
17
-    return Util.System.runApp(execPath, { clearFreeDesktopFlags: true })
18
+    var opts = {
19
+      clearFreeDesktopFlags: true,
20
+      stdout: process.stdout,
21
+      stderr: process.stderr
22
+    }
23
+
24
+    return Util.System.runApp(execPath, opts)
18 25
       .then(function() {
19 26
         dispatch({ type: RUN_APP_SUCCESS, execPath: execPath });
20 27
         // Hypothetical fix

+ 56
- 7
src/util/system.js View File

@@ -98,15 +98,64 @@ exports.runApp = function(execPath, opts) {
98 98
 
99 99
   opts = opts || {};
100 100
 
101
-  if(opts.clearFreeDesktopFlags) {
102
-    execPath = exports.clearFreeDesktopFlags(execPath);
103
-  }
104
-
105 101
   return new Promise(function(resolve, reject) {
106
-    cp.exec(execPath, function(err) {
107
-      if(err) return reject(err);
108
-      return resolve();
102
+    try {
103
+
104
+      if(opts.clearFreeDesktopFlags) {
105
+        execPath = exports.clearFreeDesktopFlags(execPath);
106
+      }
107
+
108
+      var isDev = process.env.NODE_ENV === 'development';
109
+
110
+      var child = cp.spawn(execPath, {
111
+        detached: true,
112
+        shell: true,
113
+        stdio: [
114
+          'ignore',
115
+          isDev ? process.stdout : 'ignore',
116
+          isDev ? process.stderr : 'ignore'
117
+        ]
118
+      });
119
+
120
+      // Detach the child process
121
+      child.unref();
122
+
123
+    } catch(err) {
124
+      return reject(err);
125
+    }
126
+
127
+    // Execute the rest after all I/O operations in this tick
128
+    let immediateId = setImmediate(() => {
129
+
130
+      // We do not want to be notified of child events after launch
131
+      child.removeAllListeners();
132
+
133
+      try {
134
+        // Check if the child process is still alive, should throw otherwise
135
+        child.kill(0);
136
+      } catch(err) {
137
+        return reject(err);
138
+      }
139
+
140
+      return resolve(child);
141
+
142
+    });
143
+
144
+    // If the child process exit with an exit code != 0, reject the promise
145
+    child.once('close', code => {
146
+      if(code === 0) return;
147
+      clearImmediate(immediateId);
148
+      child.removeAllListeners();
149
+      return reject(`Program exited with a exit code "${code}"`);
109 150
     });
151
+
152
+    // If an error occurs during the process launch, reject the promise
153
+    child.once('error', err => {
154
+      clearImmediate(immediateId);
155
+      child.removeAllListeners();
156
+      return reject(err);
157
+    });
158
+
110 159
   });
111 160
 };
112 161