Skip to content

Commit

Permalink
Add Memento HTTP actor
Browse files Browse the repository at this point in the history
This adds a Memento actor to the HTTP bus that has a priority over the other HTTP actors and will intercept requests to perform datetime negotiation when applicable.

The datetime can be set via the `-d` command line option.

Closes #79
  • Loading branch information
mielvds authored and rubensworks committed Aug 8, 2018
1 parent 6448535 commit 3215d15
Show file tree
Hide file tree
Showing 20 changed files with 489 additions and 2 deletions.
Empty file.
3 changes: 3 additions & 0 deletions packages/actor-http-memento/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Comunica Memento Http Actor

A comunica Memento Http Actor.
36 changes: 36 additions & 0 deletions packages/actor-http-memento/components/Actor/Http/Memento.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"@context": [
"https://linkedsoftwaredependencies.org/bundles/npm/@comunica/actor-http-memento/^1.0.0/components/context.jsonld",
"https://linkedsoftwaredependencies.org/bundles/npm/@comunica/bus-http/^1.0.0/components/context.jsonld"
],
"@id": "npmd:@comunica/actor-http-memento",
"components": [
{
"@id": "cahm:Actor/Http/Memento",
"@type": "Class",
"extends": "cbh:Actor/Http",
"requireElement": "ActorHttpMemento",
"comment": "A comunica Memento Http Actor.",
"parameters": [
{
"@id": "cahm:Actor/Http/Memento/mediatorHttp",
"comment": "The HTTP mediator",
"required": true,
"unique": true
}
],
"constructorArguments": [
{
"@id": "cahm:Actor/Http/Memento/constructorArgumentsObject",
"extends": "cbh:Actor/Http/constructorArgumentsObject",
"fields": [
{
"keyRaw": "mediatorHttp",
"value": "cahm:Actor/Http/Memento/mediatorHttp"
}
]
}
]
}
]
}
9 changes: 9 additions & 0 deletions packages/actor-http-memento/components/components.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@comunica/actor-http-memento/^1.0.0/components/context.jsonld",
"@id": "npmd:@comunica/actor-http-memento",
"@type": "Module",
"requireName": "@comunica/actor-http-memento",
"import": [
"files-cahm:components/Actor/Http/Memento.jsonld"
]
}
12 changes: 12 additions & 0 deletions packages/actor-http-memento/components/context.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"@context": [
"https://linkedsoftwaredependencies.org/bundles/npm/componentsjs/^3.0.0/components/context.jsonld",
{
"npmd": "https://linkedsoftwaredependencies.org/bundles/npm/",
"cahm": "npmd:@comunica/actor-http-memento/",
"files-cahm": "cahm:^1.0.0/",

"ActorHttpMemento": "cahm:Actor/Http/Memento"
}
]
}
1 change: 1 addition & 0 deletions packages/actor-http-memento/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lib/ActorHttpMemento';
68 changes: 68 additions & 0 deletions packages/actor-http-memento/lib/ActorHttpMemento.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { ActorHttp, IActionHttp, IActorHttpOutput } from "@comunica/bus-http";
import { ActionContext, IActorArgs, IActorTest, Mediator } from "@comunica/core";
import "isomorphic-fetch";
import * as parseLink from 'parse-link-header';

/**
* A comunica Memento Http Actor.
*/
export class ActorHttpMemento extends ActorHttp {

public readonly mediatorHttp: Mediator<ActorHttp,
IActionHttp, IActorTest, IActorHttpOutput>;

constructor(args: IActorHttpMementoArgs) {
super(args);
}

public async test(action: IActionHttp): Promise<IActorTest> {
if (!(action.context && action.context.has(KEY_CONTEXT_DATETIME) &&
action.context.get(KEY_CONTEXT_DATETIME) instanceof Date)) {
throw new Error('This actor only handles request with a set valid datetime.');
}
if (action.init && new Headers(action.init.headers || {}).has('accept-datetime')) {
throw new Error('The request already has a set datetime.');
}
return true;
}

public async run(action: IActionHttp): Promise<IActorHttpOutput> {
// Duplicate the ActionHttp to append a datetime header to the request.
const init: RequestInit = action.init ? {...action.init} : {};
const headers: Headers = init.headers = new Headers(init.headers || {});

if (action.context && action.context.has(KEY_CONTEXT_DATETIME)) {
headers.append('accept-datetime', action.context.get(KEY_CONTEXT_DATETIME).toUTCString());
}

const httpAction: IActionHttp = { context: action.context, input: action.input, init };

// Execute the request and follow the timegate in the response (if any).
const result: IActorHttpOutput = await this.mediatorHttp.mediate(httpAction);

// Did we ask for a time-negotiated response, but haven't received one?
if (headers.has('accept-datetime') && result.headers && !result.headers.has('memento-datetime')) {
// The links might have a timegate that can help us
const links = result.headers.has('link') && parseLink(result.headers.get('link'));
result.body.cancel();
if (links && links.timegate) {
// Respond with a time-negotiated response from the timegate instead
const followLink: IActionHttp = { context: action.context, input: links.timegate.url, init };
return this.mediatorHttp.mediate(followLink);
}
}

return result;
}
}

export interface IActorHttpMementoArgs
extends IActorArgs<IActionHttp, IActorTest, IActorHttpOutput> {
mediatorHttp: Mediator<ActorHttp,
IActionHttp, IActorTest, IActorHttpOutput>;
}

/**
* @type {string} Context entry for the desired datetime.
*/
export const KEY_CONTEXT_DATETIME = '@comunica/actor-http-memento:datetime';
70 changes: 70 additions & 0 deletions packages/actor-http-memento/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"name": "@comunica/actor-http-memento",
"version": "1.0.0",
"description": "A memento http actor",
"lsd:module": "https://linkedsoftwaredependencies.org/bundles/npm/@comunica/actor-http-memento",
"lsd:components": "components/components.jsonld",
"lsd:contexts": {
"https://linkedsoftwaredependencies.org/bundles/npm/@comunica/actor-http-memento/^1.0.0/components/context.jsonld": "components/context.jsonld"
},
"lsd:importPaths": {
"https://linkedsoftwaredependencies.org/bundles/npm/@comunica/actor-http-memento/^1.0.0/components/": "components/"
},
"main": "index.js",
"typings": "index",
"repository": {
"type": "git",
"url": "git+https://github.com/comunica/actor-http-memento.git"
},
"keywords": [
"comunica",
"actor",
"http",
"memento"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/comunica/actor-http-memento/issues"
},
"homepage": "https://github.com/comunica/actor-http-memento#readme",
"files": [
"components",
"lib/**/*.d.ts",
"lib/**/*.js",
"index.d.ts",
"index.js"
],
"dependencies": {
"parse-link-header": "^1.0.1",
"isomorphic-fetch": "^2.2.1"
},
"peerDependencies": {
"@comunica/bus-http": "^1.0.0",
"@comunica/core": "^1.0.0"
},
"devDependencies": {
"@comunica/core": "^1.1.0",
"@comunica/bus-http": "^1.1.0"
},
"jest": {
"transform": {
"^.+\\.ts$": "<rootDir>/../../node_modules/ts-jest/preprocessor.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"
],
"testRegex": "(/test/.*|(\\.|/)(test|spec))\\.ts$",
"moduleFileExtensions": [
"ts",
"js"
],
"collectCoverage": true
},
"scripts": {
"test": "node \"../../node_modules/jest/bin/jest.js\" ${1}",
"test-watch": "node \"../../node_modules/jest/bin/jest.js\" ${1} --watch",
"lint": "node \"../../node_modules/tslint/bin/tslint\" lib/**/*.ts test/**/*.ts --exclude '**/*.d.ts'",
"build": "node \"../../node_modules/typescript/bin/tsc\"",
"validate": "npm ls"
}
}
Loading

0 comments on commit 3215d15

Please sign in to comment.