Skip to content

Commit c9b9f7b

Browse files
committed
Get API gateway working with collab service
2 parents 9218a30 + 01f9344 commit c9b9f7b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+4715
-7090
lines changed

.env.sample

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ EMAIL_PASSWORD=
2222
## Matching service variables
2323
MATCHING_SVC_PORT=6969
2424

25+
## Collab service variables
26+
COLLAB_SVC_PORT=3002
27+
COLLAB_SVC_DB_URI=
28+
OPENAI_API_KEY=
29+
2530
## Redis variables
2631
REDIS_PORT=6379
2732

api-gateway/templates/api_conf.d/api_backends.conf.template

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ upstream matching-service {
1010
server matching-service:$MATCHING_SVC_PORT;
1111
}
1212

13+
upstream collab-service {
14+
server collab-service:$COLLAB_SVC_PORT;
15+
}
16+
1317
upstream frontend {
1418
server frontend:$FRONTEND_PORT;
1519
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
location /private/collab-service/ {
2+
proxy_pass http://collab-service/;
3+
proxy_http_version 1.1;
4+
proxy_set_header Upgrade $http_upgrade;
5+
proxy_set_header Connection $connection_upgrade;
6+
proxy_set_header Host $host;
7+
proxy_set_header X-Real-IP $remote_addr;
8+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
9+
proxy_set_header X-Forwarded-Proto $scheme;
10+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
location /public/collab-service/ {
2+
location /public/collab-service/chat {
3+
proxy_pass http://collab-service/chat;
4+
proxy_http_version 1.1;
5+
proxy_set_header Upgrade $http_upgrade;
6+
proxy_set_header Connection $connection_upgrade;
7+
proxy_set_header Host $host;
8+
proxy_set_header X-Real-IP $remote_addr;
9+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
10+
proxy_set_header X-Forwarded-Proto $scheme;
11+
}
12+
13+
location /public/collab-service/yjs {
14+
proxy_pass http://collab-service/yjs;
15+
proxy_http_version 1.1;
16+
proxy_set_header Upgrade $http_upgrade;
17+
proxy_set_header Connection $connection_upgrade;
18+
proxy_set_header Host $host;
19+
proxy_set_header X-Real-IP $remote_addr;
20+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
21+
proxy_set_header X-Forwarded-Proto $scheme;
22+
}
23+
}

collab-service/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
.env

collab-service/.prettierrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"trailingComma": "es5",
3+
"tabWidth": 2,
4+
"semi": true,
5+
"singleQuote": false
6+
}

collab-service/Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Base image
2+
FROM node:20-alpine AS base
3+
WORKDIR /app
4+
COPY package*.json ./
5+
6+
# Install dependencies in base stage
7+
RUN npm install
8+
9+
# Development stage
10+
FROM base AS dev
11+
COPY . .
12+
# Run the JavaScript code directly in dev mode (useful for hot-reloading)
13+
CMD ["npm", "run", "dev"]
14+
15+
# Production stage
16+
FROM node:20-alpine AS prod
17+
WORKDIR /app
18+
COPY --from=base /app/node_modules ./node_modules
19+
COPY . .
20+
# Start the server in production mode
21+
CMD ["npm", "start"]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { sendAiMessage } from "../model/repository.js";
2+
3+
// send ai message
4+
export async function sendAiMessageController(req, res) {
5+
const { message } = req.body;
6+
if (!message) {
7+
return res.status(400).json({ error: "Message content is required" });
8+
}
9+
10+
const data = await sendAiMessage(message);
11+
const aiResponse =
12+
data.choices?.[0]?.message?.content || "No response from AI";
13+
14+
if (aiResponse) {
15+
res.status(200).json({ data });
16+
} else {
17+
res.status(500).json({ error: "Failed to retrieve AI response" });
18+
}
19+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import {
2+
newRoom,
3+
getRoomId,
4+
getAllRooms,
5+
fetchRoomChatHistory,
6+
getQuestionIdByRoomId,
7+
getAllRoomsByUserId,
8+
} from "../model/repository.js";
9+
import crypto from "crypto";
10+
11+
// Create a room between two users
12+
export async function createRoom(req, res) {
13+
const { user1, user2, question_id } = req.body;
14+
15+
if (!user1 || !user2 || !question_id) {
16+
return res
17+
.status(400)
18+
.json({ error: "user1,user2 and question_id are required" });
19+
}
20+
21+
// Generate a unique room ID by hashing the two user IDs
22+
const timeSalt = new Date().toISOString().slice(0, 19);
23+
const roomId = crypto
24+
.createHash("sha256")
25+
.update(user1 + user2 + timeSalt)
26+
.digest("hex");
27+
const room = await newRoom(user1, user2, roomId, question_id);
28+
29+
if (room) {
30+
res.status(201).json(room);
31+
} else {
32+
res.status(500).json({ error: "Failed to create room" });
33+
}
34+
}
35+
36+
// Get room ID by user
37+
export async function getRoomByUser(req, res) {
38+
const { user } = req.params;
39+
40+
if (!user) {
41+
return res.status(400).json({ error: "User is required" });
42+
}
43+
44+
const room = await getRoomId(user);
45+
46+
if (room) {
47+
res.status(200).json(room);
48+
} else {
49+
res.status(404).json({ error: `Room not found for user: ${user}` });
50+
}
51+
}
52+
53+
// Get all rooms
54+
export async function getAllRoomsController(req, res) {
55+
const rooms = await getAllRooms();
56+
57+
if (rooms) {
58+
res.status(200).json(rooms);
59+
} else {
60+
res.status(500).json({ error: "Failed to retrieve rooms" });
61+
}
62+
}
63+
64+
// Get all rooms by user
65+
export async function getAllRoomsByUser(req, res) {
66+
const { user } = req.params;
67+
const rooms = await getAllRoomsByUserId(user);
68+
69+
if (rooms) {
70+
res.status(200).json(rooms);
71+
} else {
72+
res.status(500).json({ error: "Failed to retrieve rooms" });
73+
}
74+
}
75+
export async function getRoomChatHistory(req, res) {
76+
const { roomId } = req.params;
77+
78+
if (!roomId) {
79+
return res.status(400).json({ error: "Room ID is required" });
80+
}
81+
82+
const room = await fetchRoomChatHistory(roomId);
83+
84+
if (room) {
85+
res.status(200).json(room);
86+
} else {
87+
res.status(404).json({ error: `Room not found for ID: ${roomId}` });
88+
}
89+
}
90+
91+
// Get QuestionId from the room based on the roomId
92+
export async function getQuestionId(req, res) {
93+
const { roomId } = req.params;
94+
95+
if (!roomId) {
96+
return res.status(400).json({ error: "Room ID is required" });
97+
}
98+
const questionId = await getQuestionIdByRoomId(roomId);
99+
100+
if (questionId) {
101+
res.status(200).json({ questionId });
102+
} else {
103+
res
104+
.status(404)
105+
.json({ error: `Question ID not found for room ID: ${roomId}` });
106+
}
107+
}

collab-service/app/index.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import express from "express";
2+
import cors from "cors";
3+
import collabRoutes from "./routes/collab-routes.js";
4+
5+
const app = express();
6+
7+
app.use(express.urlencoded({ extended: true }));
8+
app.use(express.json());
9+
app.use(cors()); // config cors so that front-end can use
10+
app.options("*", cors());
11+
12+
// To handle CORS Errors
13+
app.use((req, res, next) => {
14+
res.header("Access-Control-Allow-Origin", "*"); // "*" -> Allow all links to access
15+
16+
res.header(
17+
"Access-Control-Allow-Headers",
18+
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
19+
);
20+
21+
// Browsers usually send this before PUT or POST Requests
22+
if (req.method === "OPTIONS") {
23+
res.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH");
24+
return res.status(200).json({});
25+
}
26+
27+
// Continue Route Processing
28+
next();
29+
});
30+
31+
app.use("/collab", collabRoutes);
32+
33+
app.get("/", (req, res, next) => {
34+
console.log("Sending Greetings!");
35+
res.json({
36+
message: "Hello World from collab-service",
37+
});
38+
});
39+
40+
// Handle When No Route Match Is Found
41+
app.use((req, res, next) => {
42+
const error = new Error("Route Not Found");
43+
error.status = 404;
44+
next(error);
45+
});
46+
47+
app.use((error, req, res, next) => {
48+
res.status(error.status || 500);
49+
res.json({
50+
error: {
51+
message: error.message,
52+
},
53+
});
54+
});
55+
56+
export default app;

0 commit comments

Comments
 (0)