An example:
```rust
enum RealClient {
FullNode(CkbRpcClient),
LightClient(LightClientRpcClient),
}
impl RealClient {
fn new(url: Url, user_provided_full_node: bool) -> RealClient {
if user_provided_full_node {
RealClient::FullNode(CkbRpcClient::new(url))
} else {
RealClient::LightClient(LightClientRpcClient::new(url))
}
}
/* Wrap similar RPC methods to unify into one, one by one. */
}
```
In fact, if we only use a sub-set of RPC methods, we don't have to know that such clearly.
We could split:
CKB full node RPC methods into two parts:
Core CKB RPC methods
CKB full node only RPC methods
CKB light client RPC methods into two parts:
Core CKB RPC methods
CKB light client only RPC methods
Then there appears an abstraction layer: a series of core CKB RPC methods.
When an app just uses these core CKB RPC methods, it could connect to either a full node or a light client, it doesn't have to know it clearly, but all of them works well.
Examples:
```rust
trait CkbCoreEndpoint {}
trait CkbFullNodeEndpoint {}
trait CkbLightClientEndpoint {}
impl CkbCoreEndpoint for CkbRpcClient {}
impl CkbFullNodeEndpoint for CkbRpcClient {}
impl CkbCoreEndpoint for LightClientRpcClient {}
impl CkbLightClientEndpoint for LightClientRpcClient {}
// Then, a core CKB client could be:
impl CkbCoreEndpoint for CkbCoreClient {}
// Or:
pub struct CkbCoreClient (Box);
```
Description
Now, when an app wants to connect an RPC endpoint, it has to know which kind of endpoint it connects to, a full node or a light client.
https://github.com/nervosnetwork/ckb-sdk-rust/blob/3da7ffacb58d45bc33e0bc311723a19b2ea04c7f/src/rpc/ckb.rs#L22 https://github.com/nervosnetwork/ckb-sdk-rust/blob/3da7ffacb58d45bc33e0bc311723a19b2ea04c7f/src/rpc/ckb_light_client.rs#L103
It makes things complicated.
An example:
```rust enum RealClient { FullNode(CkbRpcClient), LightClient(LightClientRpcClient), } impl RealClient { fn new(url: Url, user_provided_full_node: bool) -> RealClient { if user_provided_full_node { RealClient::FullNode(CkbRpcClient::new(url)) } else { RealClient::LightClient(LightClientRpcClient::new(url)) } } /* Wrap similar RPC methods to unify into one, one by one. */ } ```
In fact, if we only use a sub-set of RPC methods, we don't have to know that such clearly.
We could split:
Then there appears an abstraction layer: a series of core CKB RPC methods.
When an app just uses these core CKB RPC methods, it could connect to either a full node or a light client, it doesn't have to know it clearly, but all of them works well.
Examples:
```rust trait CkbCoreEndpoint {} trait CkbFullNodeEndpoint {} trait CkbLightClientEndpoint {} impl CkbCoreEndpoint for CkbRpcClient {} impl CkbFullNodeEndpoint for CkbRpcClient {} impl CkbCoreEndpoint for LightClientRpcClient {} impl CkbLightClientEndpoint for LightClientRpcClient {} // Then, a core CKB client could be: impl CkbCoreEndpoint for CkbCoreClient {} // Or: pub struct CkbCoreClient (Box