Browse Source

Handle port disconnecting

Cheng Zhao 9 years ago
parent
commit
d8db695712
3 changed files with 42 additions and 16 deletions
  1. 2 3
      atom/renderer/atom_renderer_client.cc
  2. 22 5
      lib/browser/chrome-extension.js
  3. 18 8
      lib/renderer/chrome-api.js

+ 2 - 3
atom/renderer/atom_renderer_client.cc

@@ -266,10 +266,9 @@ void AtomRendererClient::DidCreateScriptContext(
 
 void AtomRendererClient::WillReleaseScriptContext(
     v8::Handle<v8::Context> context, content::RenderFrame* render_frame) {
-  if (render_frame->IsMainFrame()) {
-    node::Environment* env = node::Environment::GetCurrent(context);
+  node::Environment* env = node::Environment::GetCurrent(context);
+  if (env)
     mate::EmitEvent(env->isolate(), env->process_object(), "exit");
-  }
 }
 
 bool AtomRendererClient::ShouldFork(blink::WebLocalFrame* frame,

+ 22 - 5
lib/browser/chrome-extension.js

@@ -78,6 +78,8 @@ const removeBackgroundPages = function (manifest) {
 }
 
 // Handle the chrome.* API messages.
+let nextId = 0
+
 ipcMain.on('CHROME_RUNTIME_CONNECT', function (event, hostname, connectInfo) {
   const page = backgroundPages[hostname]
   if (!page) {
@@ -85,18 +87,33 @@ ipcMain.on('CHROME_RUNTIME_CONNECT', function (event, hostname, connectInfo) {
     return
   }
 
-  event.returnValue = page.webContents.id
-  page.webContents.sendToAll('CHROME_RUNTIME_ONCONNECT', event.sender.id, hostname, connectInfo)
+  const portId = ++nextId
+  event.returnValue = {webContentsId: page.webContents.id, portId: portId}
+
+  event.sender.once('render-view-deleted', () => {
+    page.webContents.sendToAll(`CHROME_PORT_ONDISCONNECT_${portId}`)
+  })
+  page.webContents.sendToAll('CHROME_RUNTIME_ONCONNECT', event.sender.id, portId, connectInfo)
+})
+
+ipcMain.on('CHROME_PORT_DISCONNECT', function (event, webContentsId, portId) {
+  const contents = webContents.fromId(webContentsId)
+  if (!contents) {
+    console.error(`Disconnet to unkown webContentsId ${webContentsId}`)
+    return
+  }
+
+  contents.sendToAll(`CHROME_PORT_ONDISCONNECT_${portId}`)
 })
 
-ipcMain.on('CHROME_PORT_POSTMESSAGE', function (event, webContentsId, hostname, message) {
+ipcMain.on('CHROME_PORT_POSTMESSAGE', function (event, webContentsId, portId, message) {
   const contents = webContents.fromId(webContentsId)
   if (!contents) {
-    console.error(`Sending message to extension ${hostname} with unkown webContentsId ${webContentsId}`)
+    console.error(`Sending message to unkown webContentsId ${webContentsId}`)
     return
   }
 
-  contents.sendToAll(`CHROME_PORT_ONMESSAGE_${hostname}`, message)
+  contents.sendToAll(`CHROME_PORT_ONMESSAGE_${portId}`, message)
 })
 
 // Transfer the content scripts to renderer.

+ 18 - 8
lib/renderer/chrome-api.js

@@ -24,8 +24,8 @@ class OnConnect extends Event {
   constructor () {
     super()
 
-    ipcRenderer.on('CHROME_RUNTIME_ONCONNECT', (event, webContentsId, extensionId, connectInfo) => {
-      this.emit(new Port(webContentsId, extensionId, connectInfo.name))
+    ipcRenderer.on('CHROME_RUNTIME_ONCONNECT', (event, webContentsId, portId, connectInfo) => {
+      this.emit(new Port(webContentsId, portId, connectInfo.name))
     })
   }
 }
@@ -41,25 +41,35 @@ class MessageSender {
 }
 
 class Port {
-  constructor (webContentsId, extensionId, name) {
+  constructor (webContentsId, portId, name) {
     this.webContentsId = webContentsId
-    this.extensionId = extensionId
+    this.portId = portId
 
     this.name = name
     this.onDisconnect = new Event()
     this.onMessage = new Event()
     this.sender = new MessageSender()
 
-    ipcRenderer.on(`CHROME_PORT_ONMESSAGE_${extensionId}`, (event, message) => {
+    ipcRenderer.once(`CHROME_PORT_ONDISCONNECT_${portId}`, () => {
+      this._onDisconnect()
+    })
+    ipcRenderer.on(`CHROME_PORT_ONMESSAGE_${portId}`, (event, message) => {
       this.onMessage.emit(message, new MessageSender(), function () {})
     })
   }
 
   disconnect () {
+    ipcRenderer.send('CHROME_PORT_DISCONNECT', this.webContentsId, this.portId)
+    this._onDisconnect()
   }
 
   postMessage (message) {
-    ipcRenderer.send('CHROME_PORT_POSTMESSAGE', this.webContentsId, this.extensionId, message)
+    ipcRenderer.send('CHROME_PORT_POSTMESSAGE', this.webContentsId, this.portId, message)
+  }
+
+  _onDisconnect() {
+    ipcRenderer.removeAllListeners(`CHROME_PORT_ONMESSAGE_${this.portId}`)
+    this.onDisconnect.emit()
   }
 }
 
@@ -91,7 +101,7 @@ chrome.runtime = {
       [extensionId, connectInfo] = args
     }
 
-    const webContentsId = ipcRenderer.sendSync('CHROME_RUNTIME_CONNECT', extensionId, connectInfo)
-    return new Port(webContentsId, extensionId, connectInfo.name)
+    const {webContentsId, portId} = ipcRenderer.sendSync('CHROME_RUNTIME_CONNECT', extensionId, connectInfo)
+    return new Port(webContentsId, portId, connectInfo.name)
   }
 }