Change: simplify msg.js (#544)
* Fix: make API work in private windows * Change: simplify msg.js
This commit is contained in:
		
							parent
							
								
									b622ebc172
								
							
						
					
					
						commit
						b2657e3ebd
					
				
							
								
								
									
										195
									
								
								js/msg.js
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								js/msg.js
									
									
									
									
									
								
							|  | @ -4,30 +4,20 @@ | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| const msg = (() => { | const msg = (() => { | ||||||
|   let isBg = false; |   const runtimeSend = promisify(chrome.runtime.sendMessage.bind(chrome.runtime)); | ||||||
|   if (chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() === window) { |   const tabSend = chrome.tabs && promisify(chrome.tabs.sendMessage.bind(chrome.tabs)); | ||||||
|     isBg = true; |   const tabQuery = chrome.tabs && promisify(chrome.tabs.query.bind(chrome.tabs)); | ||||||
|  | 
 | ||||||
|  |   const isBg = chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() === window; | ||||||
|  |   if (isBg) { | ||||||
|     window._msg = { |     window._msg = { | ||||||
|       id: 1, |  | ||||||
|       storage: new Map(), |  | ||||||
|       handler: null, |       handler: null, | ||||||
|       clone: deepCopy |       clone: deepCopy | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
|   const runtimeSend = promisify(chrome.runtime.sendMessage.bind(chrome.runtime)); |   const bgReady = getBg(); | ||||||
|   const tabSend = chrome.tabs && promisify(chrome.tabs.sendMessage.bind(chrome.tabs)); |  | ||||||
|   const tabQuery = chrome.tabs && promisify(chrome.tabs.query.bind(chrome.tabs)); |  | ||||||
|   let bg; |  | ||||||
|   const preparing = !isBg && chrome.runtime.getBackgroundPage && |  | ||||||
|     promisify(chrome.runtime.getBackgroundPage.bind(chrome.runtime))() |  | ||||||
|       .catch(() => null) |  | ||||||
|       .then(_bg => { |  | ||||||
|         bg = _bg; |  | ||||||
|       }); |  | ||||||
|   bg = isBg ? window : !preparing ? null : undefined; |  | ||||||
|   const EXTENSION_URL = chrome.runtime.getURL(''); |   const EXTENSION_URL = chrome.runtime.getURL(''); | ||||||
|   let handler; |   let handler; | ||||||
|   const from_ = location.href.startsWith(EXTENSION_URL) ? 'extension' : 'content'; |  | ||||||
|   const RX_NO_RECEIVER = /Receiving end does not exist/; |   const RX_NO_RECEIVER = /Receiving end does not exist/; | ||||||
|   const RX_PORT_CLOSED = /The message port closed before a response was received/; |   const RX_PORT_CLOSED = /The message port closed before a response was received/; | ||||||
|   return { |   return { | ||||||
|  | @ -46,33 +36,29 @@ const msg = (() => { | ||||||
|     RX_PORT_CLOSED |     RX_PORT_CLOSED | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   function getBg() { | ||||||
|  |     if (isBg) { | ||||||
|  |       return Promise.resolve(window); | ||||||
|  |     } | ||||||
|  |     if (!chrome.runtime.getBackgroundPage) { | ||||||
|  |       return Promise.resolve(); | ||||||
|  |     } | ||||||
|  |     return promisify(chrome.runtime.getBackgroundPage.bind(chrome.runtime))() | ||||||
|  |       .catch(() => null); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   function send(data, target = 'extension') { |   function send(data, target = 'extension') { | ||||||
|     if (bg === undefined) { |     const message = {data, target}; | ||||||
|       return preparing.then(() => send(data, target)); |     return runtimeSend(message).then(unwrapData); | ||||||
|     } |  | ||||||
|     const message = {type: 'direct', data, target, from: from_}; |  | ||||||
|     if (bg) { |  | ||||||
|       exchangeSet(message); |  | ||||||
|     } |  | ||||||
|     const request = runtimeSend(message).then(unwrapData); |  | ||||||
|     if (message.id) { |  | ||||||
|       return withCleanup(request, () => bg._msg.storage.delete(message.id)); |  | ||||||
|     } |  | ||||||
|     return request; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function sendTab(tabId, data, options, target = 'tab') { |   function sendTab(tabId, data, options, target = 'tab') { | ||||||
|     return tabSend(tabId, {type: 'direct', data, target, from: from_}, options) |     return tabSend(tabId, {data, target}, options) | ||||||
|       .then(unwrapData); |       .then(unwrapData); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function sendBg(data) { |   function sendBg(data) { | ||||||
|     if (bg === undefined) { |     return bgReady.then(bg => { | ||||||
|       return preparing.then(doSend); |  | ||||||
|     } |  | ||||||
|     return withPromiseError(doSend); |  | ||||||
| 
 |  | ||||||
|     function doSend() { |  | ||||||
|       if (bg) { |       if (bg) { | ||||||
|         if (!bg._msg.handler) { |         if (!bg._msg.handler) { | ||||||
|           throw new Error('there is no bg handler'); |           throw new Error('there is no bg handler'); | ||||||
|  | @ -84,7 +70,7 @@ const msg = (() => { | ||||||
|           .then(deepCopy); |           .then(deepCopy); | ||||||
|       } |       } | ||||||
|       return send(data); |       return send(data); | ||||||
|     } |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function ignoreError(err) { |   function ignoreError(err) { | ||||||
|  | @ -126,15 +112,12 @@ const msg = (() => { | ||||||
|           if (!dataObj) { |           if (!dataObj) { | ||||||
|             continue; |             continue; | ||||||
|           } |           } | ||||||
|           const message = {type: 'direct', data: dataObj, target, from: from_}; |           const message = {data: dataObj, target}; | ||||||
|           if (isExtension) { |           requests.push( | ||||||
|             exchangeSet(message); |             tabSend(tab.id, message, options) | ||||||
|           } |               .then(unwrapData) | ||||||
|           let request = tabSend(tab.id, message, options).then(unwrapData); |               .catch(ignoreError) | ||||||
|           if (message.id) { |           ); | ||||||
|             request = withCleanup(request, () => bg._msg.storage.delete(message.id)); |  | ||||||
|           } |  | ||||||
|           requests.push(request.catch(ignoreError)); |  | ||||||
|         } |         } | ||||||
|         return Promise.all(requests); |         return Promise.all(requests); | ||||||
|       }); |       }); | ||||||
|  | @ -178,7 +161,7 @@ const msg = (() => { | ||||||
|       extension: [] |       extension: [] | ||||||
|     }; |     }; | ||||||
|     if (isBg) { |     if (isBg) { | ||||||
|       bg._msg.handler = handler; |       window._msg.handler = handler; | ||||||
|     } |     } | ||||||
|     chrome.runtime.onMessage.addListener(handleMessage); |     chrome.runtime.onMessage.addListener(handleMessage); | ||||||
|   } |   } | ||||||
|  | @ -202,70 +185,27 @@ const msg = (() => { | ||||||
|     if (!handlers.length) { |     if (!handlers.length) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     if (message.type === 'exchange') { |     const result = executeCallbacks(handlers, message.data, sender); | ||||||
|       const pending = exchangeGet(message, true); |     if (result === undefined) { | ||||||
|       if (pending) { |       return; | ||||||
|         pending.then(response); |  | ||||||
|         return true; |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     return response(); |     Promise.resolve(result) | ||||||
| 
 |       .then( | ||||||
|     function response() { |         data => ({ | ||||||
|       const result = executeCallbacks(handlers, message.data, sender); |           error: false, | ||||||
|       if (result === undefined) { |           data | ||||||
|         return; |         }), | ||||||
|       } |         err => ({ | ||||||
|       Promise.resolve(result) |           error: true, | ||||||
|         .then( |           data: Object.assign({ | ||||||
|           data => ({ |             message: err.message || String(err), | ||||||
|             error: false, |             // FIXME: do we want to pass the entire stack?
 | ||||||
|             data |             stack: err.stack | ||||||
|           }), |           }, err) // this allows us to pass custom properties e.g. `err.index`
 | ||||||
|           err => ({ |  | ||||||
|             error: true, |  | ||||||
|             data: Object.assign({ |  | ||||||
|               message: err.message || String(err), |  | ||||||
|               // FIXME: do we want to pass the entire stack?
 |  | ||||||
|               stack: err.stack |  | ||||||
|             }, err) // this allows us to pass custom properties e.g. `err.index`
 |  | ||||||
|           }) |  | ||||||
|         ) |  | ||||||
|         .then(function doResponse(responseMessage) { |  | ||||||
|           if (message.from === 'extension' && bg === undefined) { |  | ||||||
|             return preparing.then(() => doResponse(responseMessage)); |  | ||||||
|           } |  | ||||||
|           if (message.from === 'extension' && bg) { |  | ||||||
|             exchangeSet(responseMessage); |  | ||||||
|           } else { |  | ||||||
|             responseMessage.type = 'direct'; |  | ||||||
|           } |  | ||||||
|           return responseMessage; |  | ||||||
|         }) |         }) | ||||||
|         .then(sendResponse); |       ) | ||||||
|       return true; |       .then(sendResponse); | ||||||
|     } |     return true; | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   function exchangeGet(message, keepStorage = false) { |  | ||||||
|     if (bg === undefined) { |  | ||||||
|       return preparing.then(() => exchangeGet(message, keepStorage)); |  | ||||||
|     } |  | ||||||
|     message.data = bg._msg.storage.get(message.id); |  | ||||||
|     if (keepStorage) { |  | ||||||
|       message.data = deepCopy(message.data); |  | ||||||
|     } else { |  | ||||||
|       bg._msg.storage.delete(message.id); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   function exchangeSet(message) { |  | ||||||
|     const id = bg._msg.id; |  | ||||||
|     bg._msg.storage.set(id, message.data); |  | ||||||
|     bg._msg.id++; |  | ||||||
|     message.type = 'exchange'; |  | ||||||
|     message.id = id; |  | ||||||
|     delete message.data; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function withPromiseError(fn, ...args) { |   function withPromiseError(fn, ...args) { | ||||||
|  | @ -276,46 +216,15 @@ const msg = (() => { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function withCleanup(p, fn) { |  | ||||||
|     return p.then( |  | ||||||
|       result => { |  | ||||||
|         cleanup(); |  | ||||||
|         return result; |  | ||||||
|       }, |  | ||||||
|       err => { |  | ||||||
|         cleanup(); |  | ||||||
|         throw err; |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     function cleanup() { |  | ||||||
|       try { |  | ||||||
|         fn(); |  | ||||||
|       } catch (err) { |  | ||||||
|         // pass
 |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // {type, error, data, id}
 |   // {type, error, data, id}
 | ||||||
|   function unwrapData(result) { |   function unwrapData(result) { | ||||||
|     if (result === undefined) { |     if (result === undefined) { | ||||||
|       throw new Error('Receiving end does not exist'); |       throw new Error('Receiving end does not exist'); | ||||||
|     } |     } | ||||||
|     if (result.type === 'exchange') { |     if (result.error) { | ||||||
|       const pending = exchangeGet(result); |       throw Object.assign(new Error(result.data.message), result.data); | ||||||
|       if (pending) { |  | ||||||
|         return pending.then(unwrap); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return unwrap(); |  | ||||||
| 
 |  | ||||||
|     function unwrap() { |  | ||||||
|       if (result.error) { |  | ||||||
|         throw Object.assign(new Error(result.data.message), result.data); |  | ||||||
|       } |  | ||||||
|       return result.data; |  | ||||||
|     } |     } | ||||||
|  |     return result.data; | ||||||
|   } |   } | ||||||
| })(); | })(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user