All files / src/Program/programs projector.ts

36.11% Statements 13/36
0% Branches 0/12
0% Functions 0/2
34.28% Lines 12/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125    35x 35x         35x   35x 35x   35x 35x 35x   35x 35x                                                   35x                                                 35x                                                                                                              
import { Cardano } from '@cardano-sdk/core';
import { CommonProgramOptions, OgmiosProgramOptions, PosgresProgramOptions } from '../options';
import { DnsResolver, createDnsResolver } from '../utils';
import {
  HandlePolicyIdsOptionDescriptions,
  HandlePolicyIdsProgramOptions,
  handlePolicyIdsFromFile
} from '../options/policyIds';
import { HttpServer, HttpServerConfig } from '../../Http';
import { Logger } from 'ts-log';
import { MissingProgramOption, UnknownServiceName } from '../errors';
import { ProjectionHttpService, ProjectionName, createTypeormProjection, storeOperators } from '../../Projection';
import { SrvRecord } from 'dns';
import { createLogger } from 'bunyan';
import { createStorePoolMetricsUpdateJob, createStoreStakePoolMetadataJob } from '@cardano-sdk/projection-typeorm';
import { getConnectionConfig, getOgmiosObservableCardanoNode } from '../services';
 
export const BLOCKS_BUFFER_LENGTH_DEFAULT = 10;
export const PROJECTOR_API_URL_DEFAULT = new URL('http://localhost:3002');
 
export type ProjectorArgs = CommonProgramOptions &
  PosgresProgramOptions<''> &
  HandlePolicyIdsProgramOptions &
  OgmiosProgramOptions & {
    blocksBufferLength: number;
    dropSchema: boolean;
    dryRun: boolean;
    exitAtBlockNo: Cardano.BlockNo;
    metadataJobRetryDelay: number;
    poolsMetricsInterval: number;
    projectionNames: ProjectionName[];
    synchronize: boolean;
  };
export interface LoadProjectorDependencies {
  dnsResolver?: (serviceName: string) => Promise<SrvRecord>;
  logger?: Logger;
}
 
interface ProjectionMapFactoryOptions {
  args: ProjectorArgs;
  dnsResolver: DnsResolver;
  logger: Logger;
}
 
const createProjectionHttpService = async (options: ProjectionMapFactoryOptions) => {
  const { args, dnsResolver, logger } = options;
  storeOperators.storePoolMetricsUpdateJob = createStorePoolMetricsUpdateJob(args.poolsMetricsInterval)();
  storeOperators.storeStakePoolMetadataJob = createStoreStakePoolMetadataJob(args.metadataJobRetryDelay)();
  const cardanoNode = getOgmiosObservableCardanoNode(dnsResolver, logger, {
    ogmiosSrvServiceName: args.ogmiosSrvServiceName,
    ogmiosUrl: args.ogmiosUrl
  });
  const connectionConfig$ = getConnectionConfig(dnsResolver, 'projector', '', args);
  const { blocksBufferLength, dropSchema, dryRun, exitAtBlockNo, handlePolicyIds, projectionNames, synchronize } = args;
  const projection$ = createTypeormProjection({
    blocksBufferLength,
    cardanoNode,
    connectionConfig$,
    devOptions: { dropSchema, synchronize },
    exitAtBlockNo,
    logger,
    projectionOptions: {
      handlePolicyIds
    },
    projections: projectionNames
  });
  return new ProjectionHttpService({ dryRun, projection$, projectionNames }, { logger });
};
 
export const loadProjector = async (args: ProjectorArgs, deps: LoadProjectorDependencies = {}): Promise<HttpServer> => {
  const supportedProjections = Object.values(ProjectionName);
 
  await handlePolicyIdsFromFile(args);
 
  const {
    apiUrl,
    buildInfo,
    enableMetrics,
    handlePolicyIds,
    loggerMinSeverity,
    projectionNames,
    serviceDiscoveryBackoffFactor,
    serviceDiscoveryTimeout
  } = args;
 
  for (const projectionName of projectionNames) {
    Iif (!supportedProjections.includes(projectionName)) {
      throw new UnknownServiceName(projectionName, Object.values(ProjectionName));
    }
    Iif (projectionName === ProjectionName.Handle && !handlePolicyIds) {
      throw new MissingProgramOption(ProjectionName.Handle, [
        HandlePolicyIdsOptionDescriptions.HandlePolicyIds,
        HandlePolicyIdsOptionDescriptions.HandlePolicyIdsFile
      ]);
    }
  }
  const logger =
    deps?.logger ||
    createLogger({
      level: loggerMinSeverity,
      name: 'projector'
    });
  const dnsResolver =
    deps?.dnsResolver ||
    createDnsResolver(
      {
        factor: serviceDiscoveryBackoffFactor,
        maxRetryTime: serviceDiscoveryTimeout
      },
      logger
    );
  const service = await createProjectionHttpService({ args, dnsResolver, logger });
  const config: HttpServerConfig = {
    listen: {
      host: apiUrl.hostname,
      port: apiUrl ? Number.parseInt(apiUrl.port) : undefined
    },
    meta: { ...buildInfo, startupTime: Date.now() }
  };
  Iif (enableMetrics) {
    config.metrics = { enabled: enableMetrics };
  }
  return new HttpServer(config, { logger, services: [service] });
};