feat: add event.senderId property to IPCs sent via ipcRenderer.sendTo (#14395)
This commit is contained in:
parent
b89848d683
commit
c17a1b37ea
11 changed files with 90 additions and 31 deletions
|
@ -1556,10 +1556,17 @@ void WebContents::TabTraverse(bool reverse) {
|
||||||
bool WebContents::SendIPCMessage(bool all_frames,
|
bool WebContents::SendIPCMessage(bool all_frames,
|
||||||
const std::string& channel,
|
const std::string& channel,
|
||||||
const base::ListValue& args) {
|
const base::ListValue& args) {
|
||||||
|
return SendIPCMessageWithSender(all_frames, channel, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebContents::SendIPCMessageWithSender(bool all_frames,
|
||||||
|
const std::string& channel,
|
||||||
|
const base::ListValue& args,
|
||||||
|
int32_t sender_id) {
|
||||||
auto* frame_host = web_contents()->GetMainFrame();
|
auto* frame_host = web_contents()->GetMainFrame();
|
||||||
if (frame_host) {
|
if (frame_host) {
|
||||||
return frame_host->Send(new AtomFrameMsg_Message(
|
return frame_host->Send(new AtomFrameMsg_Message(
|
||||||
frame_host->GetRoutingID(), all_frames, channel, args));
|
frame_host->GetRoutingID(), all_frames, channel, args, sender_id));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2090,7 +2097,7 @@ void WebContents::OnRendererMessageTo(content::RenderFrameHost* frame_host,
|
||||||
isolate(), web_contents_id);
|
isolate(), web_contents_id);
|
||||||
|
|
||||||
if (web_contents) {
|
if (web_contents) {
|
||||||
web_contents->SendIPCMessage(send_to_all, channel, args);
|
web_contents->SendIPCMessageWithSender(send_to_all, channel, args, ID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
const std::string& channel,
|
const std::string& channel,
|
||||||
const base::ListValue& args);
|
const base::ListValue& args);
|
||||||
|
|
||||||
|
bool SendIPCMessageWithSender(bool all_frames,
|
||||||
|
const std::string& channel,
|
||||||
|
const base::ListValue& args,
|
||||||
|
int32_t sender_id = 0);
|
||||||
|
|
||||||
// Send WebInputEvent to the page.
|
// Send WebInputEvent to the page.
|
||||||
void SendInputEvent(v8::Isolate* isolate, v8::Local<v8::Value> input_event);
|
void SendInputEvent(v8::Isolate* isolate, v8::Local<v8::Value> input_event);
|
||||||
|
|
||||||
|
|
|
@ -39,10 +39,11 @@ IPC_MESSAGE_ROUTED4(AtomFrameHostMsg_Message_To,
|
||||||
std::string /* channel */,
|
std::string /* channel */,
|
||||||
base::ListValue /* arguments */)
|
base::ListValue /* arguments */)
|
||||||
|
|
||||||
IPC_MESSAGE_ROUTED3(AtomFrameMsg_Message,
|
IPC_MESSAGE_ROUTED4(AtomFrameMsg_Message,
|
||||||
bool /* send_to_all */,
|
bool /* send_to_all */,
|
||||||
std::string /* channel */,
|
std::string /* channel */,
|
||||||
base::ListValue /* arguments */)
|
base::ListValue /* arguments */,
|
||||||
|
int32_t /* sender_id */)
|
||||||
|
|
||||||
IPC_MESSAGE_ROUTED0(AtomViewMsg_Offscreen)
|
IPC_MESSAGE_ROUTED0(AtomViewMsg_Offscreen)
|
||||||
|
|
||||||
|
|
|
@ -36,12 +36,13 @@ RemoteCallbackFreer::~RemoteCallbackFreer() {}
|
||||||
void RemoteCallbackFreer::RunDestructor() {
|
void RemoteCallbackFreer::RunDestructor() {
|
||||||
auto* channel = "ELECTRON_RENDERER_RELEASE_CALLBACK";
|
auto* channel = "ELECTRON_RENDERER_RELEASE_CALLBACK";
|
||||||
base::ListValue args;
|
base::ListValue args;
|
||||||
|
int32_t sender_id = 0;
|
||||||
args.AppendString(context_id_);
|
args.AppendString(context_id_);
|
||||||
args.AppendInteger(object_id_);
|
args.AppendInteger(object_id_);
|
||||||
auto* frame_host = web_contents()->GetMainFrame();
|
auto* frame_host = web_contents()->GetMainFrame();
|
||||||
if (frame_host) {
|
if (frame_host) {
|
||||||
frame_host->Send(new AtomFrameMsg_Message(frame_host->GetRoutingID(), false,
|
frame_host->Send(new AtomFrameMsg_Message(frame_host->GetRoutingID(), false,
|
||||||
channel, args));
|
channel, args, sender_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
Observe(nullptr);
|
Observe(nullptr);
|
||||||
|
|
|
@ -169,7 +169,8 @@ bool AtomRenderFrameObserver::OnMessageReceived(const IPC::Message& message) {
|
||||||
|
|
||||||
void AtomRenderFrameObserver::OnBrowserMessage(bool send_to_all,
|
void AtomRenderFrameObserver::OnBrowserMessage(bool send_to_all,
|
||||||
const std::string& channel,
|
const std::string& channel,
|
||||||
const base::ListValue& args) {
|
const base::ListValue& args,
|
||||||
|
int32_t sender_id) {
|
||||||
// Don't handle browser messages before document element is created.
|
// Don't handle browser messages before document element is created.
|
||||||
// When we receive a message from the browser, we try to transfer it
|
// When we receive a message from the browser, we try to transfer it
|
||||||
// to a web page, and when we do that Blink creates an empty
|
// to a web page, and when we do that Blink creates an empty
|
||||||
|
@ -182,21 +183,22 @@ void AtomRenderFrameObserver::OnBrowserMessage(bool send_to_all,
|
||||||
if (!frame || !render_frame_->IsMainFrame())
|
if (!frame || !render_frame_->IsMainFrame())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EmitIPCEvent(frame, channel, args);
|
EmitIPCEvent(frame, channel, args, sender_id);
|
||||||
|
|
||||||
// Also send the message to all sub-frames.
|
// Also send the message to all sub-frames.
|
||||||
if (send_to_all) {
|
if (send_to_all) {
|
||||||
for (blink::WebFrame* child = frame->FirstChild(); child;
|
for (blink::WebFrame* child = frame->FirstChild(); child;
|
||||||
child = child->NextSibling())
|
child = child->NextSibling())
|
||||||
if (child->IsWebLocalFrame()) {
|
if (child->IsWebLocalFrame()) {
|
||||||
EmitIPCEvent(child->ToWebLocalFrame(), channel, args);
|
EmitIPCEvent(child->ToWebLocalFrame(), channel, args, sender_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomRenderFrameObserver::EmitIPCEvent(blink::WebLocalFrame* frame,
|
void AtomRenderFrameObserver::EmitIPCEvent(blink::WebLocalFrame* frame,
|
||||||
const std::string& channel,
|
const std::string& channel,
|
||||||
const base::ListValue& args) {
|
const base::ListValue& args,
|
||||||
|
int32_t sender_id) {
|
||||||
if (!frame)
|
if (!frame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -218,6 +220,7 @@ void AtomRenderFrameObserver::EmitIPCEvent(blink::WebLocalFrame* frame,
|
||||||
// Insert the Event object, event.sender is ipc.
|
// Insert the Event object, event.sender is ipc.
|
||||||
mate::Dictionary event = mate::Dictionary::CreateEmpty(isolate);
|
mate::Dictionary event = mate::Dictionary::CreateEmpty(isolate);
|
||||||
event.Set("sender", ipc);
|
event.Set("sender", ipc);
|
||||||
|
event.Set("senderId", sender_id);
|
||||||
args_vector.insert(args_vector.begin(), event.GetHandle());
|
args_vector.insert(args_vector.begin(), event.GetHandle());
|
||||||
mate::EmitEvent(isolate, ipc, channel, args_vector);
|
mate::EmitEvent(isolate, ipc, channel, args_vector);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,8 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver {
|
||||||
protected:
|
protected:
|
||||||
virtual void EmitIPCEvent(blink::WebLocalFrame* frame,
|
virtual void EmitIPCEvent(blink::WebLocalFrame* frame,
|
||||||
const std::string& channel,
|
const std::string& channel,
|
||||||
const base::ListValue& args);
|
const base::ListValue& args,
|
||||||
|
int32_t sender_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ShouldNotifyClient(int world_id);
|
bool ShouldNotifyClient(int world_id);
|
||||||
|
@ -54,7 +55,8 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver {
|
||||||
bool IsIsolatedWorld(int world_id);
|
bool IsIsolatedWorld(int world_id);
|
||||||
void OnBrowserMessage(bool send_to_all,
|
void OnBrowserMessage(bool send_to_all,
|
||||||
const std::string& channel,
|
const std::string& channel,
|
||||||
const base::ListValue& args);
|
const base::ListValue& args,
|
||||||
|
int32_t sender_id);
|
||||||
|
|
||||||
content::RenderFrame* render_frame_;
|
content::RenderFrame* render_frame_;
|
||||||
RendererClientBase* renderer_client_;
|
RendererClientBase* renderer_client_;
|
||||||
|
|
|
@ -107,7 +107,8 @@ class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver {
|
||||||
protected:
|
protected:
|
||||||
void EmitIPCEvent(blink::WebLocalFrame* frame,
|
void EmitIPCEvent(blink::WebLocalFrame* frame,
|
||||||
const std::string& channel,
|
const std::string& channel,
|
||||||
const base::ListValue& args) override {
|
const base::ListValue& args,
|
||||||
|
int32_t sender_id) override {
|
||||||
if (!frame)
|
if (!frame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -116,7 +117,8 @@ class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver {
|
||||||
auto context = frame->MainWorldScriptContext();
|
auto context = frame->MainWorldScriptContext();
|
||||||
v8::Context::Scope context_scope(context);
|
v8::Context::Scope context_scope(context);
|
||||||
v8::Local<v8::Value> argv[] = {mate::ConvertToV8(isolate, channel),
|
v8::Local<v8::Value> argv[] = {mate::ConvertToV8(isolate, channel),
|
||||||
mate::ConvertToV8(isolate, args)};
|
mate::ConvertToV8(isolate, args),
|
||||||
|
mate::ConvertToV8(isolate, sender_id)};
|
||||||
renderer_client_->InvokeIpcCallback(
|
renderer_client_->InvokeIpcCallback(
|
||||||
context, "onMessage",
|
context, "onMessage",
|
||||||
std::vector<v8::Local<v8::Value>>(argv, argv + node::arraysize(argv)));
|
std::vector<v8::Local<v8::Value>>(argv, argv + node::arraysize(argv)));
|
||||||
|
|
|
@ -89,3 +89,17 @@ Sends a message to a window with `windowid` via `channel`.
|
||||||
|
|
||||||
Like `ipcRenderer.send` but the event will be sent to the `<webview>` element in
|
Like `ipcRenderer.send` but the event will be sent to the `<webview>` element in
|
||||||
the host page instead of the main process.
|
the host page instead of the main process.
|
||||||
|
|
||||||
|
## Event object
|
||||||
|
|
||||||
|
The `event` object passed to the `callback` has the following methods:
|
||||||
|
|
||||||
|
### `event.senderId`
|
||||||
|
|
||||||
|
Returns the `webContents.id` that sent the message, you can call
|
||||||
|
`event.sender.sendTo(event.senderId, ...)` to reply to the message, see
|
||||||
|
[ipcRenderer.sendTo][ipc-renderer-sendto] for more information.
|
||||||
|
This only applies to messages sent from a different renderer.
|
||||||
|
Messages sent directly from the main process set `event.senderId` to `0`.
|
||||||
|
|
||||||
|
[ipc-renderer-sendto]: #ipcrenderersendtowindowid-channel--arg1-arg2-
|
||||||
|
|
|
@ -9,8 +9,8 @@ const ipcNative = process.atomBinding('ipc')
|
||||||
// private/public APIs.
|
// private/public APIs.
|
||||||
v8Util.setHiddenValue(global, 'ipcNative', ipcNative)
|
v8Util.setHiddenValue(global, 'ipcNative', ipcNative)
|
||||||
|
|
||||||
ipcNative.onMessage = function (channel, args) {
|
ipcNative.onMessage = function (channel, args, senderId) {
|
||||||
ipcRenderer.emit(channel, {sender: ipcRenderer}, ...args)
|
ipcRenderer.emit(channel, {sender: ipcRenderer, senderId}, ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcNative.onExit = function () {
|
ipcNative.onExit = function () {
|
||||||
|
|
|
@ -132,8 +132,6 @@ describe('ipc renderer module', () => {
|
||||||
describe('ipcRenderer.sendTo', () => {
|
describe('ipcRenderer.sendTo', () => {
|
||||||
let contents = null
|
let contents = null
|
||||||
|
|
||||||
beforeEach(() => { contents = webContents.create({}) })
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
ipcRenderer.removeAllListeners('pong')
|
ipcRenderer.removeAllListeners('pong')
|
||||||
contents.destroy()
|
contents.destroy()
|
||||||
|
@ -141,30 +139,58 @@ describe('ipc renderer module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sends message to WebContents', done => {
|
it('sends message to WebContents', done => {
|
||||||
const webContentsId = remote.getCurrentWebContents().id
|
contents = webContents.create({
|
||||||
|
preload: path.join(fixtures, 'module', 'preload-inject-ipc.js')
|
||||||
|
})
|
||||||
|
|
||||||
ipcRenderer.once('pong', (event, id) => {
|
const payload = 'Hello World!'
|
||||||
expect(webContentsId).to.equal(id)
|
|
||||||
|
ipcRenderer.once('pong', (event, data) => {
|
||||||
|
expect(payload).to.equal(data)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
|
||||||
contents.once('did-finish-load', () => {
|
contents.once('did-finish-load', () => {
|
||||||
ipcRenderer.sendTo(contents.id, 'ping', webContentsId)
|
ipcRenderer.sendTo(contents.id, 'ping', payload)
|
||||||
|
})
|
||||||
|
|
||||||
|
contents.loadURL(`file://${path.join(fixtures, 'pages', 'ping-pong.html')}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sends message to WebContents (sanboxed renderer)', done => {
|
||||||
|
contents = webContents.create({
|
||||||
|
preload: path.join(fixtures, 'module', 'preload-inject-ipc.js'),
|
||||||
|
sandbox: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const payload = 'Hello World!'
|
||||||
|
|
||||||
|
ipcRenderer.once('pong', (event, data) => {
|
||||||
|
expect(payload).to.equal(data)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
contents.once('did-finish-load', () => {
|
||||||
|
ipcRenderer.sendTo(contents.id, 'ping', payload)
|
||||||
})
|
})
|
||||||
|
|
||||||
contents.loadURL(`file://${path.join(fixtures, 'pages', 'ping-pong.html')}`)
|
contents.loadURL(`file://${path.join(fixtures, 'pages', 'ping-pong.html')}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('sends message to WebContents (channel has special chars)', done => {
|
it('sends message to WebContents (channel has special chars)', done => {
|
||||||
const webContentsId = remote.getCurrentWebContents().id
|
contents = webContents.create({
|
||||||
|
preload: path.join(fixtures, 'module', 'preload-inject-ipc.js')
|
||||||
|
})
|
||||||
|
|
||||||
ipcRenderer.once('pong-æøåü', (event, id) => {
|
const payload = 'Hello World!'
|
||||||
expect(webContentsId).to.equal(id)
|
|
||||||
|
ipcRenderer.once('pong-æøåü', (event, data) => {
|
||||||
|
expect(payload).to.equal(data)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
|
||||||
contents.once('did-finish-load', () => {
|
contents.once('did-finish-load', () => {
|
||||||
ipcRenderer.sendTo(contents.id, 'ping-æøåü', webContentsId)
|
ipcRenderer.sendTo(contents.id, 'ping-æøåü', payload)
|
||||||
})
|
})
|
||||||
|
|
||||||
contents.loadURL(`file://${path.join(fixtures, 'pages', 'ping-pong.html')}`)
|
contents.loadURL(`file://${path.join(fixtures, 'pages', 'ping-pong.html')}`)
|
||||||
|
|
10
spec/fixtures/pages/ping-pong.html
vendored
10
spec/fixtures/pages/ping-pong.html
vendored
|
@ -1,14 +1,12 @@
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
<script type="text/javascript" charset="utf-8">
|
<script type="text/javascript" charset="utf-8">
|
||||||
const {ipcRenderer} = require('electron')
|
ipcRenderer.on('ping', function (event, payload) {
|
||||||
ipcRenderer.on('ping', function (event, id) {
|
ipcRenderer.sendTo(event.senderId, 'pong', payload)
|
||||||
ipcRenderer.sendTo(id, 'pong', id)
|
|
||||||
})
|
})
|
||||||
ipcRenderer.on('ping-æøåü', function (event, id) {
|
ipcRenderer.on('ping-æøåü', function (event, payload) {
|
||||||
ipcRenderer.sendTo(id, 'pong-æøåü', id)
|
ipcRenderer.sendTo(event.senderId, 'pong-æøåü', payload)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue