-
Notifications
You must be signed in to change notification settings - Fork 286
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sdk): routing to nodes by ledger ID
This implements the routing of API requests to specific Cactus nodes based on a pre-specified ledger ID. The idea is that since each Cactus node has it's own API host we can store the ledger connector + ledger associations in the consortium definition and use that to look up which nodes can we send requests to when wanting to transact on a specific ledger. The theme here is to offload the bulk of the routing to consortium management. This is the first half of the routing solution that will also have to include a back-end component that will ensure that requests end up at the right connector plugin instance if the same plugin package is used within the same Cactus node but for connecting two separate ledgers which are of the same type, e.g: Two Fabric 1.4.x ledgers with their own ledger connector instances, both running in the same Cactus node (e.g. `ApiServer` class instance). Side effect: The cactus-sdk package now has to depend on the cactus-plugin-consortium-manual package which is the simplest (and only at the time of this writing) consortium management implementation we have on hand and is therefore a natural/prime candidate for being the default consortium definition provider to power the client side component of the routing. The majority of the routing functionality is implemented within the `ApiClient` class of the SDK package and for now it only supports routing based on specific ledgers, but not other pluggable aspects. To avoid circular dependencies because of the above, the plugin packages can no longer depend on the sdk package which is also reflected in this change. Other side effect: Reusability of OpenAPI spec types is now partially in effect by way of having the core-api package export it's own types into a fixed, version controlled .json file which we'll be able to reference online as well through direct links to the github repo files (which helps because OpenAPI uses JSON references to resolve dependent specification schemas) Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
- Loading branch information
Showing
17 changed files
with
3,398 additions
and
1 deletion.
There are no files selected for viewing
59 changes: 59 additions & 0 deletions
59
docs/architecture/routing-to-api-servers-deployment-diagram.puml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
@startuml Routing to Plugin Instances | ||
|
||
|
||
!include <material/common> | ||
' To import the sprite file you DON'T need to place a prefix! | ||
!include <material/cellphone> | ||
!include <material/laptop_chromebook> | ||
!include <material/database> | ||
|
||
title Routing to Plugin Instances\nDeployment Diagram\nHyperledger Cactus | ||
|
||
actor "User A" as usera <<human>> | ||
|
||
frame "End User Device" as enduserdevice { | ||
frame "Business Application" as ba { | ||
rectangle "Cactus SDK" as cactussdk { | ||
rectangle "API Client" as apiclient { | ||
} | ||
rectangle "Client Side\nRouter" as clientsiderouter { | ||
} | ||
} | ||
} | ||
} | ||
|
||
cloud "Public Internet" as publicinternet { | ||
} | ||
|
||
frame "Cactus Backend" as cactus { | ||
rectangle "API Server A" as apia { | ||
rectangle "Connector\nPlugin A" as connectorplugina { | ||
} | ||
} | ||
rectangle "API Server B" as apib { | ||
rectangle "Connector\nPlugin B" as connectorpluginb { | ||
} | ||
} | ||
} | ||
|
||
|
||
frame "Ledgers" as ledgers { | ||
MA_DATABASE(Gray, 1, ledger1, rectangle, "Ledger 1") { | ||
} | ||
MA_DATABASE(Gray, 1, ledger2, rectangle, "Ledger 2") { | ||
} | ||
} | ||
|
||
usera => apiclient: TX: Ledger 1 | ||
apiclient => clientsiderouter: TX: Ledger 1 | ||
clientsiderouter => publicinternet: TX: Ledger 1 | ||
|
||
publicinternet ==> connectorplugina: TX: Ledger 1 | ||
publicinternet -[#AAAAAA]-> connectorpluginb | ||
|
||
connectorplugina ==> ledger1: TX: Ledger 1 | ||
connectorpluginb -[#AAAAAA]-> ledger2 | ||
|
||
@enduml | ||
|
||
|
55 changes: 55 additions & 0 deletions
55
docs/architecture/routing-to-plugin-instances-deployment-diagram.puml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
@startuml Routing to Plugin Instances | ||
|
||
|
||
!include <material/common> | ||
' To import the sprite file you DON'T need to place a prefix! | ||
!include <material/cellphone> | ||
!include <material/laptop_chromebook> | ||
!include <material/database> | ||
|
||
title Routing to Plugin Instances\nDeployment Diagram\nHyperledger Cactus | ||
|
||
actor "User A" as usera <<human>> | ||
|
||
frame "End User Device" as enduserdevice { | ||
frame "Business Application" as ba { | ||
rectangle "Cactus SDK" as cactussdk { | ||
rectangle "API Client" as apiclient { | ||
} | ||
rectangle "Client Side\nRouter" as clientsiderouter { | ||
} | ||
} | ||
} | ||
} | ||
|
||
cloud "Public Internet" as publicinternet { | ||
} | ||
|
||
frame "Cactus Backend" as cactus { | ||
rectangle "API Server A" as apia { | ||
rectangle "Connector\nPlugin A" as connectorplugina { | ||
} | ||
rectangle "Connector\nPlugin B" as connectorpluginb { | ||
} | ||
} | ||
} | ||
|
||
|
||
frame "Ledgers" as ledgers { | ||
MA_DATABASE(Gray, 1, ledger1, rectangle, "Ledger 1") { | ||
} | ||
MA_DATABASE(Gray, 1, ledger2, rectangle, "Ledger 2") { | ||
} | ||
} | ||
|
||
usera => apiclient: TX: Ledger 1 | ||
apiclient => clientsiderouter: TX: Ledger 1 | ||
clientsiderouter => publicinternet: TX: Ledger 1 | ||
|
||
publicinternet ==> connectorplugina: TX: Ledger 1 | ||
publicinternet -[#AAAAAA]-> connectorpluginb | ||
|
||
connectorplugina ==> ledger1: TX: Ledger 1 | ||
connectorpluginb -[#AAAAAA]-> ledger2 | ||
|
||
@enduml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
packages/cactus-api-client/src/main/typescript/default-consortium-provider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { | ||
Logger, | ||
LogLevelDesc, | ||
LoggerProvider, | ||
} from "@hyperledger/cactus-common"; | ||
import { Checks, IAsyncProvider } from "@hyperledger/cactus-common"; | ||
import { Consortium } from "@hyperledger/cactus-core-api"; | ||
import { | ||
DefaultApi, | ||
GetConsortiumJwsResponse, | ||
} from "@hyperledger/cactus-plugin-consortium-manual"; | ||
|
||
export interface IDefaultConsortiumProviderOptions { | ||
logLevel?: LogLevelDesc; | ||
apiClient: DefaultApi; | ||
} | ||
|
||
export class DefaultConsortiumProvider implements IAsyncProvider<Consortium> { | ||
public static readonly CLASS_NAME = "DefaultConsortiumProvider"; | ||
|
||
private readonly log: Logger; | ||
|
||
public get className() { | ||
return DefaultConsortiumProvider.CLASS_NAME; | ||
} | ||
|
||
constructor(public readonly options: IDefaultConsortiumProviderOptions) { | ||
const fnTag = `${this.className}#constructor()`; | ||
Checks.truthy(options, `${fnTag} arg options`); | ||
|
||
const level = this.options.logLevel || "INFO"; | ||
const label = this.className; | ||
this.log = LoggerProvider.getOrCreate({ level, label }); | ||
} | ||
|
||
parseConsortiumJws(response: GetConsortiumJwsResponse): Consortium { | ||
const fnTag = `DefaultConsortiumProvider#parseConsortiumJws()`; | ||
|
||
Checks.truthy(response, `${fnTag}::response`); | ||
Checks.truthy(response.jws, `${fnTag}::response.jws`); | ||
Checks.truthy(response.jws.payload, `${fnTag}::response.jws.payload`); | ||
|
||
const json = Buffer.from(response.jws.payload, "base64").toString(); | ||
const consortium = JSON.parse(json)?.consortium as Consortium; | ||
|
||
Checks.truthy(consortium, `${fnTag}::consortium`); | ||
|
||
// FIXME Ideally there would be an option here to validate the JWS based on | ||
// all the signatures and the corresponding public keys (which the caller | ||
// would have to be able to supply). | ||
// We do not yet have this crypto functions available in a cross platform | ||
// manner so it is omitted for now but much needed prior to any GA release. | ||
return consortium; | ||
} | ||
|
||
public async get(): Promise<Consortium> { | ||
try { | ||
const res = await this.options.apiClient.apiV1PluginsHyperledgerCactusPluginConsortiumManualConsortiumJwsGet(); | ||
return this.parseConsortiumJws(res.data); | ||
} catch (ex) { | ||
this.log.error(`Request for Consortium JWS failed: `, ex?.toJSON()); | ||
throw ex; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export { ApiClient } from "./api-client"; | ||
export { DefaultConsortiumProvider } from "./default-consortium-provider"; | ||
export * from "./generated/openapi/typescript-axios/index"; |
Oops, something went wrong.