From 1a411f78db771284a16d7b2338ea6797b2d9cfbd Mon Sep 17 00:00:00 2001 From: Dhruv Baliyan Date: Thu, 5 Dec 2024 09:47:57 +0530 Subject: [PATCH 1/2] feat: fix setup script --- .env.sample | 1 + setup.sh | 41 ++++++++++++++++++-- src/main.ts | 6 +-- src/modules/georev/georev.controller.spec.ts | 4 +- src/modules/georev/georev.controller.ts | 4 +- 5 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 .env.sample diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..f7c85ff --- /dev/null +++ b/.env.sample @@ -0,0 +1 @@ +DATABASE_URL=postgresql://admin:password@192.168.1.43:5555/gis \ No newline at end of file diff --git a/setup.sh b/setup.sh index 49657a3..b2a711b 100755 --- a/setup.sh +++ b/setup.sh @@ -1,7 +1,40 @@ mkdir ./src/geojson-data +is_wget2_installed() { + if command -v wget2 &> /dev/null; then + return 0 # wget2 is installed + else + return 1 # wget2 is not installed + fi +} + +if is_wget2_installed; then + echo "wget2 is already installed." +else + # Check if the OS is macOS or Linux + if [[ "$(uname)" == "Darwin" ]]; then + echo "macOS detected. Installing wget2 using Homebrew..." + # Check if Homebrew is installed, if not install it + if ! command -v brew &> /dev/null; then + echo "Homebrew not found. Installing Homebrew..." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + fi + # Install wget2 using Homebrew + brew install wget + elif [[ "$(uname)" == "Linux" ]]; then + echo "Linux detected. Installing wget2 using apt..." + # Update package list and install wget2 using apt + sudo apt update + sudo apt install wget2 -y + else + echo "Unsupported OS detected." + exit 1 + fi +fi + +# curl -o ./db.mmdb -L --fail --compressed https://mmdbcdn.posthog.net # getting the latest db.mmdb -curl -o ./db.mmdb -L --fail --compressed https://mmdbcdn.posthog.net +wget2 -O db.mmdb https://mmdbcdn.posthog.net cd ./src @@ -45,6 +78,6 @@ cd ../.. # Updating geoJSON files through script to make them usable in src cd ./scripts npx ts-node parse.geojson.ts - -# Changing PWD back to /server/ -cd - &> /dev/null +npx ts-node ingestors/state.geojson.ts +npx ts-node ingestors/district.geojson.ts +npx ts-node ingestors/subdistrict.geojson.ts \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index b807fa0..10cc06e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -22,8 +22,6 @@ async function bootstrap() { const logger = new Logger('Main'); // 'Main' is the context name const configService = app.get(ConfigService); - const port = configService.get('port'); - const host = configService.get('host'); // Register plugins and middleware await app.register(multipart); @@ -44,8 +42,8 @@ async function bootstrap() { SwaggerModule.setup('api-docs', app, document); // Start the server - await app.listen(port, host, (err, address) => { - logger.log(`Server running on ${host}:${port}`); + await app.listen(3000, '0.0.0.0', (err, address) => { + logger.log(`Server running on 0.0.0.0:3000`); }); // Log additional information as needed diff --git a/src/modules/georev/georev.controller.spec.ts b/src/modules/georev/georev.controller.spec.ts index ef8bf2e..1e52a9a 100644 --- a/src/modules/georev/georev.controller.spec.ts +++ b/src/modules/georev/georev.controller.spec.ts @@ -80,7 +80,7 @@ describe('GeorevController', () => { const result = await controller.getGeoRev(lat, lon); } catch (error) { expect(error).toBeInstanceOf(HttpException); - expect(error.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR); + expect(error.getStatus()).toBe(HttpStatus.BAD_REQUEST); expect(error.getResponse()).toEqual({ status: 'fail', error: 'lat lon query missing', @@ -98,7 +98,7 @@ describe('GeorevController', () => { } catch (error) { expect(error).toBeInstanceOf(HttpException); - expect(error.getStatus()).toBe(HttpStatus.INTERNAL_SERVER_ERROR); + expect(error.getStatus()).toBe(HttpStatus.BAD_REQUEST); expect(error.getResponse()).toEqual({ status: 'fail', error: 'Invalid latitude or longitude', diff --git a/src/modules/georev/georev.controller.ts b/src/modules/georev/georev.controller.ts index 076ff08..e61c2ca 100644 --- a/src/modules/georev/georev.controller.ts +++ b/src/modules/georev/georev.controller.ts @@ -25,7 +25,7 @@ export class GeorevController { this.logger.error(`lat lon query missing`); throw new HttpException( { status: 'fail', error: `lat lon query missing` }, - HttpStatus.INTERNAL_SERVER_ERROR, + HttpStatus.BAD_REQUEST, ); } @@ -33,7 +33,7 @@ export class GeorevController { this.logger.error('Invalid latitude or longitude'); throw new HttpException( { 'status': 'fail', 'error': 'Invalid latitude or longitude' }, - HttpStatus.INTERNAL_SERVER_ERROR, + HttpStatus.BAD_REQUEST, ); } From e87d8834f8cafd1db279d69423c68ed215610110 Mon Sep 17 00:00:00 2001 From: Dhruv Baliyan Date: Thu, 5 Dec 2024 14:37:54 +0530 Subject: [PATCH 2/2] fix: docker image fix --- Dockerfile | 98 +++++++++--------------------- docker-compose.yaml | 77 ++--------------------- package.json | 9 ++- setup.sh | 5 +- src/modules/place/place.service.ts | 26 +++++--- 5 files changed, 60 insertions(+), 155 deletions(-) diff --git a/Dockerfile b/Dockerfile index 802aaab..9e86d54 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,79 +1,37 @@ -#FROM node:18.16.1-alpine -# -#COPY setup.sh -# -#RUN apk add --no-cache bash -#RUN npm i -g @nestjs/cli typescript ts-node -# -#COPY package*.json /tmp/app/ -#RUN cd /tmp/app && npm install -# -#COPY . /usr/src/app -#RUN cp -a /tmp/app/node_modules /usr/src/app -#COPY ./wait-for-it.sh /opt/wait-for-it.sh -#COPY ./startup.dev.sh /opt/startup.dev.sh -#RUN sed -i 's/ -#//g' /opt/wait-for-it.sh -#RUN sed -i 's/ -#//g' /opt/startup.dev.sh -# -#WORKDIR /usr/src/app -#RUN cp env-example .env -#RUN npx prisma generate -#RUN npm run build -# -#CMD ["/opt/startup.dev.sh"] -# -#EXPOSE 3000 +FROM node:18-slim as base +RUN apt-get update -y && apt-get install -y openssl - -#FROM node:18.16.1-alpine -# -#WORKDIR /usr/src/app -# -#COPY . . -# -#RUN apt-get update && apt-get install -y curl && apt-get install -y git -#CMD /bin/bash -#COPY ./package*.json ./ -#RUN ./setup.sh -# -#ENV NODE_ENV production -#CMD ["npm", "i"] -#CMD [ "npm", "run", "start:dev" ] -# -#EXPOSE 3000 - - -FROM node:20.11.0-alpine - -# Set the working directory -WORKDIR /usr/src/app - -# Install curl and git using apk -RUN apk update && apk add --no-cache curl git - -RUN #npm config set registry http://registry.npmjs.org/ - -# Copy package files first for better caching of npm install -COPY ./package*.json ./ - -# Install dependencies +FROM base AS install +WORKDIR /app +COPY package*.json ./ RUN npm install -# Copy the rest of the application code +FROM base as build +WORKDIR /app +COPY prisma ./prisma/ +COPY --from=install /app/node_modules ./node_modules +RUN npx prisma generate COPY . . +RUN npm run build -# Convert setup.sh to Unix-style line endings (LF) +FROM base as data +WORKDIR /app +COPY --from=install /app/node_modules ./node_modules +COPY . . RUN sed -i 's/\r$//' ./setup.sh - - -# Run any additional setup script RUN chmod +x ./setup.sh RUN ./setup.sh -# Set environment variable -ENV NODE_ENV production - -# Start the application -CMD ["npm", "run", "start:dev"] +FROM base +WORKDIR /app +COPY --from=build /app/node_modules ./node_modules +COPY --from=build /app/dist ./dist +COPY --from=build /app/package*.json ./ +COPY --from=build /app/prisma ./prisma +COPY --from=data /app/db.mmdb ./db.mmdb +COPY --from=data /app/src/geojson-data ./src/geojson-data +COPY ./src ./src +COPY tsconfig.json ./tsconfig.json +EXPOSE 3000 + +CMD ["npm", "run", "migrate:ingest:start:prod"] \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index fe27d15..ba075fe 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,74 +1,9 @@ services: - fusionauth: - image: fusionauth/fusionauth-app:latest - depends_on: - postgres: - condition: service_healthy - environment: - DATABASE_URL: jdbc:postgresql://postgres:5432/fusionauth - DATABASE_ROOT_USERNAME: ${POSTGRES_USER} - DATABASE_ROOT_PASSWORD: ${POSTGRES_PASSWORD} - DATABASE_USERNAME: ${DATABASE_USERNAME} - DATABASE_PASSWORD: ${DATABASE_PASSWORD} - FUSIONAUTH_APP_MEMORY: ${FUSIONAUTH_APP_MEMORY} - FUSIONAUTH_APP_RUNTIME_MODE: ${FUSIONAUTH_APP_RUNTIME_MODE} - FUSIONAUTH_APP_URL: http://fusionauth:9011 - FUSIONAUTH_APP_KICKSTART_FILE: /usr/local/fusionauth/kickstarts/kickstart.json - env_file: - - ./env-example - volumes: - - fa-config:/usr/local/fusionauth/config - - ./kickstart:/usr/local/fusionauth/kickstarts - networks: - - default - restart: unless-stopped - ports: - - 9011:9011 - - postgres: - image: postgres:15.3-alpine + geoquery: + build: + context: . + dockerfile: Dockerfile ports: - - ${DATABASE_PORT}:5432 - volumes: - - ./.data/db:/var/lib/postgresql/data + - "3000:3000" environment: - POSTGRES_USER: ${DATABASE_USERNAME} - POSTGRES_PASSWORD: ${DATABASE_PASSWORD} - POSTGRES_DB: ${DATABASE_NAME} - healthcheck: - test: ['CMD-SHELL', 'pg_isready -U postgres'] - interval: 5s - timeout: 5s - retries: 5 - - shadow-postgres: - image: postgres:15.3-alpine - ports: - - ${SHADOW_DATABASE_PORT}:5432 - volumes: - - ./.data/shadow-db:/var/lib/postgresql/data - environment: - POSTGRES_USER: ${SHADOW_DATABASE_USERNAME} - POSTGRES_PASSWORD: ${SHADOW_DATABASE_PASSWORD} - POSTGRES_DB: ${SHADOW_DATABASE_NAME} - - cache: - image: redis:6.2-alpine - restart: always - ports: - - '${CACHE_PORT}:6379' - command: redis-server --save 20 1 - volumes: - - cache:/data - - # api: - # build: - # context: . - # dockerfile: Dockerfile - # ports: - # - 3000:3000 -volumes: - fa-config: - cache: -networks: - default: + DATABASE_URL: postgresql://admin:password@192.168.1.43:5555/gis \ No newline at end of file diff --git a/package.json b/package.json index 568eeae..b54407a 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "start:dev": "stencil start --watch", "start:debug": "stencil start --debug --watch", "start:prod": "NODE_ENV=production node dist/main", + "migrate:ingest:start:prod": "npx ts-node src/scripts/ingestors/state.geojson.ts && npx ts-node src/scripts/ingestors/district.geojson.ts && npx ts-node src/scripts/ingestors/subdistrict.geojson.ts && npm run migrate:start:prod", + "migrate:start:prod": "npx prisma migrate deploy && npm run start:prod", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "test": "jest", "test:watch": "jest --watch", @@ -41,7 +43,12 @@ "multer": "^1.4.5-lts.1", "reflect-metadata": "^0.1.13", "request-ip": "^3.3.0", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.1.3" }, "devDependencies": { "@nestjs/testing": "^10.0.0", diff --git a/setup.sh b/setup.sh index b2a711b..5678fd1 100755 --- a/setup.sh +++ b/setup.sh @@ -77,7 +77,4 @@ cd ../.. # Updating geoJSON files through script to make them usable in src cd ./scripts -npx ts-node parse.geojson.ts -npx ts-node ingestors/state.geojson.ts -npx ts-node ingestors/district.geojson.ts -npx ts-node ingestors/subdistrict.geojson.ts \ No newline at end of file +npx ts-node parse.geojson.ts \ No newline at end of file diff --git a/src/modules/place/place.service.ts b/src/modules/place/place.service.ts index 229c728..a3d03d9 100644 --- a/src/modules/place/place.service.ts +++ b/src/modules/place/place.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from "@nestjs/common"; +import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common"; import { CreatePlaceDto, SearchPlaceDto } from "./dto/place.dto"; import { PrismaService } from "../prisma/prisma.service"; @@ -12,12 +12,16 @@ export class PlaceService { const { name, type, tag, lat, lon } = createPlaceDto; const point = `ST_SetSRID(ST_MakePoint(${lon}, ${lat}), 4326)`; this.logger.debug(`Adding place ${createPlaceDto}`) - return this.prisma.$executeRawUnsafe( - `INSERT INTO "Place" (name, type, tag, location) VALUES ($1, $2, $3, ${point})`, - name, - type, - tag, - ); + try { + return this.prisma.$executeRawUnsafe( + `INSERT INTO "Place" (name, type, tag, location) VALUES ($1, $2, $3, ${point})`, + name, + type, + tag, + ); + } catch (error) { + throw new HttpException('Error adding places', HttpStatus.INTERNAL_SERVER_ERROR); + } } async searchPlaces(searchPlaceDto: SearchPlaceDto): Promise { @@ -46,7 +50,11 @@ export class PlaceService { query += ` AND type ILIKE '%${type}%'`; } - // Execute the query - return this.prisma.$queryRawUnsafe(query); + try { + // Execute the query + return this.prisma.$queryRawUnsafe(query); + } catch (error) { + throw new HttpException('Error querying database', HttpStatus.INTERNAL_SERVER_ERROR); + } } }