Skip to content

Commit

Permalink
feat(cmd-api-server): add Socket.IO as transport hyperledger#297
Browse files Browse the repository at this point in the history
Primary changes:
---------------

1. The API server now has a SocketIO server running on the same port
as the HTTP REST API.

2. The API server now has an ApiServerApiClient class which is an
extension of the DefaultApi class that we generate from the OpenAPI
specifications. The reason why this extension was necessary (something
that we try to avoid like the plague normally) is because OpenAPI is
strictly for defining HTTP/REST based APIs and not async/streaming
ones such as WebSocket/SocketIO based ones and therefore the OpenAPI
generator does not support these types of transports at all meaning
that we have to manually write the client code for async endpoints
which is why the class extension here is not something that we can
get around.

3. The idea is that all async endpoints would declare their event
names as constants in the OpenAPI specification so as to make it
easier at least to some degree to implement solutions on top even
if we cannot support async endpoints with the OpenAPI code
generator to the same extend we do for HTTP RESTful endpoints.
The five default events are Subscribe, Next, Unsubscribe, Error and
Complete. These are defined in order to match what the client can
do on the RxJS Observable object returned by the API client object's
method that invokes the async endpoints.
The difference between Unsubscribe and complete is subtle, but it definitely
exists. The unsubscribe event is used by the client to tell the backend
that it no longer requires updates, regardless of the streaming of data
having been completed or not.
The complete event on the other hand is for the backend to signal that
the streaming of data is in fact completed. The complete event is only
applicable for endpoints that do have an ending which is not the case
for some endpoints that are usually time-series related and therefore
a lot of times just stream endlessly until stopped.

Secondary change(s):
--------------------

1. Added an async endpoint powered by the just now added SocketIO
integration that streams the health check response every one second
which is mainly added to that we can test the functionality but at
could also be used for monitoring purposes by someone who'd rather
implement something from scratch than use Prometheus for example.

To-do:
------

1. Socket provider singleton on client side for connection multiplexing

Fixes hyperledger#297

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
  • Loading branch information
petermetz committed May 25, 2021
1 parent 4c0b0bf commit 86c0fbf
Show file tree
Hide file tree
Showing 23 changed files with 3,505 additions and 25,036 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ test("BEFORE " + testCase, async (t: Test) => {
test(testCase, async (t: Test) => {
const jwtKeyPair = await JWK.generate("RSA", 4096);
const jwtPublicKey = jwtKeyPair.toPEM(false);
const middlewareOptions: expressJwt.Options = {
const expressJwtOptions: expressJwt.Options = {
algorithms: ["RS256"],
secret: jwtPublicKey,
audience: "carbon-accounting-tool-servers-hostname-here",
issuer: uuidv4(),
};
t.ok(middlewareOptions, "Express JWT config truthy OK");
t.ok(expressJwtOptions, "Express JWT config truthy OK");
const socketIoJwtOptions = { secret: jwtPublicKey };

const httpGui = await Servers.startOnPreferredPort(3000);
t.true(httpGui.listening, `httpGui.listening === true`);
Expand All @@ -67,7 +68,8 @@ test(testCase, async (t: Test) => {

const authorizationConfig: IAuthorizationConfig = {
unprotectedEndpointExemptions: [],
middlewareOptions,
expressJwtOptions,
socketIoJwtOptions,
};

const configService = new ConfigService();
Expand Down Expand Up @@ -109,8 +111,8 @@ test(testCase, async (t: Test) => {
};
const jwtSignOptions: JWT.SignOptions = {
algorithm: "RS256",
issuer: middlewareOptions.issuer,
audience: middlewareOptions.audience,
issuer: expressJwtOptions.issuer,
audience: expressJwtOptions.audience,
};
const tokenWithScope = JWT.sign(jwtPayload, jwtKeyPair, jwtSignOptions);
const verification = JWT.verify(tokenWithScope, jwtKeyPair, jwtSignOptions);
Expand Down
Loading

0 comments on commit 86c0fbf

Please sign in to comment.