-
Notifications
You must be signed in to change notification settings - Fork 10
chore: beacon-related tweaks #131
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,13 @@ | ||
import { EnsureLookup } from "../util/types.ts"; | ||
import { LOOKUP } from "./generated.ts"; | ||
|
||
export type EnsureKnownLookup< | ||
T, | ||
L extends { [N in keyof LOOKUP]: T }, | ||
> = EnsureLookup<keyof LOOKUP, T, L>; | ||
|
||
export const ACALA_PROXY_WS_URL = "wss://acala-polkadot.api.onfinality.io/public-ws"; | ||
export const acalaBeacon = [ACALA_PROXY_WS_URL] as const; | ||
|
||
export const KUSAMA_PROXY_WS_URL = "wss://kusama-rpc.polkadot.io"; | ||
export const kusamaBeacon = [KUSAMA_PROXY_WS_URL] as const; | ||
|
||
export const MOONBEAM_PROXY_WS_URL = "wss://wss.api.moonbeam.network"; | ||
export const moonbeamBeacon = [MOONBEAM_PROXY_WS_URL] as const; | ||
|
||
export const POLKADOT_PROXY_WS_URL = "wss://rpc.polkadot.io"; | ||
export const polkadotBeacon = [POLKADOT_PROXY_WS_URL] as const; | ||
|
||
export const STATEMINT_PROXY_WS_URL = "wss://statemint-rpc.polkadot.io"; | ||
export const statemintBeacon = [STATEMINT_PROXY_WS_URL] as const; | ||
|
||
export const SUBSOCIAL_PROXY_WS_URL = "wss://para.subsocial.network"; | ||
export const subsocialBeacon = [SUBSOCIAL_PROXY_WS_URL] as const; | ||
|
||
export const WESTEND_PROXY_WS_URL = "wss://westend-rpc.polkadot.io"; | ||
export const westendBeacon = [WESTEND_PROXY_WS_URL] as const; | ||
import { beacon } from "../rpc/mod.ts"; | ||
import { KnownRpcMethods } from "./methods.ts"; | ||
|
||
// TODO: swap out `KnownRpcMethods` with narrowed lookups | ||
export const acalaBeacon = beacon<KnownRpcMethods>( | ||
"wss://acala-polkadot.api.onfinality.io/public-ws", | ||
); | ||
export const kusamaBeacon = beacon<KnownRpcMethods>("wss://kusama-rpc.polkadot.io"); | ||
export const moonbeamBeacon = beacon<KnownRpcMethods>("wss://wss.api.moonbeam.network"); | ||
export const polkadotBeacon = beacon<KnownRpcMethods>("wss://rpc.polkadot.io"); | ||
export const statemintBeacon = beacon<KnownRpcMethods>("wss://statemint-rpc.polkadot.io"); | ||
export const subsocialBeacon = beacon<KnownRpcMethods>("wss://para.subsocial.network"); | ||
export const westendBeacon = beacon<KnownRpcMethods>("wss://westend-rpc.polkadot.io"); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,3 @@ | ||
import { Branded } from "../util/mod.ts"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Proper branded types are still a todo. |
||
|
||
// TODO: narrowly type the template literal of `ProxyWsUrlBeacon` | ||
declare const _proxyWsUrl: unique symbol; | ||
export type ProxyWsUrl = Branded<`wss://${string}`, typeof _proxyWsUrl>; | ||
|
||
// TODO: use branded type to represent validated chain spec string | ||
declare const _chainSpec: unique symbol; | ||
export type ChainSpec = Branded<string, typeof _proxyWsUrl>; | ||
|
||
export type Beacon = ProxyWsUrl | ChainSpec; | ||
|
||
export * from "./beacons.ts"; | ||
export * from "./generated.ts"; | ||
export * from "./methods.ts"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,10 +18,10 @@ export type Subscription<NotificationResult = any> = { [_N]: NotificationResult | |
|
||
export interface ClientProps< | ||
M extends AnyMethods, | ||
Beacon, | ||
DiscoveryValue, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Zeroing in on correct terminology. Beacons contain discovery values (such as URLs and chain specs). Beacons are encoded with the type information necessary to constrain client usage. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Zeroing in on correct terminology. Beacons contain discovery values (such as URLs and chain specs). Beacons are encoded with the type information necessary to constrain client usage. |
||
ParsedError extends Error, | ||
> { | ||
beacon: Beacon; | ||
discoveryValue: DiscoveryValue; | ||
hooks?: { | ||
send?: (message: InitMessage<M>) => void; | ||
receive?: (message: IngressMessage<M>) => void; | ||
|
@@ -51,7 +51,17 @@ export abstract class Client< | |
* | ||
* @param egressMessage the message you wish to send to the RPC server | ||
*/ | ||
abstract send: (egressMessage: InitMessage<M>) => void; | ||
send = (egressMessage: InitMessage<M>): void => { | ||
this.props.hooks?.send?.(egressMessage); | ||
this._send(egressMessage); | ||
}; | ||
|
||
/** | ||
* The provider-specific send implementation | ||
* | ||
* @param egressMessage the message you wish to send to the RPC server | ||
*/ | ||
abstract _send: (egressMessage: InitMessage<M>) => void; | ||
|
||
/** | ||
* Parse messages returned from the RPC server (this includes RPC server errors) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import * as rpc from "../rpc/mod.ts"; | ||
|
||
export type DiscoveryValues = [string, ...string[]]; | ||
|
||
declare const _M: unique symbol; | ||
|
||
export class Beacon<M extends rpc.AnyMethods> { | ||
declare [_M]: M; | ||
discoveryValues; | ||
|
||
constructor(...discoveryValues: DiscoveryValues) { | ||
this.discoveryValues = discoveryValues; | ||
} | ||
} | ||
export function beacon<M extends rpc.AnyMethods>(...discoveryValues: DiscoveryValues): Beacon<M> { | ||
return new Beacon(...discoveryValues); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,35 @@ | ||
import { ErrorCtor } from "../util/mod.ts"; | ||
import { ErrorCtor, isWsUrl } from "../util/mod.ts"; | ||
import { AnyMethods } from "./Base.ts"; | ||
import { Beacon } from "./Beacon.ts"; | ||
import { FailedToAddChainError, FailedToStartSmoldotError, SmoldotClient } from "./smoldot.ts"; | ||
import { FailedToOpenConnectionError, ProxyWsUrlClient } from "./ws.ts"; | ||
|
||
type DiscoveryValues = readonly [string, ...string[]]; | ||
// TODO: replace with better branded types | ||
type Beacon<M extends AnyMethods> = DiscoveryValues & { _beacon: { supported: M } }; | ||
export function beacon<Supported extends AnyMethods>( | ||
discoveryValues: DiscoveryValues, | ||
): Beacon<Supported> { | ||
return discoveryValues as Beacon<Supported>; | ||
} | ||
|
||
// TODO: use branded beacon types instead of string | ||
// TODO: dyn import smoldot and provider if chain spec is provided | ||
// TODO: handle retry | ||
// TODO: narrow to `[string, ...string[]]` | ||
export async function client<M extends AnyMethods>(beacon: Beacon<M>): Promise< | ||
export async function client<M extends AnyMethods>( | ||
beacon: Beacon<M>, | ||
currentDiscoveryValueI = 0, | ||
): Promise< | ||
| SmoldotClient<M> | ||
| ProxyWsUrlClient<M> | ||
| FailedToOpenConnectionError | ||
| FailedToStartSmoldotError | ||
| FailedToAddChainError | ||
| AllBeaconsErroredError | ||
| BeaconFailedError | ||
> { | ||
const [e0, ...rest] = beacon; | ||
const result = await (async () => { | ||
if (isWsUrl(e0)) { | ||
return ProxyWsUrlClient.open({ beacon: e0 }); | ||
} else { | ||
return SmoldotClient.open({ beacon: e0 }); | ||
} | ||
})(); | ||
if (result instanceof Error) { | ||
if (rest.length > 0) { | ||
return await client(rest as unknown as Beacon<M>); | ||
const currentDiscoveryValue = beacon.discoveryValues[currentDiscoveryValueI]; | ||
if (currentDiscoveryValue) { | ||
const result = await (async () => { | ||
if (isWsUrl(currentDiscoveryValue)) { | ||
return ProxyWsUrlClient.open<M>({ discoveryValue: currentDiscoveryValue }); | ||
} else { | ||
return SmoldotClient.open<M>({ discoveryValue: currentDiscoveryValue }); | ||
} | ||
})(); | ||
if (result instanceof Error) { | ||
return await client(beacon, currentDiscoveryValueI + 1); | ||
} | ||
return new AllBeaconsErroredError(); | ||
return result; | ||
} | ||
// TODO: fix | ||
return result as any; | ||
} | ||
|
||
// TODO: validate chain spec as well | ||
// TODO: better validation | ||
function isWsUrl(inQuestion: string): boolean { | ||
return inQuestion.startsWith("wss://"); | ||
return new BeaconFailedError(); | ||
} | ||
|
||
export class AllBeaconsErroredError extends ErrorCtor("AllBeaconsErrored") {} | ||
export class BeaconFailedError extends ErrorCtor("AllBeaconsErrored") {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// TODO: validate chain spec as well | ||
// TODO: better ws validation | ||
|
||
export function isWsUrl(inQuestion: string): boolean { | ||
return inQuestion.startsWith("wss://"); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
export * from "./branded.ts"; | ||
export * from "./discovery_value_validation.ts"; | ||
export * from "./ErrorCtor.ts"; | ||
export * from "./fn.ts"; | ||
export * as hex from "./hex.ts"; | ||
export * from "./load_env.ts"; | ||
export * from "./types.ts"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Effects are in need of a refactor, given the way that RPC types flow through the beacon into any/all calls. This
any
-ifying is temporary