summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke "Jared" Bennett <lbennett@gitlab.com>2017-01-01 13:12:38 +0000
committerLuke "Jared" Bennett <lbennett@gitlab.com>2017-01-02 09:34:39 +0000
commitdd8e4632f4c3ccf95b228110b2b5cec7a7455eb9 (patch)
tree41b73c2b3f2ca71557a7c2a9fca1c3e549c79077
parent8dc2163ce580f1d71be1cf45e5dfcb2b4763d7bb (diff)
downloadgitlab-ce-add-offline-cache-worker.tar.gz
Started on service worker, basics setup but still not a working pocadd-offline-cache-worker
-rw-r--r--app/assets/javascripts/application.js1
-rw-r--r--app/assets/javascripts/cache_worker_client.js.es650
-rw-r--r--app/assets/javascripts/service_workers/cache_worker.js.es673
-rw-r--r--app/controllers/manifest_json_controller.rb14
-rw-r--r--app/views/layouts/_head.html.haml2
-rw-r--r--app/views/shared/manifest.json.erb20
-rw-r--r--config/application.rb2
-rw-r--r--config/routes.rb2
-rw-r--r--lib/gitlab/gon_helper.rb5
9 files changed, 169 insertions, 0 deletions
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index e43afbb4cc9..405e7d2a95e 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -61,6 +61,7 @@
/*= require_directory . */
/*= require fuzzaldrin-plus */
/*= require es6-promise.auto */
+/*= require cache_worker_client */
(function () {
document.addEventListener('page:fetch', function () {
diff --git a/app/assets/javascripts/cache_worker_client.js.es6 b/app/assets/javascripts/cache_worker_client.js.es6
new file mode 100644
index 00000000000..db45b6adf8e
--- /dev/null
+++ b/app/assets/javascripts/cache_worker_client.js.es6
@@ -0,0 +1,50 @@
+(() => {
+ const global = window.gl || (window.gl = {});
+
+ class ServiceWorkerClient {
+ constructor() {
+ if (!navigator.serviceWorker) throw new ReferenceError('Your browser does not support service workers');
+
+ this.worker = navigator.serviceWorker;
+ this.cacheWorkerPath = gon.cache_worker_path;
+ this.assetPaths = gon.asset_paths;
+ }
+
+ install() {
+ this.worker.register(this.cacheWorkerPath)
+ .then((registration) => {
+ console.log('registration successful!', registration);
+ this.sendMessage(registration.active, {
+ type: 'add_assets',
+ data: this.assetPaths,
+ });
+ })
+ .catch((err) => {
+ console.log('registration failed!', err);
+ });
+ }
+
+ sendMessage(client = this.worker.controller, message, transferable = []) {
+ return new Promise((resolve, reject) => {
+ const messageChannel = new MessageChannel();
+
+ messageChannel.port1.onmessage = event => this.receiveReply(event, message, resolve, reject);
+
+ client.postMessage(message, [messageChannel.port2].concat(transferable));
+ });
+ }
+
+ receiveReply(event, message, resolve, reject) {
+ console.log('reply received', event, message);
+ resolve();
+ }
+ }
+
+ global.ServiceWorkerClient = ServiceWorkerClient;
+
+ $(() => {
+ if (global.serviceWorkerClient) return;
+ global.serviceWorkerClient = new global.ServiceWorkerClient();
+ global.serviceWorkerClient.install();
+ });
+})();
diff --git a/app/assets/javascripts/service_workers/cache_worker.js.es6 b/app/assets/javascripts/service_workers/cache_worker.js.es6
new file mode 100644
index 00000000000..c4b21e454ce
--- /dev/null
+++ b/app/assets/javascripts/service_workers/cache_worker.js.es6
@@ -0,0 +1,73 @@
+var CACHE = 'cache-update-and-refresh';
+
+// On install, cache some resource.
+self.addEventListener('install', function(evt) {
+ console.log('The service worker is being installed.');
+});
+
+// On fetch, use cache but update the entry with the latest contents
+// from the server.
+self.addEventListener('fetch', function(evt) {
+ console.log('The service worker is serving the asset.');
+ // You can use `respondWith()` to answer ASAP...
+ evt.respondWith(fromCache(evt.request));
+ // ...and `waitUntil()` to prevent the worker to be killed until
+ // the cache is updated.
+ evt.waitUntil(
+ update(evt.request)
+ // Finally, send a message to the client to inform it about the
+ // resource is up to date.
+ .then(refresh)
+ );
+});
+
+self.addEventListener('message', function(event) {
+ console.log('message recieved is', event);
+ if (event.data.type === 'add_assets') {
+ event.waitUntil(caches.open(CACHE).then(cache => cache.addAll(event.data.data)));
+ }
+});
+
+// Open the cache where the assets were stored and search for the requested
+// resource. Notice that in case of no matching, the promise still resolves
+// but it does with `undefined` as value.
+function fromCache(request) {
+ return caches.open(CACHE).then(function (cache) {
+ return cache.match(request);
+ });
+}
+
+
+// Update consists in opening the cache, performing a network request and
+// storing the new response data.
+function update(request) {
+ return caches.open(CACHE).then(function (cache) {
+ return fetch(request).then(function (response) {
+ return cache.put(request, response.clone()).then(function () {
+ return response;
+ });
+ });
+ });
+}
+
+// Sends a message to the clients.
+function refresh(response) {
+ if (self.clients.length === 0) return;
+ return self.clients.matchAll().then(function (clients) {
+ clients.forEach(function (client) {
+ // Encode which resource has been updated. By including the
+ // [ETag](https://en.wikipedia.org/wiki/HTTP_ETag) the client can
+ // check if the content has changed.
+ var message = {
+ type: 'refresh',
+ url: response.url,
+ // Notice not all servers return the ETag header. If this is not
+ // provided you should use other cache headers or rely on your own
+ // means to check if the content has changed.
+ eTag: response.headers.get('ETag')
+ };
+ // Tell the client about the update.
+ client.postMessage(JSON.stringify(message));
+ });
+ });
+}
diff --git a/app/controllers/manifest_json_controller.rb b/app/controllers/manifest_json_controller.rb
new file mode 100644
index 00000000000..319a661b3f1
--- /dev/null
+++ b/app/controllers/manifest_json_controller.rb
@@ -0,0 +1,14 @@
+class ManifestJsonController < ApplicationController
+ skip_before_action :authenticate_user!, :reject_blocked!
+
+ def index
+ puts Gitlab.config.gitlab.inspect
+ render 'shared/manifest.json', locals: {
+ homepage_url: Gitlab.config.gitlab.url,
+ icons: {
+ '32' => ActionController::Base.helpers.asset_path('favicon.ico'),
+ '128' => ActionController::Base.helpers.asset_path('gitlab_logo.png')
+ }
+ }
+ end
+end
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 3096f0ee19e..94f63f1c072 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -47,6 +47,8 @@
= favicon_link_tag 'touch-icon-ipad-retina.png', rel: 'apple-touch-icon', sizes: '152x152'
%link{ rel: 'mask-icon', href: image_path('logo.svg'), color: 'rgb(226, 67, 41)' }
+ %link{ rel: 'manifest', href: manifest_json_path }
+
-# Windows 8 pinned site tile
%meta{ name: 'msapplication-TileImage', content: image_path('msapplication-tile.png') }
%meta{ name: 'msapplication-TileColor', content: '#30353E' }
diff --git a/app/views/shared/manifest.json.erb b/app/views/shared/manifest.json.erb
new file mode 100644
index 00000000000..364c171fb47
--- /dev/null
+++ b/app/views/shared/manifest.json.erb
@@ -0,0 +1,20 @@
+{
+ "name": "GitLab",
+ "short_name": "GitLab",
+ "description": "Next-generation developer collaboration software.",
+ "start_url": ".",
+ "lang": "en-US",
+ "dir": "ltr",
+ "display": "standalone",
+ "background_color": "#fff",
+ "theme_color": "#e24329",
+ "icons": [{
+ "src": "<%=icons['32']%>",
+ "sizes": "32x32",
+ "type": "image/x-icon"
+ }, {
+ "src": "<%=icons['128']%>",
+ "sizes": "128x128",
+ "type": "image/png"
+ }]
+}
diff --git a/config/application.rb b/config/application.rb
index d36c6d5c92e..f59d42c6b26 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -108,6 +108,8 @@ module Gitlab
config.assets.precompile << "terminal/terminal_bundle.js"
config.assets.precompile << "lib/utils/*.js"
config.assets.precompile << "lib/*.js"
+ config.assets.precompile << "service_workers/*.js"
+ config.assets.precompile << "manifest.json"
config.assets.precompile << "u2f.js"
config.assets.precompile << "vendor/assets/fonts/*"
diff --git a/config/routes.rb b/config/routes.rb
index 06d565df469..aa378154bd1 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -43,6 +43,8 @@ Rails.application.routes.draw do
# Koding route
get 'koding' => 'koding#index'
+ get 'manifest.json', to: 'manifest_json#index', as: :manifest_json
+
draw :api
draw :sidekiq
draw :help
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 4d4e04e9e35..d30b5d7a4c5 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -10,6 +10,11 @@ module Gitlab
gon.award_menu_url = emojis_path
gon.katex_css_url = ActionController::Base.helpers.asset_path('katex.css')
gon.katex_js_url = ActionController::Base.helpers.asset_path('katex.js')
+ gon.cache_worker_path = ActionController::Base.helpers.asset_path('service_workers/cache_worker.js')
+ gon.asset_paths = [
+ ActionController::Base.helpers.asset_path('application.js'),
+ ActionController::Base.helpers.asset_path('application.css')
+ ]
if current_user
gon.current_user_id = current_user.id