Skip to content

Commit

Permalink
feat: add support for dynamic proxying of requests
Browse files Browse the repository at this point in the history
adds support for localfile specification, service
initialization with exponential backoff,and
programatic instantiation of service runner
  • Loading branch information
zcstarr committed Aug 2, 2019
1 parent 38b5b76 commit f69819a
Show file tree
Hide file tree
Showing 51 changed files with 7,092 additions and 2,552 deletions.
16 changes: 16 additions & 0 deletions examples/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
/*
import ServiceRunner from "../build/generated-client/typescript";
import EthClient from "../build/example-client/build";
const client = new ServiceRunner({
transport: {
type: "http",
port: 8002,
host: "localhost",
},
});
const ethClient = new EthClient({
transport: {
host: "localhost",
port: 8002,
type: "http",
path: "multi-geth/mainnet/1.9.0",
},
});
console.log("starting client");
client.installService("multi-geth", "1.9.0")
.then(() => client.listInstalledServices())
.then(() => client.listRunningServices())
Expand All @@ -14,7 +26,11 @@ client.installService("multi-geth", "1.9.0")
.then(console.log)//tslint:disable-line
.then(() => client.listRunningServices())
.then(console.log)//tslint:disable-line
client.startService("multi-geth", "1.9.0", "mainnet")
.then(() => ethClient.eth_getBalance("0xc1912fee45d61c87cc5ea59dae31190fffff232d", "0x0"))
.then(console.log)
.catch((e) => {
console.log(e);//tslint:disable-line
throw e;
});
*/
8 changes: 8 additions & 0 deletions fixtures/src/testService/_package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "simple-math-test",
"version": "0.0.0-simple-math-test",
"dependencies": {
"@open-rpc/client-js": "^1.0.1",
"@open-rpc/server-js": "^1.3.0"
}
}
118 changes: 118 additions & 0 deletions fixtures/src/testService/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@

// Code generated by @open-rpc/client-generator DO NOT EDIT.
import { RequestManager, WebSocketTransport, HTTPTransport, Client } from "@open-rpc/client-js";
import _ from "lodash";
import { OpenRPC, MethodObject, ContentDescriptorObject } from "@open-rpc/meta-schema";
import { MethodCallValidator, MethodNotFoundError } from "@open-rpc/schema-utils-js";

export type IntegerTfIB8Svh = number;
export type Addition = (a?: IntegerTfIB8Svh, b?: IntegerTfIB8Svh) => Promise<IntegerTfIB8Svh>;
export type Subtraction = (a?: IntegerTfIB8Svh, b?: IntegerTfIB8Svh) => Promise<IntegerTfIB8Svh>;

export interface Options {
transport: {
type: "websocket" | "http" | "https";
host: string;
port: number;
path?: string;
};
}

export class SimpleMath {
public static openrpcDocument: OpenRPC = { "openrpc": "1.0.0-rc1", "info": { "title": "Simple Math", "description": "A simple math example", "version": "1.0.0" }, "servers": [{ "name": "my simple math server", "summary": "simple math server summary", "description": "simple math server description", "url": "http://${username}.simple-math.example.org:${port}/${basePath}/", "variables": { "username": { "default": "demo", "description": "this is applied to the url as the subdomain" }, "port": { "default": "443", "enum": ["8545", "443"] }, "basePath": { "default": "jsonrpc" } } }], "methods": [{ "name": "addition", "params": [{ "name": "a", "schema": { "type": "integer" } }, { "name": "b", "schema": { "type": "integer" } }], "result": { "name": "c", "schema": { "type": "integer" } }, "examples": [{ "name": "simpleMathAdditionTwo", "params": [{ "name": "two", "summary": "its a sample two", "description": "Im not sure how else to say two", "value": 2 }, { "name": "two", "summary": "its a sample two", "description": "Im not sure how else to say two", "value": 2 }], "result": { "name": "four", "summary": "its a sample four", "description": "Im not sure how else to say four", "value": 4 } }, { "name": "simpleMathAdditionFour", "params": [{ "name": "four", "summary": "its a sample four", "description": "Im not sure how else to say four", "value": 4 }, { "name": "four", "summary": "its a sample four", "description": "Im not sure how else to say four", "value": 4 }], "result": { "name": "eight", "summary": "its a sample eight", "description": "Im not sure how else to say eight", "value": 8 } }], "links": [{ "name": "subtractionLink", "description": "use the parameters from addition for subtraction", "method": "subtraction", "params": { "a": "$params.a", "b": "$params.b" } }] }, { "name": "subtraction", "params": [{ "name": "a", "schema": { "type": "integer" } }, { "name": "b", "schema": { "type": "integer" } }], "result": { "name": "c", "schema": { "type": "integer" } }, "examples": [{ "name": "examplesSubtractFourTwo", "params": [{ "name": "four", "summary": "its a sample four", "description": "Im not sure how else to say four", "value": 4 }, { "name": "two", "summary": "its a sample two", "description": "Im not sure how else to say two", "value": 2 }], "result": { "name": "two", "summary": "its a sample two", "description": "Im not sure how else to say two", "value": 2 } }, { "name": "examplesSubtractEightFour", "params": [{ "name": "eight", "summary": "its a sample eight", "description": "Im not sure how else to say eight", "value": 8 }, { "name": "four", "summary": "its a sample four", "description": "Im not sure how else to say four", "value": 4 }], "result": { "name": "four", "summary": "its a sample four", "description": "Im not sure how else to say four", "value": 4 } }], "links": [{ "name": "additionLink", "description": "use the parameters from subtraction for addition", "method": "addition", "params": { "a": "$params.a", "b": "$params.b" } }] }], "components": { "contentDescriptors": { "c": { "name": "c", "schema": { "type": "integer" } } }, "schemas": { "Integer": { "type": "integer" } }, "examples": { "integerTwo": { "name": "two", "summary": "its a sample two", "description": "Im not sure how else to say two", "value": 2 }, "integerFour": { "name": "four", "summary": "its a sample four", "description": "Im not sure how else to say four", "value": 4 }, "integerEight": { "name": "eight", "summary": "its a sample eight", "description": "Im not sure how else to say eight", "value": 8 } } } };
public rpc: Client;
public transport: HTTPTransport | WebSocketTransport;
private validator: MethodCallValidator;

constructor(options: Options) {
// this.openrpcDocument = {"openrpc":"1.0.0-rc1","info":{"title":"Simple Math","description":"A simple math example","version":"1.0.0"},"servers":[{"name":"my simple math server","summary":"simple math server summary","description":"simple math server description","url":"http://${username}.simple-math.example.org:${port}/${basePath}/","variables":{"username":{"default":"demo","description":"this is applied to the url as the subdomain"},"port":{"default":"443","enum":["8545","443"]},"basePath":{"default":"jsonrpc"}}}],"methods":[{"name":"addition","params":[{"name":"a","schema":{"type":"integer"}},{"name":"b","schema":{"type":"integer"}}],"result":{"name":"c","schema":{"type":"integer"}},"examples":[{"name":"simpleMathAdditionTwo","params":[{"name":"two","summary":"its a sample two","description":"Im not sure how else to say two","value":2},{"name":"two","summary":"its a sample two","description":"Im not sure how else to say two","value":2}],"result":{"name":"four","summary":"its a sample four","description":"Im not sure how else to say four","value":4}},{"name":"simpleMathAdditionFour","params":[{"name":"four","summary":"its a sample four","description":"Im not sure how else to say four","value":4},{"name":"four","summary":"its a sample four","description":"Im not sure how else to say four","value":4}],"result":{"name":"eight","summary":"its a sample eight","description":"Im not sure how else to say eight","value":8}}],"links":[{"name":"subtractionLink","description":"use the parameters from addition for subtraction","method":"subtraction","params":{"a":"$params.a","b":"$params.b"}}]},{"name":"subtraction","params":[{"name":"a","schema":{"type":"integer"}},{"name":"b","schema":{"type":"integer"}}],"result":{"name":"c","schema":{"type":"integer"}},"examples":[{"name":"examplesSubtractFourTwo","params":[{"name":"four","summary":"its a sample four","description":"Im not sure how else to say four","value":4},{"name":"two","summary":"its a sample two","description":"Im not sure how else to say two","value":2}],"result":{"name":"two","summary":"its a sample two","description":"Im not sure how else to say two","value":2}},{"name":"examplesSubtractEightFour","params":[{"name":"eight","summary":"its a sample eight","description":"Im not sure how else to say eight","value":8},{"name":"four","summary":"its a sample four","description":"Im not sure how else to say four","value":4}],"result":{"name":"four","summary":"its a sample four","description":"Im not sure how else to say four","value":4}}],"links":[{"name":"additionLink","description":"use the parameters from subtraction for addition","method":"addition","params":{"a":"$params.a","b":"$params.b"}}]}],"components":{"contentDescriptors":{"c":{"name":"c","schema":{"type":"integer"}}},"schemas":{"Integer":{"type":"integer"}},"examples":{"integerTwo":{"name":"two","summary":"its a sample two","description":"Im not sure how else to say two","value":2},"integerFour":{"name":"four","summary":"its a sample four","description":"Im not sure how else to say four","value":4},"integerEight":{"name":"eight","summary":"its a sample eight","description":"Im not sure how else to say eight","value":8}}}};

if (options.transport === undefined || options.transport.type === undefined) {
throw new Error("Invalid constructor params");
}
const { type, host, port } = options.transport;
let path = options.transport.path || "";
if (path && path[0] !== "/") {
path = "/" + path;
}
switch (type) {
case "http":
case "https":
this.transport = new HTTPTransport(type + "://" + host + ":" + port + path);
break;
case "websocket":
this.transport = new WebSocketTransport("ws://" + host + ":" + port + path);
break;
default:
throw new Error("unsupported transport");
break;
}
this.rpc = new Client(new RequestManager([this.transport]));
this.validator = new MethodCallValidator(SimpleMath.openrpcDocument);
}

/**
* Initiates [[SimpleMath.startBatch]] in order to build a batch call.
*
* Subsequent calls to [[SimpleMath.request]] will be added to the batch.
* Once [[SimpleMath.stopBatch]] is called, the promises for the [[SimpleMath.request]]
* will then be resolved. If there is already a batch in progress this method is a noop.
*
* @example
* myClient.startBatch();
* myClient.foo().then(() => console.log("foobar"))
* myClient.bar().then(() => console.log("foobarbaz"))
* myClient.stopBatch();
*/
public startBatch(): void {
// return this.rpc.startBatch();
}

/**
* Initiates [[Client.stopBatch]] in order to finalize and send the batch to the underlying transport.
*
* stopBatch will send the [[SimpleMath]] calls made since the last [[SimpleMath.startBatch]] call. For
* that reason, [[SimpleMath.startBatch]] MUST be called before [[SimpleMath.stopBatch]].
*
* @example
* myClient.startBatch();
* myClient.foo().then(() => console.log("foobar"))
* myClient.bar().then(() => console.log("foobarbaz"))
* myClient.stopBatch();
*/
public stopBatch(): void {
return this.rpc.stopBatch();
}

/**
*
*/
public addition: Addition = (...params) => {
return this.request("addition", params);
}

/**
*
*/
public subtraction: Subtraction = (...params) => {
return this.request("subtraction", params);
}

private request(methodName: string, params: any[]): Promise<any> {
const methodObject = _.find(SimpleMath.openrpcDocument.methods, ({ name }) => name === methodName) as MethodObject;
const openRpcMethodValidationErrors = this.validator.validate(methodName, params);
if (openRpcMethodValidationErrors instanceof MethodNotFoundError || openRpcMethodValidationErrors.length > 0) {
return Promise.reject(openRpcMethodValidationErrors);
}

let rpcParams;
if (methodObject.paramStructure && methodObject.paramStructure === "by-name") {
rpcParams = _.zipObject(params, _.map(methodObject.params, "name"));
} else {
rpcParams = params;
}
return this.rpc.request(methodName, rpcParams);
}

}
export default SimpleMath;
72 changes: 72 additions & 0 deletions fixtures/src/testService/extended_config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
export const simpleMathConfig = (assetLocation: string) => {
return {
services: [
{
name: "simple-math",
version: "1.0.0",
rpcPort: "${DYNAMIC_TCP_PORT_1}",
environments: [
{
name: "http",
args: {
start: ["${SERVICE_DIR}/index.js", "--port=${DYNAMIC_TCP_PORT_1}", "--mode=http"],
stop: [],
teardown: [],
},
health: {
interval: 20000,
retries: 5,
port: "${DYNAMIC_TCP_PORT_1}",
protocol: "tcp",
},
},
{
rpcPort: "${DYNAMIC_TCP_PORT_1}",
name: "ws",
args: {
start: ["${SERVICE_DIR}/index.js", "--port=${DYNAMIC_TCP_PORT_1}", "--mode=ws"],
stop: [],
teardown: [],
},
health: {
interval: 20000,
retries: 5,
port: "${DYNAMIC_TCP_PORT_1}",
protocol: "tcp",
},
},
],
os: {
osx: {
commands: {
setup: [],
start: "node",
stop: "",
teardown: "",
},
assets: [`file://${assetLocation}/testService.zip`],
},
linux: {
commands: {
setup: [],
start: "node",
stop: "",
teardown: "",
},
assets: [`file://${assetLocation}/testService.zip`],
},
windows: {
commands: {
setup: [],
start: "node",
stop: "",
teardown: "",
},
assets: [`file://${assetLocation}/testService.zip`],
},
},

},
],
};
};
24 changes: 24 additions & 0 deletions fixtures/src/testService/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { testServer } from "./server";
import { SimpleMath } from "./client";
import program from "commander";
program
.option(
"-p, --port <port>",
"Set port for simple math",
"8900",
)
.option(
"-m, --mode <mode>",
"Set protocol for simple math ws, wss, http, https",
"ws",
)
.action(async () => {
const port = parseInt(program.port, 10);
const server = testServer(port, program.mode, SimpleMath.openrpcDocument, {});
// tslint:disable-next-line:no-console
console.log(`simplemath test server starting with ${program.mode} - ${program.port}`);
server.start();
// tslint:disable-next-line:no-console
console.log("simplemath test server started");
})
.parse(process.argv);
40 changes: 40 additions & 0 deletions fixtures/src/testService/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { OpenRPC } from "@open-rpc/meta-schema";
import { Server, IServerOptions } from "@open-rpc/server-js";
export type TestProtocol = "ws" | "http";

export const testServer = (port: number, protocol: TestProtocol, openrpcDocument: OpenRPC, opts: any) => {

let options = {} as IServerOptions;

let transportConfigs;
switch ( protocol) {
case "ws":
transportConfigs = [
{
options: {
middleware: [],
port,
},
type: "WebSocketTransport",
},
];
break;
case "http":
transportConfigs = [
{
options: {
middleware: [],
port,
},
type: "HTTPTransport",
},
];
break;
}
options = {
methodMapping: { mockMode: true },
openrpcDocument,
transportConfigs,
} as IServerOptions;
return new Server(options);
};
Loading

0 comments on commit f69819a

Please sign in to comment.