There are 3 layers in libindy code organization:
Each of them contains multiply modules devoted to particular part of the flow, like "wallet", "pool", "crypto", etc.
API layer is the smallest one and contains minimal logic. Commands Executors layer splits complex commands to atomic actions. Services are isolated and process atomic operations without "vertical" dependencies between them.
- Library interface layer
- Basic validation
- Conversion of C types to Rust types
- JSONs conversion to Domain types and basic validation
- Propagation of execution to commands layer
- Splitting complex commands to atomic operations
- Working threads management
- "main" thread of libindy is hosted by Root Command Executor. Majorty of libindy logic is run in this thread.
- Threads Pool is managed by this layer as well. These threads are used for CPU-heavy operations.
- Propagation of atomic operations execution to service layer
- Joining atomic operations results to complex result
- Execution of user defined callbacks
- Services provide isolation in codebase
- Implements operations business logic and extended validation
- Management of sockets polling threads for network IO
There is no dependencies or calls between different API modules.
Root Commands Executor contains "main" thread of the library. It accepts Commands from API via standard Rust mechanism std::sync::mpsc::channel
.
A command contains user callback wrapped to Rust closure. It will be called with a result of the processing.
Incoming commands are queued by Reciver
in this channel synchronization.
Commands Executors can communicate to each other using various Commands. These commands will be put into the same queue as incoming from API.
Command Executor has access to all services required for the flow. It calls public function of the services, gather partial results from them and aggregate the final result. The final result is returned to the user via appropriate closure. Sometime service may have async API. In this case Command Executor stores the closure and wait "Ack" command from the service.
In majority of cases services return result as the output of public functions from it. For async responses "Ack" commands are used.
Services are completely isolated against each other, so no direct interaction between them is allowed.
It is used by Command Executors for CPU-heavy operations. The Command Executor prepare isolated data to be computed and pass a closure to pool thread. At the end of computation the closure generates "Ack" command with a result. While execution this closure Command Executors thread are free to process other commands.
A set of structures definitions used while parsing incoming JSON from API of the library.
Secrets from libindy wallet are never escape from it. Private keys are available only at wallet service and for Command Executors which are consuming wallet service directly. Anoncreds and Crypto services consume some secrets as input for their API. As a result no secrets are available above Commands Executor layer.