Skip to content

Commit

Permalink
feat: add event.senderId property to IPCs sent via ipcRenderer.sendTo (
Browse files Browse the repository at this point in the history
  • Loading branch information
miniak authored and ckerr committed Sep 1, 2018
1 parent b89848d commit c17a1b3
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 31 deletions.
11 changes: 9 additions & 2 deletions atom/browser/api/atom_api_web_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1556,10 +1556,17 @@ void WebContents::TabTraverse(bool reverse) {
bool WebContents::SendIPCMessage(bool all_frames,
const std::string& channel,
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();
if (frame_host) {
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;
}
Expand Down Expand Up @@ -2090,7 +2097,7 @@ void WebContents::OnRendererMessageTo(content::RenderFrameHost* frame_host,
isolate(), web_contents_id);

if (web_contents) {
web_contents->SendIPCMessage(send_to_all, channel, args);
web_contents->SendIPCMessageWithSender(send_to_all, channel, args, ID());
}
}

Expand Down
5 changes: 5 additions & 0 deletions atom/browser/api/atom_api_web_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
const std::string& channel,
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.
void SendInputEvent(v8::Isolate* isolate, v8::Local<v8::Value> input_event);

Expand Down
5 changes: 3 additions & 2 deletions atom/common/api/api_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ IPC_MESSAGE_ROUTED4(AtomFrameHostMsg_Message_To,
std::string /* channel */,
base::ListValue /* arguments */)

IPC_MESSAGE_ROUTED3(AtomFrameMsg_Message,
IPC_MESSAGE_ROUTED4(AtomFrameMsg_Message,
bool /* send_to_all */,
std::string /* channel */,
base::ListValue /* arguments */)
base::ListValue /* arguments */,
int32_t /* sender_id */)

IPC_MESSAGE_ROUTED0(AtomViewMsg_Offscreen)

Expand Down
3 changes: 2 additions & 1 deletion atom/common/api/remote_callback_freer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@ RemoteCallbackFreer::~RemoteCallbackFreer() {}
void RemoteCallbackFreer::RunDestructor() {
auto* channel = "ELECTRON_RENDERER_RELEASE_CALLBACK";
base::ListValue args;
int32_t sender_id = 0;
args.AppendString(context_id_);
args.AppendInteger(object_id_);
auto* frame_host = web_contents()->GetMainFrame();
if (frame_host) {
frame_host->Send(new AtomFrameMsg_Message(frame_host->GetRoutingID(), false,
channel, args));
channel, args, sender_id));
}

Observe(nullptr);
Expand Down
11 changes: 7 additions & 4 deletions atom/renderer/atom_render_frame_observer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ bool AtomRenderFrameObserver::OnMessageReceived(const IPC::Message& message) {

void AtomRenderFrameObserver::OnBrowserMessage(bool send_to_all,
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.
// 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
Expand All @@ -182,21 +183,22 @@ void AtomRenderFrameObserver::OnBrowserMessage(bool send_to_all,
if (!frame || !render_frame_->IsMainFrame())
return;

EmitIPCEvent(frame, channel, args);
EmitIPCEvent(frame, channel, args, sender_id);

// Also send the message to all sub-frames.
if (send_to_all) {
for (blink::WebFrame* child = frame->FirstChild(); child;
child = child->NextSibling())
if (child->IsWebLocalFrame()) {
EmitIPCEvent(child->ToWebLocalFrame(), channel, args);
EmitIPCEvent(child->ToWebLocalFrame(), channel, args, sender_id);
}
}
}

void AtomRenderFrameObserver::EmitIPCEvent(blink::WebLocalFrame* frame,
const std::string& channel,
const base::ListValue& args) {
const base::ListValue& args,
int32_t sender_id) {
if (!frame)
return;

Expand All @@ -218,6 +220,7 @@ void AtomRenderFrameObserver::EmitIPCEvent(blink::WebLocalFrame* frame,
// Insert the Event object, event.sender is ipc.
mate::Dictionary event = mate::Dictionary::CreateEmpty(isolate);
event.Set("sender", ipc);
event.Set("senderId", sender_id);
args_vector.insert(args_vector.begin(), event.GetHandle());
mate::EmitEvent(isolate, ipc, channel, args_vector);
}
Expand Down
6 changes: 4 additions & 2 deletions atom/renderer/atom_render_frame_observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver {
protected:
virtual void EmitIPCEvent(blink::WebLocalFrame* frame,
const std::string& channel,
const base::ListValue& args);
const base::ListValue& args,
int32_t sender_id);

private:
bool ShouldNotifyClient(int world_id);
Expand All @@ -54,7 +55,8 @@ class AtomRenderFrameObserver : public content::RenderFrameObserver {
bool IsIsolatedWorld(int world_id);
void OnBrowserMessage(bool send_to_all,
const std::string& channel,
const base::ListValue& args);
const base::ListValue& args,
int32_t sender_id);

content::RenderFrame* render_frame_;
RendererClientBase* renderer_client_;
Expand Down
6 changes: 4 additions & 2 deletions atom/renderer/atom_sandboxed_renderer_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver {
protected:
void EmitIPCEvent(blink::WebLocalFrame* frame,
const std::string& channel,
const base::ListValue& args) override {
const base::ListValue& args,
int32_t sender_id) override {
if (!frame)
return;

Expand All @@ -116,7 +117,8 @@ class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver {
auto context = frame->MainWorldScriptContext();
v8::Context::Scope context_scope(context);
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(
context, "onMessage",
std::vector<v8::Local<v8::Value>>(argv, argv + node::arraysize(argv)));
Expand Down
14 changes: 14 additions & 0 deletions docs/api/ipc-renderer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
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-
4 changes: 2 additions & 2 deletions lib/sandboxed_renderer/api/ipc-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const ipcNative = process.atomBinding('ipc')
// private/public APIs.
v8Util.setHiddenValue(global, 'ipcNative', ipcNative)

ipcNative.onMessage = function (channel, args) {
ipcRenderer.emit(channel, {sender: ipcRenderer}, ...args)
ipcNative.onMessage = function (channel, args, senderId) {
ipcRenderer.emit(channel, {sender: ipcRenderer, senderId}, ...args)
}

ipcNative.onExit = function () {
Expand Down
46 changes: 36 additions & 10 deletions spec/api-ipc-renderer-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,39 +132,65 @@ describe('ipc renderer module', () => {
describe('ipcRenderer.sendTo', () => {
let contents = null

beforeEach(() => { contents = webContents.create({}) })

afterEach(() => {
ipcRenderer.removeAllListeners('pong')
contents.destroy()
contents = null
})

it('sends message to WebContents', done => {
const webContentsId = remote.getCurrentWebContents().id
contents = webContents.create({
preload: path.join(fixtures, 'module', 'preload-inject-ipc.js')
})

const payload = 'Hello World!'

ipcRenderer.once('pong', (event, id) => {
expect(webContentsId).to.equal(id)
ipcRenderer.once('pong', (event, data) => {
expect(payload).to.equal(data)
done()
})

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')}`)
})

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')
})

const payload = 'Hello World!'

ipcRenderer.once('pong-æøåü', (event, id) => {
expect(webContentsId).to.equal(id)
ipcRenderer.once('pong-æøåü', (event, data) => {
expect(payload).to.equal(data)
done()
})

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')}`)
Expand Down
10 changes: 4 additions & 6 deletions spec/fixtures/pages/ping-pong.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
<html>
<body>
<script type="text/javascript" charset="utf-8">
const {ipcRenderer} = require('electron')
ipcRenderer.on('ping', function (event, id) {
ipcRenderer.sendTo(id, 'pong', id)
ipcRenderer.on('ping', function (event, payload) {
ipcRenderer.sendTo(event.senderId, 'pong', payload)
})
ipcRenderer.on('ping-æøåü', function (event, id) {
ipcRenderer.sendTo(id, 'pong-æøåü', id)
ipcRenderer.on('ping-æøåü', function (event, payload) {
ipcRenderer.sendTo(event.senderId, 'pong-æøåü', payload)
})
</script>
</body>
</html>

0 comments on commit c17a1b3

Please sign in to comment.