Browse Source

refactor: implement ipcRenderer.sendTo in native code for better performance (#14285)

Milan Burda 6 years ago
parent
commit
c23e7fa101

+ 14 - 0
atom/browser/api/atom_api_web_contents.cc

@@ -1019,6 +1019,7 @@ bool WebContents::OnMessageReceived(const IPC::Message& message,
     IPC_MESSAGE_HANDLER(AtomFrameHostMsg_Message, OnRendererMessage)
     IPC_MESSAGE_FORWARD_DELAY_REPLY(AtomFrameHostMsg_Message_Sync, &helper,
                                     FrameDispatchHelper::OnRendererMessageSync)
+    IPC_MESSAGE_HANDLER(AtomFrameHostMsg_Message_To, OnRendererMessageTo)
     IPC_MESSAGE_FORWARD_DELAY_REPLY(
         AtomFrameHostMsg_SetTemporaryZoomLevel, &helper,
         FrameDispatchHelper::OnSetTemporaryZoomLevel)
@@ -2077,6 +2078,19 @@ void WebContents::OnRendererMessageSync(content::RenderFrameHost* frame_host,
   EmitWithSender(channel, frame_host, message, args);
 }
 
+void WebContents::OnRendererMessageTo(content::RenderFrameHost* frame_host,
+                                      bool send_to_all,
+                                      int32_t web_contents_id,
+                                      const base::string16& channel,
+                                      const base::ListValue& args) {
+  auto* web_contents = mate::TrackableObject<WebContents>::FromWeakMapID(
+      isolate(), web_contents_id);
+
+  if (web_contents) {
+    web_contents->SendIPCMessage(send_to_all, channel, args);
+  }
+}
+
 // static
 mate::Handle<WebContents> WebContents::CreateFrom(
     v8::Isolate* isolate,

+ 7 - 0
atom/browser/api/atom_api_web_contents.h

@@ -419,6 +419,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
                              const base::ListValue& args,
                              IPC::Message* message);
 
+  // Called when received a message from renderer to be forwarded.
+  void OnRendererMessageTo(content::RenderFrameHost* frame_host,
+                           bool send_to_all,
+                           int32_t web_contents_id,
+                           const base::string16& channel,
+                           const base::ListValue& args);
+
   // Called when received a synchronous message from renderer to
   // set temporary zoom level.
   void OnSetTemporaryZoomLevel(content::RenderFrameHost* frame_host,

+ 6 - 0
atom/common/api/api_messages.h

@@ -33,6 +33,12 @@ IPC_SYNC_MESSAGE_ROUTED2_1(AtomFrameHostMsg_Message_Sync,
                            base::ListValue /* arguments */,
                            base::ListValue /* result */)
 
+IPC_MESSAGE_ROUTED4(AtomFrameHostMsg_Message_To,
+                    bool /* send_to_all */,
+                    int32_t /* web_contents_id */,
+                    base::string16 /* channel */,
+                    base::ListValue /* arguments */)
+
 IPC_MESSAGE_ROUTED3(AtomFrameMsg_Message,
                     bool /* send_to_all */,
                     std::string /* channel */,

+ 18 - 0
atom/renderer/api/atom_api_renderer_ipc.cc

@@ -60,6 +60,23 @@ base::ListValue SendSync(mate::Arguments* args,
   return result;
 }
 
+void SendTo(mate::Arguments* args,
+            bool send_to_all,
+            int32_t web_contents_id,
+            const base::string16& channel,
+            const base::ListValue& arguments) {
+  RenderFrame* render_frame = GetCurrentRenderFrame();
+  if (render_frame == nullptr)
+    return;
+
+  bool success = render_frame->Send(
+      new AtomFrameHostMsg_Message_To(render_frame->GetRoutingID(), send_to_all,
+                                      web_contents_id, channel, arguments));
+
+  if (!success)
+    args->ThrowError("Unable to send AtomFrameHostMsg_Message_To");
+}
+
 void Initialize(v8::Local<v8::Object> exports,
                 v8::Local<v8::Value> unused,
                 v8::Local<v8::Context> context,
@@ -67,6 +84,7 @@ void Initialize(v8::Local<v8::Object> exports,
   mate::Dictionary dict(context->GetIsolate(), exports);
   dict.SetMethod("send", &Send);
   dict.SetMethod("sendSync", &SendSync);
+  dict.SetMethod("sendTo", &SendTo);
 }
 
 }  // namespace api

+ 6 - 0
atom/renderer/api/atom_api_renderer_ipc.h

@@ -22,6 +22,12 @@ base::ListValue SendSync(mate::Arguments* args,
                          const std::string& channel,
                          const base::ListValue& arguments);
 
+void SendTo(mate::Arguments* args,
+            bool send_to_all,
+            int32_t web_contents_id,
+            const base::string16& channel,
+            const base::ListValue& arguments);
+
 void Initialize(v8::Local<v8::Object> exports,
                 v8::Local<v8::Value> unused,
                 v8::Local<v8::Context> context,

+ 1 - 15
lib/browser/rpc-server.js

@@ -5,7 +5,7 @@ const {EventEmitter} = require('events')
 const fs = require('fs')
 const v8Util = process.atomBinding('v8_util')
 
-const {ipcMain, isPromise, webContents} = electron
+const {ipcMain, isPromise} = electron
 
 const objectsRegistry = require('./objects-registry')
 const bufferUtils = require('../common/buffer-utils')
@@ -417,20 +417,6 @@ ipcMain.on('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function (event, context
   }
 })
 
-ipcMain.on('ELECTRON_BROWSER_SEND_TO', function (event, sendToAll, webContentsId, channel, ...args) {
-  let contents = webContents.fromId(webContentsId)
-  if (!contents) {
-    console.error(`Sending message to WebContents with unknown ID ${webContentsId}`)
-    return
-  }
-
-  if (sendToAll) {
-    contents.sendToAll(channel, ...args)
-  } else {
-    contents.send(channel, ...args)
-  }
-})
-
 // Implements window.close()
 ipcMain.on('ELECTRON_BROWSER_WINDOW_CLOSE', function (event) {
   const window = event.sender.getOwnerBrowserWindow()

+ 2 - 10
lib/renderer/api/ipc-renderer.js

@@ -19,19 +19,11 @@ ipcRenderer.sendToHost = function (...args) {
 }
 
 ipcRenderer.sendTo = function (webContentsId, channel, ...args) {
-  if (typeof webContentsId !== 'number') {
-    throw new TypeError('First argument has to be webContentsId')
-  }
-
-  ipcRenderer.send('ELECTRON_BROWSER_SEND_TO', false, webContentsId, channel, ...args)
+  return binding.sendTo(false, webContentsId, channel, args)
 }
 
 ipcRenderer.sendToAll = function (webContentsId, channel, ...args) {
-  if (typeof webContentsId !== 'number') {
-    throw new TypeError('First argument has to be webContentsId')
-  }
-
-  ipcRenderer.send('ELECTRON_BROWSER_SEND_TO', true, webContentsId, channel, ...args)
+  return binding.sendTo(true, webContentsId, channel, args)
 }
 
 const removeAllListeners = ipcRenderer.removeAllListeners.bind(ipcRenderer)