From b46c48fdb220e89d3e1de4c1690f73610c450acb Mon Sep 17 00:00:00 2001 From: rodg <41761494+rodg@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:54:17 -0500 Subject: [PATCH 1/8] this somewhat works --- api/.dockerignore | 4 ++++ api/Containerfile | 16 +++++++++++++++ api/start.sh | 7 +++++++ docker-compose.yaml | 48 +++++++++++++++++++++++++++++++++++++++++++++ web/.dockerignore | 4 ++++ web/Containerfile | 13 ++++++++++++ 6 files changed, 92 insertions(+) create mode 100644 api/.dockerignore create mode 100644 api/Containerfile create mode 100644 api/start.sh create mode 100644 docker-compose.yaml create mode 100644 web/.dockerignore create mode 100644 web/Containerfile diff --git a/api/.dockerignore b/api/.dockerignore new file mode 100644 index 00000000..a67d3628 --- /dev/null +++ b/api/.dockerignore @@ -0,0 +1,4 @@ +*.log +*.db +node_modules/* +build/* \ No newline at end of file diff --git a/api/Containerfile b/api/Containerfile new file mode 100644 index 00000000..2bd9d765 --- /dev/null +++ b/api/Containerfile @@ -0,0 +1,16 @@ +FROM node:20 + +WORKDIR /api + +COPY tsconfig.json package.json package-lock.json ./ +COPY ./prisma ./prisma +COPY .eslintrc ./ +COPY .prettierignore ./ + +RUN npm i && npm i -g tsx + + +COPY ./src ./src +COPY start.sh ./ + +CMD [ "bash", "start.sh" ] \ No newline at end of file diff --git a/api/start.sh b/api/start.sh new file mode 100644 index 00000000..ac028833 --- /dev/null +++ b/api/start.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +npx prisma migrate dev + +tsx prisma/seed.ts + +npm run dev \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..0f695d2d --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,48 @@ +version: "3.9" + +services: + api: + build: + context: ./api + dockerfile: Containerfile + container_name: api + ports: + - "8000:8000" # Map container port to host port + environment: + ROOM_TOKEN_SECRET: your-room-token-secret + SESSION_SECRET: your-session-secret + CLIENT_URL: http://web:3000 # Assuming the Web service runs on this URL + DATABASE_URL: postgres://devuser:devpassword@database:5432/devdb + # SMTP_HOST: your-smtp-host + # SMTP_USER: your-email-address + # SMTP_PASSWORD: your-email-password + PORT: 8000 + depends_on: + - database # Optional if you have a database container defined separately + + web: + build: + context: ./web + dockerfile: Containerfile + container_name: web + ports: + - "3000:3000" # Map container port to host port + environment: + NEXT_PUBLIC_API_PATH: http://api:8000 # Assuming the API service runs on this URL + depends_on: + - api + + database: + image: postgres:latest + container_name: database + ports: + - "5432:5432" + environment: + POSTGRES_USER: devuser + POSTGRES_PASSWORD: devpassword + POSTGRES_DB: devdb + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: diff --git a/web/.dockerignore b/web/.dockerignore new file mode 100644 index 00000000..a67d3628 --- /dev/null +++ b/web/.dockerignore @@ -0,0 +1,4 @@ +*.log +*.db +node_modules/* +build/* \ No newline at end of file diff --git a/web/Containerfile b/web/Containerfile new file mode 100644 index 00000000..f797cb7f --- /dev/null +++ b/web/Containerfile @@ -0,0 +1,13 @@ +FROM node:20 + +WORKDIR /web + +COPY tsconfig.json package.json package-lock.json ./ +COPY ./public ./public +COPY .eslintrc.json .prettierignore next.config.js ./ + +RUN npm i + +COPY ./src ./src + +CMD [ "npm", "run", "dev" ] \ No newline at end of file From b6d3acfc69dd4dfad979a848b75eebc03d6d750e Mon Sep 17 00:00:00 2001 From: rodg <41761494+rodg@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:54:28 -0500 Subject: [PATCH 2/8] i might remove this --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..18561c07 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +build-api: + cd api && docker build -t bingo-api:local -f Containerfile . + +build-web: + cd web && docker build -t bingo-web:local -f Containerfile . \ No newline at end of file From 4ab6799e22854fe36c864e3c4be9c8a7e58f9324 Mon Sep 17 00:00:00 2001 From: rodg <41761494+rodg@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:36:43 -0500 Subject: [PATCH 3/8] add some checks on startup --- api/prisma/ready.ts | 38 ++++++++++++++++++++++++++++++++++++++ api/prisma/seed.ts | 11 ++++++++--- api/start.sh | 3 +++ 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 api/prisma/ready.ts diff --git a/api/prisma/ready.ts b/api/prisma/ready.ts new file mode 100644 index 00000000..858c8f72 --- /dev/null +++ b/api/prisma/ready.ts @@ -0,0 +1,38 @@ +import { PrismaClient } from "@prisma/client"; +import { exec } from "child_process"; +import util from "util"; + +const prisma = new PrismaClient(); +const execAsync = util.promisify(exec); + +const waitForDatabase = async (retries: number = 5, delay: number = 2000) => { + for (let i = 0; i < retries; i++) { + try { + await prisma.$connect(); + console.log("Database is up!"); + return; + } catch { + console.log(`Attempt ${i + 1} failed. Retrying in ${delay / 1000}s...`); + await new Promise(res => setTimeout(res, delay)); + } + } + throw new Error("Database is not reachable after retries."); +}; + +const checkDatabaseAndMigrate = async () => { + try { + await waitForDatabase(); + console.log("Running Prisma migrations..."); + const { stdout, stderr } = await execAsync("npx prisma migrate dev"); + console.log(stdout); + if (stderr) console.error(stderr); + console.log("Migrations applied successfully."); + } catch (error: any) { + console.error("Error:", error.message); + process.exit(1); + } finally { + await prisma.$disconnect(); + } +}; + +checkDatabaseAndMigrate(); diff --git a/api/prisma/seed.ts b/api/prisma/seed.ts index 88f6f5fc..6538b4c6 100644 --- a/api/prisma/seed.ts +++ b/api/prisma/seed.ts @@ -6,6 +6,12 @@ const prisma = new PrismaClient(); async function main() { console.log('Seeding database'); + const users = await prisma.user.findMany() + if (users.length != 0) { + console.log('Database already has some users, skipping seeding') + return + } + console.log('Creating users'); await prisma.user.deleteMany(); const salt = randomBytes(16); @@ -338,9 +344,8 @@ async function main() { }, ...Array.from({ length: 54 }).map((_, i) => ({ goal: `Side Quest ${i + 27}`, - description: `Complete side quest number ${ - i + 27 - } for extra rewards.`, + description: `Complete side quest number ${i + 27 + } for extra rewards.`, categories: [realisticCategories[i % realisticCategories.length]], difficulty: ((i + 1) % 25) + 1, })), diff --git a/api/start.sh b/api/start.sh index ac028833..6da6b268 100644 --- a/api/start.sh +++ b/api/start.sh @@ -1,4 +1,7 @@ #!/bin/bash +set -e + +tsx prisma/ready.ts npx prisma migrate dev From e951e44cf9a3f0a1d65761f899d125d08e619346 Mon Sep 17 00:00:00 2001 From: rodg <41761494+rodg@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:36:52 -0500 Subject: [PATCH 4/8] make lint happier --- api/tsconfig.json | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/api/tsconfig.json b/api/tsconfig.json index 37e67b0c..92fdf21f 100644 --- a/api/tsconfig.json +++ b/api/tsconfig.json @@ -10,10 +10,22 @@ "outDir": "build", "baseUrl": "./src", "declarationMap": true, + "types": [ + "node" + ] }, "ts-node": { "esm": true }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/main.ts", "prisma/seed.ts"], - "exclude": ["src/__tests__/**/*", "src/coverage/**/*"] -} + "include": [ + "src/**/*.ts", + "src/**/*.d.ts", + "src/main.ts", + "prisma/seed.ts", + "prisma/ready.ts" + ], + "exclude": [ + "src/__tests__/**/*", + "src/coverage/**/*" + ] +} \ No newline at end of file From 7ea44ad33112567b8cd6e6703e322d4eef78ed51 Mon Sep 17 00:00:00 2001 From: rodg <41761494+rodg@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:37:00 -0500 Subject: [PATCH 5/8] compose make command --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 18561c07..8dc105ef 100644 --- a/Makefile +++ b/Makefile @@ -2,4 +2,7 @@ build-api: cd api && docker build -t bingo-api:local -f Containerfile . build-web: - cd web && docker build -t bingo-web:local -f Containerfile . \ No newline at end of file + cd web && docker build -t bingo-web:local -f Containerfile . + +compose: + docker compose up --build \ No newline at end of file From 8af65d3cd6b036d174831a879f413fce78520701 Mon Sep 17 00:00:00 2001 From: rodg <41761494+rodg@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:04:04 -0500 Subject: [PATCH 6/8] fix websocket for docker --- docker-compose.yaml | 5 +++++ web/src/context/RoomContext.tsx | 31 +++++++++++++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 0f695d2d..bbb51e54 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -17,6 +17,8 @@ services: # SMTP_USER: your-email-address # SMTP_PASSWORD: your-email-password PORT: 8000 + # volumes: + # - ./api:/api depends_on: - database # Optional if you have a database container defined separately @@ -29,6 +31,9 @@ services: - "3000:3000" # Map container port to host port environment: NEXT_PUBLIC_API_PATH: http://api:8000 # Assuming the API service runs on this URL + NEXT_PUBLIC_SOCKET_PATH: "ws://localhost:8000" # this needs to be routable from the client + # volumes: + # - ./web:/web depends_on: - api diff --git a/web/src/context/RoomContext.tsx b/web/src/context/RoomContext.tsx index 80aa6bd7..bba63dc9 100644 --- a/web/src/context/RoomContext.tsx +++ b/web/src/context/RoomContext.tsx @@ -22,10 +22,7 @@ import { RoomData } from '../types/RoomData'; import { ChatMessage, Player, ServerMessage } from '../types/ServerMessage'; import { alertError } from '../lib/Utils'; -const websocketBase = (process.env.NEXT_PUBLIC_API_PATH ?? '').replace( - 'http', - 'ws', -); +const websocketBase = (process.env.NEXT_PUBLIC_SOCKET_PATH ?? '') export enum ConnectionStatus { UNINITIALIZED, // the room connection is uninitialized and there is no authentication data present @@ -76,17 +73,17 @@ export const RoomContext = createContext({ async connect() { return { success: false }; }, - sendChatMessage(message) {}, - markGoal(row, col) {}, - unmarkGoal(row, col) {}, - changeColor() {}, - regenerateCard() {}, - disconnect() {}, - createRacetimeRoom() {}, - updateRacetimeRoom() {}, - joinRacetimeRoom() {}, - racetimeReady() {}, - racetimeUnready() {}, + sendChatMessage(message) { }, + markGoal(row, col) { }, + unmarkGoal(row, col) { }, + changeColor() { }, + regenerateCard() { }, + disconnect() { }, + createRacetimeRoom() { }, + updateRacetimeRoom() { }, + joinRacetimeRoom() { }, + racetimeReady() { }, + racetimeUnready() { }, }); interface RoomContextProps { @@ -239,7 +236,7 @@ export function RoomContextProvider({ slug, children }: RoomContextProps) { }, }, connectionStatus === ConnectionStatus.CONNECTING || - connectionStatus === ConnectionStatus.CONNECTED, + connectionStatus === ConnectionStatus.CONNECTED, ); // actions @@ -255,6 +252,7 @@ export function RoomContextProvider({ slug, children }: RoomContextProps) { ); const connect = useCallback( async (nickname: string, password: string) => { + console.log("I'm connecting") const res = await fetch(`/api/rooms/${slug}/authorize`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -275,6 +273,7 @@ export function RoomContextProvider({ slug, children }: RoomContextProps) { setConnectionStatus(ConnectionStatus.CONNECTING); setNickname(nickname); join(token.authToken, nickname); + console.log("I've finished connecting") return { success: true }; }, [slug, join], From 3f97cc98a2f7a610f8b5b8355440f4fffb180ce1 Mon Sep 17 00:00:00 2001 From: rodg <41761494+rodg@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:05:26 -0500 Subject: [PATCH 7/8] readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 822babfb..9317dc2e 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ function. ##### Web - NEXT_PUBLIC_API_PATH is the url that the api service is running at +- NEXT_PUBLIC_SOCKET_PATH is the url that the web socket is available at #### Optional ##### API From 5975d686db7185592240f0fa209d499478bef302 Mon Sep 17 00:00:00 2001 From: rodg <41761494+rodg@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:08:40 -0500 Subject: [PATCH 8/8] remove comment --- web/src/context/RoomContext.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/web/src/context/RoomContext.tsx b/web/src/context/RoomContext.tsx index bba63dc9..d663253e 100644 --- a/web/src/context/RoomContext.tsx +++ b/web/src/context/RoomContext.tsx @@ -252,7 +252,6 @@ export function RoomContextProvider({ slug, children }: RoomContextProps) { ); const connect = useCallback( async (nickname: string, password: string) => { - console.log("I'm connecting") const res = await fetch(`/api/rooms/${slug}/authorize`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -273,7 +272,6 @@ export function RoomContextProvider({ slug, children }: RoomContextProps) { setConnectionStatus(ConnectionStatus.CONNECTING); setNickname(nickname); join(token.authToken, nickname); - console.log("I've finished connecting") return { success: true }; }, [slug, join],