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.
|
||||
|
||||
#### Event: 'close'
|
||||
|
||||
Emitted when the remote end of a MessagePortMain object becomes disconnected.
|
||||
|
||||
[`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
|
||||
|
|
|
@ -91,3 +91,4 @@ feat_enable_offscreen_rendering_with_viz_compositor.patch
|
|||
delay_lock_the_protocol_scheme_registry.patch
|
||||
gpu_notify_when_dxdiag_request_fails.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;
|
||||
if (!HasPendingActivity())
|
||||
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) {
|
||||
|
@ -196,6 +202,7 @@ void MessagePort::Pin() {
|
|||
if (!pinned_.IsEmpty())
|
||||
return;
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Value> self;
|
||||
if (GetWrapper(isolate).ToLocal(&self)) {
|
||||
pinned_.Reset(isolate, self);
|
||||
|
|
|
@ -278,6 +278,57 @@ describe('ipc module', () => {
|
|||
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', () => {
|
||||
it('can be created', () => {
|
||||
const { port1, port2 } = new MessageChannelMain()
|
||||
|
|
Loading…
Reference in a new issue