From a7a4fb43ffa256636d9a2d8a710a95add6e09112 Mon Sep 17 00:00:00 2001 From: Joshua Aruokhai Date: Tue, 5 Nov 2024 14:24:20 +0100 Subject: [PATCH] added docker file and necessary utils for production environment --- .gitignore | 3 ++ config/config.template.yaml | 19 ++++++++ config/config.yaml | 20 -------- config/dev.config.yaml | 20 -------- dockerfile | 44 +++++++++++++++++ migrate.js | 47 +++++++++++++++++++ migrations/001_create_transaction_table.sql | 8 ++++ .../002_create_operation_state_table.sql | 4 ++ 8 files changed, 125 insertions(+), 40 deletions(-) create mode 100644 config/config.template.yaml delete mode 100644 config/config.yaml delete mode 100644 config/dev.config.yaml create mode 100644 dockerfile create mode 100644 migrate.js create mode 100644 migrations/001_create_transaction_table.sql create mode 100644 migrations/002_create_operation_state_table.sql diff --git a/.gitignore b/.gitignore index 5cba756..cc57d48 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ lerna-debug.log* #e2e /e2e/.logs + +#dev +/config/dev.config.yaml diff --git a/config/config.template.yaml b/config/config.template.yaml new file mode 100644 index 0000000..ce60b36 --- /dev/null +++ b/config/config.template.yaml @@ -0,0 +1,19 @@ +db: + path: ${SQLITE_PATH} + synchronize: false +app: + port: ${PORT} + network: ${NETWORK} + requestRetry: + delay: ${DELAY} # delay in Milliseconds + count: ${COUNT} +providerType: ${PROVIDER_TYPE} +esplora: + url: ${HOST} + batchSize: ${BATCH_SIZE} +bitcoinCore: + protocol: ${PROTOCOL} # http | https + rpcHost: ${RPC_HOST} + rpcPass: ${RPC_PASS} + rpcUser: ${RPC_USER} + rpcPort: ${RPC_PORT} \ No newline at end of file diff --git a/config/config.yaml b/config/config.yaml deleted file mode 100644 index 81fd494..0000000 --- a/config/config.yaml +++ /dev/null @@ -1,20 +0,0 @@ -db: - path: ~/.silent-pay-indexer/db/database.sqlite - synchronize: false -app: - port: - network: - requestRetry: - delay: # delay in Milliseconds - count: -providerType: -esplora: - url: - batchSize: -bitcoinCore: - protocol: - rpcHost: - rpcPass: - rpcUser: - rpcPort: - diff --git a/config/dev.config.yaml b/config/dev.config.yaml deleted file mode 100644 index ccc87f8..0000000 --- a/config/dev.config.yaml +++ /dev/null @@ -1,20 +0,0 @@ -db: - path: ./.silent-pay-indexer/db/database.sqlite - synchronize: true -app: - port: 3000 - network: regtest - requestRetry: - delay: 3000 - count: 3 -providerType: ESPLORA -esplora: - url: https://blockstream.info - batchSize: 5 -bitcoinCore: - protocol: http - rpcHost: 127.0.0.1 - rpcPass: polarpass - rpcUser: polaruser - rpcPort: 18445 - diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..76c3065 --- /dev/null +++ b/dockerfile @@ -0,0 +1,44 @@ +# Stage 1: Build the NestJS application +FROM node:18-alpine AS builder + +# Set the working directory in the container +WORKDIR /app + +# Copy package.json and package-lock.json for efficient layer caching +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application code +COPY . . + +# Build the application +RUN npm run build + +# Stage 2: Production image +FROM node:18-alpine AS production + +#Set the working directory in the container +WORKDIR /app + +# Generate config.yml by replacing placeholders in config.yml.template +RUN apk add --no-cache gettext + +#Copy the compiled application from the build stage +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/migrations ./migrations +COPY --from=builder /app/migrate.js ./migrate.js + +#Copy package.json and install only production dependencies +COPY package.json ./ +RUN npm install --only=production + +# Set environment variables for SQLite path and app port +ENV SQLITE_PATH="/app/.silent-pay-indexer/db/database.sqlite" +ENV APP_PORT="3000" + +EXPOSE $APP_PORT + +# Set up entrypoint to handle database migration and config generation +ENTRYPOINT ["sh", "-c", "node migrate.js && envsubst < dist/config/config.template.yaml > dist/config/config.yaml && node dist/main.js"] diff --git a/migrate.js b/migrate.js new file mode 100644 index 0000000..e1dbec6 --- /dev/null +++ b/migrate.js @@ -0,0 +1,47 @@ +/* eslint-disable no-console */ +/* eslint-disable @typescript-eslint/no-var-requires */ +const sqlite3 = require('sqlite3').verbose(); +const fs = require('fs'); +const path = require('path'); + +// Set the database directory and file path +const dbPath = process.env.SQLITE_PATH; +const dbDir = path.dirname(dbPath); + +// Ensure the database directory exists, creating it if necessary +if (!fs.existsSync(dbDir)) { + fs.mkdirSync(dbDir, { recursive: true }); +} + +const db = new sqlite3.Database(dbPath); + +// Function to run migrations +async function runMigrations() { + const migrationsDir = path.join(__dirname, 'migrations'); + + // Read migration files in sorted order + const files = fs.readdirSync(migrationsDir).sort(); + + for (const file of files) { + const filePath = path.join(migrationsDir, file); + const sql = fs.readFileSync(filePath, 'utf-8'); + console.log(`Running migration: ${file}`); + + // Execute each SQL file + await new Promise((resolve, reject) => { + db.exec(sql, (err) => { + if (err) reject(err); + else resolve(); + }); + }); + } + console.log('All migrations applied.'); +} + +// Run migrations, then close the database connection +runMigrations() + .then(() => db.close()) + .catch((err) => { + console.error('Migration failed:', err); + db.close(); + }); diff --git a/migrations/001_create_transaction_table.sql b/migrations/001_create_transaction_table.sql new file mode 100644 index 0000000..2f90220 --- /dev/null +++ b/migrations/001_create_transaction_table.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS "transaction" ( + id TEXT PRIMARY KEY, + blockHeight INTEGER NOT NULL, + blockHash TEXT NOT NULL, + scanTweak TEXT NOT NULL, + outputs TEXT NOT NULL, + isSpent BOOLEAN NOT NULL +); \ No newline at end of file diff --git a/migrations/002_create_operation_state_table.sql b/migrations/002_create_operation_state_table.sql new file mode 100644 index 0000000..d94123c --- /dev/null +++ b/migrations/002_create_operation_state_table.sql @@ -0,0 +1,4 @@ +CREATE TABLE IF NOT EXISTS "operation_state" ( + id TEXT PRIMARY KEY, + state TEXT +); \ No newline at end of file