Skip to content

Commit

Permalink
refactor: use 'appKey' instead of 'environment, index' as app environ…
Browse files Browse the repository at this point in the history
…ment identifier
  • Loading branch information
beeman committed Dec 14, 2022
1 parent b6ca341 commit 91d421f
Show file tree
Hide file tree
Showing 19 changed files with 112 additions and 121 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ApiAppDataAccessService } from '@kin-kinetic/api/app/data-access'
import { ApiCoreDataAccessService, AppEnvironment } from '@kin-kinetic/api/core/data-access'
import { getAppKey } from '@kin-kinetic/api/core/util'
import { ApiSolanaDataAccessService } from '@kin-kinetic/api/solana/data-access'
import {
ApiTransactionDataAccessService,
Expand Down Expand Up @@ -75,7 +76,8 @@ export class ApiAccountDataAccessService implements OnModuleInit {
}

async closeAccount(req: Request, input: CloseAccountRequest): Promise<Transaction> {
const { appEnv, appKey } = await this.data.getAppEnvironment(input.environment, input.index)
const appKey = getAppKey(input.environment, input.index)
const appEnv = await this.data.getAppEnvironmentByAppKey(appKey)
const { ip, ua } = this.transaction.validateRequest(appEnv, req)

return this.handleCloseAccount(input, { appEnv, appKey, ip, ua })
Expand All @@ -92,7 +94,7 @@ export class ApiAccountDataAccessService implements OnModuleInit {
}: { appKey: string; appEnv: AppEnvironment; headers?: Record<string, string>; ip?: string; ua?: string },
): Promise<Transaction> {
this.closeAccountRequestCounter.add(1, { appKey })
const accountInfo = await this.getAccountInfo(input.environment, input.index, input.account)
const accountInfo = await this.getAccountInfo(appKey, input.account)

try {
const tokenAccount = validateCloseAccount({
Expand All @@ -116,10 +118,7 @@ export class ApiAccountDataAccessService implements OnModuleInit {
ua,
})

const { blockhash, lastValidBlockHeight } = await this.transaction.getLatestBlockhash(
input.environment,
input.index,
)
const { blockhash, lastValidBlockHeight } = await this.transaction.getLatestBlockhash(appKey)

const signer = Keypair.fromSecret(mint.wallet?.secretKey)

Expand Down Expand Up @@ -152,8 +151,8 @@ export class ApiAccountDataAccessService implements OnModuleInit {
}
}

async getAccountInfo(environment: string, index: number, accountId: PublicKeyString) {
const solana = await this.solana.getConnection(environment, index)
async getAccountInfo(appKey: string, accountId: PublicKeyString) {
const solana = await this.solana.getConnection(appKey)
const account = getPublicKey(accountId)
const accountInfo = await solana.connection.getParsedAccountInfo(account)

Expand Down Expand Up @@ -183,7 +182,7 @@ export class ApiAccountDataAccessService implements OnModuleInit {
return result
}

const appEnv = await this.app.getAppConfig(environment, index)
const appEnv = await this.app.getAppConfig(appKey)
const mint = appEnv.mint

const tokenAccounts = await solana.getTokenAccounts(account, mint.publicKey)
Expand All @@ -207,48 +206,34 @@ export class ApiAccountDataAccessService implements OnModuleInit {
}
}

async getBalance(
environment: string,
index: number,
accountId: PublicKeyString,
commitment: Commitment,
): Promise<BalanceSummary> {
const solana = await this.solana.getConnection(environment, index)
const appEnv = await this.app.getAppConfig(environment, index)
async getBalance(appKey: string, accountId: PublicKeyString, commitment: Commitment): Promise<BalanceSummary> {
const solana = await this.solana.getConnection(appKey)
const appEnv = await this.app.getAppConfig(appKey)

const mints: BalanceMint[] = appEnv.mints.map(({ decimals, publicKey }) => ({ decimals, publicKey }))

return solana.getBalance(accountId, mints, commitment)
}

async getHistory(
environment: string,
index: number,
accountId: PublicKeyString,
mint?: PublicKeyString,
): Promise<HistoryResponse[]> {
const solana = await this.solana.getConnection(environment, index)
const appEnv = await this.app.getAppConfig(environment, index)
async getHistory(appKey: string, accountId: PublicKeyString, mint?: PublicKeyString): Promise<HistoryResponse[]> {
const solana = await this.solana.getConnection(appKey)
const appEnv = await this.app.getAppConfig(appKey)
mint = mint || appEnv.mint.publicKey

return solana.getTokenHistory(accountId, mint.toString())
}

async getTokenAccounts(
environment: string,
index: number,
accountId: PublicKeyString,
mint?: PublicKeyString,
): Promise<string[]> {
const solana = await this.solana.getConnection(environment, index)
const appEnv = await this.app.getAppConfig(environment, index)
async getTokenAccounts(appKey: string, accountId: PublicKeyString, mint?: PublicKeyString): Promise<string[]> {
const solana = await this.solana.getConnection(appKey)
const appEnv = await this.app.getAppConfig(appKey)
mint = mint || appEnv.mint.publicKey

return solana.getTokenAccounts(accountId, mint.toString())
}

async createAccount(req: Request, input: CreateAccountRequest): Promise<Transaction> {
const { appEnv, appKey } = await this.data.getAppEnvironment(input.environment, input.index)
const appKey = getAppKey(input.environment, input.index)
const appEnv = await this.data.getAppEnvironmentByAppKey(appKey)
this.createAccountRequestCounter.add(1, { appKey })

const { ip, ua } = this.transaction.validateRequest(appEnv, req)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
CreateAccountRequest,
HistoryResponse,
} from '@kin-kinetic/api/account/data-access'
import { PublicKeyPipe } from '@kin-kinetic/api/core/util'
import { getAppKey, PublicKeyPipe } from '@kin-kinetic/api/core/util'
import { Transaction } from '@kin-kinetic/api/transaction/data-access'
import { Commitment } from '@kin-kinetic/solana'
import { Body, Controller, Get, Param, ParseIntPipe, Post, Query, Req } from '@nestjs/common'
Expand Down Expand Up @@ -43,7 +43,7 @@ export class ApiAccountFeatureController {
@Param('index', ParseIntPipe) index: number,
@Param('accountId', new PublicKeyPipe('accountId')) accountId: string,
) {
return this.service.getAccountInfo(environment, index, accountId)
return this.service.getAccountInfo(getAppKey(environment, index), accountId)
}

@Get('balance/:environment/:index/:accountId')
Expand All @@ -57,7 +57,7 @@ export class ApiAccountFeatureController {
@Param('accountId', new PublicKeyPipe('accountId')) accountId: string,
@Query('commitment') commitment: Commitment,
) {
return this.service.getBalance(environment, index, accountId, commitment)
return this.service.getBalance(getAppKey(environment, index), accountId, commitment)
}

@Get('history/:environment/:index/:accountId/:mint')
Expand All @@ -70,7 +70,7 @@ export class ApiAccountFeatureController {
@Param('accountId', new PublicKeyPipe('accountId')) accountId: string,
@Param('mint', new PublicKeyPipe('mint')) mint: string,
) {
return this.service.getHistory(environment, index, accountId, mint)
return this.service.getHistory(getAppKey(environment, index), accountId, mint)
}

@Get('token-accounts/:environment/:index/:accountId/:mint')
Expand All @@ -83,6 +83,6 @@ export class ApiAccountFeatureController {
@Param('accountId', new PublicKeyPipe('accountId')) accountId: string,
@Param('mint', new PublicKeyPipe('mint')) mint: string,
) {
return this.service.getTokenAccounts(environment, index, accountId, mint)
return this.service.getTokenAccounts(getAppKey(environment, index), accountId, mint)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Airdrop } from '@kin-kinetic/api/airdrop/util'
import { ApiCoreDataAccessService } from '@kin-kinetic/api/core/data-access'
import { getAppKey } from '@kin-kinetic/api/core/util'
import { ApiSolanaDataAccessService } from '@kin-kinetic/api/solana/data-access'
import { Commitment } from '@kin-kinetic/solana'
import { BadRequestException, Injectable, Logger } from '@nestjs/common'
Expand All @@ -13,15 +14,15 @@ export class ApiAirdropDataAccessService {

constructor(private readonly data: ApiCoreDataAccessService, private readonly solana: ApiSolanaDataAccessService) {}

async requestAirdrop(request: RequestAirdropRequest): Promise<RequestAirdropResponse> {
const { environment, index } = request
const solana = await this.solana.getConnection(environment, index)
const appEnv = await this.data.getAppByEnvironmentIndex(environment, index)
async requestAirdrop(input: RequestAirdropRequest): Promise<RequestAirdropResponse> {
const appKey = getAppKey(input.environment, input.index)
const appEnv = await this.data.getAppEnvironmentByAppKey(appKey)
const solana = await this.solana.getConnection(appKey)

// Make sure the requested mint is enabled for this app
const appMint = appEnv.mints.find((mint) => mint.mint.address === request.mint)
const appMint = appEnv.mints.find((mint) => mint.mint.address === input.mint)
if (!appMint) {
throw new BadRequestException(`Can't find mint ${request.mint} in environment ${environment} for index ${index}`)
throw new BadRequestException(`Can't find mint ${input.mint} in app ${appKey}`)
}
const mint = appMint.mint

Expand All @@ -33,7 +34,7 @@ export class ApiAirdropDataAccessService {

// Make sure there is an Airdrop configured with a Solana connection
if (!this.airdrop.get(mint.id)) {
this.logger.verbose(`Creating airdrop for ${mint.symbol} (${mint.address}) on ${environment}`)
this.logger.verbose(`Creating airdrop for ${mint.symbol} (${mint.address}) in app ${appKey}`)
this.airdrop.set(
mint.id,
new Airdrop({
Expand All @@ -44,10 +45,10 @@ export class ApiAirdropDataAccessService {
}

try {
const commitment = request.commitment || Commitment.Confirmed
const account = request.account
const amount = request.amount ? request.amount : 1
this.logger.verbose(`Requesting airdrop: ${account} ${amount} ${mint.symbol} (${mint.address}) on ${environment}`)
const commitment = input.commitment || Commitment.Confirmed
const account = input.account
const amount = input.amount ? input.amount : 1
this.logger.verbose(`Requesting airdrop: ${account} ${amount} ${mint.symbol} (${mint.address}) in app ${appKey}`)
const result = await this.airdrop.get(mint.id).airdrop(account, amount, commitment)

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export class ApiAppDataAccessService implements OnModuleInit {
})
}

async getAppConfig(environment: string, index: number): Promise<AppConfig> {
const { appEnv, appKey } = await this.data.getAppEnvironment(environment, index)
async getAppConfig(appKey: string): Promise<AppConfig> {
const appEnv = await this.data.getAppEnvironmentByAppKey(appKey)
if (!appEnv) {
this.getAppConfigErrorCounter.add(1, { appKey })
throw new NotFoundException(`App not found :(`)
Expand Down Expand Up @@ -99,9 +99,9 @@ export class ApiAppDataAccessService implements OnModuleInit {
}
}

async getAppHealth(environment: string, index: number): Promise<AppHealth> {
async getAppHealth(appKey: string): Promise<AppHealth> {
const isKineticOk = true
const solana = await this.solana.getConnection(environment, index)
const solana = await this.solana.getConnection(appKey)

const isSolanaOk = await solana.healthCheck()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,6 @@ export class ApiAppEnvUserDataAccessService {
return this.data.deleteAppEnv(appId, appEnvId)
}

getAppKey(name: string, index: number) {
return this.data.getAppKey(name, index)
}

getEndpoint() {
return this.data.config.apiUrl?.replace('/api', '')
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ApiAppEnvUserDataAccessService, AppEnv, AppEnvStats } from '@kin-kinetic/api/app/data-access'
import { ApiAuthGraphqlGuard, CtxUser } from '@kin-kinetic/api/auth/data-access'
import { getAppKey } from '@kin-kinetic/api/core/util'
import { TransactionStatus } from '@kin-kinetic/api/transaction/data-access'
import { User } from '@kin-kinetic/api/user/data-access'
import { Wallet } from '@kin-kinetic/api/wallet/data-access'
import { TransactionStatus } from '@kin-kinetic/api/transaction/data-access'
import { UseGuards } from '@nestjs/common'
import { Args, Mutation, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql'

Expand Down Expand Up @@ -76,7 +77,7 @@ export class ApiAppEnvUserFeatureResolver {

@ResolveField(() => String, { nullable: true })
key(@Parent() appEnv: AppEnv) {
return this.service.getAppKey(appEnv?.name, appEnv?.app?.index)
return getAppKey(appEnv?.name, appEnv?.app?.index)
}

@ResolveField(() => [Wallet], { nullable: true })
Expand Down
5 changes: 3 additions & 2 deletions libs/api/app/feature/src/lib/api-app-feature.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ApiAppDataAccessService, AppConfig, AppHealth } from '@kin-kinetic/api/app/data-access'
import { getAppKey } from '@kin-kinetic/api/core/util'
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common'
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger'

Expand All @@ -12,14 +13,14 @@ export class ApiAppFeatureController {
@ApiParam({ name: 'index', type: 'integer' })
@ApiResponse({ type: AppConfig })
app(@Param('environment') environment: string, @Param('index', ParseIntPipe) index: number) {
return this.service.getAppConfig(environment, index)
return this.service.getAppConfig(getAppKey(environment, index))
}

@Get(':environment/:index/health')
@ApiOperation({ operationId: 'getAppHealth' })
@ApiParam({ name: 'index', type: 'integer' })
@ApiResponse({ type: AppHealth })
appHealth(@Param('environment') environment: string, @Param('index', ParseIntPipe) index: number) {
return this.service.getAppHealth(environment, index)
return this.service.getAppHealth(getAppKey(environment, index))
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ApiCoreDataAccessService } from '@kin-kinetic/api/core/data-access'
import { getAppKey } from '@kin-kinetic/api/core/util'
import { ApiSolanaDataAccessService } from '@kin-kinetic/api/solana/data-access'
import { Keypair } from '@kin-kinetic/keypair'
import { BadRequestException, Injectable, Logger } from '@nestjs/common'
Expand Down Expand Up @@ -77,7 +78,7 @@ export class ApiClusterAdminDataAccessService {
include: { app: true },
})
for (const env of envs) {
this.solana.deleteConnection(env.name, env.app.index)
this.solana.deleteConnection(getAppKey(env.name, env.app.index))
}
return updated
}
Expand Down
18 changes: 3 additions & 15 deletions libs/api/core/data-access/src/lib/api-core-data-access.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AirdropConfig } from '@kin-kinetic/api/airdrop/util'
import { hashPassword } from '@kin-kinetic/api/auth/util'
import { ProvisionedCluster } from '@kin-kinetic/api/cluster/util'
import { ApiConfigDataAccessService } from '@kin-kinetic/api/config/data-access'
import { parseAppKey } from '@kin-kinetic/api/core/util'
import { Keypair } from '@kin-kinetic/keypair'
import { getPublicKey } from '@kin-kinetic/solana'
import { Injectable, Logger, NotFoundException, OnModuleInit, UnauthorizedException } from '@nestjs/common'
Expand Down Expand Up @@ -164,17 +165,8 @@ export class ApiCoreDataAccessService extends PrismaClient implements OnModuleIn
})
}

async getAppEnvironment(environment: string, index: number): Promise<{ appEnv: AppEnvironment; appKey: string }> {
const appEnv = await this.getAppByEnvironmentIndex(environment, index)
const appKey = this.getAppKey(environment, index)
return {
appEnv,
appKey,
}
}

getAppByEnvironmentIndex(environment: string, index: number): Promise<AppEnvironment> {
const appKey = this.getAppKey(environment, index)
getAppEnvironmentByAppKey(appKey: string): Promise<AppEnvironment> {
const { environment, index } = parseAppKey(appKey)
this.getAppByEnvironmentIndexCounter?.add(1, { appKey })
return this.appEnv.findFirst({
where: { app: { index }, name: environment },
Expand Down Expand Up @@ -223,10 +215,6 @@ export class ApiCoreDataAccessService extends PrismaClient implements OnModuleIn
return this.appEnv.findUnique({ where: { id: appEnvId }, include: { app: true } })
}

getAppKey(environment: string, index: number): string {
return `app-${index}-${environment}`
}

async getUserByEmail(email: string) {
const found = await this.userEmail.findUnique({ where: { email } })

Expand Down
1 change: 1 addition & 0 deletions libs/api/core/util/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './lib/get-parse-app-key'
export * from './lib/open-telemetry-sdk'
export * from './lib/public-key.pipe'
14 changes: 14 additions & 0 deletions libs/api/core/util/src/lib/get-parse-app-key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const APP_KEY_PREFIX = 'app'

// We use the 'appKey' to identify a specific app in a specific environment.
// The appKey is a combination of the environment and the index of the app in that environment.
// The appKey is used to identify the app in the database and in the cache and internal API requests.
export function getAppKey(environment: string, index: number): string {
return `${APP_KEY_PREFIX}-${index}-${environment}`
}

export function parseAppKey(appKey: string): { environment: string; index: number } {
const [index, environment] = appKey.replace(`${APP_KEY_PREFIX}-`, '').split('-')

return { environment, index: Number(index) }
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ApiCoreDataAccessService } from '@kin-kinetic/api/core/data-access'
import { getAppKey } from '@kin-kinetic/api/core/util'
import { Injectable, Logger, NotFoundException } from '@nestjs/common'
import { AdminQueueLoadInput } from './dto/admin-queue-load.input'
import { JobStatus } from './entity/job-status.enum'
Expand Down Expand Up @@ -97,6 +98,7 @@ export class ApiQueueDataAccessService {
}

async loadAccountQueue({ environment, index, payload }: AdminQueueLoadInput) {
const appKey = getAppKey(environment, index)
const accounts = payload
.toString()
.split(/\r?\n/)
Expand All @@ -105,11 +107,8 @@ export class ApiQueueDataAccessService {

const uniqueAccounts = [...new Set(accounts)]

this.logger.debug(
`Loading ${uniqueAccounts.length} accounts into ${QueueType.CloseAccount} ${environment}-${index} queue`,
)

const { appEnv } = await this.data.getAppEnvironment(environment, index)
this.logger.debug(`Loading ${uniqueAccounts.length} accounts into ${QueueType.CloseAccount} queue in app ${appKey}`)
const appEnv = await this.data.getAppEnvironmentByAppKey(appKey)

// TODO: Add support for specifying which Mint accounts to close
// Currently, only the token account for the default Mint is closed
Expand Down
Loading

0 comments on commit 91d421f

Please sign in to comment.