Convert messaging to use ports (#38)
* Convert messageing to use ports * Small listeneing cleanups
This commit is contained in:
parent
dc155556d4
commit
01f2f16b79
@ -6,19 +6,45 @@ import { AuthorizeRequest, MessageTypes, SigningRequest } from '@polkadot/extens
|
||||
import { KeyringJson } from '@polkadot/ui-keyring/types';
|
||||
import { KeypairType } from '@polkadot/util-crypto/types';
|
||||
|
||||
import extension from 'extensionizer';
|
||||
import { PORT_POPUP } from '@polkadot/extension/defaults';
|
||||
|
||||
type Handlers = {
|
||||
[index: number]: {
|
||||
resolve: (data: any) => void,
|
||||
reject: (error: Error) => void
|
||||
}
|
||||
};
|
||||
|
||||
const port = extension.runtime.connect({ name: PORT_POPUP });
|
||||
const handlers: Handlers = {};
|
||||
let idCounter = 0;
|
||||
|
||||
// setup a listener for messages, any incoming resolves the promise
|
||||
port.onMessage.addListener((data) => {
|
||||
const handler = handlers[data.id];
|
||||
|
||||
if (!handler) {
|
||||
console.error(`Uknown response: ${JSON.stringify(data)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
delete handlers[data.id];
|
||||
|
||||
if (data.error) {
|
||||
handler.reject(new Error(data.error));
|
||||
} else {
|
||||
handler.resolve(data.response);
|
||||
}
|
||||
});
|
||||
|
||||
function sendMessage (message: MessageTypes, request: any = {}): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = ++idCounter;
|
||||
|
||||
chrome.runtime.sendMessage({ id, message, request }, ({ error, response }) => {
|
||||
if (error) {
|
||||
reject(new Error(error));
|
||||
} else {
|
||||
resolve(response);
|
||||
}
|
||||
});
|
||||
handlers[id] = { resolve, reject };
|
||||
|
||||
port.postMessage({ id, message, request });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
import { MessageRequest } from '../types';
|
||||
|
||||
import { PORT_POPUP } from '../../defaults';
|
||||
import Extension from './Extension';
|
||||
import State from './State';
|
||||
import Tabs from './Tabs';
|
||||
@ -12,27 +13,34 @@ const state = new State();
|
||||
const extension = new Extension(state);
|
||||
const tabs = new Tabs(state);
|
||||
|
||||
export default function handler ({ id, message, request }: MessageRequest, { tab }: chrome.runtime.MessageSender, sendResponse: (response?: any) => void): boolean {
|
||||
const source = `${tab ? tab.url : 'extension'}: ${id}: ${message}`;
|
||||
export default function handler ({ id, message, request }: MessageRequest, port: chrome.runtime.Port): boolean {
|
||||
const isPopup = port.name === PORT_POPUP;
|
||||
const sender = port.sender as chrome.runtime.MessageSender;
|
||||
const from = isPopup
|
||||
? 'popup'
|
||||
: sender.tab
|
||||
? sender.tab.url
|
||||
: '<unknown>';
|
||||
const source = `${from}: ${id}: ${message}`;
|
||||
|
||||
console.log(` [in] ${source}`); // :: ${JSON.stringify(request)}`);
|
||||
|
||||
const promise = tab
|
||||
? tabs.handle(message, request, tab.url)
|
||||
: extension.handle(message, request);
|
||||
const promise = isPopup
|
||||
? extension.handle(message, request)
|
||||
: tabs.handle(message, request, from);
|
||||
|
||||
promise
|
||||
.then((response) => {
|
||||
console.log(`[out] ${source}`); // :: ${JSON.stringify(response)}`);
|
||||
|
||||
sendResponse({ id, response });
|
||||
port.postMessage({ id, response });
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(`[err] ${source}:: ${error.message}`);
|
||||
|
||||
sendResponse({ id, error: error.message });
|
||||
port.postMessage({ id, error: error.message });
|
||||
});
|
||||
|
||||
// return true to indicate we are sending the respionse async
|
||||
// return true to indicate we are sending the response async
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -7,14 +7,27 @@ import extension from 'extensionizer';
|
||||
// Runs in the extension background, handling all keyring access
|
||||
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import { assert } from '@polkadot/util';
|
||||
import { cryptoWaitReady } from '@polkadot/util-crypto';
|
||||
|
||||
import { PORT_CONTENT, PORT_POPUP } from '../defaults';
|
||||
import ChromeStore from './ChromeStore';
|
||||
import handlers from './handlers';
|
||||
|
||||
// setup the notification
|
||||
extension.browserAction.setBadgeBackgroundColor({ color: '#ff0000' });
|
||||
extension.runtime.onMessage.addListener(handlers);
|
||||
|
||||
// listen to all messages and handle appropriately
|
||||
extension.runtime.onConnect.addListener((port) => {
|
||||
// shouldn't happen, however... only listen to what we know about
|
||||
assert([PORT_CONTENT, PORT_POPUP].includes(port.name), `Unknown connection from ${port.name}`);
|
||||
|
||||
// message and disconnect handlers
|
||||
port.onMessage.addListener((data) => handlers(data, port));
|
||||
port.onDisconnect.addListener(() => console.log(`Disconnected from ${port.name}`));
|
||||
});
|
||||
|
||||
// initial setup
|
||||
cryptoWaitReady()
|
||||
.then(() => {
|
||||
console.log('crypto initialized');
|
||||
|
||||
@ -4,27 +4,24 @@
|
||||
|
||||
import extension from 'extensionizer';
|
||||
|
||||
function sendResponse (data: any): void {
|
||||
window.postMessage({ ...data, origin: 'content' }, '*');
|
||||
}
|
||||
import { PORT_CONTENT } from './defaults';
|
||||
|
||||
// Handle all messages, passing messages to the extension
|
||||
// connect to the extension
|
||||
const port = extension.runtime.connect({ name: PORT_CONTENT });
|
||||
|
||||
// send any messages from the extension back to the page
|
||||
port.onMessage.addListener((data) => {
|
||||
window.postMessage({ ...data, origin: 'content' }, '*');
|
||||
});
|
||||
|
||||
// all messages from the page, pass them to the extension
|
||||
window.addEventListener('message', ({ data, source }) => {
|
||||
// only allow messages from our window, by the inject
|
||||
if (source !== window || data.origin !== 'page') {
|
||||
return;
|
||||
}
|
||||
|
||||
// pass the detail as-is as a message to the extension
|
||||
extension.runtime.sendMessage(data, (response) => {
|
||||
if (!response) {
|
||||
// no data, send diconnected/unknown error
|
||||
sendResponse({ id: data.id, error: 'Unknown response' });
|
||||
} else {
|
||||
// handle the response, passing as a custom event
|
||||
sendResponse(response);
|
||||
}
|
||||
});
|
||||
port.postMessage(data);
|
||||
});
|
||||
|
||||
// inject our data injector
|
||||
|
||||
11
packages/extension/src/defaults.ts
Normal file
11
packages/extension/src/defaults.ts
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright 2019 @polkadot/extension authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
const PORT_CONTENT = 'content';
|
||||
const PORT_POPUP = 'popup';
|
||||
|
||||
export {
|
||||
PORT_CONTENT,
|
||||
PORT_POPUP
|
||||
};
|
||||
@ -14,7 +14,7 @@ import Injected from './Injected';
|
||||
// - this injector, reads listends on the events, maps it to the original
|
||||
// - resolves/rejects the promise with the result
|
||||
|
||||
type Callbacks = {
|
||||
type Handlers = {
|
||||
[index: number]: {
|
||||
resolve: (data: any) => void,
|
||||
reject: (error: Error) => void
|
||||
@ -23,7 +23,7 @@ type Callbacks = {
|
||||
|
||||
// small helper with the typescript types, just cast window
|
||||
const windowInject = window as InjectedWindow;
|
||||
const callbacks: Callbacks = {};
|
||||
const handlers: Handlers = {};
|
||||
let idCounter = 0;
|
||||
|
||||
// a generic message sender that creates an event, returning a promise that will
|
||||
@ -32,7 +32,7 @@ function sendMessage (message: MessageTypes, request: any = null): Promise<any>
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = ++idCounter;
|
||||
|
||||
callbacks[id] = { resolve, reject };
|
||||
handlers[id] = { resolve, reject };
|
||||
|
||||
window.postMessage({ id, message, origin: 'page', request }, '*');
|
||||
});
|
||||
@ -52,19 +52,19 @@ window.addEventListener('message', ({ data, source }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const promise = callbacks[data.id];
|
||||
const handler = handlers[data.id];
|
||||
|
||||
if (!promise) {
|
||||
if (!handler) {
|
||||
console.error(`Uknown response: ${JSON.stringify(data)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
delete callbacks[data.id];
|
||||
delete handlers[data.id];
|
||||
|
||||
if (data.error) {
|
||||
promise.reject(new Error(data.error));
|
||||
handler.reject(new Error(data.error));
|
||||
} else {
|
||||
promise.resolve(data.response);
|
||||
handler.resolve(data.response);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user