UNPKG

skeet

Version:

Full-stack TypeScript Serverless Framework

252 lines (230 loc) 8.13 kB
import fs from 'fs' import { createHash } from 'crypto' import { execSync } from 'child_process' import { workerPluginList } from '@/types/skeetTypes' import { skeetWorkerPluginList } from './workerPluginList' export const KEYFILE_PATH = './keyfile.json' export const GRAPHQL_PATH = './apps/api/src/graphql' export const PRISMA_SCHEMA_PATH = './apps/api/prisma/schema.prisma' export const API_PATH = './apps/api' export const API_TYPE_PATH = API_PATH + '/src/types' export const API_ENV_PRODUCTION_PATH = './apps/api/.env.production' export const API_ENV_BUILD_PATH = './apps/api/.env.build' export const WORKER_PATH = './apps/workers' export const SKEET_CONFIG_PATH = './skeet-cloud.config.json' export const ROUTE_PACKAGE_JSON_PATH = './package.json' export const API_REPO_URL = 'https://github.com/elsoul/skeet-api' export const WORKER_REPO_URL = 'https://github.com/elsoul/skeet-worker' export const WORKER_SOLANA_TRANSFER_REPO_URL = 'https://github.com/elsoul/skeet-worker-solana-transfer' export const ENUM_FILE_PATH = './apps/api/src/graphql' export const FRONT_APP_REPO_URL = 'https://github.com/elsoul/skeet-app-template' export const FRONT_APP_PATH = './apps/app' export enum WorkerPlugins { SOLANA_TRANSFER = 'solana-transfer', ORCA_SWAP = 'orca-swap', JUPITER_SWAP = 'jupiter-swap', } export const isWorkerPlugin = async (workerName: string) => { if (!Object.values(WorkerPlugins)?.includes(workerName as WorkerPlugins)) { return false } return true } export const getPluginData = async (pluginName: string) => { try { const plugin = skeetWorkerPluginList.filter( (value) => value.name === pluginName ) if (plugin.length === 0) return { id: 0, name: '', port: 0 } return plugin[0] } catch (error) { console.log(`getPluginData: ${error}`) return { id: 0, name: '', port: 0 } } } export const getWorkerEnvPath = async (workerName: string) => { return `${WORKER_PATH}/${workerName}/.env` } export const getWorkerName = async (appName: string, workerName: string) => { return `skeet-${appName}-worker-${workerName}` } export const getWorkerEnvName = async (workerName: string) => { const str = await getEnvString(`${workerName}_WORKER_URL`) return str } export const getEnvString = async (str: string) => { const output = str .replace(/-/g, '_') .replace(/([a-z])([A-Z])/g, '$1_$2') .toUpperCase() return output } export const genSecret = async (name: string) => { return createHash('sha256').update(name).digest('hex') } export const defaultProductionEnvArray = [ 'NO_PEER_DEPENDENCY_CHECK=1', 'DATABASE_URL=postgresql://postgres:${{ secrets.SKEET_GCP_DB_PASSWORD }}@${{ secrets.SKEET_GCP_DB_PRIVATE_IP }}:5432/skeet-${{ secrets.SKEET_APP_NAME }}-production?schema=public', 'SKEET_JWT_SALT=${{ secrets.SKEET_JWT_SALT }}', 'SKEET_BASE_URL=${{ secrets.SKEET_BASE_URL }}', 'SKEET_CRYPTO_SALT=${{ secrets.SKEET_CRYPTO_SALT }}', 'SKEET_PW_SALT=${{ secrets.SKEET_PW_SALT }}', 'SKEET_GCP_PROJECT_ID=${{ secrets.SKEET_GCP_PROJECT_ID }}', 'SKEET_GCP_TASK_REGION=${{ secrets.SKEET_GCP_TASK_REGION }}', 'GOOGLE_CLOUD_PROJECT=${{ secrets.SKEET_FB_PROJECT_ID }}', 'SKEET_API_ENDPOINT_URL=${{ secrets.SKEET_API_ENDPOINT_URL }}', 'TZ=${{ secrets.TZ }}', ] export const getBuidEnvArray = async ( projectId: string, fbProjectId: string, databaseUrl: string, tz: string ) => { return [ 'NO_PEER_DEPENDENCY_CHECK=1', `SKEET_GCP_PROJECT_ID=${projectId}`, `SKEET_FB_PROJECT_ID=${fbProjectId}`, `TZ=${tz}`, `DATABASE_URL=${databaseUrl}`, ] } export const getActionsEnvString = async (filePath: string) => { const stream = fs.readFileSync(filePath) const envArray: Array<string> = String(stream).split('\n') let newEnv: Array<string> = [] for await (const envLine of envArray) { let keyAndValue = envLine.match(/([A-Z_]+)="?([^"]*)"?/) if (keyAndValue) { if (keyAndValue[1].match('SKEET_')) continue if (keyAndValue[1] === 'TZ') continue const envString = `${keyAndValue[1]}=$` + '{{ ' + `secrets.${keyAndValue[1]}` + ' }}' newEnv.push(envString) } } const returnArray = defaultProductionEnvArray.concat(newEnv) return returnArray.join(',') } export const getBuidEnvString = async () => { const stream = fs.readFileSync(API_ENV_PRODUCTION_PATH) const envArray: Array<string> = String(stream).split('\n') let hash: { [key: string]: string } = {} for await (const line of envArray) { const value = line.split('=') hash[value[0]] = value[1] } const dabaseUrl = `postgresql://postgres:${hash['SKEET_GCP_DB_PASSWORD']}@${hash['SKEET_GCP_DB_PRIVATE_IP']}:5432/skeet-${hash['SKEET_APP_NAME']}-production?schema=public` const buildEnvArray = await getBuidEnvArray( hash['SKEET_GCP_PROJECT_ID'], hash['GOOGLE_CLOUD_PROJECT'], dabaseUrl, hash['TZ'] ) const newEnv = envArray.filter((value) => { if ( !value.match('SKEET_GCP_PROJECT_ID') && !value.match('SKEET_GCP_DB_PASSWORD') ) { return value } }) const returnArray = buildEnvArray.concat(newEnv) return returnArray.join(',') } export const getNetworkConfig = async (projectId: string, appName: string) => { const skeetHeader = 'skeet-' + appName return { projectId, appName, cloudRunName: `skeet-${appName}-api`, instanceName: skeetHeader + '-db', networkName: skeetHeader + '-network', firewallTcpName: skeetHeader + '-fw-tcp', firewallSshName: skeetHeader + '-fw-ssh', natName: skeetHeader + '-nat', routerName: skeetHeader + '-router', subnetName: skeetHeader + '-subnet', connectorName: appName + '-con', ipName: skeetHeader + '-external-ip', loadBalancerIpName: skeetHeader + '-lb-ip', ipRangeName: skeetHeader + '-ip-range', serviceAccountName: `${appName}@${projectId}.iam.gserviceaccount.com`, networkEndpointGroupName: `${skeetHeader}-neg`, backendServiceName: `${skeetHeader}-bs`, loadBalancerName: `${skeetHeader}-lb`, sslName: `${skeetHeader}-ssl`, proxyName: `${skeetHeader}-px`, forwardingRuleName: `${skeetHeader}-fr`, zoneName: `${skeetHeader}-zone`, securityPolicyName: `${skeetHeader}-armor`, } } export const getContainerImageUrl = async ( projectId: string, appName: string, region: string, workerName: string = '', isPlugin: boolean = false ) => { const cRegion = await getContainerRegion(region) let imageName = '' if (workerName !== '' && isPlugin) { imageName = 'skeet-worker-' + workerName } else if (workerName !== '') { imageName = 'skeet-' + appName + '-worker-' + workerName } else { imageName = 'skeet-' + appName + '-api' } let containerProjectName = isPlugin ? 'skeet-framework' : projectId return cRegion + '/' + containerProjectName + '/' + imageName + ':latest' } export const getContainerImageName = async ( appName: string, workerName: string = '' ) => { const imageName = workerName !== '' ? 'skeet-' + appName + '-worker-' + workerName : 'skeet-' + appName + '-api' return imageName } export const getContainerRegion = async (region: string) => { switch (region) { case region.match('asia')?.input: return 'asia.gcr.io' case region.match('eu')?.input: return 'eu.gcr.io' default: return 'gcr.io' } } export const regionToTimezone = async (region: string) => { switch (true) { case region.includes('asia'): return 'Asia/Tokyo' case region.includes('europe'): return 'Europe/Amsterdam' default: return 'America/Los_Angeles' } } export const getRunUrl = async ( projectId: string, appName: string, workerName: string = '' ) => { try { const runName = workerName !== '' ? await getWorkerName(appName, workerName) : (await getNetworkConfig(projectId, appName)).cloudRunName console.log(runName) const cmd = `gcloud run services list --project=${projectId} | grep ${runName} | awk '{print $4}'` const res = String(execSync(cmd)).replace(/\r?\n/g, '') return res } catch (error) { return '' } }