From 17ace17f331a2f1eedabb682456952a000e39a9c Mon Sep 17 00:00:00 2001 From: greg Date: Wed, 29 May 2013 01:16:21 -0700 Subject: [PATCH 01/63] cp --- api_bridge.js | 74 ++++++++++++++++++++++++++++++++++++++++++--- background.html | 8 ++--- background.js | 2 ++ extension_server.js | 9 +++--- manifest.json | 6 ++-- options.html | 16 ---------- popup.html | 12 ++++---- popup.js | 10 ++++-- server_model.js | 61 ++++++++++++++++++++++++++----------- 9 files changed, 140 insertions(+), 58 deletions(-) create mode 100644 background.js diff --git a/api_bridge.js b/api_bridge.js index 38b2286..f87603a 100644 --- a/api_bridge.js +++ b/api_bridge.js @@ -1,7 +1,7 @@ /** * Functionality to communicate with the Asana API. This should get loaded * in the "server" portion of the chrome extension because it will make - * HTTP requests and needs cross-domain priveleges. + * HTTP requests and needs cross-domain privileges. * * The bridge does not need to use an auth token to connect to * the API, because since it is a browser extension it can access @@ -17,6 +17,26 @@ Asana.ApiBridge = { */ API_VERSION: "1.0", + /** + * @type {Integer} How long an entry stays in the cache. + */ + CACHE_TTL_MS: 15 * 60 * 1000, + + /** + * @type {Boolean} Set to true on the server (background page), which will + * actually make the API requests. Clients will just talk to the API + * through the ExtensionServer. + * + */ + is_server: false, + + /** + * @type {dict} Map from API path to cache entry for recent GET requests. + * date {Date} When cache entry was last refreshed + * response {*} Cached request. + */ + _cache: {}, + /** * @param opt_options {dict} Options to use; if unspecified will be loaded. * @return {String} The base URL to use for API requests. @@ -37,9 +57,37 @@ Asana.ApiBridge = { * data {dict} Object representing response of API call, depends on * method. Only available if response was a 200. * error {String?} Error message, if there was a problem. + * @param options {dict?} + * miss_cache {Boolean} Do not check cache before requesting */ - request: function(http_method, path, params, callback) { - var url = this.baseApiUrl() + path; + request: function(http_method, path, params, callback, options) { + var me = this; + + // If we're not the server page, send a message to it to make the + // API request. + if (!me.is_server) { + chrome.extension.sendRequest({ + type: "api", + method: http_method, + path: path, + params: params, + options: options || {} + }, callback); + return; + } + + // Serve from cache first. + if (!options.miss_cache && http_method.toLowerCase() === "get") { + var data = me._readCache(path, new Date()); + if (data) { + console.log("Serving request from cache", path); + callback(data); + return; + } + } + + console.log("Making request to API", http_method, path); + var url = me.baseApiUrl() + path; chrome.cookies.get({ url: url, name: 'ticket' @@ -63,6 +111,9 @@ Asana.ApiBridge = { }, accept: "application/json", success: function(data, status, xhr) { + if (http_method.toLowerCase() === "get") { + me._writeCache(path, data, new Date()); + } callback(data); }, error: function(xhr, status, error) { @@ -80,7 +131,7 @@ Asana.ApiBridge = { } callback(response); } else { - callback({ error: error || status }); + callback({ errors: [{message: error || status }]}); } }, xhrFields: { @@ -95,5 +146,20 @@ Asana.ApiBridge = { } $.ajax(attrs); }); + }, + + _readCache: function(path, date) { + var entry = this._cache[path]; + if (entry && entry.date >= date - this.CACHE_TTL_MS) { + return entry.response; + } + return null; + }, + + _writeCache: function(path, response, date) { + this._cache[path] = { + response: response, + date: date + }; } }; diff --git a/background.html b/background.html index ea54961..7131ce1 100644 --- a/background.html +++ b/background.html @@ -1,13 +1,11 @@ + + - + \ No newline at end of file diff --git a/background.js b/background.js new file mode 100644 index 0000000..302af45 --- /dev/null +++ b/background.js @@ -0,0 +1,2 @@ +Asana.ExtensionServer.listen(); +Asana.ServerModel.startPrimingCache(); diff --git a/extension_server.js b/extension_server.js index eaeb190..fe7f42c 100644 --- a/extension_server.js +++ b/extension_server.js @@ -9,13 +9,14 @@ Asana.ExtensionServer = { * requests from page clients, which can't make cross-domain requests. */ listen: function() { - var self = this; + Asana.ApiBridge.is_server = true; chrome.extension.onRequest.addListener(function(request, sender, sendResponse) { if (request.type === "api") { // Request to the API. Pass it on to the bridge. - Asana.ApiBridge.api( - request.method, request.path, request.data || {}, sendResponse); - + Asana.ApiBridge.request( + request.method, request.path, request.data || {}, sendResponse, + request.options || {}); + return true; // will call sendResponse asynchronously } else if (request.type === "quick_add") { // QuickAdd request, made from a content window. // Open up a new popup, and set the request information on its window diff --git a/manifest.json b/manifest.json index e67fc44..f7d3bec 100644 --- a/manifest.json +++ b/manifest.json @@ -1,12 +1,12 @@ { "manifest_version": 2, "name": "Asana Extension for Chrome", - "version": "0.9.1", + "version": "1.0.0", "description": "Integrates Asana with your browsing experience.", "icons": { "128": "icon128.png" }, - "minimum_chrome_version": "16", + "minimum_chrome_version": "24", "browser_action": { "default_icon": "icon19.png", @@ -30,7 +30,7 @@ "" ], "exclude_matches": [ - "*://*.asana.com/*" + "*://app.asana.com/*" ], "js": [ "asana.js", diff --git a/options.html b/options.html index e44be0a..15d7c9d 100644 --- a/options.html +++ b/options.html @@ -19,22 +19,6 @@ - - - - - - - - - - -
Default Workspace: -
Loading...
-
- The default workspace where new tasks are added. You can always select - a different workspace when you're creating a task. -
Asana Host: diff --git a/popup.html b/popup.html index 5d3aecf..16def5a 100644 --- a/popup.html +++ b/popup.html @@ -24,7 +24,12 @@
- - - -