Skip to content

Commit

Permalink
feat: implement automatic offline cache
Browse files Browse the repository at this point in the history
  • Loading branch information
tripodsan committed Nov 25, 2022
1 parent a43fe93 commit 66b0bf7
Show file tree
Hide file tree
Showing 9 changed files with 11,299 additions and 44 deletions.
11,180 changes: 11,149 additions & 31 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/import.cmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ export default class ImportCommand extends AbstractCommand {
}

withCache(value) {
this._cache = value;
this._cache = value
? path.resolve(process.cwd(), value)
: '';
return this;
}

Expand Down
10 changes: 8 additions & 2 deletions src/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,16 @@ export default function up() {
})
.group(['port', 'stop-other'], 'Server options')
.option('cache', {
describe: 'Path to local folder to cache the responses',
describe: 'Path to local folder to cache the proxy responses',
type: 'string',
default: '.hlx/cache',
})
.group(['open', 'no-open', 'cache'], 'Franklin Import Options')
.option('no-cache', {
alias: 'noCache',
describe: 'Disables the proxy cache.',
type: 'boolean',
})
.group(['open', 'no-open', 'cache', 'no-cache'], 'Franklin Import Options')

.help();
},
Expand Down
24 changes: 24 additions & 0 deletions src/server/HelixProject.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import HelixServer from './HelixServer.js';
import LiveReload from './LiveReload.js';
import HeadHtmlSupport from './HeadHtmlSupport.js';
import Indexer from './Indexer.js';
import NetworkState from './NetworkState.js';

export default class HelixProject {
constructor() {
Expand All @@ -24,6 +25,7 @@ export default class HelixProject {
this._enableLiveReload = false;
this._proxyUrl = null;
this._cacheDirectory = null;
this._cacheMode = null;
this._headHtml = null;
this._indexer = null;
this._printIndex = false;
Expand Down Expand Up @@ -65,6 +67,11 @@ export default class HelixProject {
return this;
}

withCacheMode(value) {
this._cacheMode = value;
return this;
}

withPrintIndex(value) {
this._printIndex = value;
return this;
Expand All @@ -90,6 +97,21 @@ export default class HelixProject {
return this._cacheDirectory;
}

get cacheMode() {
return this._cacheMode;
}

get netState() {
return this._netState;
}

get preferCache() {
if (this._cacheMode === 'always') {
return true;
}
return this._netState.down;
}

get directory() {
return this._cwd;
}
Expand Down Expand Up @@ -175,6 +197,7 @@ export default class HelixProject {
if (this._indexer) {
await this._indexer.init();
}
this._netState = new NetworkState(this.log);
return this;
}

Expand All @@ -187,6 +210,7 @@ export default class HelixProject {
if (this._indexer) {
await this._indexer.close();
}
await this._netState.close();
return this;
}
}
18 changes: 16 additions & 2 deletions src/server/HelixServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,22 @@ export default class HelixServer extends EventEmitter {
for (const [key, value] of proxyUrl.searchParams.entries()) {
url.searchParams.append(key, value);
}
await utils.proxyRequest(ctx, url.href, req, res, {
const opts = {
injectLiveReload: this._project.liveReload,
headHtml: this._project.headHtml,
indexer: this._project.indexer,
cacheDirectory: this._project.cacheDirectory,
});
preferCache: this._project.preferCache,
};
await utils.proxyRequest(ctx, url.href, req, res, opts);
if (!this._project.preferCache) {
this._project.netState.onProxyStatus(res.statusCode);
// if cache is now preferred, try again
if (this._project.preferCache) {
opts.preferCache = true;
await utils.proxyRequest(ctx, url.href, req, res, opts);
}
}
} catch (err) {
log.error(`Failed to proxy Franklin request ${ctx.path}: ${err.message}`);
res.status(502).send(`Failed to proxy Franklin request: ${err.message}`);
Expand Down Expand Up @@ -157,6 +167,10 @@ export default class HelixServer extends EventEmitter {
if (this._project.proxyUrl) {
log.info(`Enabled reverse proxy to ${this._project.proxyUrl}`);
}
if (this._project.cacheDirectory) {
const mode = this._project.cacheMode === 'auto' ? 'auto-' : '';
log.info(`Enabled proxy ${mode}cache using ${path.relative(process.cwd(), this._project.cacheDirectory)}`);
}
resolve();
});
});
Expand Down
62 changes: 62 additions & 0 deletions src/server/NetworkState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2022 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import fs from 'fs';
import chokidar from 'chokidar';
import WebSocket from 'faye-websocket';
import { EventEmitter } from 'events';
import { createRequire } from 'module';

/**
* Client connection for the live reload server.
*/
export default class NetworkState extends EventEmitter {
constructor(log) {
super();
this.log = log;
this._up = true;
}

enable(value) {
if (value !== this._up) {
this._up = value;
if (value) {
this.emit('up');
} else {
this.emit('down');
}
}
}

onProxyStatus(status) {
if (status === 504 || status === 503) {
if (this._up) {
this.log.info(`received ${status} from server, setting network status to degraded.`);
// todo: start monitor
this.enable(false);
}
}
}

get up() {
return this._up;
}

get down() {
return !this._up;
}

// eslint-disable-next-line class-methods-use-this
close() {
// ignore
}
}

11 changes: 9 additions & 2 deletions src/server/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,18 +191,25 @@ const utils = {
},

/**
* @typedef ProxyRequestOptions
* @property {boolean} injectLiveReload
* @property {string} headHtml
* @property {Indexer} indexer
* @property {string} cacheDirectory
* @property {boolean} preferCache
*
* Fetches the content from the url and streams it back to the response.
* @param {RequestContext} ctx Context
* @param {string} url The url to fetch from
* @param {Request} req The original express request
* @param {Response} res The express response
* @param {object} opts additional request options
* @param {ProxyRequestOptions} opts additional request options
* @return {Promise} A promise that resolves when the stream is done.
*/
async proxyRequest(ctx, url, req, res, opts = {}) {
ctx.log.debug(`Proxy ${req.method} request to ${url}`);

if (opts.cacheDirectory) {
if (opts.cacheDirectory && opts.preferCache) {
const cached = await utils.getFromCache(url, opts.cacheDirectory, ctx.log);
if (cached) {
res
Expand Down
11 changes: 10 additions & 1 deletion src/up.cmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default class UpCommand extends AbstractCommand {
this._liveReload = false;
this._url = null;
this._cache = null;
this._cacheMode = 'auto';
this._printIndex = false;
}

Expand All @@ -51,7 +52,14 @@ export default class UpCommand extends AbstractCommand {
}

withCache(value) {
this._cache = value;
this._cache = value
? path.resolve(process.cwd(), value)
: '';
return this;
}

withCacheMode(value) {
this._cacheMode = value;
return this;
}

Expand Down Expand Up @@ -134,6 +142,7 @@ export default class UpCommand extends AbstractCommand {
if (this._cache) {
await fse.ensureDir(this._cache);
this._project.withCacheDirectory(this._cache);
this._project.withCacheMode(this._cacheMode);
}

this._project.withProxyUrl(this._url);
Expand Down
23 changes: 18 additions & 5 deletions src/up.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,24 @@ export default function up() {
describe: 'The origin url to fetch content from.',
type: 'string',
})
.option('alpha-cache', {
alias: 'alphaCache',
describe: 'Path to local folder to cache the responses (note: this is an alpha feature, it may be removed without notice)',
.option('cache', {
describe: 'Path to local folder to cache the proxy responses',
type: 'string',
default: '.hlx/cache',
})
.group(['url', 'livereload', 'no-livereload', 'open', 'no-open', 'print-index', 'cache'], 'Franklin Options')
.option('cache-mode', {
alias: 'cacheMode',
describe: 'Cache mode. use "auto" to automatically respond from cache when network is down.',
type: 'string',
choices: ['auto', 'always'], // todo: maybe have a mode that checks with admin when documents are previewed
default: 'auto',
})
.option('no-cache', {
alias: 'noCache',
describe: 'Disables the proxy cache.',
type: 'boolean',
})
.group(['url', 'livereload', 'no-livereload', 'open', 'no-open', 'print-index', 'cache', 'no-cache', 'cache-mode'], 'Franklin Options')

.help();
},
Expand All @@ -93,7 +105,8 @@ export default function up() {
.withUrl(argv.url)
.withPrintIndex(argv.printIndex)
.withKill(argv.stopOther)
.withCache(argv.alphaCache)
.withCache(argv.cache)
.withCacheMode(argv.cacheMode)
.run();
},
};
Expand Down

0 comments on commit 66b0bf7

Please sign in to comment.