Skip to content

Commit

Permalink
feat(cardano-services): implement provider selection based on env var…
Browse files Browse the repository at this point in the history
…iables and config
  • Loading branch information
ginnun committed Sep 6, 2024
1 parent 6209d90 commit 55b50dd
Show file tree
Hide file tree
Showing 6 changed files with 399 additions and 86 deletions.
1 change: 1 addition & 0 deletions packages/cardano-services/src/Program/options/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './providers';
export * from './common';
export * from './ogmios';
export * from './policyIds';
Expand Down
79 changes: 79 additions & 0 deletions packages/cardano-services/src/Program/options/providers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { newOption } from './util';

export enum ProviderImplementation {
TYPEORM = 'typeorm',
BLOCKFROST = 'blockfrost',
DBSYNC = 'dbsync',
// Below ones are specific to TxSubmitProvider
'SUBMIT_NODE' = 'submit-node',
'SUBMIT_API' = 'submit-api'
}

export type ProviderImplementations = {
assetProvider?: ProviderImplementation;
rewardsProvider?: ProviderImplementation;
networkInfoProvider?: ProviderImplementation;
utxoProvider?: ProviderImplementation;
txSubmitProvider?: ProviderImplementation;
chainHistoryProvider?: ProviderImplementation;
stakePoolProvider?: ProviderImplementation;
};
export const ProviderImplementationDescription = 'Select one of the available provider implementations';
const argParser = (impl: string) => ProviderImplementation[impl.toUpperCase() as keyof typeof ProviderImplementation];
export const providerSelectionOptions = [
newOption(
'--asset-provider <implementation>',
ProviderImplementationDescription,
'ASSET_PROVIDER',
argParser,
ProviderImplementation.DBSYNC
)
.conflicts('useTypeormAssetProvider')
.choices([ProviderImplementation.BLOCKFROST, ProviderImplementation.DBSYNC, ProviderImplementation.TYPEORM]),
newOption(
'--stake-pool-provider <implementation>',
ProviderImplementationDescription,
'STAKE_POOL_PROVIDER',
argParser,
ProviderImplementation.DBSYNC
)
.conflicts('useTypeormStakePoolProvider')
.choices([ProviderImplementation.DBSYNC, ProviderImplementation.TYPEORM]),
newOption(
'--utxo-provider <implementation>',
ProviderImplementationDescription,
'UTXO_PROVIDER',
argParser,
ProviderImplementation.DBSYNC
).choices([ProviderImplementation.BLOCKFROST, ProviderImplementation.DBSYNC]),
newOption(
'--chain-history-provider <implementation>',
ProviderImplementationDescription,
'CHAIN_HISTORY_PROVIDER',
argParser,
ProviderImplementation.DBSYNC
).choices([ProviderImplementation.BLOCKFROST, ProviderImplementation.DBSYNC]),
newOption(
'--rewards-provider <implementation>',
ProviderImplementationDescription,
'REWARDS_PROVIDER',
argParser,
ProviderImplementation.DBSYNC
).choices([ProviderImplementation.BLOCKFROST, ProviderImplementation.DBSYNC]),
newOption(
'--network-info-provider <implementation>',
ProviderImplementationDescription,
'NETWORK_INFO_PROVIDER',
argParser,
ProviderImplementation.DBSYNC
).choices([ProviderImplementation.BLOCKFROST, ProviderImplementation.DBSYNC]),
newOption(
'--tx-submit-provider <implementation>',
ProviderImplementationDescription,
'TX_SUBMIT_PROVIDER',
argParser,
ProviderImplementation.SUBMIT_NODE
)
.conflicts('useSubmitApi')
.choices([ProviderImplementation.BLOCKFROST, ProviderImplementation.SUBMIT_API, ProviderImplementation.SUBMIT_NODE])
];
253 changes: 170 additions & 83 deletions packages/cardano-services/src/Program/programs/providerServer.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,62 @@
/* eslint-disable complexity */
import { AssetProvider, CardanoNode, HandleProvider, Provider, Seconds, StakePoolProvider } from '@cardano-sdk/core';
import { CardanoWsClient, TxSubmitApiProvider } from '@cardano-sdk/cardano-services-client';
import { Logger } from 'ts-log';
import { Observable } from 'rxjs';
import { OgmiosCardanoNode } from '@cardano-sdk/ogmios';
import { PgConnectionConfig } from '@cardano-sdk/projection-typeorm';
import { Pool } from 'pg';
import { SrvRecord } from 'dns';
import { WarmCache } from '../../InMemoryCache/WarmCache';
import { createLogger } from 'bunyan';
import { isNotNil } from '@cardano-sdk/util';
import memoize from 'lodash/memoize.js';
/* eslint-disable sonarjs/cognitive-complexity */
import {
AssetHttpService,
BlockfrostAssetProvider,
CardanoTokenRegistry,
DbSyncAssetProvider,
DbSyncNftMetadataService,
StubTokenMetadataService
StubTokenMetadataService,
TypeormAssetProvider
} from '../../Asset';
import { CardanoNode, HandleProvider, Seconds } from '@cardano-sdk/core';
import { CardanoWsClient, TxSubmitApiProvider } from '@cardano-sdk/cardano-services-client';
import { ChainHistoryHttpService, DbSyncChainHistoryProvider } from '../../ChainHistory';
import { CommonOptionsDescriptions } from '../options';
import { ConnectionNames, PostgresOptionDescriptions, suffixType2Cli } from '../options/postgres';
import { DbPools, DbSyncEpochPollService } from '../../util';
import { DbSyncNetworkInfoProvider, NetworkInfoHttpService } from '../../NetworkInfo';
import { DbSyncRewardsProvider, RewardsHttpService } from '../../Rewards';
import { DbSyncStakePoolProvider, StakePoolHttpService, createHttpStakePoolMetadataService } from '../../StakePool';
import { DbSyncUtxoProvider, UtxoHttpService } from '../../Utxo';
import {
BlockfrostChainHistoryProvider,
ChainHistoryHttpService,
DbSyncChainHistoryProvider
} from '../../ChainHistory';
import { BlockfrostNetworkInfoProvider, DbSyncNetworkInfoProvider, NetworkInfoHttpService } from '../../NetworkInfo';
import { BlockfrostProvider } from '../../util/BlockfrostProvider/BlockfrostProvider';
import { BlockfrostRewardsProvider, DbSyncRewardsProvider, RewardsHttpService } from '../../Rewards';
import { BlockfrostTxSubmitProvider, NodeTxSubmitProvider, TxSubmitHttpService } from '../../TxSubmit';
import { BlockfrostUtxoProvider, DbSyncUtxoProvider, UtxoHttpService } from '../../Utxo';
import {
CommonOptionsDescriptions,
ConnectionNames,
HandlePolicyIdsOptionDescriptions,
PostgresOptionDescriptions,
ProviderImplementation,
handlePolicyIdsFromFile,
suffixType2Cli
} from '../options';
import { DbPools, DbSyncEpochPollService, TypeormProvider, getBlockfrostApi } from '../../util';
import {
DbSyncStakePoolProvider,
StakePoolHttpService,
TypeormStakePoolProvider,
createHttpStakePoolMetadataService
} from '../../StakePool';
import { DnsResolver, createDnsResolver, getCardanoNode, getDbPools, getGenesisData } from '../utils';
import { GenesisData } from '../../types';
import { HandleHttpService, TypeOrmHandleProvider } from '../../Handle';
import { HandlePolicyIdsOptionDescriptions, handlePolicyIdsFromFile } from '../options/policyIds';
import { HttpServer, HttpServerConfig, HttpService, getListen } from '../../Http';
import { InMemoryCache, NoCache } from '../../InMemoryCache';
import { Logger } from 'ts-log';
import { MissingProgramOption, MissingServiceDependency, RunnableDependencies, UnknownServiceName } from '../errors';
import { NodeTxSubmitProvider, TxSubmitHttpService } from '../../TxSubmit';
import { Observable } from 'rxjs';
import { OgmiosCardanoNode } from '@cardano-sdk/ogmios';
import { PgConnectionConfig } from '@cardano-sdk/projection-typeorm';
import { Pool } from 'pg';
import { ProviderServerArgs, ProviderServerOptionDescriptions, ServiceNames } from './types';
import { SrvRecord } from 'dns';
import { TypeormAssetProvider } from '../../Asset/TypeormAssetProvider';
import { TypeormStakePoolProvider } from '../../StakePool/TypeormStakePoolProvider/TypeormStakePoolProvider';
import { WarmCache } from '../../InMemoryCache/WarmCache';
import { createDbSyncMetadataService } from '../../Metadata';
import { createLogger } from 'bunyan';
import { getConnectionConfig, getOgmiosObservableCardanoNode } from '../services';
import { getEntities } from '../../Projection/prepareTypeormProjection';
import { isNotNil } from '@cardano-sdk/util';
import memoize from 'lodash/memoize.js';
import { getEntities } from '../../Projection';

export const ALLOWED_ORIGINS_DEFAULT = false;
export const DISABLE_STAKE_POOL_METRIC_APY_DEFAULT = false;
Expand Down Expand Up @@ -72,6 +88,18 @@ const connectionConfigs: { [k in ConnectionNames]?: Observable<PgConnectionConfi

let sharedHandleProvider: HandleProvider;

const selectProviderImplementation = <T extends Provider>(
impl: ProviderImplementation,
typeorm?: () => T & TypeormProvider,
dbsync?: () => T & Provider,
blockfrost?: () => T & BlockfrostProvider
) =>
(impl === ProviderImplementation.TYPEORM
? typeorm!()
: impl === ProviderImplementation.DBSYNC
? dbsync!()
: blockfrost!()) as T;

const serviceMapFactory = (options: ServiceMapFactoryOptions) => {
const { args, pools, dnsResolver, genesisData, logger, node } = options;

Expand Down Expand Up @@ -248,73 +276,132 @@ const serviceMapFactory = (options: ServiceMapFactoryOptions) => {
);
}, ServiceNames.Asset);

const getBlockfrostAssetProvider = () => new BlockfrostAssetProvider({ blockfrost: getBlockfrostApi(), logger });

const getBlockfrostEnabledNetworkInfoHttpService = () =>
new NetworkInfoHttpService({
logger,
networkInfoProvider: new BlockfrostNetworkInfoProvider({ blockfrost: getBlockfrostApi(), logger })
});

const getBlockfrostEnabledChainHistoryHttpService = () =>
new ChainHistoryHttpService({
chainHistoryProvider: new BlockfrostChainHistoryProvider({ blockfrost: getBlockfrostApi(), logger }),
logger
});

const getBlockfrostEnabledRewardsHttpService = () =>
new RewardsHttpService({
logger,
rewardsProvider: new BlockfrostRewardsProvider({ blockfrost: getBlockfrostApi(), logger })
});

const getBlockfrostTxSubmitProvider = () =>
new BlockfrostTxSubmitProvider({ blockfrost: getBlockfrostApi(), logger });

const getBlockfrostEnabledUtxoHttpService = () =>
new UtxoHttpService({
logger,
utxoProvider: new BlockfrostUtxoProvider({ blockfrost: getBlockfrostApi(), logger })
});

return {
[ServiceNames.Asset]: async () => {
const assetProvider = args.useTypeormAssetProvider ? getTypeormAssetProvider() : getDbSyncAssetProvider();
const chosenImplementation = args.useTypeormAssetProvider
? ProviderImplementation.TYPEORM
: args.assetProvider ?? ProviderImplementation.DBSYNC;
const assetProvider = selectProviderImplementation<AssetProvider>(
chosenImplementation,
getTypeormAssetProvider,
getDbSyncAssetProvider,
getBlockfrostAssetProvider
);
return new AssetHttpService({ assetProvider, logger });
},
[ServiceNames.StakePool]: async () => {
const stakePoolProvider = args.useTypeormStakePoolProvider
? getTypeormStakePoolProvider()
: getDbSyncStakePoolProvider();
const chosenImplementation = args.useTypeormStakePoolProvider
? ProviderImplementation.TYPEORM
: args.stakePoolProvider ?? ProviderImplementation.DBSYNC;

const stakePoolProvider = selectProviderImplementation<StakePoolProvider>(
chosenImplementation,
getTypeormStakePoolProvider,
getDbSyncStakePoolProvider
);

return new StakePoolHttpService({ logger, stakePoolProvider });
},
[ServiceNames.Utxo]: withDbSyncProvider(
async (dbPools, cardanoNode) =>
new UtxoHttpService({
logger,
utxoProvider: new DbSyncUtxoProvider({
cache: {
healthCheck: healthCheckCache
},
cardanoNode,
dbPools,
logger
})
}),
ServiceNames.Utxo
),
[ServiceNames.ChainHistory]: withDbSyncProvider(async (dbPools, cardanoNode) => {
const metadataService = createDbSyncMetadataService(dbPools.main, logger);
const chainHistoryProvider = new DbSyncChainHistoryProvider(
{ paginationPageSizeLimit: args.paginationPageSizeLimit! },
{
cache: {
healthCheck: healthCheckCache
},
cardanoNode,
dbPools,
logger,
metadataService
}
);
return new ChainHistoryHttpService({ chainHistoryProvider, logger });
}, ServiceNames.ChainHistory),
[ServiceNames.Utxo]:
args.utxoProvider === ProviderImplementation.BLOCKFROST
? getBlockfrostEnabledUtxoHttpService
: withDbSyncProvider(
async (dbPools, cardanoNode) =>
new UtxoHttpService({
logger,
utxoProvider: new DbSyncUtxoProvider({
cache: {
healthCheck: healthCheckCache
},
cardanoNode,
dbPools,
logger
})
}),
ServiceNames.Utxo
),
[ServiceNames.ChainHistory]:
args.chainHistoryProvider === ProviderImplementation.BLOCKFROST
? getBlockfrostEnabledChainHistoryHttpService
: withDbSyncProvider(async (dbPools, cardanoNode) => {
const chainHistoryProvider = new DbSyncChainHistoryProvider(
{ paginationPageSizeLimit: args.paginationPageSizeLimit! },
{
cache: {
healthCheck: healthCheckCache
},
cardanoNode,
dbPools,
logger,
metadataService: createDbSyncMetadataService(dbPools.main, logger)
}
);
return new ChainHistoryHttpService({ chainHistoryProvider, logger });
}, ServiceNames.ChainHistory),
[ServiceNames.Handle]: async () => new HandleHttpService({ handleProvider: await getHandleProvider(), logger }),
[ServiceNames.Rewards]: withDbSyncProvider(async (dbPools, cardanoNode) => {
const rewardsProvider = new DbSyncRewardsProvider(
{ paginationPageSizeLimit: args.paginationPageSizeLimit! },
{
cache: {
healthCheck: healthCheckCache
},
cardanoNode,
dbPools,
logger
}
);
return new RewardsHttpService({ logger, rewardsProvider });
}, ServiceNames.Rewards),
[ServiceNames.NetworkInfo]: withDbSyncProvider(
async (dbPools, cardanoNode) =>
new NetworkInfoHttpService({
logger,
networkInfoProvider: getNetworkInfoProvider(cardanoNode, dbPools)
}),
ServiceNames.NetworkInfo
),
[ServiceNames.Rewards]:
args.rewardsProvider === ProviderImplementation.BLOCKFROST
? getBlockfrostEnabledRewardsHttpService
: withDbSyncProvider(async (dbPools, cardanoNode) => {
const rewardsProvider = new DbSyncRewardsProvider(
{ paginationPageSizeLimit: args.paginationPageSizeLimit! },
{
cache: {
healthCheck: healthCheckCache
},
cardanoNode,
dbPools,
logger
}
);
return new RewardsHttpService({ logger, rewardsProvider });
}, ServiceNames.Rewards),
[ServiceNames.NetworkInfo]:
args.networkInfoProvider === ProviderImplementation.BLOCKFROST
? getBlockfrostEnabledNetworkInfoHttpService
: withDbSyncProvider(
async (dbPools, cardanoNode) =>
new NetworkInfoHttpService({
logger,
networkInfoProvider: getNetworkInfoProvider(cardanoNode, dbPools)
}),
ServiceNames.NetworkInfo
),
[ServiceNames.TxSubmit]: async () => {
const txSubmitProvider = args.useSubmitApi
? getSubmitApiProvider()
: args.txSubmitProvider === ProviderImplementation.BLOCKFROST
? getBlockfrostTxSubmitProvider()
: args.txSubmitProvider === ProviderImplementation.SUBMIT_API
? getSubmitApiProvider()
: new NodeTxSubmitProvider({
cardanoNode: getOgmiosObservableCardanoNode(dnsResolver, logger, args),
Expand Down
Loading

0 comments on commit 55b50dd

Please sign in to comment.