Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions lib/classes/http-incoming.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { validators } from '@eik/common';

/**
* A bearer object to hold misc data through a http
* request / response cyclus.
Expand Down Expand Up @@ -26,16 +28,30 @@ const HttpIncoming = class HttpIncoming {

this._request = request;
this._headers = request ? request.headers : {};

this._handle = '';
}

set version(value) {
this._version = validators.version(value);
}

get version() {
return this._version;
}

set extras(value) {
this._extras = validators.extra(value);
}

get extras() {
return this._extras;
}

set author(value) {
this._author = value;
}

get author() {
return this._author;
}
Expand All @@ -44,14 +60,26 @@ const HttpIncoming = class HttpIncoming {
return this._alias;
}

set name(value) {
this._name = validators.name(value);
}

get name() {
return this._name;
}

set type(value) {
this._type = validators.type(value);
}

get type() {
return this._type;
}

set org(value) {
this._org = value;
}

get org() {
return this._org;
}
Expand All @@ -64,6 +92,14 @@ const HttpIncoming = class HttpIncoming {
return this._headers;
}

set handle(value) {
this._handle = value;
}

get handle() {
return this._handle;
}

get [Symbol.toStringTag]() {
return 'HttpIncoming';
}
Expand Down
38 changes: 38 additions & 0 deletions lib/classes/plugin-demo-a.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Plugin from './plugin.js';

const PluginDemoA = class PluginDemoA extends Plugin {
constructor({
name = '',
} = {}) {
super();
this._name = name;
}

get name() {
return this._name;
}

onRequestStart(incoming) {
if (incoming.handle !== 'put:pkg:version') {
return;
}

return new Promise((resolve, reject) => {
// console.log('PLUGIN A START', this._name, incoming.type, 'pkg:put:start');
resolve(incoming);
});
}

onRequestEnd(incoming, outgoing) {
return new Promise((resolve, reject) => {
// console.log('PLUGIN A END', this._name, incoming.type, 'pkg:put:end');
resolve(incoming);
});
}

get [Symbol.toStringTag]() {
return 'PluginDemoA';
}
}

export default PluginDemoA;
31 changes: 31 additions & 0 deletions lib/classes/plugin-demo-b.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Plugin from './plugin.js';

const PluginDemoB = class PluginDemoB extends Plugin {
constructor({
name = '',
} = {}) {
super();
this._name = name;
}

get name() {
return this._name;
}

onRequestStart(incoming) {
if (incoming.handle !== 'put:pkg:version') {
return false;
}

return new Promise((resolve, reject) => {
// console.log('PLUGIN B START', this._name, incoming.type, 'pkg:put:start');
resolve(incoming);
});
}

get [Symbol.toStringTag]() {
return 'PluginDemoB';
}
}

export default PluginDemoB;
26 changes: 26 additions & 0 deletions lib/classes/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import abslog from 'abslog';

const Plugin = class Plugin {
constructor({
logger,
} = {}) {
this._log = abslog(logger);
}

onRequestStart() {
return undefined;
}

onRequestEnd() {
return undefined;
}

healthcheck() {
return undefined;
}

get [Symbol.toStringTag]() {
return 'Plugin';
}
}
export default Plugin;
90 changes: 66 additions & 24 deletions lib/handlers/pkg.get.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { validators } from '@eik/common';
import originalUrl from 'original-url';
import HttpError from 'http-errors';
import abslog from 'abslog';
import Metrics from '@metrics/client';

import { createFilePathToAsset } from '../utils/path-builders-fs.js';
import { decodeUriComponent } from '../utils/utils.js';
import HttpIncoming from '../classes/http-incoming.js';
import HttpOutgoing from '../classes/http-outgoing.js';
import Asset from '../classes/asset.js';
import config from '../utils/defaults.js';
Expand All @@ -14,6 +14,7 @@ const PkgGet = class PkgGet {
constructor({
organizations,
cacheControl,
plugins,
logger,
sink,
etag,
Expand Down Expand Up @@ -45,6 +46,7 @@ const PkgGet = class PkgGet {
],
});
this._orgRegistry = new Map(this._organizations);
this._plugins = plugins || [];
}

get metrics() {
Expand All @@ -53,16 +55,15 @@ const PkgGet = class PkgGet {

async handler(req, type, name, version, extra) {
const end = this._histogram.timer();

const pVersion = decodeUriComponent(version);
const pExtra = decodeUriComponent(extra);
const pName = decodeUriComponent(name);
const incoming = new HttpIncoming(req);
incoming.handle = `put:${type}:version`;

try {
validators.version(pVersion);
validators.extra(pExtra);
validators.name(pName);
validators.type(type);
incoming.version = decodeUriComponent(version);
incoming.extras = decodeUriComponent(extra);
incoming.name = decodeUriComponent(name);
incoming.type = type;

} catch (error) {
this._log.debug(`pkg:get - Validation failed - ${error.message}`);
const e = new HttpError.NotFound();
Expand All @@ -71,30 +72,51 @@ const PkgGet = class PkgGet {
}

const url = originalUrl(req);
const org = this._orgRegistry.get(url.hostname);
incoming.org = this._orgRegistry.get(url.hostname);

if (!org) {
if (!incoming.org) {
this._log.info(`pkg:get - Hostname does not match a configured organization - ${url.hostname}`);
const e = new HttpError.InternalServerError();
end({ labels: { success: false, status: e.status, type } });
throw e;
}



// Run On Request Start plugin methods
if (this._plugins.length !== 0) {
const pluginStart = this._plugins.map((plugin) => plugin.onRequestStart(incoming)).filter(plugin => plugin !== undefined);

if (pluginStart.length !== 0) {
try {
await Promise.all(pluginStart);
} catch (error) {
this._log.info(`pkg:put - A plugin errored during on request start exection - ${error.message}`);
const e = new HttpError.InternalServerError();
end({ labels: { success: false, status: e.status, type } });
throw e;
}
}
}



const asset = new Asset({
pathname: pExtra,
version: pVersion,
name: pName,
type,
org,
pathname: incoming.extras,
version: incoming.version,
name: incoming.name,
type: incoming.type,
org: incoming.org,
});

const path = createFilePathToAsset(asset);

const outgoing = new HttpOutgoing();
outgoing.cacheControl = this._cacheControl;
outgoing.mimeType = asset.mimeType;

try {
const file = await this._sink.read(path);
const outgoing = new HttpOutgoing();
outgoing.cacheControl = this._cacheControl;
outgoing.mimeType = asset.mimeType;

if (this._etag) {
outgoing.etag = file.etag;
Expand All @@ -111,17 +133,37 @@ const PkgGet = class PkgGet {
outgoing.stream = file.stream;
}

this._log.debug(`pkg:get - Asset found - Pathname: ${path}`);

end({ labels: { status: outgoing.statusCode, type } });

return outgoing;
} catch (error) {
this._log.debug(`pkg:get - Asset not found - Pathname: ${path}`);
const e = new HttpError.NotFound();
end({ labels: { success: false, status: e.status, type } });
throw e;
}



// Run On Request End plugin methods
if (this._plugins.length !== 0) {
const pluginEnd = this._plugins.map((plugin) => plugin.onRequestEnd(incoming, outgoing)).filter(plugin => plugin !== undefined);

if (pluginEnd.length !== 0) {
try {
await Promise.all(pluginEnd);
} catch (error) {
this._log.info(`pkg:put - A plugin errored during on request end exection - ${error.message}`);
const e = new HttpError.InternalServerError();
end({ labels: { success: false, status: e.status, type } });
throw e;
}
}
}



this._log.debug(`pkg:get - Asset found - Pathname: ${path}`);

end({ labels: { status: outgoing.statusCode, type } });
return outgoing;
}
};
export default PkgGet;
Loading