Browse Source

Make simple runtime.connect work

Cheng Zhao 9 years ago
parent
commit
e76c36a9a8
2 changed files with 109 additions and 2 deletions
  1. 24 1
      lib/browser/chrome-extension.js
  2. 85 1
      lib/renderer/chrome-api.js

+ 24 - 1
lib/browser/chrome-extension.js

@@ -1,4 +1,4 @@
-const {app, protocol, webContents, BrowserWindow} = require('electron')
+const {app, ipcMain, protocol, webContents, BrowserWindow} = require('electron')
 const renderProcessPreferences = process.atomBinding('render_process_preferences').forAllBrowserWindow()
 
 const fs = require('fs')
@@ -67,6 +67,7 @@ const startBackgroundPages = function (manifest) {
     hostname: manifest.hostname,
     pathname: '_generated_background_page.html'
   }))
+  contents.openDevTools()
 }
 
 const removeBackgroundPages = function (manifest) {
@@ -76,6 +77,28 @@ const removeBackgroundPages = function (manifest) {
   delete backgroundPages[manifest.hostname]
 }
 
+// Handle the chrome.* API messages.
+ipcMain.on('CHROME_RUNTIME_CONNECT', function (event, hostname, connectInfo) {
+  const page = backgroundPages[hostname]
+  if (!page) {
+    console.error(`Connect to unkown extension ${hostname}`)
+    return
+  }
+
+  event.returnValue = page.webContents.id
+  page.webContents.sendToAll('CHROME_RUNTIME_ONCONNECT', event.sender.id, hostname, connectInfo)
+})
+
+ipcMain.on('CHROME_PORT_POSTMESSAGE', function (event, webContentsId, hostname, message) {
+  const contents = webContents.fromId(webContentsId)
+  if (!contents) {
+    console.error(`Sending message to extension ${hostname} with unkown webContentsId ${webContentsId}`)
+    return
+  }
+
+  contents.sendToAll(`CHROME_PORT_ONMESSAGE_${hostname}`, message)
+})
+
 // Transfer the content scripts to renderer.
 const contentScripts = {}
 

+ 85 - 1
lib/renderer/chrome-api.js

@@ -1,4 +1,68 @@
+const {ipcRenderer} = require('electron')
 const url = require('url')
+
+// TODO(zcbenz): Set it to correct value for content scripts.
+const currentExtensionId = window.location.hostname
+
+class Event {
+  constructor () {
+    this.listeners = []
+  }
+
+  addListener (callback) {
+    this.listeners.push(callback)
+  }
+
+  emit (...args) {
+    for (const listener of this.listeners) {
+      listener(...args)
+    }
+  }
+}
+
+class OnConnect extends Event {
+  constructor () {
+    super()
+
+    ipcRenderer.on('CHROME_RUNTIME_ONCONNECT', (event, webContentsId, extensionId, connectInfo) => {
+      this.emit(new Port(webContentsId, extensionId, connectInfo.name))
+    })
+  }
+}
+
+class MessageSender {
+  constructor () {
+    this.tab = null
+    this.frameId = null
+    this.id = null
+    this.url = null
+    this.tlsChannelId = null
+  }
+}
+
+class Port {
+  constructor (webContentsId, extensionId, name) {
+    this.webContentsId = webContentsId
+    this.extensionId = extensionId
+
+    this.name = name
+    this.onDisconnect = new Event()
+    this.onMessage = new Event()
+    this.sender = new MessageSender()
+
+    ipcRenderer.on(`CHROME_PORT_ONMESSAGE_${extensionId}`, (event, message) => {
+      this.onMessage.emit(message, new MessageSender(), function () {})
+    })
+  }
+
+  disconnect () {
+  }
+
+  postMessage (message) {
+    ipcRenderer.send('CHROME_PORT_POSTMESSAGE', this.webContentsId, this.extensionId, message)
+  }
+}
+
 const chrome = window.chrome = window.chrome || {}
 
 chrome.extension = {
@@ -6,8 +70,28 @@ chrome.extension = {
     return url.format({
       protocol: window.location.protocol,
       slashes: true,
-      hostname: window.location.hostname,
+      hostname: currentExtensionId,
       pathname: path
     })
   }
 }
+
+chrome.runtime = {
+  getURL: chrome.extension.getURL,
+
+  onConnect: new OnConnect(),
+
+  connect (...args) {
+    // Parse the optional args.
+    let extensionId = currentExtensionId
+    let connectInfo = {name: ''}
+    if (args.length === 1) {
+      connectInfo = args[0]
+    } else if (args.length === 2) {
+      [extensionId, connectInfo] = args
+    }
+
+    const webContentsId = ipcRenderer.sendSync('CHROME_RUNTIME_CONNECT', extensionId, connectInfo)
+    return new Port(webContentsId, extensionId, connectInfo.name)
+  }
+}