| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2014 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2014 The Native Client Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 /* globals lib, NaClProcessManager, hterm */ |
| 8 |
| 7 'use strict'; | 9 'use strict'; |
| 8 | 10 |
| 9 lib.rtdep('lib.f', | 11 lib.rtdep('lib.f', |
| 10 'hterm', | 12 'hterm', |
| 11 'NaClProcessManager'); | 13 'NaClProcessManager'); |
| 12 | 14 |
| 13 // CSP means that we can't kick off the initialization from the html file, | 15 // CSP means that we can't kick off the initialization from the html file, |
| 14 // so we do it like this instead. | 16 // so we do it like this instead. |
| 15 window.onload = function() { | 17 window.onload = function() { |
| 16 lib.init(function() { | 18 lib.init(function() { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 37 // Has the initial process finished loading? | 39 // Has the initial process finished loading? |
| 38 this.loaded = false; | 40 this.loaded = false; |
| 39 | 41 |
| 40 this.print = this.io.print.bind(this.io); | 42 this.print = this.io.print.bind(this.io); |
| 41 | 43 |
| 42 var mgr = this.processManager = new NaClProcessManager(); | 44 var mgr = this.processManager = new NaClProcessManager(); |
| 43 mgr.setStdoutListener(this.handleStdout_.bind(this)); | 45 mgr.setStdoutListener(this.handleStdout_.bind(this)); |
| 44 mgr.setErrorListener(this.handleError_.bind(this)); | 46 mgr.setErrorListener(this.handleError_.bind(this)); |
| 45 mgr.setRootProgressListener(this.handleRootProgress_.bind(this)); | 47 mgr.setRootProgressListener(this.handleRootProgress_.bind(this)); |
| 46 mgr.setRootLoadListener(this.handleRootLoad_.bind(this)); | 48 mgr.setRootLoadListener(this.handleRootLoad_.bind(this)); |
| 47 }; | 49 } |
| 48 | 50 |
| 49 /** | 51 /** |
| 50 * Flag for cyan coloring in the terminal. | 52 * Flag for cyan coloring in the terminal. |
| 51 * @const | 53 * @const |
| 52 */ | 54 */ |
| 53 NaClTerm.ANSI_CYAN = '\x1b[36m'; | 55 NaClTerm.ANSI_CYAN = '\x1b[36m'; |
| 54 | 56 |
| 55 /** | 57 /** |
| 56 * Flag for color reset in the terminal. | 58 * Flag for color reset in the terminal. |
| 57 * @const | 59 * @const |
| 58 */ | 60 */ |
| 59 NaClTerm.ANSI_RESET = '\x1b[0m'; | 61 NaClTerm.ANSI_RESET = '\x1b[0m'; |
| 60 | 62 |
| 61 /* | 63 /* |
| 62 * Character code for Control+C in the terminal. | 64 * Character code for Control+C in the terminal. |
| 63 * @type {number} | 65 * @type {number} |
| 64 */ | 66 */ |
| 65 NaClTerm.CONTROL_C = 3; | 67 NaClTerm.CONTROL_C = 3; |
| 66 | 68 |
| 67 /** | 69 /** |
| 68 * Add the appropriate hooks to HTerm to start the session. | 70 * Add the appropriate hooks to HTerm to start the session. |
| 69 */ | 71 */ |
| 70 NaClTerm.prototype.run = function() { | 72 NaClTerm.prototype.run = function() { |
| 71 this.io.onVTKeystroke = this.onVTKeystroke_.bind(this); | 73 this.io.onVTKeystroke = this.onVTKeystroke_.bind(this); |
| 72 this.io.sendString = this.onVTKeystroke_.bind(this); | 74 this.io.sendString = this.onVTKeystroke_.bind(this); |
| 73 this.io.onTerminalResize = this.onTerminalResize_.bind(this); | 75 this.io.onTerminalResize = this.onTerminalResize_.bind(this); |
| 74 | 76 |
| 75 this.print(NaClTerm.ANSI_CYAN); | 77 this.print(NaClTerm.ANSI_CYAN); |
| 76 } | 78 }; |
| 77 | 79 |
| 78 /** | 80 /** |
| 79 * Static initializer called from index.html. | 81 * Static initializer called from index.html. |
| 80 * | 82 * |
| 81 * This constructs a new Terminal instance and instructs it to run a NaClTerm. | 83 * This constructs a new Terminal instance and instructs it to run a NaClTerm. |
| 82 */ | 84 */ |
| 83 NaClTerm.init = function() { | 85 NaClTerm.init = function() { |
| 84 var profileName = lib.f.parseQuery(document.location.search)['profile']; | 86 var profileName = lib.f.parseQuery(document.location.search)['profile']; |
| 85 var terminal = new hterm.Terminal(profileName); | 87 var terminal = new hterm.Terminal(profileName); |
| 86 terminal.decorate(document.querySelector('#terminal')); | 88 terminal.decorate(document.querySelector('#terminal')); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 112 * Handle stdout event from NaClProcessManager. | 114 * Handle stdout event from NaClProcessManager. |
| 113 * @private | 115 * @private |
| 114 * @param {string} msg The string sent to stdout. | 116 * @param {string} msg The string sent to stdout. |
| 115 */ | 117 */ |
| 116 NaClTerm.prototype.handleStdout_ = function(msg) { | 118 NaClTerm.prototype.handleStdout_ = function(msg) { |
| 117 if (!this.loaded) { | 119 if (!this.loaded) { |
| 118 this.bufferedOutput += msg; | 120 this.bufferedOutput += msg; |
| 119 } else { | 121 } else { |
| 120 this.print(msg); | 122 this.print(msg); |
| 121 } | 123 } |
| 122 } | 124 }; |
| 123 | 125 |
| 124 /** | 126 /** |
| 125 * Handle error event from NaCl. | 127 * Handle error event from NaCl. |
| 126 * @private | 128 * @private |
| 127 * @param {string} cmd The name of the process with the error. | 129 * @param {string} cmd The name of the process with the error. |
| 128 * @param {string} err The error message. | 130 * @param {string} err The error message. |
| 129 */ | 131 */ |
| 130 NaClTerm.prototype.handleError_ = function(cmd, err) { | 132 NaClTerm.prototype.handleError_ = function(cmd, err) { |
| 131 this.print(cmd + ': ' + err + '\n'); | 133 this.print(cmd + ': ' + err + '\n'); |
| 132 } | 134 }; |
| 133 | 135 |
| 134 /** | 136 /** |
| 135 * Notify the user when we are done loading a URL. | 137 * Notify the user when we are done loading a URL. |
| 136 * @private | 138 * @private |
| 137 */ | 139 */ |
| 138 NaClTerm.prototype.doneLoadingUrl_ = function() { | 140 NaClTerm.prototype.doneLoadingUrl_ = function() { |
| 139 var width = this.width; | 141 var width = this.width; |
| 140 this.print('\r' + Array(width+1).join(' ')); | 142 this.print('\r' + new Array(width+1).join(' ')); |
| 141 var message = '\rLoaded ' + this.lastUrl; | 143 var message = '\rLoaded ' + this.lastUrl; |
| 142 if (this.lastTotal) { | 144 if (this.lastTotal) { |
| 143 var kbsize = Math.round(this.lastTotal/1024) | 145 var kbsize = Math.round(this.lastTotal/1024); |
| 144 message += ' ['+ kbsize + ' KiB]'; | 146 message += ' ['+ kbsize + ' KiB]'; |
| 145 } | 147 } |
| 146 this.print(message.slice(0, width) + '\n') | 148 this.print(message.slice(0, width) + '\n'); |
| 147 } | 149 }; |
| 148 | 150 |
| 149 /** | 151 /** |
| 150 * Handle load progress event from NaCl for the root process. | 152 * Handle load progress event from NaCl for the root process. |
| 151 * @private | 153 * @private |
| 152 * @param {string} url The URL that is being loaded. | 154 * @param {string} url The URL that is being loaded. |
| 153 * @param {boolean} lengthComputable Is our progress quantitatively measurable? | 155 * @param {boolean} lengthComputable Is our progress quantitatively measurable? |
| 154 * @param {number} loaded The number of bytes that have been loaded. | 156 * @param {number} loaded The number of bytes that have been loaded. |
| 155 * @param {number} total The total number of bytes to be loaded. | 157 * @param {number} total The total number of bytes to be loaded. |
| 156 */ | 158 */ |
| 157 NaClTerm.prototype.handleRootProgress_ = function( | 159 NaClTerm.prototype.handleRootProgress_ = function( |
| 158 url, lengthComputable, loaded, total) { | 160 url, lengthComputable, loaded, total) { |
| 159 if (url !== undefined) | 161 if (url !== undefined) |
| 160 url = url.substring(url.lastIndexOf('/') + 1); | 162 url = url.substring(url.lastIndexOf('/') + 1); |
| 161 | 163 |
| 162 if (this.lastUrl && this.lastUrl !== url) | 164 if (this.lastUrl && this.lastUrl !== url) |
| 163 this.doneLoadingUrl_() | 165 this.doneLoadingUrl_(); |
| 164 | 166 |
| 165 if (!url) | 167 if (!url) |
| 166 return; | 168 return; |
| 167 | 169 |
| 168 this.lastUrl = url; | 170 this.lastUrl = url; |
| 169 this.lastTotal = total; | 171 this.lastTotal = total; |
| 170 | 172 |
| 171 var message = 'Loading ' + url; | 173 var message = 'Loading ' + url; |
| 172 if (lengthComputable && total) { | 174 if (lengthComputable && total) { |
| 173 var percent = Math.round(loaded * 100 / total); | 175 var percent = Math.round(loaded * 100 / total); |
| 174 var kbloaded = Math.round(loaded / 1024); | 176 var kbloaded = Math.round(loaded / 1024); |
| 175 var kbtotal = Math.round(total / 1024); | 177 var kbtotal = Math.round(total / 1024); |
| 176 message += ' [' + kbloaded + ' KiB/' + kbtotal + ' KiB ' + percent + '%]'; | 178 message += ' [' + kbloaded + ' KiB/' + kbtotal + ' KiB ' + percent + '%]'; |
| 177 } | 179 } |
| 178 | 180 |
| 179 this.print('\r' + message.slice(-this.width)); | 181 this.print('\r' + message.slice(-this.width)); |
| 180 } | 182 }; |
| 181 | 183 |
| 182 /** | 184 /** |
| 183 * Handle load end event from NaCl for the root process. | 185 * Handle load end event from NaCl for the root process. |
| 184 * @private | 186 * @private |
| 185 */ | 187 */ |
| 186 NaClTerm.prototype.handleRootLoad_ = function() { | 188 NaClTerm.prototype.handleRootLoad_ = function() { |
| 187 if (this.lastUrl) | 189 if (this.lastUrl) |
| 188 this.doneLoadingUrl_(); | 190 this.doneLoadingUrl_(); |
| 189 else | 191 else |
| 190 this.print('Loaded.\n'); | 192 this.print('Loaded.\n'); |
| 191 | 193 |
| 192 this.print(NaClTerm.ANSI_RESET); | 194 this.print(NaClTerm.ANSI_RESET); |
| 193 | 195 |
| 194 // Now that have completed loading and displaying | 196 // Now that have completed loading and displaying |
| 195 // loading messages we output any messages from the | 197 // loading messages we output any messages from the |
| 196 // NaCl module that were buffered up unto this point | 198 // NaCl module that were buffered up unto this point |
| 197 this.loaded = true; | 199 this.loaded = true; |
| 198 this.print(this.bufferedOutput); | 200 this.print(this.bufferedOutput); |
| 199 this.bufferedOutput = ''; | 201 this.bufferedOutput = ''; |
| 200 } | 202 }; |
| 201 | 203 |
| 202 /** | 204 /** |
| 203 * Clean up once the root process exits. | 205 * Clean up once the root process exits. |
| 204 * @private | 206 * @private |
| 205 * @param {number} pid The PID of the process that exited. | 207 * @param {number} pid The PID of the process that exited. |
| 206 * @param {number} status The exit code of the process. | 208 * @param {number} status The exit code of the process. |
| 207 */ | 209 */ |
| 208 NaClTerm.prototype.handleExit_ = function(pid, status) { | 210 NaClTerm.prototype.handleExit_ = function(pid, status) { |
| 209 this.print(NaClTerm.ANSI_CYAN) | 211 this.print(NaClTerm.ANSI_CYAN); |
| 210 | 212 |
| 211 // The root process finished. | 213 // The root process finished. |
| 212 if (status === -1) { | 214 if (status === -1) { |
| 213 this.print('Program (' + NaClTerm.nmf + | 215 this.print('Program (' + NaClTerm.nmf + |
| 214 ') crashed (exit status -1)\n'); | 216 ') crashed (exit status -1)\n'); |
| 215 } else { | 217 } else { |
| 216 this.print('Program (' + NaClTerm.nmf + ') exited ' + | 218 this.print('Program (' + NaClTerm.nmf + ') exited ' + |
| 217 '(status=' + status + ')\n'); | 219 '(status=' + status + ')\n'); |
| 218 } | 220 } |
| 219 this.argv.io.pop(); | 221 this.argv.io.pop(); |
| 220 // Remove window close handler. | 222 // Remove window close handler. |
| 221 window.onbeforeunload = function() { return null; }; | 223 window.onbeforeunload = function() { return null; }; |
| 222 if (this.argv.onExit) { | 224 if (this.argv.onExit) { |
| 223 this.argv.onExit(status); | 225 this.argv.onExit(status); |
| 224 } | 226 } |
| 225 } | 227 }; |
| 226 | 228 |
| 227 /** | 229 /** |
| 228 * Spawn the root process (usually bash). | 230 * Spawn the root process (usually bash). |
| 229 * @private | 231 * @private |
| 230 * | 232 * |
| 231 * We delay this call until the first terminal resize event so that we start | 233 * We delay this call until the first terminal resize event so that we start |
| 232 * with the correct size. | 234 * with the correct size. |
| 233 */ | 235 */ |
| 234 NaClTerm.prototype.spawnRootProcess_ = function() { | 236 NaClTerm.prototype.spawnRootProcess_ = function() { |
| 235 var self = this; | 237 var self = this; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 253 var handleFailure = function(message) { | 255 var handleFailure = function(message) { |
| 254 self.print(message); | 256 self.print(message); |
| 255 }; | 257 }; |
| 256 self.processManager.checkUrlNaClManifestType( | 258 self.processManager.checkUrlNaClManifestType( |
| 257 NaClTerm.nmf, handleSuccess, handleFailure); | 259 NaClTerm.nmf, handleSuccess, handleFailure); |
| 258 } catch (e) { | 260 } catch (e) { |
| 259 self.print(e.message); | 261 self.print(e.message); |
| 260 } | 262 } |
| 261 | 263 |
| 262 self.started = true; | 264 self.started = true; |
| 263 } | 265 }; |
| 264 | 266 |
| 265 /** | 267 /** |
| 266 * Handle hterm terminal resize events. | 268 * Handle hterm terminal resize events. |
| 267 * @private | 269 * @private |
| 268 * @param {number} width The width of the terminal. | 270 * @param {number} width The width of the terminal. |
| 269 * @param {number} height The height of the terminal. | 271 * @param {number} height The height of the terminal. |
| 270 */ | 272 */ |
| 271 NaClTerm.prototype.onTerminalResize_ = function(width, height) { | 273 NaClTerm.prototype.onTerminalResize_ = function(width, height) { |
| 272 this.processManager.onTerminalResize(width, height); | 274 this.processManager.onTerminalResize(width, height); |
| 273 if (!this.started) { | 275 if (!this.started) { |
| 274 this.spawnRootProcess_(); | 276 this.spawnRootProcess_(); |
| 275 } | 277 } |
| 276 } | 278 }; |
| 277 | 279 |
| 278 /** | 280 /** |
| 279 * Handle hterm keystroke events. | 281 * Handle hterm keystroke events. |
| 280 * @private | 282 * @private |
| 281 * @param {string} str The characters sent by hterm. | 283 * @param {string} str The characters sent by hterm. |
| 282 */ | 284 */ |
| 283 NaClTerm.prototype.onVTKeystroke_ = function(str) { | 285 NaClTerm.prototype.onVTKeystroke_ = function(str) { |
| 284 try { | 286 try { |
| 285 if (str.charCodeAt(0) === NaClTerm.CONTROL_C) { | 287 if (str.charCodeAt(0) === NaClTerm.CONTROL_C) { |
| 286 if (this.processManager.sigint()) { | 288 if (this.processManager.sigint()) { |
| 287 this.print('\n'); | 289 this.print('\n'); |
| 288 return; | 290 return; |
| 289 } | 291 } |
| 290 } | 292 } |
| 291 this.processManager.sendStdinForeground(str); | 293 this.processManager.sendStdinForeground(str); |
| 292 } catch (e) { | 294 } catch (e) { |
| 293 this.print(e.message); | 295 this.print(e.message); |
| 294 } | 296 } |
| 295 } | 297 }; |
| OLD | NEW |