From 410e80682a042886cbdfc0b98904e73d57426cb3 Mon Sep 17 00:00:00 2001 From: TanninOne Date: Thu, 9 Mar 2017 15:41:31 +0100 Subject: [PATCH 01/31] Update browser-window.md Notes that maximize will also show the window and that ready-to-show won't fire if the window is already being displayed. (See issue #8861) --- docs/api/browser-window.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index fe870ecb36..b169230094 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -36,8 +36,8 @@ without visual flash, there are two solutions for different situations. ### Using `ready-to-show` event While loading the page, the `ready-to-show` event will be emitted when renderer -process has done drawing for the first time, showing window after this event -will have no visual flash: +process has done drawing for the first time if the window is not shown yet. Showing +the window after this event will have no visual flash: ```javascript const {BrowserWindow} = require('electron') @@ -390,7 +390,7 @@ Emitted when the window is hidden. #### Event: 'ready-to-show' -Emitted when the web page has been rendered and window can be displayed without +Emitted when the web page has been rendered (while not being shown) and window can be displayed without a visual flash. #### Event: 'maximize' @@ -632,7 +632,8 @@ Returns `Boolean` - Whether current window is a modal window. #### `win.maximize()` -Maximizes the window. +Maximizes the window. This will also show (but not focus) the window if it +isn't being displayed already. #### `win.unmaximize()` From 3b265747fef74682c26909570181a1673bddccfd Mon Sep 17 00:00:00 2001 From: Adham Saad Date: Sun, 12 Mar 2017 14:17:03 +0200 Subject: [PATCH 02/31] updating README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 655d613baf..0822d70742 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +Attempting to add full kiosk mode functionality on windows 7 +== + [![Electron Logo](https://electron.atom.io/images/electron-logo.svg)](https://electron.atom.io/) [![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) From 713e2568436e99c21243a39958838933d8dbf131 Mon Sep 17 00:00:00 2001 From: Adham Saad Date: Thu, 16 Mar 2017 13:34:53 +0200 Subject: [PATCH 03/31] :bug: #8919 - add new command that cleans only out & dist dirs --- package.json | 1 + script/clean-build.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100755 script/clean-build.py diff --git a/package.json b/package.json index a572a1918e..ef0a405fb4 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "bump-version": "./script/bump-version.py", "build": "python ./script/build.py -c D", "clean": "python ./script/clean.py", + "clean-build": "python ./script/clean-build.py", "coverage": "npm run instrument-code-coverage && npm test -- --use-instrumented-asar", "instrument-code-coverage": "electabul instrument --input-path ./lib --output-path ./out/coverage/electron.asar", "lint": "npm run lint-js && npm run lint-cpp && npm run lint-py && npm run lint-api-docs-js && npm run lint-api-docs", diff --git a/script/clean-build.py b/script/clean-build.py new file mode 100755 index 0000000000..7dad790daf --- /dev/null +++ b/script/clean-build.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +import os +import sys + +from lib.util import rm_rf + + +SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) + + +def main(): + os.chdir(SOURCE_ROOT) + rm_rf('dist') + rm_rf('out') + +if __name__ == '__main__': + sys.exit(main()) From 818738ce840be9e6c0463fe43dd40d392b5f6168 Mon Sep 17 00:00:00 2001 From: Todd Wolfson Date: Fri, 17 Mar 2017 08:21:37 -0700 Subject: [PATCH 04/31] :bug: Add toString support to remote functions --- lib/renderer/api/remote.js | 3 +++ spec/api-ipc-spec.js | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index 8277e16c21..60a34785be 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -175,6 +175,9 @@ const proxyFunctionProperties = function (remoteMemberFunction, metaId, name) { return true }, get: (target, property, receiver) => { + if (property === 'toString' && typeof target.toString === 'function') { + return target.toString.bind(target) + } if (!target.hasOwnProperty(property)) loadRemoteProperties() return target[property] }, diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index e812eb5fef..f86d06507c 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -161,6 +161,11 @@ describe('ipc module', function () { assert.equal(typeof remote.clipboard.readText, 'function') assert.equal(typeof remote.shell.openExternal, 'function') }) + + it('returns toString() of original function via toString()', function () { + var readText = remote.clipboard.readText + assert(readText.toString().startsWith('function')) + }) }) describe('remote object in renderer', function () { From 648d3324fb84fd243850f55ea1a22f5499a76527 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 17 Mar 2017 10:28:23 -0700 Subject: [PATCH 05/31] Add spec for remote function with toString property --- spec/api-ipc-spec.js | 5 ++++- spec/fixtures/module/to-string-non-function.js | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/module/to-string-non-function.js diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index f86d06507c..47f2eef216 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -163,8 +163,11 @@ describe('ipc module', function () { }) it('returns toString() of original function via toString()', function () { - var readText = remote.clipboard.readText + const {readText} = remote.clipboard assert(readText.toString().startsWith('function')) + + var {functionWithToStringProperty} = remote.require(path.join(fixtures, 'module', 'to-string-non-function.js')) + assert.equal(functionWithToStringProperty.toString, 'hello') }) }) diff --git a/spec/fixtures/module/to-string-non-function.js b/spec/fixtures/module/to-string-non-function.js new file mode 100644 index 0000000000..3e91921037 --- /dev/null +++ b/spec/fixtures/module/to-string-non-function.js @@ -0,0 +1,4 @@ +function hello () { +} +hello.toString = 'hello' +module.exports = {functionWithToStringProperty: hello} From c50b5184933b764ecb5bef7641a9a9db8980f9db Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 17 Mar 2017 10:29:07 -0700 Subject: [PATCH 06/31] Check toString after loading remote properties --- lib/renderer/api/remote.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index 60a34785be..5059dd69f3 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -175,11 +175,16 @@ const proxyFunctionProperties = function (remoteMemberFunction, metaId, name) { return true }, get: (target, property, receiver) => { - if (property === 'toString' && typeof target.toString === 'function') { - return target.toString.bind(target) - } if (!target.hasOwnProperty(property)) loadRemoteProperties() - return target[property] + const value = target[property] + + // Bind toString to target if it is a function to avoid + // Function.prototype.toString is not generic errors + if (property === 'toString' && typeof value === 'function') { + return value.bind(target) + } + + return value }, ownKeys: (target) => { loadRemoteProperties() From 487a195320c8f33f5e441f4b8ece8af882ae6b6b Mon Sep 17 00:00:00 2001 From: Adham Saad Date: Fri, 17 Mar 2017 20:44:18 +0200 Subject: [PATCH 07/31] :bug: #8919 - add new command to the docs --- README.md | 3 --- docs/development/build-instructions-linux.md | 8 ++++++++ docs/development/build-instructions-osx.md | 8 ++++++++ docs/development/build-instructions-windows.md | 8 ++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0822d70742..655d613baf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,3 @@ -Attempting to add full kiosk mode functionality on windows 7 -== - [![Electron Logo](https://electron.atom.io/images/electron-logo.svg)](https://electron.atom.io/) [![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) diff --git a/docs/development/build-instructions-linux.md b/docs/development/build-instructions-linux.md index 42b7730a84..8d88d2ee87 100644 --- a/docs/development/build-instructions-linux.md +++ b/docs/development/build-instructions-linux.md @@ -117,6 +117,14 @@ To clean the build files: $ npm run clean ``` +To clean only `out` and `dir` directories: + +```bash +$ npm run clean-build +``` + +Note that both commands will require to do run bootstrap again . + ## Troubleshooting ### Error While Loading Shared Libraries: libtinfo.so.5 diff --git a/docs/development/build-instructions-osx.md b/docs/development/build-instructions-osx.md index 7b934cd55b..af0d01173d 100644 --- a/docs/development/build-instructions-osx.md +++ b/docs/development/build-instructions-osx.md @@ -85,6 +85,14 @@ To clean the build files: $ npm run clean ``` +To clean only `out` and `dir` directories: + +```bash +$ npm run clean-build +``` + +Note that both commands will require to do run bootstrap again . + ## Tests See [Build System Overview: Tests](build-system-overview.md#tests) diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 2146abad97..20981b8aa9 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -83,6 +83,14 @@ To clean the build files: $ npm run clean ``` +To clean only `out` and `dir` directories: + +```bash +$ npm run clean-build +``` + +Note that both commands will require to do run bootstrap again . + ## Tests See [Build System Overview: Tests](build-system-overview.md#tests) From 8060b0966fcc93bbf64da0edbe586f210cb11411 Mon Sep 17 00:00:00 2001 From: Adham Saad Date: Fri, 17 Mar 2017 20:47:20 +0200 Subject: [PATCH 08/31] :bug: #8919 - fix typo --- docs/development/build-instructions-linux.md | 2 +- docs/development/build-instructions-osx.md | 2 +- docs/development/build-instructions-windows.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/development/build-instructions-linux.md b/docs/development/build-instructions-linux.md index 8d88d2ee87..296f08ab19 100644 --- a/docs/development/build-instructions-linux.md +++ b/docs/development/build-instructions-linux.md @@ -117,7 +117,7 @@ To clean the build files: $ npm run clean ``` -To clean only `out` and `dir` directories: +To clean only `out` and `dist` directories: ```bash $ npm run clean-build diff --git a/docs/development/build-instructions-osx.md b/docs/development/build-instructions-osx.md index af0d01173d..2d7cc36db6 100644 --- a/docs/development/build-instructions-osx.md +++ b/docs/development/build-instructions-osx.md @@ -85,7 +85,7 @@ To clean the build files: $ npm run clean ``` -To clean only `out` and `dir` directories: +To clean only `out` and `dist` directories: ```bash $ npm run clean-build diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 20981b8aa9..c66b8b423d 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -83,7 +83,7 @@ To clean the build files: $ npm run clean ``` -To clean only `out` and `dir` directories: +To clean only `out` and `dist` directories: ```bash $ npm run clean-build From deef2da87c8bdb48ae1461ada5a933bdd736ccdd Mon Sep 17 00:00:00 2001 From: Felipe Serafim Date: Sat, 18 Mar 2017 23:23:14 +0100 Subject: [PATCH 09/31] Update README.md Correcting some Spanish words mistakes. --- docs-translations/es/project/README.md | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs-translations/es/project/README.md b/docs-translations/es/project/README.md index c62c5c7dc6..1aac1d3c78 100644 --- a/docs-translations/es/project/README.md +++ b/docs-translations/es/project/README.md @@ -5,19 +5,19 @@ [![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev) [![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) -:memo: Traducciones disponibles: [Koreano](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/README.md) | [Chino Simplificado](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/README.md) | [Portugues Brasileño](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/README.md) | [Chino Tradicional](https://github.com/electron/electron/tree/master/docs-translations/zh-TW/project/README.md) +:memo: Traducciones disponibles: [Koreano](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/README.md) | [Chino Simplificado](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/README.md) | [Portugués Brasileño](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/README.md) | [Chino Tradicional](https://github.com/electron/electron/tree/master/docs-translations/zh-TW/project/README.md) -Electron es framework que permite escribir aplicaciones de escritorio multiplataforma -usando JavaScript, HTML y CSS. Está basado en [Node.js](https://nodejs.org/) con -[Chromium](http://www.chromium.org). Es usado por [Atom +Electron es un framework que permite escribir aplicaciones de escritorio multiplataforma +usando JavaScript, HTML y CSS. Está basado en [Node.js](https://nodejs.org/) con +[Chromium](http://www.chromium.org). Es usado por [Atom editor](https://github.com/atom/atom) y muchas otras [aplicaciones](https://electron.atom.io/apps). Sigue a [@ElectronJS](https://twitter.com/electronjs) en Twitter para estar informado de anuncios importantes. -Este projecto se adhiere a [Código de Conducta convenido para Contribuyentes](CODE_OF_CONDUCT.md). +Este proyecto se adhiere al [Código de Conducta convenido para Colaboradores](CODE_OF_CONDUCT.md). Si desea participar, debes seguir este código de conducta. Por favor reporta un comportamiento -no aceptado a electron@github.com. +no aceptado a electron@github.com. ## Downloads @@ -33,7 +33,7 @@ npm install electron -g ``` Mira la [página de lanzamientos](https://github.com/electron/electron/releases) para -los prebuilt binaries, debug symbols, and more. +los prebuilt binaries, debug symbols, y más. ### Mirrors @@ -41,13 +41,13 @@ los prebuilt binaries, debug symbols, and more. ## Documentación -Las guias y API de referencia están disponibles en el directorio +Las guías y API de referencia están disponibles en el directorio [docs](https://github.com/electron/electron/tree/master/docs). Ahí también -puedes encontrar documentos que describen como construir y contribuir a Electron. +puedes encontrar documentos que describen cómo construir y contribuir en Electron. ## Traducciones de la Documentación -- [Portugues Brasileño](https://github.com/electron/electron/tree/master/docs-translations/pt-BR) +- [Portugués Brasileño](https://github.com/electron/electron/tree/master/docs-translations/pt-BR) - [Koreano](https://github.com/electron/electron/tree/master/docs-translations/ko-KR) - [Japonés](https://github.com/electron/electron/tree/master/docs-translations/jp) - [Español](https://github.com/electron/electron/tree/master/docs-translations/es) @@ -57,12 +57,12 @@ puedes encontrar documentos que describen como construir y contribuir a Electron - [Thai](https://github.com/electron/electron/tree/master/docs-Translations/th-TH) - [Ucraniano](https://github.com/electron/electron/tree/master/docs-translations/uk-UA) - [Ruso](https://github.com/electron/electron/tree/master/docs-translations/ru-RU) -- [Frances](https://github.com/electron/electron/tree/master/docs-translations/fr-FR) +- [Francés](https://github.com/electron/electron/tree/master/docs-translations/fr-FR) ## Inicio rápido Clona y ejecuta el repositorio [`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) -para ver una aplicación minima en acción. +para ver una aplicación mínima en acción. ## Comunidad @@ -71,7 +71,7 @@ Puedes preguntar y interactuar con la comunidad en los siguientes lugares: Atom. - `#atom-shell` canal de IRC en Freenode - [`Atom`](http://atom-slack.herokuapp.com/) canales en Slack -- [`electron-br`](https://electron-br.slack.com) *(Portugues Brasileño)* +- [`electron-br`](https://electron-br.slack.com) *(Portugués Brasileño)* - [`electron-kr`](http://www.meetup.com/electron-kr/) *(Koreano)* - [`electron-jp`](https://electron-jp.slack.com) *(Japonés)* - [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(Turco)* @@ -84,4 +84,4 @@ donde la comunidad mantiene una lista útil de ejemplos de aplicaciones, herrami [MIT](https://github.com/electron/electron/blob/master/LICENSE) -Si usas los logos de Electron ó GitHub, asegurate de seguir las [GitHub logo guidelines](https://github.com/logos). +Si usas los logos de Electron ó GitHub, asegúrate de seguir las [GitHub logo guidelines](https://github.com/logos). From caae03f954a64ee93d57f17a301802e17c44e016 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Mar 2017 10:13:45 -0700 Subject: [PATCH 10/31] Use rendered language in both ready-to-show docs --- docs/api/browser-window.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index b169230094..bd33bac354 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -35,8 +35,8 @@ without visual flash, there are two solutions for different situations. ### Using `ready-to-show` event -While loading the page, the `ready-to-show` event will be emitted when renderer -process has done drawing for the first time if the window is not shown yet. Showing +While loading the page, the `ready-to-show` event will be emitted when the renderer +process has rendered the page for the first time if the window has not been shown yet. Showing the window after this event will have no visual flash: ```javascript From 2d638e5da7e3efd956ffdc38b17a41ed2caf6ea3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Mar 2017 10:32:16 -0700 Subject: [PATCH 11/31] Add option to clean.py to only remove dist and out dirs --- docs/development/build-instructions-linux.md | 2 +- docs/development/build-instructions-osx.md | 2 +- .../development/build-instructions-windows.md | 2 +- package.json | 2 +- script/clean-build.py | 18 ---------- script/clean.py | 36 +++++++++++++++---- 6 files changed, 33 insertions(+), 29 deletions(-) delete mode 100755 script/clean-build.py diff --git a/docs/development/build-instructions-linux.md b/docs/development/build-instructions-linux.md index 296f08ab19..e6b5004bf2 100644 --- a/docs/development/build-instructions-linux.md +++ b/docs/development/build-instructions-linux.md @@ -123,7 +123,7 @@ To clean only `out` and `dist` directories: $ npm run clean-build ``` -Note that both commands will require to do run bootstrap again . +**Note:** Both clean commands require running `bootstrap` again before building. ## Troubleshooting diff --git a/docs/development/build-instructions-osx.md b/docs/development/build-instructions-osx.md index 2d7cc36db6..d0e95aaf18 100644 --- a/docs/development/build-instructions-osx.md +++ b/docs/development/build-instructions-osx.md @@ -91,7 +91,7 @@ To clean only `out` and `dist` directories: $ npm run clean-build ``` -Note that both commands will require to do run bootstrap again . +**Note:** Both clean commands require running `bootstrap` again before building. ## Tests diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index c66b8b423d..4f7335e108 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -89,7 +89,7 @@ To clean only `out` and `dist` directories: $ npm run clean-build ``` -Note that both commands will require to do run bootstrap again . +**Note:** Both clean commands require running `bootstrap` again before building. ## Tests diff --git a/package.json b/package.json index ef0a405fb4..8de882fbf5 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "bump-version": "./script/bump-version.py", "build": "python ./script/build.py -c D", "clean": "python ./script/clean.py", - "clean-build": "python ./script/clean-build.py", + "clean-build": "python ./script/clean.py --build", "coverage": "npm run instrument-code-coverage && npm test -- --use-instrumented-asar", "instrument-code-coverage": "electabul instrument --input-path ./lib --output-path ./out/coverage/electron.asar", "lint": "npm run lint-js && npm run lint-cpp && npm run lint-py && npm run lint-api-docs-js && npm run lint-api-docs", diff --git a/script/clean-build.py b/script/clean-build.py deleted file mode 100755 index 7dad790daf..0000000000 --- a/script/clean-build.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python - -import os -import sys - -from lib.util import rm_rf - - -SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) - - -def main(): - os.chdir(SOURCE_ROOT) - rm_rf('dist') - rm_rf('out') - -if __name__ == '__main__': - sys.exit(main()) diff --git a/script/clean.py b/script/clean.py index 669b6b4dd5..c63bdbbade 100755 --- a/script/clean.py +++ b/script/clean.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import argparse import os import sys @@ -11,13 +12,34 @@ SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) def main(): os.chdir(SOURCE_ROOT) - rm_rf('node_modules') - rm_rf('dist') - rm_rf('out') - rm_rf('spec/node_modules') - rm_rf('vendor/brightray/vendor/download/libchromiumcontent') - rm_rf('vendor/brightray/vendor/libchromiumcontent/src') - rm_rf(os.path.expanduser('~/.node-gyp')) + + args = parse_args() + + remove_directory('dist') + remove_directory('out') + + if not args.build: + remove_directory('node_modules') + remove_directory('spec/node_modules') + + remove_directory('vendor/brightray/vendor/download/libchromiumcontent') + remove_directory('vendor/brightray/vendor/libchromiumcontent/src') + + remove_directory(os.path.expanduser('~/.node-gyp')) + + +def parse_args(): + parser = argparse.ArgumentParser(description='Remove generated and' \ + 'downloaded build files') + parser.add_argument('-b', '--build', + help='Only remove out and dist directories', + action='store_true') + return parser.parse_args() + + +def remove_directory(directory): + print 'Removing %s' % directory + rm_rf(directory) if __name__ == '__main__': From e017e157ba849f6dcf6a61c61767444503b9496e Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Mar 2017 19:35:03 +0900 Subject: [PATCH 12/31] Insert node integrations into WebWorker --- atom/renderer/atom_renderer_client.cc | 11 +++++ atom/renderer/atom_renderer_client.h | 4 ++ atom/renderer/web_worker_observer.cc | 71 +++++++++++++++++++++++++++ atom/renderer/web_worker_observer.h | 37 ++++++++++++++ filenames.gypi | 2 + 5 files changed, 125 insertions(+) create mode 100644 atom/renderer/web_worker_observer.cc create mode 100644 atom/renderer/web_worker_observer.h diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 9b3d2214b4..623e09015b 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -23,6 +23,7 @@ #include "atom/renderer/guest_view_container.h" #include "atom/renderer/node_array_buffer_bridge.h" #include "atom/renderer/preferences_manager.h" +#include "atom/renderer/web_worker_observer.h" #include "base/command_line.h" #include "chrome/renderer/media/chrome_key_systems.h" #include "chrome/renderer/pepper/pepper_helper.h" @@ -436,6 +437,16 @@ void AtomRendererClient::AddSupportedKeySystems( AddChromeKeySystems(key_systems); } +void AtomRendererClient::DidInitializeWorkerContextOnWorkerThread( + v8::Local context) { + WebWorkerObserver::GetCurrent()->ContextCreated(context); +} + +void AtomRendererClient::WillDestroyWorkerContextOnWorkerThread( + v8::Local context) { + WebWorkerObserver::GetCurrent()->ContextWillDestroy(context); +} + v8::Local AtomRendererClient::GetContext( blink::WebFrame* frame, v8::Isolate* isolate) { if (isolated_world()) diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h index c1d86cddf5..af8397854e 100644 --- a/atom/renderer/atom_renderer_client.h +++ b/atom/renderer/atom_renderer_client.h @@ -65,6 +65,10 @@ class AtomRendererClient : public content::ContentRendererClient { void AddSupportedKeySystems( std::vector>* key_systems) override; + void DidInitializeWorkerContextOnWorkerThread( + v8::Local context) override; + void WillDestroyWorkerContextOnWorkerThread( + v8::Local context) override; // Whether the node integration has been initialized. bool node_integration_initialized_; diff --git a/atom/renderer/web_worker_observer.cc b/atom/renderer/web_worker_observer.cc new file mode 100644 index 0000000000..223b39322a --- /dev/null +++ b/atom/renderer/web_worker_observer.cc @@ -0,0 +1,71 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/renderer/web_worker_observer.h" + +#include "atom/common/api/atom_bindings.h" +#include "atom/common/api/event_emitter_caller.h" +#include "atom/common/node_bindings.h" +#include "base/lazy_instance.h" +#include "base/threading/thread_local.h" + +#include "atom/common/node_includes.h" + +namespace atom { + +namespace { + +static base::LazyInstance> + lazy_tls = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +// static +WebWorkerObserver* WebWorkerObserver::GetCurrent() { + WebWorkerObserver* self = lazy_tls.Pointer()->Get(); + return self ? self : new WebWorkerObserver; +} + +WebWorkerObserver::WebWorkerObserver() + : node_bindings_(NodeBindings::Create(false)), + atom_bindings_(new AtomBindings) { + lazy_tls.Pointer()->Set(this); +} + +WebWorkerObserver::~WebWorkerObserver() { + lazy_tls.Pointer()->Set(nullptr); +} + +void WebWorkerObserver::ContextCreated(v8::Local context) { + node_bindings_->Initialize(); + node_bindings_->PrepareMessageLoop(); + + // Setup node environment for each window. + node::Environment* env = node_bindings_->CreateEnvironment(context); + + // Add Electron extended APIs. + atom_bindings_->BindTo(env->isolate(), env->process_object()); + + // Load everything. + node_bindings_->LoadEnvironment(env); + + // Make uv loop being wrapped by window context. + node_bindings_->set_uv_env(env); + + // Give the node loop a run to make sure everything is ready. + node_bindings_->RunMessageLoop(); +} + +void WebWorkerObserver::ContextWillDestroy(v8::Local context) { + node::Environment* env = node::Environment::GetCurrent(context); + if (env) + mate::EmitEvent(env->isolate(), env->process_object(), "exit"); + + // Destroy the node environment. + node::FreeEnvironment(env); + atom_bindings_.reset(); + node_bindings_.reset(); +} + +} // namespace atom diff --git a/atom/renderer/web_worker_observer.h b/atom/renderer/web_worker_observer.h new file mode 100644 index 0000000000..45ccfc3dc9 --- /dev/null +++ b/atom/renderer/web_worker_observer.h @@ -0,0 +1,37 @@ +// Copyright (c) 2017 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_RENDERER_WEB_WORKER_OBSERVER_H_ +#define ATOM_RENDERER_WEB_WORKER_OBSERVER_H_ + +#include "base/macros.h" +#include "v8/include/v8.h" + +namespace atom { + +class AtomBindings; +class NodeBindings; + +// Watches for WebWorker and insert node integration to it. +class WebWorkerObserver { + public: + // Returns the WebWorkerObserver for current worker thread. + static WebWorkerObserver* GetCurrent(); + + void ContextCreated(v8::Local context); + void ContextWillDestroy(v8::Local context); + + private: + WebWorkerObserver(); + ~WebWorkerObserver(); + + std::unique_ptr node_bindings_; + std::unique_ptr atom_bindings_; + + DISALLOW_COPY_AND_ASSIGN(WebWorkerObserver); +}; + +} // namespace atom + +#endif // ATOM_RENDERER_WEB_WORKER_OBSERVER_H_ diff --git a/filenames.gypi b/filenames.gypi index 000e08c0a3..31d4fddd65 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -479,6 +479,8 @@ 'atom/renderer/node_array_buffer_bridge.h', 'atom/renderer/preferences_manager.cc', 'atom/renderer/preferences_manager.h', + 'atom/renderer/web_worker_observer.cc', + 'atom/renderer/web_worker_observer.h', 'atom/utility/atom_content_utility_client.cc', 'atom/utility/atom_content_utility_client.h', 'chromium_src/chrome/browser/browser_process.cc', From 2cbdb6bac3798a01e0f984863ddf1fb7a6c28eae Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 7 Mar 2017 19:59:48 +0900 Subject: [PATCH 13/31] Wrap ContextCreated with context scope --- atom/renderer/web_worker_observer.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atom/renderer/web_worker_observer.cc b/atom/renderer/web_worker_observer.cc index 223b39322a..121da69cea 100644 --- a/atom/renderer/web_worker_observer.cc +++ b/atom/renderer/web_worker_observer.cc @@ -38,6 +38,8 @@ WebWorkerObserver::~WebWorkerObserver() { } void WebWorkerObserver::ContextCreated(v8::Local context) { + v8::Context::Scope context_scope(context); + node_bindings_->Initialize(); node_bindings_->PrepareMessageLoop(); From aac934b34effce1b9ef474d9a3b3c1df39c3ac95 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 8 Mar 2017 16:33:46 +0900 Subject: [PATCH 14/31] Update native_mate: Make Wrappable thread safe --- vendor/native_mate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/native_mate b/vendor/native_mate index ad0fd82566..fd0e7dc4ab 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit ad0fd825663932ee3fa29ff935dfec99933bdd8c +Subproject commit fd0e7dc4ab778f0d1ccda6c9640464ea06ee771e From b467c3939e8d3aeff444532902b279954ab4b159 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 8 Mar 2017 17:33:44 +0900 Subject: [PATCH 15/31] Add a new type of NodeBindings --- atom/browser/atom_browser_main_parts.cc | 2 +- atom/common/node_bindings.cc | 45 ++++++++++++++++--------- atom/common/node_bindings.h | 14 +++++--- atom/common/node_bindings_linux.cc | 8 ++--- atom/common/node_bindings_linux.h | 2 +- atom/common/node_bindings_mac.cc | 8 ++--- atom/common/node_bindings_mac.h | 2 +- atom/common/node_bindings_win.cc | 8 ++--- atom/common/node_bindings_win.h | 2 +- atom/renderer/atom_renderer_client.cc | 2 +- atom/renderer/web_worker_observer.cc | 2 +- 11 files changed, 57 insertions(+), 38 deletions(-) diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index eeae1d5911..095bcbc138 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -60,7 +60,7 @@ AtomBrowserMainParts::AtomBrowserMainParts() : fake_browser_process_(new BrowserProcess), exit_code_(nullptr), browser_(new Browser), - node_bindings_(NodeBindings::Create(true)), + node_bindings_(NodeBindings::Create(NodeBindings::BROWSER)), atom_bindings_(new AtomBindings), gc_timer_(true, true) { DCHECK(!self_) << "Cannot have two AtomBrowserMainParts"; diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 4cf2ba56e4..cb6cf34426 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -98,8 +98,8 @@ base::FilePath GetResourcesPath(bool is_browser) { } // namespace -NodeBindings::NodeBindings(bool is_browser) - : is_browser_(is_browser), +NodeBindings::NodeBindings(BrowserEnvironment browser_env) + : browser_env_(browser_env), uv_loop_(uv_default_loop()), embed_closed_(false), uv_env_(nullptr), @@ -122,12 +122,12 @@ NodeBindings::~NodeBindings() { void NodeBindings::Initialize() { // Open node's error reporting system for browser process. - node::g_standalone_mode = is_browser_; + node::g_standalone_mode = browser_env_ == BROWSER; node::g_upstream_node_mode = false; #if defined(OS_LINUX) // Get real command line in renderer process forked by zygote. - if (!is_browser_) + if (browser_env_ != BROWSER) AtomCommandLine::InitializeFromCommandLine(); #endif @@ -139,7 +139,7 @@ void NodeBindings::Initialize() { // uv_init overrides error mode to suppress the default crash dialog, bring // it back if user wants to show it. std::unique_ptr env(base::Environment::Create()); - if (is_browser_ || env->HasVar("ELECTRON_DEFAULT_ERROR_MODE")) + if (browser_env_ == BROWSER || env->HasVar("ELECTRON_DEFAULT_ERROR_MODE")) SetErrorMode(GetErrorMode() & ~SEM_NOGPFAULTERRORBOX); #endif } @@ -149,9 +149,19 @@ node::Environment* NodeBindings::CreateEnvironment( auto args = AtomCommandLine::argv(); // Feed node the path to initialization script. - base::FilePath::StringType process_type = is_browser_ ? - FILE_PATH_LITERAL("browser") : FILE_PATH_LITERAL("renderer"); - base::FilePath resources_path = GetResourcesPath(is_browser_); + base::FilePath::StringType process_type; + switch (browser_env_) { + case BROWSER: + process_type = FILE_PATH_LITERAL("browser"); + break; + case RENDERER: + process_type = FILE_PATH_LITERAL("renderer"); + break; + case WORKER: + process_type = FILE_PATH_LITERAL("worker"); + break; + } + base::FilePath resources_path = GetResourcesPath(browser_env_ == BROWSER); base::FilePath script_path = resources_path.Append(FILE_PATH_LITERAL("electron.asar")) .Append(process_type) @@ -164,7 +174,7 @@ node::Environment* NodeBindings::CreateEnvironment( new node::IsolateData(context->GetIsolate(), uv_default_loop()), context, args.size(), c_argv.get(), 0, nullptr); - if (is_browser_) { + if (browser_env_ == BROWSER) { // SetAutorunMicrotasks is no longer called in node::CreateEnvironment // so instead call it here to match expected node behavior context->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit); @@ -178,7 +188,7 @@ node::Environment* NodeBindings::CreateEnvironment( process.Set("type", process_type); process.Set("resourcesPath", resources_path); // Do not set DOM globals for renderer process. - if (!is_browser_) + if (browser_env_ != BROWSER) process.Set("_noBrowserGlobals", resources_path); // The path to helper app. base::FilePath helper_exec_path; @@ -187,7 +197,7 @@ node::Environment* NodeBindings::CreateEnvironment( // Set process._debugWaitConnect if --debug-brk was specified to stop // the debugger on the first line - if (is_browser_ && + if (browser_env_ == BROWSER && base::CommandLine::ForCurrentProcess()->HasSwitch("debug-brk")) process.Set("_debugWaitConnect", true); @@ -200,7 +210,8 @@ void NodeBindings::LoadEnvironment(node::Environment* env) { } void NodeBindings::PrepareMessageLoop() { - DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(browser_env_ != BROWSER || + BrowserThread::CurrentlyOn(BrowserThread::UI)); // Add dummy handle for libuv, otherwise libuv would quit when there is // nothing to do. @@ -212,7 +223,8 @@ void NodeBindings::PrepareMessageLoop() { } void NodeBindings::RunMessageLoop() { - DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(browser_env_ != BROWSER || + BrowserThread::CurrentlyOn(BrowserThread::UI)); // The MessageLoop should have been created, remember the one in main thread. task_runner_ = base::ThreadTaskRunnerHandle::Get(); @@ -222,7 +234,8 @@ void NodeBindings::RunMessageLoop() { } void NodeBindings::UvRunOnce() { - DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(browser_env_ != BROWSER || + BrowserThread::CurrentlyOn(BrowserThread::UI)); node::Environment* env = uv_env(); @@ -237,13 +250,13 @@ void NodeBindings::UvRunOnce() { v8::MicrotasksScope script_scope(env->isolate(), v8::MicrotasksScope::kRunMicrotasks); - if (!is_browser_) + if (browser_env_ != BROWSER) TRACE_EVENT_BEGIN0("devtools.timeline", "FunctionCall"); // Deal with uv events. int r = uv_run(uv_loop_, UV_RUN_NOWAIT); - if (!is_browser_) + if (browser_env_ != BROWSER) TRACE_EVENT_END0("devtools.timeline", "FunctionCall"); if (r == 0) diff --git a/atom/common/node_bindings.h b/atom/common/node_bindings.h index 663b0acf07..5a77162b92 100644 --- a/atom/common/node_bindings.h +++ b/atom/common/node_bindings.h @@ -23,7 +23,13 @@ namespace atom { class NodeBindings { public: - static NodeBindings* Create(bool is_browser); + enum BrowserEnvironment { + BROWSER, + RENDERER, + WORKER, + }; + + static NodeBindings* Create(BrowserEnvironment browser_env); virtual ~NodeBindings(); @@ -47,7 +53,7 @@ class NodeBindings { node::Environment* uv_env() const { return uv_env_; } protected: - explicit NodeBindings(bool is_browser); + explicit NodeBindings(BrowserEnvironment browser_env); // Called to poll events in new thread. virtual void PollEvents() = 0; @@ -61,8 +67,8 @@ class NodeBindings { // Interrupt the PollEvents. void WakeupEmbedThread(); - // Are we running in browser. - bool is_browser_; + // Which environment we are running. + BrowserEnvironment browser_env_; // Main thread's MessageLoop. scoped_refptr task_runner_; diff --git a/atom/common/node_bindings_linux.cc b/atom/common/node_bindings_linux.cc index 34b9ea9523..3ced7029cb 100644 --- a/atom/common/node_bindings_linux.cc +++ b/atom/common/node_bindings_linux.cc @@ -8,8 +8,8 @@ namespace atom { -NodeBindingsLinux::NodeBindingsLinux(bool is_browser) - : NodeBindings(is_browser), +NodeBindingsLinux::NodeBindingsLinux(BrowserEnvironment browser_env) + : NodeBindings(browser_env), epoll_(epoll_create(1)) { int backend_fd = uv_backend_fd(uv_loop_); struct epoll_event ev = { 0 }; @@ -50,8 +50,8 @@ void NodeBindingsLinux::PollEvents() { } // static -NodeBindings* NodeBindings::Create(bool is_browser) { - return new NodeBindingsLinux(is_browser); +NodeBindings* NodeBindings::Create(BrowserEnvironment browser_env) { + return new NodeBindingsLinux(browser_env); } } // namespace atom diff --git a/atom/common/node_bindings_linux.h b/atom/common/node_bindings_linux.h index 341bf133ed..829a9d84dd 100644 --- a/atom/common/node_bindings_linux.h +++ b/atom/common/node_bindings_linux.h @@ -12,7 +12,7 @@ namespace atom { class NodeBindingsLinux : public NodeBindings { public: - explicit NodeBindingsLinux(bool is_browser); + explicit NodeBindingsLinux(BrowserEnvironment browser_env); virtual ~NodeBindingsLinux(); void RunMessageLoop() override; diff --git a/atom/common/node_bindings_mac.cc b/atom/common/node_bindings_mac.cc index cbcbdba360..e7006a507b 100644 --- a/atom/common/node_bindings_mac.cc +++ b/atom/common/node_bindings_mac.cc @@ -14,8 +14,8 @@ namespace atom { -NodeBindingsMac::NodeBindingsMac(bool is_browser) - : NodeBindings(is_browser) { +NodeBindingsMac::NodeBindingsMac(BrowserEnvironment browser_env) + : NodeBindings(browser_env) { } NodeBindingsMac::~NodeBindingsMac() { @@ -60,8 +60,8 @@ void NodeBindingsMac::PollEvents() { } // static -NodeBindings* NodeBindings::Create(bool is_browser) { - return new NodeBindingsMac(is_browser); +NodeBindings* NodeBindings::Create(BrowserEnvironment browser_env) { + return new NodeBindingsMac(browser_env); } } // namespace atom diff --git a/atom/common/node_bindings_mac.h b/atom/common/node_bindings_mac.h index 96c79ec6f0..6b0082bc22 100644 --- a/atom/common/node_bindings_mac.h +++ b/atom/common/node_bindings_mac.h @@ -12,7 +12,7 @@ namespace atom { class NodeBindingsMac : public NodeBindings { public: - explicit NodeBindingsMac(bool is_browser); + explicit NodeBindingsMac(BrowserEnvironment browser_env); virtual ~NodeBindingsMac(); void RunMessageLoop() override; diff --git a/atom/common/node_bindings_win.cc b/atom/common/node_bindings_win.cc index b8de4f59da..419b0ce4c6 100644 --- a/atom/common/node_bindings_win.cc +++ b/atom/common/node_bindings_win.cc @@ -14,8 +14,8 @@ extern "C" { namespace atom { -NodeBindingsWin::NodeBindingsWin(bool is_browser) - : NodeBindings(is_browser) { +NodeBindingsWin::NodeBindingsWin(BrowserEnvironment browser_env) + : NodeBindings(browser_env) { } NodeBindingsWin::~NodeBindingsWin() { @@ -45,8 +45,8 @@ void NodeBindingsWin::PollEvents() { } // static -NodeBindings* NodeBindings::Create(bool is_browser) { - return new NodeBindingsWin(is_browser); +NodeBindings* NodeBindings::Create(BrowserEnvironment browser_env) { + return new NodeBindingsWin(browser_env); } } // namespace atom diff --git a/atom/common/node_bindings_win.h b/atom/common/node_bindings_win.h index 3950098e5e..793586d88d 100644 --- a/atom/common/node_bindings_win.h +++ b/atom/common/node_bindings_win.h @@ -12,7 +12,7 @@ namespace atom { class NodeBindingsWin : public NodeBindings { public: - explicit NodeBindingsWin(bool is_browser); + explicit NodeBindingsWin(BrowserEnvironment browser_env); virtual ~NodeBindingsWin(); private: diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 623e09015b..14ca3b60ec 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -216,7 +216,7 @@ std::vector ParseSchemesCLISwitch(const char* switch_name) { AtomRendererClient::AtomRendererClient() : node_integration_initialized_(false), - node_bindings_(NodeBindings::Create(false)), + node_bindings_(NodeBindings::Create(NodeBindings::RENDERER)), atom_bindings_(new AtomBindings) { isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kContextIsolation); diff --git a/atom/renderer/web_worker_observer.cc b/atom/renderer/web_worker_observer.cc index 121da69cea..a6296f92d5 100644 --- a/atom/renderer/web_worker_observer.cc +++ b/atom/renderer/web_worker_observer.cc @@ -28,7 +28,7 @@ WebWorkerObserver* WebWorkerObserver::GetCurrent() { } WebWorkerObserver::WebWorkerObserver() - : node_bindings_(NodeBindings::Create(false)), + : node_bindings_(NodeBindings::Create(NodeBindings::WORKER)), atom_bindings_(new AtomBindings) { lazy_tls.Pointer()->Set(this); } From bb5ad4ac0501cd43c269f202ff08a443541193af Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 8 Mar 2017 18:58:54 +0900 Subject: [PATCH 16/31] Correctly initialize Node environment in worker --- filenames.gypi | 1 + lib/renderer/init.js | 2 +- lib/worker/init.js | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 lib/worker/init.js diff --git a/filenames.gypi b/filenames.gypi index 31d4fddd65..3b557fcb88 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -76,6 +76,7 @@ 'lib/renderer/extensions/i18n.js', 'lib/renderer/extensions/storage.js', 'lib/renderer/extensions/web-navigation.js', + 'lib/worker/init.js', ], 'js2c_sources': [ 'lib/common/asar.js', diff --git a/lib/renderer/init.js b/lib/renderer/init.js index 892be116d9..38441c9ec1 100644 --- a/lib/renderer/init.js +++ b/lib/renderer/init.js @@ -6,7 +6,7 @@ const Module = require('module') const resolvePromise = Promise.resolve.bind(Promise) // We modified the original process.argv to let node.js load the -// atom-renderer.js, we need to restore it here. +// init.js, we need to restore it here. process.argv.splice(1, 1) // Clear search paths. diff --git a/lib/worker/init.js b/lib/worker/init.js new file mode 100644 index 0000000000..6a38ce85dc --- /dev/null +++ b/lib/worker/init.js @@ -0,0 +1,37 @@ +'use strict' + +const path = require('path') +const Module = require('module') + +// We modified the original process.argv to let node.js load the +// init.js, we need to restore it here. +process.argv.splice(1, 1) + +// Clear search paths. +require('../common/reset-search-paths') + +// Import common settings. +require('../common/init') + +// Expose public APIs. +Module.globalPaths.push(path.join(__dirname, 'api', 'exports')) + +// Export node bindings to global. +global.require = require +global.module = module + +// Set the __filename to the path of html file if it is file: protocol. +if (self.location.protocol === 'file:') { + let pathname = process.platform === 'win32' && self.location.pathname[0] === '/' ? self.location.pathname.substr(1) : self.location.pathname + global.__filename = path.normalize(decodeURIComponent(pathname)) + global.__dirname = path.dirname(global.__filename) + + // Set module's filename so relative require can work as expected. + module.filename = global.__filename + + // Also search for module under the html file. + module.paths = module.paths.concat(Module._nodeModulePaths(global.__dirname)) +} else { + global.__filename = __filename + global.__dirname = __dirname +} From 69df934710c81d233d80a7143d4603cab8ff1969 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 10 Mar 2017 11:01:17 +0900 Subject: [PATCH 17/31] Converter for base::Callback is not thread safe --- atom/common/api/atom_api_asar.cc | 15 ++++++++------- atom/common/native_mate_converters/callback.cc | 2 -- atom/common/native_mate_converters/callback.h | 2 ++ atom/common/node_bindings.cc | 11 ----------- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/atom/common/api/atom_api_asar.cc b/atom/common/api/atom_api_asar.cc index e94099bacf..3151da6f17 100644 --- a/atom/common/api/atom_api_asar.cc +++ b/atom/common/api/atom_api_asar.cc @@ -141,15 +141,16 @@ void InitAsarSupport(v8::Isolate* isolate, v8::Local result = asar_init->Run(); // Initialize asar support. - base::Callback, - v8::Local, - std::string)> init; - if (mate::ConvertFromV8(isolate, result, &init)) { + if (result->IsFunction()) { const char* asar_native = reinterpret_cast( static_cast(node::asar_data)); - init.Run(process, - require, - std::string(asar_native, sizeof(node::asar_data) - 1)); + base::StringPiece asar_data(asar_native, sizeof(node::asar_data) - 1); + v8::Local args[] = { + process, + require, + mate::ConvertToV8(isolate, asar_data), + }; + result.As()->Call(result, 3, args); } } diff --git a/atom/common/native_mate_converters/callback.cc b/atom/common/native_mate_converters/callback.cc index dc6d30fd23..a6a500be73 100644 --- a/atom/common/native_mate_converters/callback.cc +++ b/atom/common/native_mate_converters/callback.cc @@ -4,8 +4,6 @@ #include "atom/common/native_mate_converters/callback.h" -#include "content/public/browser/browser_thread.h" - using content::BrowserThread; namespace mate { diff --git a/atom/common/native_mate_converters/callback.h b/atom/common/native_mate_converters/callback.h index decc36eb57..f42ee87b4e 100644 --- a/atom/common/native_mate_converters/callback.h +++ b/atom/common/native_mate_converters/callback.h @@ -10,7 +10,9 @@ #include "atom/common/api/locker.h" #include "base/bind.h" #include "base/callback.h" +#include "base/message_loop/message_loop.h" #include "base/memory/weak_ptr.h" +#include "content/public/browser/browser_thread.h" #include "native_mate/function_template.h" #include "native_mate/scoped_persistent.h" diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index cb6cf34426..e6dcb4e545 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -25,8 +25,6 @@ #include "atom/common/node_includes.h" -using content::BrowserThread; - // Force all builtin modules to be referenced so they can actually run their // DSO constructors, see http://git.io/DRIqCg. #define REFERENCE_MODULE(name) \ @@ -210,9 +208,6 @@ void NodeBindings::LoadEnvironment(node::Environment* env) { } void NodeBindings::PrepareMessageLoop() { - DCHECK(browser_env_ != BROWSER || - BrowserThread::CurrentlyOn(BrowserThread::UI)); - // Add dummy handle for libuv, otherwise libuv would quit when there is // nothing to do. uv_async_init(uv_loop_, &dummy_uv_handle_, nullptr); @@ -223,9 +218,6 @@ void NodeBindings::PrepareMessageLoop() { } void NodeBindings::RunMessageLoop() { - DCHECK(browser_env_ != BROWSER || - BrowserThread::CurrentlyOn(BrowserThread::UI)); - // The MessageLoop should have been created, remember the one in main thread. task_runner_ = base::ThreadTaskRunnerHandle::Get(); @@ -234,9 +226,6 @@ void NodeBindings::RunMessageLoop() { } void NodeBindings::UvRunOnce() { - DCHECK(browser_env_ != BROWSER || - BrowserThread::CurrentlyOn(BrowserThread::UI)); - node::Environment* env = uv_env(); // Use Locker in browser process. From d2f185bea5ffe47c90bc3d87b94bee746055a568 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 10 Mar 2017 15:22:25 +0900 Subject: [PATCH 18/31] Create new uv loop in each worker --- atom/common/node_bindings.cc | 4 ++-- atom/renderer/web_worker_observer.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index e6dcb4e545..7c1342359b 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -98,7 +98,7 @@ base::FilePath GetResourcesPath(bool is_browser) { NodeBindings::NodeBindings(BrowserEnvironment browser_env) : browser_env_(browser_env), - uv_loop_(uv_default_loop()), + uv_loop_(browser_env == WORKER ? uv_loop_new() : uv_default_loop()), embed_closed_(false), uv_env_(nullptr), weak_factory_(this) { @@ -169,7 +169,7 @@ node::Environment* NodeBindings::CreateEnvironment( std::unique_ptr c_argv = StringVectorToArgArray(args); node::Environment* env = node::CreateEnvironment( - new node::IsolateData(context->GetIsolate(), uv_default_loop()), context, + new node::IsolateData(context->GetIsolate(), uv_loop_), context, args.size(), c_argv.get(), 0, nullptr); if (browser_env_ == BROWSER) { diff --git a/atom/renderer/web_worker_observer.cc b/atom/renderer/web_worker_observer.cc index a6296f92d5..65ca81c677 100644 --- a/atom/renderer/web_worker_observer.cc +++ b/atom/renderer/web_worker_observer.cc @@ -40,7 +40,7 @@ WebWorkerObserver::~WebWorkerObserver() { void WebWorkerObserver::ContextCreated(v8::Local context) { v8::Context::Scope context_scope(context); - node_bindings_->Initialize(); + // Start the embed thread. node_bindings_->PrepareMessageLoop(); // Setup node environment for each window. From 9c9c8ec5f131bd3600fe48e67e5a688e0b8fd0cb Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 10 Mar 2017 15:35:44 +0900 Subject: [PATCH 19/31] WebWorkerObserver should be destroyed on exit --- atom/renderer/web_worker_observer.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/atom/renderer/web_worker_observer.cc b/atom/renderer/web_worker_observer.cc index 65ca81c677..aa335a92d5 100644 --- a/atom/renderer/web_worker_observer.cc +++ b/atom/renderer/web_worker_observer.cc @@ -68,6 +68,7 @@ void WebWorkerObserver::ContextWillDestroy(v8::Local context) { node::FreeEnvironment(env); atom_bindings_.reset(); node_bindings_.reset(); + delete this; } } // namespace atom From c068285ff8f2c0faa8a5ec204767a3a7143606f7 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 10 Mar 2017 17:07:51 +0900 Subject: [PATCH 20/31] AtomBindings should not use default uv loop --- atom/browser/atom_browser_main_parts.cc | 2 +- atom/common/api/atom_bindings.cc | 4 ++-- atom/common/api/atom_bindings.h | 2 +- atom/common/node_bindings.cc | 4 ++++ atom/common/node_bindings.h | 6 ++++-- atom/renderer/atom_renderer_client.cc | 2 +- atom/renderer/web_worker_observer.cc | 4 +--- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index 095bcbc138..c175b3d2e5 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -61,7 +61,7 @@ AtomBrowserMainParts::AtomBrowserMainParts() exit_code_(nullptr), browser_(new Browser), node_bindings_(NodeBindings::Create(NodeBindings::BROWSER)), - atom_bindings_(new AtomBindings), + atom_bindings_(new AtomBindings(uv_default_loop())), gc_timer_(true, true) { DCHECK(!self_) << "Cannot have two AtomBrowserMainParts"; self_ = this; diff --git a/atom/common/api/atom_bindings.cc b/atom/common/api/atom_bindings.cc index f1b56c6759..c82589d6b1 100644 --- a/atom/common/api/atom_bindings.cc +++ b/atom/common/api/atom_bindings.cc @@ -78,8 +78,8 @@ void FatalErrorCallback(const char* location, const char* message) { } // namespace -AtomBindings::AtomBindings() { - uv_async_init(uv_default_loop(), &call_next_tick_async_, OnCallNextTick); +AtomBindings::AtomBindings(uv_loop_t* loop) { + uv_async_init(loop, &call_next_tick_async_, OnCallNextTick); call_next_tick_async_.data = this; } diff --git a/atom/common/api/atom_bindings.h b/atom/common/api/atom_bindings.h index 3fd43cc8a1..8157417150 100644 --- a/atom/common/api/atom_bindings.h +++ b/atom/common/api/atom_bindings.h @@ -20,7 +20,7 @@ namespace atom { class AtomBindings { public: - AtomBindings(); + explicit AtomBindings(uv_loop_t* loop); virtual ~AtomBindings(); // Add process.atomBinding function, which behaves like process.binding but diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 7c1342359b..314a7b9c03 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -116,6 +116,10 @@ NodeBindings::~NodeBindings() { // Clear uv. uv_sem_destroy(&embed_sem_); uv_close(reinterpret_cast(&dummy_uv_handle_), nullptr); + + // Destroy loop. + if (uv_loop_ != uv_default_loop()) + uv_loop_delete(uv_loop_); } void NodeBindings::Initialize() { diff --git a/atom/common/node_bindings.h b/atom/common/node_bindings.h index 5a77162b92..5047a9afb2 100644 --- a/atom/common/node_bindings.h +++ b/atom/common/node_bindings.h @@ -52,6 +52,8 @@ class NodeBindings { void set_uv_env(node::Environment* env) { uv_env_ = env; } node::Environment* uv_env() const { return uv_env_; } + uv_loop_t* uv_loop() const { return uv_loop_; } + protected: explicit NodeBindings(BrowserEnvironment browser_env); @@ -70,10 +72,10 @@ class NodeBindings { // Which environment we are running. BrowserEnvironment browser_env_; - // Main thread's MessageLoop. + // Current thread's MessageLoop. scoped_refptr task_runner_; - // Main thread's libuv loop. + // Current thread's libuv loop. uv_loop_t* uv_loop_; private: diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 14ca3b60ec..37a16ee56f 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -217,7 +217,7 @@ std::vector ParseSchemesCLISwitch(const char* switch_name) { AtomRendererClient::AtomRendererClient() : node_integration_initialized_(false), node_bindings_(NodeBindings::Create(NodeBindings::RENDERER)), - atom_bindings_(new AtomBindings) { + atom_bindings_(new AtomBindings(uv_default_loop())) { isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kContextIsolation); // Parse --standard-schemes=scheme1,scheme2 diff --git a/atom/renderer/web_worker_observer.cc b/atom/renderer/web_worker_observer.cc index aa335a92d5..323c9be7f2 100644 --- a/atom/renderer/web_worker_observer.cc +++ b/atom/renderer/web_worker_observer.cc @@ -29,7 +29,7 @@ WebWorkerObserver* WebWorkerObserver::GetCurrent() { WebWorkerObserver::WebWorkerObserver() : node_bindings_(NodeBindings::Create(NodeBindings::WORKER)), - atom_bindings_(new AtomBindings) { + atom_bindings_(new AtomBindings(node_bindings_->uv_loop())) { lazy_tls.Pointer()->Set(this); } @@ -66,8 +66,6 @@ void WebWorkerObserver::ContextWillDestroy(v8::Local context) { // Destroy the node environment. node::FreeEnvironment(env); - atom_bindings_.reset(); - node_bindings_.reset(); delete this; } From e496e18f6e3a34ab97cc6a12aa757c8e48d2066f Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 10 Mar 2017 17:33:27 +0900 Subject: [PATCH 21/31] Make Archive thread safe --- atom/browser/atom_browser_main_parts.cc | 2 ++ atom/common/asar/asar_util.cc | 13 +++++++++++-- atom/common/asar/asar_util.h | 3 +++ atom/common/native_mate_converters/callback.h | 2 +- atom/renderer/atom_renderer_client.cc | 2 ++ atom/renderer/web_worker_observer.cc | 5 +++-- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc index c175b3d2e5..d3f8237d5e 100644 --- a/atom/browser/atom_browser_main_parts.cc +++ b/atom/browser/atom_browser_main_parts.cc @@ -14,6 +14,7 @@ #include "atom/browser/javascript_environment.h" #include "atom/browser/node_debugger.h" #include "atom/common/api/atom_bindings.h" +#include "atom/common/asar/asar_util.h" #include "atom/common/node_bindings.h" #include "atom/common/node_includes.h" #include "base/command_line.h" @@ -71,6 +72,7 @@ AtomBrowserMainParts::AtomBrowserMainParts() } AtomBrowserMainParts::~AtomBrowserMainParts() { + asar::ClearArchives(); // Leak the JavascriptEnvironment on exit. // This is to work around the bug that V8 would be waiting for background // tasks to finish on exit, while somehow it waits forever in Electron, more diff --git a/atom/common/asar/asar_util.cc b/atom/common/asar/asar_util.cc index 1eee09949a..0ffbfc6c36 100644 --- a/atom/common/asar/asar_util.cc +++ b/atom/common/asar/asar_util.cc @@ -12,6 +12,7 @@ #include "base/files/file_util.h" #include "base/lazy_instance.h" #include "base/stl_util.h" +#include "base/threading/thread_local.h" namespace asar { @@ -19,14 +20,17 @@ namespace { // The global instance of ArchiveMap, will be destroyed on exit. typedef std::map> ArchiveMap; -static base::LazyInstance g_archive_map = LAZY_INSTANCE_INITIALIZER; +base::LazyInstance>::Leaky + g_archive_map_tls = LAZY_INSTANCE_INITIALIZER; const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar"); } // namespace std::shared_ptr GetOrCreateAsarArchive(const base::FilePath& path) { - ArchiveMap& archive_map = *g_archive_map.Pointer(); + if (!g_archive_map_tls.Pointer()->Get()) + g_archive_map_tls.Pointer()->Set(new ArchiveMap); + ArchiveMap& archive_map = *g_archive_map_tls.Pointer()->Get(); if (!ContainsKey(archive_map, path)) { std::shared_ptr archive(new Archive(path)); if (!archive->Init()) @@ -36,6 +40,11 @@ std::shared_ptr GetOrCreateAsarArchive(const base::FilePath& path) { return archive_map[path]; } +void ClearArchives() { + if (g_archive_map_tls.Pointer()->Get()) + delete g_archive_map_tls.Pointer()->Get(); +} + bool GetAsarArchivePath(const base::FilePath& full_path, base::FilePath* asar_path, base::FilePath* relative_path) { diff --git a/atom/common/asar/asar_util.h b/atom/common/asar/asar_util.h index 4cb5b88e04..90ffb9b46a 100644 --- a/atom/common/asar/asar_util.h +++ b/atom/common/asar/asar_util.h @@ -19,6 +19,9 @@ class Archive; // Gets or creates a new Archive from the path. std::shared_ptr GetOrCreateAsarArchive(const base::FilePath& path); +// Destroy cached Archive objects. +void ClearArchives(); + // Separates the path to Archive out. bool GetAsarArchivePath(const base::FilePath& full_path, base::FilePath* asar_path, diff --git a/atom/common/native_mate_converters/callback.h b/atom/common/native_mate_converters/callback.h index f42ee87b4e..28bff3c82a 100644 --- a/atom/common/native_mate_converters/callback.h +++ b/atom/common/native_mate_converters/callback.h @@ -10,8 +10,8 @@ #include "atom/common/api/locker.h" #include "base/bind.h" #include "base/callback.h" -#include "base/message_loop/message_loop.h" #include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" #include "content/public/browser/browser_thread.h" #include "native_mate/function_template.h" #include "native_mate/scoped_persistent.h" diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 37a16ee56f..c4f739c305 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -13,6 +13,7 @@ #include "atom/common/api/atom_bindings.h" #include "atom/common/api/event_emitter_caller.h" #include "atom/common/atom_constants.h" +#include "atom/common/asar/asar_util.h" #include "atom/common/color_util.h" #include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/node_bindings.h" @@ -228,6 +229,7 @@ AtomRendererClient::AtomRendererClient() } AtomRendererClient::~AtomRendererClient() { + asar::ClearArchives(); } void AtomRendererClient::RenderThreadStarted() { diff --git a/atom/renderer/web_worker_observer.cc b/atom/renderer/web_worker_observer.cc index 323c9be7f2..954b2f2361 100644 --- a/atom/renderer/web_worker_observer.cc +++ b/atom/renderer/web_worker_observer.cc @@ -6,6 +6,7 @@ #include "atom/common/api/atom_bindings.h" #include "atom/common/api/event_emitter_caller.h" +#include "atom/common/asar/asar_util.h" #include "atom/common/node_bindings.h" #include "base/lazy_instance.h" #include "base/threading/thread_local.h" @@ -35,6 +36,8 @@ WebWorkerObserver::WebWorkerObserver() WebWorkerObserver::~WebWorkerObserver() { lazy_tls.Pointer()->Set(nullptr); + node::FreeEnvironment(node_bindings_->uv_env()); + asar::ClearArchives(); } void WebWorkerObserver::ContextCreated(v8::Local context) { @@ -64,8 +67,6 @@ void WebWorkerObserver::ContextWillDestroy(v8::Local context) { if (env) mate::EmitEvent(env->isolate(), env->process_object(), "exit"); - // Destroy the node environment. - node::FreeEnvironment(env); delete this; } From a49af26e39816d6c13456f4ccb0eebff26968c00 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 15 Mar 2017 18:51:21 +0900 Subject: [PATCH 22/31] Add nodeIntegrationInWorker option --- atom/browser/web_contents_preferences.cc | 4 ++++ atom/common/options_switches.cc | 6 ++++++ atom/common/options_switches.h | 2 ++ atom/renderer/atom_renderer_client.cc | 10 ++++++++-- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/atom/browser/web_contents_preferences.cc b/atom/browser/web_contents_preferences.cc index c6527dd6f6..7bb8605039 100644 --- a/atom/browser/web_contents_preferences.cc +++ b/atom/browser/web_contents_preferences.cc @@ -97,6 +97,10 @@ void WebContentsPreferences::AppendExtraCommandLineSwitches( command_line->AppendSwitchASCII(switches::kNodeIntegration, node_integration ? "true" : "false"); + // Whether to enable node integration in Worker. + if (web_preferences.GetBoolean(options::kNodeIntegrationInWorker, &b) && b) + command_line->AppendSwitch(switches::kNodeIntegrationInWorker); + // If the `sandbox` option was passed to the BrowserWindow's webPreferences, // pass `--enable-sandbox` to the renderer so it won't have any node.js // integration. diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index 6db479ceb7..d040489b9f 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -122,6 +122,9 @@ const char kBlinkFeatures[] = "blinkFeatures"; // Disable blink features. const char kDisableBlinkFeatures[] = "disableBlinkFeatures"; +// Enable the node integration in WebWorker. +const char kNodeIntegrationInWorker[] = "nodeIntegrationInWorker"; + } // namespace options namespace switches { @@ -164,6 +167,9 @@ const char kOpenerID[] = "opener-id"; const char kScrollBounce[] = "scroll-bounce"; const char kHiddenPage[] = "hidden-page"; +// Command switch passed to renderer process to control nodeIntegration. +const char kNodeIntegrationInWorker[] = "node-integration-in-worker"; + // Widevine options // Path to Widevine CDM binaries. const char kWidevineCdmPath[] = "widevine-cdm-path"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index abe3856cd8..dd2824c55c 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -62,6 +62,7 @@ extern const char kOpenerID[]; extern const char kScrollBounce[]; extern const char kBlinkFeatures[]; extern const char kDisableBlinkFeatures[]; +extern const char kNodeIntegrationInWorker[]; } // namespace options @@ -89,6 +90,7 @@ extern const char kGuestInstanceID[]; extern const char kOpenerID[]; extern const char kScrollBounce[]; extern const char kHiddenPage[]; +extern const char kNodeIntegrationInWorker[]; extern const char kWidevineCdmPath[]; extern const char kWidevineCdmVersion[]; diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index c4f739c305..2a5c0218aa 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -441,12 +441,18 @@ void AtomRendererClient::AddSupportedKeySystems( void AtomRendererClient::DidInitializeWorkerContextOnWorkerThread( v8::Local context) { - WebWorkerObserver::GetCurrent()->ContextCreated(context); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kNodeIntegrationInWorker)) { + WebWorkerObserver::GetCurrent()->ContextCreated(context); + } } void AtomRendererClient::WillDestroyWorkerContextOnWorkerThread( v8::Local context) { - WebWorkerObserver::GetCurrent()->ContextWillDestroy(context); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kNodeIntegrationInWorker)) { + WebWorkerObserver::GetCurrent()->ContextWillDestroy(context); + } } v8::Local AtomRendererClient::GetContext( From ab83aa0bfd0b60c26e5615ed90b96f3d6d6f56d4 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 15 Mar 2017 19:34:21 +0900 Subject: [PATCH 23/31] docs: Multithreading --- default_app/default_app.js | 3 ++ docs/api/browser-window.md | 3 ++ docs/tutorial/multithreading.md | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 docs/tutorial/multithreading.md diff --git a/default_app/default_app.js b/default_app/default_app.js index bfb97a9ab0..2a3ce3a85e 100644 --- a/default_app/default_app.js +++ b/default_app/default_app.js @@ -15,6 +15,9 @@ exports.load = (appUrl) => { height: 600, autoHideMenuBar: true, backgroundColor: '#FFFFFF', + webPreferences: { + nodeIntegrationInWorker: true + }, useContentSize: true } if (process.platform === 'linux') { diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 3fdda95ed7..2456c73e80 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -215,6 +215,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `devTools` Boolean (optional) - Whether to enable DevTools. If it is set to `false`, can not use `BrowserWindow.webContents.openDevTools()` to open DevTools. Default is `true`. * `nodeIntegration` Boolean (optional) - Whether node integration is enabled. Default is `true`. + * `nodeIntegrationInWorker` Boolean (optional) - Whether node integration is + enabled in web workers. Default is `false`. More about this can be found + in [Multithreading](../tutorial/multithreading.md). * `preload` String (optional) - Specifies a script that will be loaded before other scripts run in the page. This script will always have access to node APIs no matter whether node integration is turned on or off. The value should diff --git a/docs/tutorial/multithreading.md b/docs/tutorial/multithreading.md new file mode 100644 index 0000000000..38a45d5301 --- /dev/null +++ b/docs/tutorial/multithreading.md @@ -0,0 +1,50 @@ +# Multithreading + +With [Web Workers][web-workers], it is possible to run JavaScript in OS-level +threads. + +## Multi-threaded Node.js + +In Electron, it is supported to use Node.js integration in Web Workers. To do +so the `nodeIntegrationInWorker` option should be set to `true` in +`webPreferences`. + +```javascript +let win = new BrowserWindow({ + webPreferences: { + nodeIntegrationInWorker: true + } +}) +``` + +The `nodeIntegrationInWorker` can be used independent of `nodeIntegration`, but +`sandbox` must not be set to `true`. + +## Available APIs + +All built-in modules of Node.js are supported in Web Workers, and `asar` +archives can still be read with Node.js APIs. However non of Electron's built-in +modules can be used in multi-threaded environment. + +## Native Node.js modules + +Any native Node.js module can be loaded directly in Web Workers, but it is +strongly recommended not to do so. Most existing native modules have been +written assuming single-thread environment, using them in a Web Workers will +lead to crashes and memory corruptions. + +Even when using a thread-safe native Node.js module, it should be noticed that +the `process.dlopen` function is not thread safe, so loading a native module +in Web Workers is not thread safe. + +The only way to load a native module safely for now, is to make sure the app +loads no native modules after the Web Workers get started. + +```javascript +process.dlopen = () => { + throw new Error('Load native module is not safe') +} +new Worker('script.js') +``` + +[web-workers]: https://developer.mozilla.org/en/docs/Web/API/Web_Workers_API/Using_web_workers From 033aa16e04ef9e29087961a06658e5ad7ee0ce3d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 15 Mar 2017 20:07:28 +0900 Subject: [PATCH 24/31] test: Node integration in web workers --- atom/renderer/atom_renderer_client.cc | 1 + docs/tutorial/multithreading.md | 2 +- spec/chromium-spec.js | 44 +++++++++++++++++++++ spec/fixtures/api/unload | 1 + spec/fixtures/pages/shared_worker.html | 12 ++++++ spec/fixtures/pages/worker.html | 12 ++++++ spec/fixtures/workers/shared_worker_node.js | 5 +++ spec/fixtures/workers/worker_node.js | 1 + 8 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/api/unload create mode 100644 spec/fixtures/pages/shared_worker.html create mode 100644 spec/fixtures/pages/worker.html create mode 100644 spec/fixtures/workers/shared_worker_node.js create mode 100644 spec/fixtures/workers/worker_node.js diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 2a5c0218aa..1f96b1754b 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -441,6 +441,7 @@ void AtomRendererClient::AddSupportedKeySystems( void AtomRendererClient::DidInitializeWorkerContextOnWorkerThread( v8::Local context) { + LOG(ERROR) << "DidInitializeWorkerContextOnWorkerThread"; if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kNodeIntegrationInWorker)) { WebWorkerObserver::GetCurrent()->ContextCreated(context); diff --git a/docs/tutorial/multithreading.md b/docs/tutorial/multithreading.md index 38a45d5301..41b0235720 100644 --- a/docs/tutorial/multithreading.md +++ b/docs/tutorial/multithreading.md @@ -30,7 +30,7 @@ modules can be used in multi-threaded environment. Any native Node.js module can be loaded directly in Web Workers, but it is strongly recommended not to do so. Most existing native modules have been -written assuming single-thread environment, using them in a Web Workers will +written assuming single-thread environment, using them in Web Workers will lead to crashes and memory corruptions. Even when using a thread-safe native Node.js module, it should be noticed that diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index dd06f4455e..e0707ec536 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -590,6 +590,27 @@ describe('chromium feature', function () { worker.postMessage(message) }) + it('Worker has no node integration by default', function (done) { + let worker = new Worker('../fixtures/workers/worker_node.js') + worker.onmessage = function (event) { + assert.equal(event.data, 'undefined undefined undefined undefined') + worker.terminate() + done() + } + }) + + it('Worker has node integration with nodeIntegrationInWorker', function (done) { + let webview = new WebView + webview.addEventListener('ipc-message', function (e) { + assert.equal(e.channel, 'object function object function') + webview.remove() + done() + }) + webview.src = 'file://' + fixtures + '/pages/worker.html' + webview.setAttribute('webpreferences', 'nodeIntegration, nodeIntegrationInWorker') + document.body.appendChild(webview) + }) + it('SharedWorker can work', function (done) { var worker = new SharedWorker('../fixtures/workers/shared_worker.js') var message = 'ping' @@ -599,6 +620,29 @@ describe('chromium feature', function () { } worker.port.postMessage(message) }) + + it('SharedWorker has no node integration by default', function (done) { + let worker = new SharedWorker('../fixtures/workers/shared_worker_node.js') + worker.port.onmessage = function (event) { + assert.equal(event.data, 'undefined undefined undefined undefined') + done() + } + }) + + it('SharedWorker has node integration with nodeIntegrationInWorker', function (done) { + let webview = new WebView + webview.addEventListener('console-message', function (e) { + console.log(e) + }) + webview.addEventListener('ipc-message', function (e) { + assert.equal(e.channel, 'object function object function') + webview.remove() + done() + }) + webview.src = 'file://' + fixtures + '/pages/shared_worker.html' + webview.setAttribute('webpreferences', 'nodeIntegration, nodeIntegrationInWorker') + document.body.appendChild(webview) + }) }) describe('iframe', function () { diff --git a/spec/fixtures/api/unload b/spec/fixtures/api/unload new file mode 100644 index 0000000000..98974dbb9f --- /dev/null +++ b/spec/fixtures/api/unload @@ -0,0 +1 @@ +unload \ No newline at end of file diff --git a/spec/fixtures/pages/shared_worker.html b/spec/fixtures/pages/shared_worker.html new file mode 100644 index 0000000000..7a0d0757ab --- /dev/null +++ b/spec/fixtures/pages/shared_worker.html @@ -0,0 +1,12 @@ + + + + + diff --git a/spec/fixtures/pages/worker.html b/spec/fixtures/pages/worker.html new file mode 100644 index 0000000000..c84ef52065 --- /dev/null +++ b/spec/fixtures/pages/worker.html @@ -0,0 +1,12 @@ + + + + + diff --git a/spec/fixtures/workers/shared_worker_node.js b/spec/fixtures/workers/shared_worker_node.js new file mode 100644 index 0000000000..0a52d60fbf --- /dev/null +++ b/spec/fixtures/workers/shared_worker_node.js @@ -0,0 +1,5 @@ +self.onconnect = function (event) { + let port = event.ports[0] + port.start() + port.postMessage([typeof process, typeof setImmediate, typeof global, typeof Buffer].join(' ')) +} diff --git a/spec/fixtures/workers/worker_node.js b/spec/fixtures/workers/worker_node.js new file mode 100644 index 0000000000..5d59d2d0c3 --- /dev/null +++ b/spec/fixtures/workers/worker_node.js @@ -0,0 +1 @@ +self.postMessage([typeof process, typeof setImmediate, typeof global, typeof Buffer].join(' ')) From 940d77b9a0e990315894d3fd881e4b6df2c2d755 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 16 Mar 2017 17:41:25 +0900 Subject: [PATCH 25/31] Fix typos and adjust sentences --- atom/renderer/atom_renderer_client.cc | 1 - docs/tutorial/multithreading.md | 14 +++++++------- spec/fixtures/api/unload | 1 - 3 files changed, 7 insertions(+), 9 deletions(-) delete mode 100644 spec/fixtures/api/unload diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 1f96b1754b..2a5c0218aa 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -441,7 +441,6 @@ void AtomRendererClient::AddSupportedKeySystems( void AtomRendererClient::DidInitializeWorkerContextOnWorkerThread( v8::Local context) { - LOG(ERROR) << "DidInitializeWorkerContextOnWorkerThread"; if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kNodeIntegrationInWorker)) { WebWorkerObserver::GetCurrent()->ContextCreated(context); diff --git a/docs/tutorial/multithreading.md b/docs/tutorial/multithreading.md index 41b0235720..2bf0a5645e 100644 --- a/docs/tutorial/multithreading.md +++ b/docs/tutorial/multithreading.md @@ -5,7 +5,7 @@ threads. ## Multi-threaded Node.js -In Electron, it is supported to use Node.js integration in Web Workers. To do +It is possible to use Node.js features in Electron's Web Workers, to do so the `nodeIntegrationInWorker` option should be set to `true` in `webPreferences`. @@ -23,19 +23,19 @@ The `nodeIntegrationInWorker` can be used independent of `nodeIntegration`, but ## Available APIs All built-in modules of Node.js are supported in Web Workers, and `asar` -archives can still be read with Node.js APIs. However non of Electron's built-in -modules can be used in multi-threaded environment. +archives can still be read with Node.js APIs. However none of Electron's +built-in modules can be used in a multi-threaded environment. ## Native Node.js modules Any native Node.js module can be loaded directly in Web Workers, but it is strongly recommended not to do so. Most existing native modules have been -written assuming single-thread environment, using them in Web Workers will +written assuming single-threaded environment, using them in Web Workers will lead to crashes and memory corruptions. -Even when using a thread-safe native Node.js module, it should be noticed that -the `process.dlopen` function is not thread safe, so loading a native module -in Web Workers is not thread safe. +Note that even if a native Node.js module is thread-safe it's still not safe to +load it in a Web Worker because the `process.dlopen` function is not thread +safe. The only way to load a native module safely for now, is to make sure the app loads no native modules after the Web Workers get started. diff --git a/spec/fixtures/api/unload b/spec/fixtures/api/unload deleted file mode 100644 index 98974dbb9f..0000000000 --- a/spec/fixtures/api/unload +++ /dev/null @@ -1 +0,0 @@ -unload \ No newline at end of file From 40b35a991f415973b7f35ad106d735002e989cf7 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 16 Mar 2017 19:51:43 +0900 Subject: [PATCH 26/31] Fix js lint --- spec/chromium-spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index e0707ec536..a54c6744f7 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -600,7 +600,7 @@ describe('chromium feature', function () { }) it('Worker has node integration with nodeIntegrationInWorker', function (done) { - let webview = new WebView + let webview = new WebView() webview.addEventListener('ipc-message', function (e) { assert.equal(e.channel, 'object function object function') webview.remove() @@ -630,7 +630,7 @@ describe('chromium feature', function () { }) it('SharedWorker has node integration with nodeIntegrationInWorker', function (done) { - let webview = new WebView + let webview = new WebView() webview.addEventListener('console-message', function (e) { console.log(e) }) From 0287f23e3b546bd8c7f334b3b8ea9a469cd0da58 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 16 Mar 2017 20:14:16 +0900 Subject: [PATCH 27/31] Fix cpplint warning --- atom/renderer/atom_renderer_client.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 2a5c0218aa..8dd8e04e1a 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -12,8 +12,8 @@ #include "atom/common/api/api_messages.h" #include "atom/common/api/atom_bindings.h" #include "atom/common/api/event_emitter_caller.h" -#include "atom/common/atom_constants.h" #include "atom/common/asar/asar_util.h" +#include "atom/common/atom_constants.h" #include "atom/common/color_util.h" #include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/node_bindings.h" From 71c3e97e81f790b6b9087edfa7f087f248aba761 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 16 Mar 2017 20:18:16 +0900 Subject: [PATCH 28/31] Fix docs lint warnings --- docs/tutorial/multithreading.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/multithreading.md b/docs/tutorial/multithreading.md index 2bf0a5645e..b0d298e57e 100644 --- a/docs/tutorial/multithreading.md +++ b/docs/tutorial/multithreading.md @@ -44,7 +44,7 @@ loads no native modules after the Web Workers get started. process.dlopen = () => { throw new Error('Load native module is not safe') } -new Worker('script.js') +let worker = new Worker('script.js') ``` [web-workers]: https://developer.mozilla.org/en/docs/Web/API/Web_Workers_API/Using_web_workers From 99d3fce3c749dfc0a8ab54da231c3379ee674d87 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 20 Mar 2017 13:01:28 -0700 Subject: [PATCH 29/31] node::Environment should be destroyed before AtomBindings The shutdown code may still uses the APIs provieded by AtomBindings. --- atom/browser/atom_browser_main_parts.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h index 71adc43d5e..2ba7d341f4 100644 --- a/atom/browser/atom_browser_main_parts.h +++ b/atom/browser/atom_browser_main_parts.h @@ -80,9 +80,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts { std::unique_ptr browser_; std::unique_ptr js_env_; - std::unique_ptr node_env_; std::unique_ptr node_bindings_; std::unique_ptr atom_bindings_; + std::unique_ptr node_env_; std::unique_ptr node_debugger_; base::Timer gc_timer_; From 23b235c9c73bc8db956e06d3d612ec555caee4ad Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 20 Mar 2017 20:24:01 -0700 Subject: [PATCH 30/31] Default async to false when object is specified --- lib/browser/api/menu.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 9615962ac6..99d650d773 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -144,7 +144,7 @@ Menu.prototype._init = function () { } Menu.prototype.popup = function (window, x, y, positioningItem) { - let asyncPopup = false + let asyncPopup // menu.popup(x, y, positioningItem) if (window != null && (typeof window !== 'object' || window.constructor !== BrowserWindow)) { @@ -174,6 +174,9 @@ Menu.prototype.popup = function (window, x, y, positioningItem) { // Default to not highlighting any item. if (typeof positioningItem !== 'number') positioningItem = -1 + // Default to synchronous for backwards compatibility. + if (typeof asyncPopup !== 'boolean') asyncPopup = false + this.popupAt(window, x, y, positioningItem, asyncPopup) } From 46aed5ff6f4f2e27222dc197f67c48106cf817c8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 22 Mar 2017 08:21:05 -0700 Subject: [PATCH 31/31] Bump v1.6.4 --- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- electron.gyp | 2 +- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 9a1d671324..091614ffd4 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile electron.icns CFBundleVersion - 1.6.3 + 1.6.4 CFBundleShortVersionString - 1.6.3 + 1.6.4 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 4a500e3e64..5a2d8ea32e 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -56,8 +56,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,6,3,0 - PRODUCTVERSION 1,6,3,0 + FILEVERSION 1,6,4,0 + PRODUCTVERSION 1,6,4,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "1.6.3" + VALUE "FileVersion", "1.6.4" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "1.6.3" + VALUE "ProductVersion", "1.6.4" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 155d9566f0..73528b45ea 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 1 #define ATOM_MINOR_VERSION 6 -#define ATOM_PATCH_VERSION 3 +#define ATOM_PATCH_VERSION 4 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/electron.gyp b/electron.gyp index ab9810bfc0..15336a4e6b 100644 --- a/electron.gyp +++ b/electron.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '1.6.3', + 'version%': '1.6.4', 'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c', }, 'includes': [ diff --git a/package.json b/package.json index 8de882fbf5..d321d7831f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "1.6.3", + "version": "1.6.4", "devDependencies": { "asar": "^0.11.0", "browserify": "^13.1.0",