Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Unified Diff: remoting/webapp/base/js/ipc.js

Issue 877993002: Implement base.IPC (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add unittest Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: remoting/webapp/base/js/ipc.js
diff --git a/remoting/webapp/base/js/ipc.js b/remoting/webapp/base/js/ipc.js
new file mode 100644
index 0000000000000000000000000000000000000000..ea2359a32b7bedadf7812331ef327a2442056f2f
--- /dev/null
+++ b/remoting/webapp/base/js/ipc.js
@@ -0,0 +1,182 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+* @fileoverview
+*
+* In Chrome Apps, some platform APIs can only be called from the background
+* page (e.g. reloading a chrome.app.AppWindow). Likewise, some chrome API's
+* must be initiated by user interaction, which can only be called from the
+* foreground.
+*
+* This class provides helper functions to invoke methods on different pages
+* using chrome.runtime.sendMessage. Messages are passed in the following
+* format:
+* {methodName:{string}, params:{Array}}
+*
+* chrome.runtime.sendMessage allows multiple handlers to be registered on a
+* document, but only one handler can send a response.
+* This class uniquely identifies a method with the |methodName| and enforces
+* that only one handler can be registered per |methodName| in the document.
+*
+* For example, to call method foo() in the background page from the foreground
+* chrome.app.AppWindow, you can do the following.
+* In the background page:
+* base.IPC.getInstance().register('my.service.name', foo);
+*
+* In the AppWindow document:
+* base.IPC.invoke('my.service.name', arg1, arg2, ...).then(
+* function(result) {
+* console.log('The result is ' + result);
+* });
+*
+* This will invoke foo() with the arg1, arg2 and ... .
+* The return value of foo() will be passed back to the caller in the
+* form of a promise.
+*/
+
+/** @suppress {duplicate} */
+var base = base || {};
+
+(function() {
+
+'use strict';
+
+/**
+ * @constructor
Jamie 2015/01/27 22:52:24 Maybe declare this @private?
kelvinp 2015/01/28 01:31:51 Done. JSCompile doesn't throw any error if you try
+ */
+base.IPC = function() {
+ base.debug.assert(instance_ === null);
+ /**
+ * @type {!Object.<Function>}
+ * @private
+ */
+ this.handlers_ = {};
+ this.onMessageHandler_ = this.onMessage_.bind(this);
+ chrome.runtime.onMessage.addListener(this.onMessageHandler_);
+};
+
+/** @private */
+base.IPC.prototype.dispose_ = function() {
+ chrome.runtime.onMessage.removeListener(this.onMessageHandler_);
+};
+
+/** @enum {string} */
+base.IPC.Error = {
+ UNSUPPORTED_REQUEST_TYPE: 'Unsupported method name.',
+ INVALID_REQUEST_ORIGIN:
+ 'base.IPC only accept incoming requests from the same extension.'
+};
+
+/**
+ * @constructor
+ * @param {string} methodName
+ * @param {?Array} params
+ * @struct
+ */
+base.IPC.Request_ = function(methodName, params) {
+ this.methodName = methodName;
+ this.params = params;
+};
+
+
+/**
+ * @param {string} methodName
+ * @param {Function} handler The handler can be invoked by calling
+ * base.IPC.invoke(|methodName|, arg1, arg2, ...)
+ * Async handlers that return promises are currently not supported.
+ * @return {boolean} Whether the handler is successfully registered.
+ */
+base.IPC.prototype.register = function(methodName, handler) {
+ if (methodName in this.handlers_) {
+ console.error('service :' + methodName + ' is already registered.');
Jamie 2015/01/27 22:52:24 Nit: No colon needed.
kelvinp 2015/01/28 01:31:51 Done.
+ return false;
+ }
+ this.handlers_[methodName] = handler;
+ return true;
+};
+
+/**
+ * @param {string} methodName
+ */
+base.IPC.prototype.unregister = function(methodName) {
+ delete this.handlers_[methodName];
+};
+
+/**
+ * @param {base.IPC.Request_} message
+ * @param {chrome.runtime.MessageSender} sender
+ * @param {function(*): void} sendResponse
+ */
+base.IPC.prototype.onMessage_ = function(message, sender,
+ sendResponse) {
Jamie 2015/01/27 22:52:25 Indentation.
kelvinp 2015/01/28 01:31:51 Done.
+ var methodName = message.methodName;
+ if (typeof methodName !== 'string') {
+ return;
+ }
+
+ if (sender.id !== chrome.runtime.id) {
+ sendResponse({error : base.IPC.Error.INVALID_REQUEST_ORIGIN});
Jamie 2015/01/27 22:52:25 Nit: No space before colon, here and below.
kelvinp 2015/01/28 01:31:51 Done.
+ return;
+ }
+
+ var remoteMethod =
+ /** @type {function(*):void} */ (this.handlers_[methodName]);
+ if (!remoteMethod) {
+ sendResponse({error : base.IPC.Error.UNSUPPORTED_REQUEST_TYPE});
+ return;
+ }
+
+ try {
+ sendResponse(remoteMethod.apply(null, message.params));
+ } catch (/** @type {Error} */ e) {
+ sendResponse({error: e.message});
+ }
+};
+
+/**
+ * Invokes a method on a remote page
+ *
+ * @param {string} methodName
+ * @param {...} var_args
+ * @return A Promise that would resolve to the return value of the handler or
+ * reject if the handler throws an exception.
+ */
+base.IPC.invoke = function(methodName, var_args) {
+ var params = Array.prototype.slice.call(arguments, 1);
+ var sendMessage = base.Promise.as(
+ chrome.runtime.sendMessage,
+ [null, new base.IPC.Request_(methodName, params)]);
+
+ return sendMessage.then(
+ /** @param {?{error: Error}} response */
+ function(response) {
+ if (response && response.error) {
+ return Promise.reject(response.error);
+ } else {
+ return Promise.resolve(response);
+ }
+ });
+};
+
+
+/** @type {base.IPC} */
+var instance_ = null;
+
+/** @return {base.IPC} */
+base.IPC.getInstance = function() {
+ if (!instance_) {
+ instance_ = new base.IPC();
+ }
+ return instance_;
+};
+
+base.IPC.deleteInstance = function() {
+ if (instance_) {
+ instance_.dispose_();
+ instance_ = null;
+ }
+};
+
+})();

Powered by Google App Engine
This is Rietveld 408576698