aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/ui.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/scripts/ui.js')
-rw-r--r--app/scripts/ui.js125
1 files changed, 108 insertions, 17 deletions
diff --git a/app/scripts/ui.js b/app/scripts/ui.js
index 2dde14b48..a1f904f61 100644
--- a/app/scripts/ui.js
+++ b/app/scripts/ui.js
@@ -1,12 +1,19 @@
-const startPopup = require('./popup-core')
const PortStream = require('extension-port-stream')
const { getEnvironmentType } = require('./lib/util')
-const { ENVIRONMENT_TYPE_NOTIFICATION, ENVIRONMENT_TYPE_FULLSCREEN } = require('./lib/enums')
+const { ENVIRONMENT_TYPE_NOTIFICATION, ENVIRONMENT_TYPE_FULLSCREEN, ENVIRONMENT_TYPE_POPUP } = require('./lib/enums')
const extension = require('extensionizer')
const ExtensionPlatform = require('./platforms/extension')
const NotificationManager = require('./lib/notification-manager')
const notificationManager = new NotificationManager()
const setupSentry = require('./lib/setupSentry')
+const {EventEmitter} = require('events')
+const Dnode = require('dnode')
+const Eth = require('ethjs')
+const EthQuery = require('eth-query')
+const urlUtil = require('url')
+const launchMetaMaskUi = require('../../ui')
+const StreamProvider = require('web3-stream-provider')
+const {setupMultiplex} = require('./lib/stream-utils.js')
const log = require('loglevel')
start().catch(log.error)
@@ -39,20 +46,8 @@ async function start () {
const extensionPort = extension.runtime.connect({ name: windowType })
const connectionStream = new PortStream(extensionPort)
- // start ui
- const container = document.getElementById('app-content')
- startPopup({ container, connectionStream }, (err, store) => {
- if (err) return displayCriticalError(err)
-
- const state = store.getState()
- const { metamask: { completedOnboarding } = {} } = state
-
- if (!completedOnboarding && windowType !== ENVIRONMENT_TYPE_FULLSCREEN) {
- global.platform.openExtensionInBrowser()
- return
- }
- })
-
+ const activeTab = await queryCurrentActiveTab(windowType)
+ initializeUiWithTab(activeTab)
function closePopupIfOpen (windowType) {
if (windowType !== ENVIRONMENT_TYPE_NOTIFICATION) {
@@ -61,11 +56,107 @@ async function start () {
}
}
- function displayCriticalError (err) {
+ function displayCriticalError (container, err) {
container.innerHTML = '<div class="critical-error">The MetaMask app failed to load: please open and close MetaMask again to restart.</div>'
container.style.height = '80px'
log.error(err.stack)
throw err
}
+ function initializeUiWithTab (tab) {
+ const container = document.getElementById('app-content')
+ initializeUi(tab, container, connectionStream, (err, store) => {
+ if (err) {
+ return displayCriticalError(container, err)
+ }
+
+ const state = store.getState()
+ const { metamask: { completedOnboarding } = {} } = state
+
+ if (!completedOnboarding && windowType !== ENVIRONMENT_TYPE_FULLSCREEN) {
+ global.platform.openExtensionInBrowser()
+ }
+ })
+ }
+}
+
+async function queryCurrentActiveTab (windowType) {
+ return new Promise((resolve) => {
+ // At the time of writing we only have the `activeTab` permission which means
+ // that this query will only succeed in the popup context (i.e. after a "browserAction")
+ if (windowType !== ENVIRONMENT_TYPE_POPUP) {
+ resolve({})
+ return
+ }
+
+ extension.tabs.query({active: true, currentWindow: true}, (tabs) => {
+ const [activeTab] = tabs
+ const {title, url} = activeTab
+ const origin = url ? urlUtil.parse(url).hostname : null
+ resolve({
+ title, origin, url,
+ })
+ })
+ })
+}
+
+function initializeUi (activeTab, container, connectionStream, cb) {
+ connectToAccountManager(connectionStream, (err, backgroundConnection) => {
+ if (err) {
+ return cb(err)
+ }
+
+ launchMetaMaskUi({
+ activeTab,
+ container,
+ backgroundConnection,
+ }, cb)
+ })
+}
+
+/**
+ * Establishes a connection to the background and a Web3 provider
+ *
+ * @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
+ * @param {Function} cb Called when controller connection is established
+ */
+function connectToAccountManager (connectionStream, cb) {
+ const mx = setupMultiplex(connectionStream)
+ setupControllerConnection(mx.createStream('controller'), cb)
+ setupWeb3Connection(mx.createStream('provider'))
+}
+
+/**
+ * Establishes a streamed connection to a Web3 provider
+ *
+ * @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
+ */
+function setupWeb3Connection (connectionStream) {
+ const providerStream = new StreamProvider()
+ providerStream.pipe(connectionStream).pipe(providerStream)
+ connectionStream.on('error', console.error.bind(console))
+ providerStream.on('error', console.error.bind(console))
+ global.ethereumProvider = providerStream
+ global.ethQuery = new EthQuery(providerStream)
+ global.eth = new Eth(providerStream)
+}
+
+/**
+ * Establishes a streamed connection to the background account manager
+ *
+ * @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
+ * @param {Function} cb Called when the remote account manager connection is established
+ */
+function setupControllerConnection (connectionStream, cb) {
+ const eventEmitter = new EventEmitter()
+ const backgroundDnode = Dnode({
+ sendUpdate: function (state) {
+ eventEmitter.emit('update', state)
+ },
+ })
+ connectionStream.pipe(backgroundDnode).pipe(connectionStream)
+ backgroundDnode.once('remote', function (backgroundConnection) {
+ backgroundConnection.on = eventEmitter.on.bind(eventEmitter)
+ cb(null, backgroundConnection)
+ })
}