@parity/light.js
Version:
A high-level reactive JS library optimized for light clients
110 lines (71 loc) • 4.63 kB
Markdown
# RpcObservables
The whole library `@parity/light.js` works with the concept of RpcObservables.
The name _RpcObservable_ might actually not be the best, because it's actually **not** an Observable. A RpcObservable is a function returning an Observable.
Here's the TypeScript type of a RpcObservable:
```javascript
export interface RpcObservable<Source, Out> {
(...args: any[]): Observable<Out>;
metadata?: Metadata<Source, Out>;
}
```
Or in simple words: a RpcObservable is a function returning an Observable, and this function has some metadata.
Let's have a look at `MetaData`:
```javascript
export interface Metadata<Source, Out> {
// --snip--
frequency?: FrequencyObservable<Source>[];
name?: string;
pipes?: (...args: any[]) => OperatorFunction<Source, Out>[];
}
```
These are the most important fields of `MetaData`, which we will explain.
## Main Idea
We believe that data streams are an intuitive way to express events happening on the Ethereum blockchain. The most obvious example is the pubsub pattern we described [before](/concepts/light-client-development.html#pubsub), where we wanted to fetch the balance on every new block.
It's intuitive to have an Observable, called `onEveryBlock$`, that would fire an event each time it receives a new block from the network. Then, every time it fires, we declaratively make an JSONRPC call to `eth_getBalance`. Into code, it looks like this:
```javascript
import { from } from 'rxjs';
import { switchMap } from 'rxjs/operators';
// Observable that makes a JSONRPC request
const fetchBalance = () => from(api.eth.getBalance('0x12..ff'));
// On every block, we make that JSONRPC request
onEveryBlock$.pipe(switchMap(fetchBalance)));
```
Similarly, if we want to check our peer count every 5 seconds, we'd do
```javascript
import { from } from 'rxjs';
import { switchMap } from 'rxjs/operators';
// Observable that makes a JSONRPC request
const checkPeerCount = () => from(api.net.peerCount());
// On every block, we make that JSONRPC request
onEvery5Seconds$.pipe(switchMap(checkPeerCount)));
```
The main idea of `@parity/light.js` is the following: **"on every [frequency], we do [something]"**.
On every new block, we call `eth_balance`. On every 5 seconds, we call `net_peerCount`. Etc.
Looking back at the `MetaData` above, the `frequency` field holds the **frequency**, which is an array of `FrequencyObservable`s, and the `pipes` hold an array of RxJS pipe functions, and each of them does **something**.
## `FrequencyObservable`
Some examples of `FrequencyObservable` shipped with `@parity/light.js` are:
- `onEveryBlock$`
- `onEvery2Blocks$`
- `onEverySecond$`
- `onEvery5Seconds$`
- `onSyncingChanged$` (fires when sync status changes)
- `onAccountsChanged$` (fires when you change account)
- `onStartup$` (fires once at dapp start)
- etc.
The full list can be seen in the [API section](/api/API.md).
## RpcObservable
An RpcObservable can either have a frequency, or depend on another RpcObservable which has a frequency.
### RpcObservable with frequencies
An RpcObservable with a frequency has its `Metadata.frequency` field filled with one or more `FrequencyObservable`s. For example, `balanceOf$` has as frequency of `[onEveryBlock$]`.
Then, this RpcObservable has an array of pipes, which will be piped to the `FrequencyObservable`. For example, `balanceOf$` has one pipe which make a `eth_getBalance` JSONRPC request.
### RpcObservable which depends on another RpcObservable
Some RpcObservable don't have their own frequencies, but depend on a parent RpcObservable. This is the case of `defaultAccount$`, which depends on `account$`. In this case, the `Metadata.dependsOn` field points to the parent RpcObservable.
These RpcObservables still have some pipes. For example `defaultAccount$` has one pipe which takes the 1st element of the array returned by `accounts$`.
### Calling an RpcObservable
As per the TypeScript signature, the RpcObservable function can take arguments. These arguments are then passed down into the pipes. For instance, the argument `0x123` in `balanceOf$('0x123')` is passed down into `balanceOf$`'s pipes, i.e. into the JSONRPC `eth_getBalance` call.
### Examples of RpcObservable
- `accounts$`: Returns the array of accounts managed by the node. Frequency is `onAccountsChanged$`.
- `defaultAccount$`: Returns the default active account. Depends on `accounts$`.
- `blockNumber$`: Returns the current block number. Frequency is `onEveryBlock$`.
- `peerCount$`: Returns the number of peers. Frequency is `onEvery5Seconds$`.
The full list can be seen in the [API section](/api/API.md).