From 237a6eeee62c97abddfbcb009935acf7478992ae Mon Sep 17 00:00:00 2001 From: bridiver Date: Tue, 5 Dec 2017 13:46:33 -0700 Subject: [PATCH] remote callbacks are still used in electron.remote.Menu in browser-laptop --- atom/common/BUILD.gn | 2 + atom/common/api/atom_api_v8_util.cc | 2 + atom/common/api/remote_callback_freer.cc | 51 ++++++++++++++++++++++++ atom/common/api/remote_callback_freer.h | 40 +++++++++++++++++++ lib/browser/rpc-server.js | 28 +++++++++++++ lib/renderer/api/remote.js | 10 +++++ 6 files changed, 133 insertions(+) create mode 100644 atom/common/api/remote_callback_freer.cc create mode 100644 atom/common/api/remote_callback_freer.h diff --git a/atom/common/BUILD.gn b/atom/common/BUILD.gn index a60692988b..a207947355 100644 --- a/atom/common/BUILD.gn +++ b/atom/common/BUILD.gn @@ -81,6 +81,8 @@ source_set("common") { "api/api_messages.h", "api/object_life_monitor.cc", "api/object_life_monitor.h", + "api/remote_callback_freer.cc", + "api/remote_callback_freer.h", "api/remote_object_freer.cc", "api/remote_object_freer.h", "asar/archive.cc", diff --git a/atom/common/api/atom_api_v8_util.cc b/atom/common/api/atom_api_v8_util.cc index de848924f0..7b7655c6cd 100644 --- a/atom/common/api/atom_api_v8_util.cc +++ b/atom/common/api/atom_api_v8_util.cc @@ -6,6 +6,7 @@ #include #include "atom/common/api/atom_api_key_weak_map.h" +#include "atom/common/api/remote_callback_freer.h" #include "atom/common/api/remote_object_freer.h" #include "atom/common/native_mate_converters/content_converter.h" #include "atom/common/node_includes.h" @@ -99,6 +100,7 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("deleteHiddenValue", &DeleteHiddenValue); dict.SetMethod("getObjectHash", &GetObjectHash); dict.SetMethod("takeHeapSnapshot", &TakeHeapSnapshot); + dict.SetMethod("setRemoteCallbackFreer", &atom::RemoteCallbackFreer::BindTo); dict.SetMethod("setRemoteObjectFreer", &atom::RemoteObjectFreer::BindTo); dict.SetMethod("createIDWeakMap", &atom::api::KeyWeakMap::Create); dict.SetMethod("createDoubleIDWeakMap", diff --git a/atom/common/api/remote_callback_freer.cc b/atom/common/api/remote_callback_freer.cc new file mode 100644 index 0000000000..ef0f836cd7 --- /dev/null +++ b/atom/common/api/remote_callback_freer.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/common/api/remote_callback_freer.h" + +#include "atom/common/api/api_messages.h" +#include "base/strings/utf_string_conversions.h" +#include "base/values.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" + +namespace atom { + +// static +void RemoteCallbackFreer::BindTo(v8::Isolate* isolate, + v8::Local target, + int object_id, + content::WebContents* web_contents) { + new RemoteCallbackFreer(isolate, target, object_id, web_contents); +} + +RemoteCallbackFreer::RemoteCallbackFreer(v8::Isolate* isolate, + v8::Local target, + int object_id, + content::WebContents* web_contents) + : ObjectLifeMonitor(isolate, target), + content::WebContentsObserver(web_contents), + object_id_(object_id) { +} + +RemoteCallbackFreer::~RemoteCallbackFreer() { +} + +void RemoteCallbackFreer::RunDestructor() { + base::string16 channel = + base::ASCIIToUTF16("ELECTRON_RENDERER_RELEASE_CALLBACK"); + base::ListValue args; + args.AppendInteger(object_id_); + web_contents()->GetRenderViewHost()->Send(new AtomViewMsg_Message( + web_contents()->GetRenderViewHost()->GetRoutingID(), channel, + args)); + + Observe(nullptr); +} + +void RemoteCallbackFreer::RenderViewDeleted(content::RenderViewHost*) { + delete this; +} + +} // namespace atom diff --git a/atom/common/api/remote_callback_freer.h b/atom/common/api/remote_callback_freer.h new file mode 100644 index 0000000000..8fe80c8d47 --- /dev/null +++ b/atom/common/api/remote_callback_freer.h @@ -0,0 +1,40 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_ +#define ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_ +#include "atom/common/api/object_life_monitor.h" +#include "content/public/browser/web_contents_observer.h" + +namespace atom { + +class RemoteCallbackFreer : public ObjectLifeMonitor, + public content::WebContentsObserver { + public: + static void BindTo(v8::Isolate* isolate, + v8::Local target, + int object_id, + content::WebContents* web_conents); + + protected: + RemoteCallbackFreer(v8::Isolate* isolate, + v8::Local target, + int object_id, + content::WebContents* web_conents); + ~RemoteCallbackFreer() override; + + void RunDestructor() override; + + // content::WebContentsObserver: + void RenderViewDeleted(content::RenderViewHost*) override; + + private: + int object_id_; + + DISALLOW_COPY_AND_ASSIGN(RemoteCallbackFreer); +}; + +} // namespace atom + +#endif // ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_ diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index 943d2c2b87..5ca4107969 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -167,6 +167,34 @@ const unwrapArgs = function (sender, args) { } return ret } + case 'function-with-return-value': + returnValue = metaToValue(meta.value) + return function () { + return returnValue + } + case 'function': { + // Merge webContentsId and meta.id, since meta.id can be the same in + // different webContents. + const webContentsId = sender.getId() + const objectId = [webContentsId, meta.id] + + // Cache the callbacks in renderer. + if (rendererFunctions.has(objectId)) { + return rendererFunctions.get(objectId) + } + + let callIntoRenderer = function (...args) { + if (!sender.isDestroyed() && webContentsId === sender.getId()) { + sender.send('ELECTRON_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args)) + } else { + throw new Error(`Attempting to call a function in a renderer window that has been closed or released. Function provided here: ${meta.location}.`) + } + } + + v8Util.setRemoteCallbackFreer(callIntoRenderer, meta.id, sender) + rendererFunctions.set(objectId, callIntoRenderer) + return callIntoRenderer + } default: throw new TypeError(`Unknown type: ${meta.type}`) } diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index d062b4878e..4668390768 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -279,6 +279,16 @@ const metaToPlainObject = function (meta) { return obj } +// Browser calls a callback in renderer. +ipcRenderer.on('ELECTRON_RENDERER_CALLBACK', function (event, id, args) { + callbacksRegistry.apply(id, metaToValue(args)) +}) + +// // A callback in browser is released. +ipcRenderer.on('ELECTRON_RENDERER_RELEASE_CALLBACK', function (event, id) { + callbacksRegistry.remove(id) +}) + var binding = {} binding.require = function (module) {