feat: add onclose method to MessagePort (#22532)
* feat: add onclose method to MessagePort * more scope, more good * de-flake GC test
This commit is contained in:
parent
829d4815a9
commit
0c02d794c9
5 changed files with 114 additions and 0 deletions
|
@ -45,5 +45,9 @@ Returns:
|
||||||
|
|
||||||
Emitted when a MessagePortMain object receives a message.
|
Emitted when a MessagePortMain object receives a message.
|
||||||
|
|
||||||
|
#### Event: 'close'
|
||||||
|
|
||||||
|
Emitted when the remote end of a MessagePortMain object becomes disconnected.
|
||||||
|
|
||||||
[`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
|
[`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
|
||||||
[Channel Messaging API]: https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API
|
[Channel Messaging API]: https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API
|
||||||
|
|
|
@ -91,3 +91,4 @@ feat_enable_offscreen_rendering_with_viz_compositor.patch
|
||||||
delay_lock_the_protocol_scheme_registry.patch
|
delay_lock_the_protocol_scheme_registry.patch
|
||||||
gpu_notify_when_dxdiag_request_fails.patch
|
gpu_notify_when_dxdiag_request_fails.patch
|
||||||
feat_allow_embedders_to_add_observers_on_created_hunspell.patch
|
feat_allow_embedders_to_add_observers_on_created_hunspell.patch
|
||||||
|
feat_add_onclose_to_messageport.patch
|
||||||
|
|
51
patches/chromium/feat_add_onclose_to_messageport.patch
Normal file
51
patches/chromium/feat_add_onclose_to_messageport.patch
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jeremy Apthorp <nornagon@nornagon.net>
|
||||||
|
Date: Wed, 4 Mar 2020 11:18:03 -0800
|
||||||
|
Subject: feat: add onclose to MessagePort
|
||||||
|
|
||||||
|
This adds the 'onclose' event to MessagePort. This is
|
||||||
|
[proposed](https://github.com/w3ctag/design-reviews/issues/269#issuecomment-407584290)
|
||||||
|
in w3c and has been discussed for years without conclusion. I'd like to
|
||||||
|
get this standardised, but in lieu of that, this makes MessagePort a
|
||||||
|
whole bunch more useful!
|
||||||
|
|
||||||
|
diff --git a/third_party/blink/renderer/core/messaging/message_port.cc b/third_party/blink/renderer/core/messaging/message_port.cc
|
||||||
|
index e2ddbafc9ea2836a302da481702e2922949ffe78..7da7071862e384bce65ecb52996b5287891a33f9 100644
|
||||||
|
--- a/third_party/blink/renderer/core/messaging/message_port.cc
|
||||||
|
+++ b/third_party/blink/renderer/core/messaging/message_port.cc
|
||||||
|
@@ -156,6 +156,7 @@ void MessagePort::close() {
|
||||||
|
Entangle(mojo::MessagePipe().handle0);
|
||||||
|
}
|
||||||
|
closed_ = true;
|
||||||
|
+ DispatchEvent(*Event::Create(event_type_names::kClose));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessagePort::Entangle(mojo::ScopedMessagePipeHandle handle) {
|
||||||
|
diff --git a/third_party/blink/renderer/core/messaging/message_port.h b/third_party/blink/renderer/core/messaging/message_port.h
|
||||||
|
index 2a08335398b30671a61aee0f1ebe060222a4f1ff..874aecb9c038f19cc03641a19ce51cf2f958d80c 100644
|
||||||
|
--- a/third_party/blink/renderer/core/messaging/message_port.h
|
||||||
|
+++ b/third_party/blink/renderer/core/messaging/message_port.h
|
||||||
|
@@ -119,6 +119,13 @@ class CORE_EXPORT MessagePort : public EventTargetWithInlineData,
|
||||||
|
return GetAttributeEventListener(event_type_names::kMessageerror);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ void setOnclose(EventListener* listener) {
|
||||||
|
+ SetAttributeEventListener(event_type_names::kClose, listener);
|
||||||
|
+ }
|
||||||
|
+ EventListener* onclose() {
|
||||||
|
+ return GetAttributeEventListener(event_type_names::kClose);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// A port starts out its life entangled, and remains entangled until it is
|
||||||
|
// closed or is cloned.
|
||||||
|
bool IsEntangled() const { return !closed_ && !IsNeutered(); }
|
||||||
|
diff --git a/third_party/blink/renderer/core/messaging/message_port.idl b/third_party/blink/renderer/core/messaging/message_port.idl
|
||||||
|
index 6fab27fcdf1c333739b6ffe88b3cc4eed3301ee4..3f1f181d9b8a66997136f870f55c97c08294b6eb 100644
|
||||||
|
--- a/third_party/blink/renderer/core/messaging/message_port.idl
|
||||||
|
+++ b/third_party/blink/renderer/core/messaging/message_port.idl
|
||||||
|
@@ -40,4 +40,5 @@
|
||||||
|
// event handlers
|
||||||
|
attribute EventHandler onmessage;
|
||||||
|
attribute EventHandler onmessageerror;
|
||||||
|
+ attribute EventHandler onclose;
|
||||||
|
};
|
|
@ -103,6 +103,12 @@ void MessagePort::Close() {
|
||||||
closed_ = true;
|
closed_ = true;
|
||||||
if (!HasPendingActivity())
|
if (!HasPendingActivity())
|
||||||
Unpin();
|
Unpin();
|
||||||
|
|
||||||
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
v8::Local<v8::Object> self;
|
||||||
|
if (GetWrapper(isolate).ToLocal(&self))
|
||||||
|
gin_helper::EmitEvent(isolate, self, "close");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagePort::Entangle(mojo::ScopedMessagePipeHandle handle) {
|
void MessagePort::Entangle(mojo::ScopedMessagePipeHandle handle) {
|
||||||
|
@ -196,6 +202,7 @@ void MessagePort::Pin() {
|
||||||
if (!pinned_.IsEmpty())
|
if (!pinned_.IsEmpty())
|
||||||
return;
|
return;
|
||||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
v8::Local<v8::Value> self;
|
v8::Local<v8::Value> self;
|
||||||
if (GetWrapper(isolate).ToLocal(&self)) {
|
if (GetWrapper(isolate).ToLocal(&self)) {
|
||||||
pinned_.Reset(isolate, self);
|
pinned_.Reset(isolate, self);
|
||||||
|
|
|
@ -278,6 +278,57 @@ describe('ipc module', () => {
|
||||||
expect(data).to.equal('a message')
|
expect(data).to.equal('a message')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('close event', () => {
|
||||||
|
describe('in renderer', () => {
|
||||||
|
it('is emitted when the main process closes its end of the port', async () => {
|
||||||
|
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } })
|
||||||
|
w.loadURL('about:blank')
|
||||||
|
await w.webContents.executeJavaScript(`(${function () {
|
||||||
|
const { ipcRenderer } = require('electron')
|
||||||
|
ipcRenderer.on('port', (e) => {
|
||||||
|
const [port] = e.ports
|
||||||
|
port.start();
|
||||||
|
(port as any).onclose = () => {
|
||||||
|
ipcRenderer.send('closed')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}})()`)
|
||||||
|
const { port1, port2 } = new MessageChannelMain()
|
||||||
|
w.webContents.postMessage('port', null, [port2])
|
||||||
|
port1.close()
|
||||||
|
await emittedOnce(ipcMain, 'closed')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('is emitted when the other end of a port is garbage-collected', async () => {
|
||||||
|
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } })
|
||||||
|
w.loadURL('about:blank')
|
||||||
|
await w.webContents.executeJavaScript(`(${async function () {
|
||||||
|
const { port2 } = new MessageChannel()
|
||||||
|
await new Promise(resolve => {
|
||||||
|
port2.start();
|
||||||
|
(port2 as any).onclose = resolve
|
||||||
|
process.electronBinding('v8_util').requestGarbageCollectionForTesting()
|
||||||
|
})
|
||||||
|
}})()`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('is emitted when the other end of a port is sent to nowhere', async () => {
|
||||||
|
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } })
|
||||||
|
w.loadURL('about:blank')
|
||||||
|
ipcMain.once('do-a-gc', () => v8Util.requestGarbageCollectionForTesting())
|
||||||
|
await w.webContents.executeJavaScript(`(${async function () {
|
||||||
|
const { port1, port2 } = new MessageChannel()
|
||||||
|
await new Promise(resolve => {
|
||||||
|
port2.start();
|
||||||
|
(port2 as any).onclose = resolve
|
||||||
|
require('electron').ipcRenderer.postMessage('nobody-listening', null, [port1])
|
||||||
|
require('electron').ipcRenderer.send('do-a-gc')
|
||||||
|
})
|
||||||
|
}})()`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('MessageChannelMain', () => {
|
describe('MessageChannelMain', () => {
|
||||||
it('can be created', () => {
|
it('can be created', () => {
|
||||||
const { port1, port2 } = new MessageChannelMain()
|
const { port1, port2 } = new MessageChannelMain()
|
||||||
|
|
Loading…
Reference in a new issue