Skip to content
Snippets Groups Projects
Commit db4d5e94 authored by Ulf Seltmann's avatar Ulf Seltmann
Browse files

initial commit

parents
No related merge requests found
/node_modules
*.js.map
\ No newline at end of file
{
"version": "0.2.0",
"configurations": [
{
"name": "Docker: Attach to Node",
"type": "node",
"request": "attach",
"port": 9229,
"address": "localhost",
"localRoot": "${workspaceRoot}",
"remoteRoot": "/app"
}
]
}
\ No newline at end of file
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"output": "always",
"tasks": [
{
"isBackground": true,
"taskName": "tsc-watch",
"type": "process",
"command": "docker-compose",
"args": [
"run", "--rm", "node", "npm", "run", "tsc", "--", "-w"
],
"problemMatcher": [
"$tsc",
"$lessCompile"
],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"isBackground": true,
"taskName": "up",
"type": "process",
"command": "docker-compose",
"args": [
"up"
],
"problemMatcher": [
"$tsc",
"$lessCompile"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
\ No newline at end of file
version: '2'
services:
node:
image: docker.io/smoebody/dev-nodejs:latest
volumes:
- ./:/app:z
- npm-cache:/home/dev/.npm:z
- app-data:/var/lib/app:z
ports:
- 3000:3000
- 127.0.0.1:9229:9229
networks:
cache-network:
aliases:
- api.ub.uni-leipzig.de
environment:
- NODE_ENV=development
- DEBUG=dacap:*
- APP_DATA_DIR=/var/lib/app
- APP_TMP_DIR=/tmp
- DEBUG=*
command:
- npm run inspect
hostname: api.ub.uni-leipzig.de
volumes:
npm-cache: {}
app-data: {}
networks:
cache-network: {}
# Welcome to MkDocs
For full documentation visit [mkdocs.org](http://mkdocs.org).
## Commands
* `mkdocs new [dir-name]` - Create a new project.
* `mkdocs serve` - Start the live-reloading docs server.
* `mkdocs build` - Build the documentation site.
* `mkdocs help` - Print this help message.
## Project layout
mkdocs.yml # The configuration file.
docs/
index.md # The documentation homepage.
... # Other markdown pages, images and other files.
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const debugFactory = require("debug");
const NodeCache = require("node-cache");
const crypto = require("crypto");
const endpoint_1 = require("./endpoint");
const debug = debugFactory('decap:cache');
var Register;
(function (Register) {
const cacheRegister = {};
Register.getByName = (name) => {
if (!cacheRegister[name])
throw new Error(`no endpoint registered for "${name}"`);
return cacheRegister[name];
};
Register.register = (name, serverUrl) => {
const endpoint = new endpoint_1.Endpoint(serverUrl);
const nodeCache = new NodeCache();
cacheRegister[name] = new Cache(endpoint, nodeCache);
};
})(Register = exports.Register || (exports.Register = {}));
class Cache {
constructor(endpoint, realCache) {
this.endpoint = endpoint;
this.realCache = realCache;
}
get(hash, path) {
return __awaiter(this, void 0, void 0, function* () {
let value = this.realCache.get(hash);
if (value == undefined) {
debug(`no cache hit. fetching ${path}`);
value = {
contentType: '',
data: ''
};
try {
yield this.endpoint.request(path, value);
this.realCache.set(hash, value);
}
catch (err) {
console.error(err);
}
}
return value;
});
}
}
exports.Cache = Cache;
function Middleware(req, res, next) {
return __awaiter(this, void 0, void 0, function* () {
const pattern = new RegExp('^/([^/]+)(.*)$');
const match = req.url.match(pattern);
try {
const cache = Register.getByName(match[1]);
const uniQueryString = Object.keys(req.query).sort().map(function (key) { return `${key}=${req.query[key]}`; }).join('&');
const hash = crypto.createHash('sha1').update(req.path + uniQueryString).digest('base64');
const value = yield cache.get(hash, match[2]);
res.setHeader('content-type', value.contentType);
res.send(value.data);
}
catch (err) {
next(err);
}
});
}
exports.Middleware = Middleware;
//# sourceMappingURL=cache.js.map
\ No newline at end of file
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const https = require("https");
const Q = require("q");
class Endpoint {
constructor(serverUrl) {
this.serverUrl = serverUrl;
}
request(uriPath, value) {
const deferred = Q.defer();
const req = https.request(this.serverUrl + uriPath, (res) => {
value.contentType = res.headers['content-type'];
res.on('data', (chunk) => {
value.data += chunk;
});
res.on('end', () => {
if (res.statusCode !== 200)
return deferred.reject(new Error(`No status 200. not caching the result`));
deferred.resolve();
});
});
req.on('error', (err) => {
console.error(err);
deferred.reject(err);
});
req.end();
return deferred.promise;
}
}
exports.Endpoint = Endpoint;
//# sourceMappingURL=endpoint.js.map
\ No newline at end of file
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const express = require("express");
const compression = require("compression");
const debugFactory = require("debug");
// import endpointFactory from './endpoint';
const cache = require("./cache");
const debug = debugFactory('decap:index');
// import cacheInterface from './cache';
// import adminInterface from './admin';
const app = express();
app.use(compression());
// restore from persistent memory after startup
// app.get('/admin', adminInterface);
// app.get('*', apicacheInterface)
cache.Register.register('amsl', 'https://live.amsl.technology/inhouseservices/');
app.use(cache.Middleware);
const server = app.listen(3000, () => {
debug('server up and running');
});
server.on('close', () => {
debug('closing');
});
//# sourceMappingURL=index.js.map
\ No newline at end of file
site_name: DynamicAndCompressingApiCache
This diff is collapsed.
{
"name": "dynamic-api-proxy",
"version": "1.0.0",
"description": "proxies,compresses and caches api-requests",
"main": "lib/index.js",
"directories": {
"test": "test"
},
"scripts": {
"tsc": "tsc",
"inspect": "tsc-watch --onSuccess 'node --inspect=0.0.0.0:9229 lib/index.js'",
"test": "mocha test"
},
"author": "Ulf Seltmann <ulf.seltmann@uni-leipzig.de>",
"license": "GPL-2.0",
"dependencies": {
"compression": "^1.7.0",
"debug": "^3.0.0",
"express": "^4.15.4",
"node-cache": "^4.1.1",
"q": "^1.5.0"
},
"devDependencies": {
"@types/compression": "0.0.33",
"@types/debug": "0.0.30",
"@types/express": "^4.0.36",
"@types/node": "^8.0.20",
"@types/node-cache": "^4.1.0",
"eslint": "^4.4.1",
"tsc-watch": "^1.0.7",
"typescript": "^2.4.2"
}
}
import * as debugFactory from 'debug';
import * as express from 'express';
import * as NodeCache from 'node-cache';
import * as crypto from 'crypto';
import { Endpoint, EndpointValue } from './endpoint';
const debug = debugFactory('decap:cache');
export namespace Register {
const cacheRegister:{[key: string]: Cache} = {};
export let getByName = (name: string): Cache => {
if (!cacheRegister[name]) throw new Error(`no endpoint registered for "${name}"`);
return cacheRegister[name];
}
export let register = (name: string, serverUrl) => {
const endpoint:Endpoint = new Endpoint(serverUrl);
const nodeCache:NodeCache = new NodeCache()
cacheRegister[name] = new Cache(endpoint, nodeCache);
}
}
export class Cache {
constructor (private endpoint: Endpoint, private realCache: NodeCache) {
}
async get(hash: string, path: string): Promise<EndpointValue> {
let value:EndpointValue|undefined = this.realCache.get(hash);
if (value == undefined) {
debug(`no cache hit. fetching ${path}`);
value = {
contentType: '',
data: ''
};
try {
await this.endpoint.request(path, value);
this.realCache.set(hash, value);
} catch (err) {
console.error(err);
}
}
return value;
}
}
export async function Middleware(req: express.Request, res: express.Response, next: express.NextFunction) {
const pattern = new RegExp('^/([^/]+)(.*)$');
const match = req.url.match(pattern);
try {
const cache = Register.getByName(match[1]);
const uniQueryString = Object.keys(req.query).sort().map(function (key) { return `${key}=${req.query[key]}` }).join('&');
const hash = crypto.createHash('sha1').update(req.path + uniQueryString).digest('base64');
const value = await cache.get(hash, match[2]);
res.setHeader('content-type', value.contentType)
res.send(value.data);
} catch (err) {
next(err);
}
}
import * as https from 'https';
import * as path from 'path';
import * as Q from 'q';
export interface EndpointValue {
contentType: string;
data: string;
}
export class Endpoint {
constructor(private serverUrl:string) {
}
public request(uriPath:string, value:EndpointValue): Promise<void>{
const deferred = Q.defer();
const req = https.request(this.serverUrl + uriPath, (res) => {
value.contentType = <string>res.headers['content-type'];
res.on('data', (chunk) => {
value.data += chunk;
});
res.on('end', () => {
if (res.statusCode !== 200)
return deferred.reject(new Error(`No status 200. not caching the result`));
deferred.resolve();
});
})
req.on('error', (err) => {
console.error(err);
deferred.reject(err);
});
req.end();
return deferred.promise;
}
}
\ No newline at end of file
import * as express from 'express';
import * as compression from 'compression';
import * as debugFactory from 'debug';
import * as https from 'https';
import * as NodeCache from 'node-cache';
import * as Url from 'url';
import * as crypto from 'crypto';
import * as stream from 'stream';
import * as Q from 'q';
// import endpointFactory from './endpoint';
import * as cache from './cache';
const debug = debugFactory('decap:index');
// import cacheInterface from './cache';
// import adminInterface from './admin';
const app = express();
app.use(compression());
// restore from persistent memory after startup
// app.get('/admin', adminInterface);
// app.get('*', apicacheInterface)
cache.Register.register('amsl', 'https://live.amsl.technology/inhouseservices/');
app.use(cache.Middleware);
const server = app.listen(3000, () => {
debug('server up and running');
});
server.on('close', () => {
debug('closing');
})
\ No newline at end of file
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"noImplicitAny": false,
"sourceMap": true,
"outDir": "lib"
},
"include": [
"src/*"
]
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment