Initial commit

This commit is contained in:
Torsten Schulz
2024-07-17 22:24:56 +02:00
commit 3880a265eb
126 changed files with 10959 additions and 0 deletions

20
backend/app.js Normal file
View File

@@ -0,0 +1,20 @@
import express from 'express';
import path from 'path';
import { fileURLToPath } from 'url';
import chatRouter from './routers/chatRouter.js';
import bodyParser from 'body-parser';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
app.use(bodyParser.json());
app.use('/api/chat', chatRouter);
app.use('/images', express.static(path.join(__dirname, '../frontend/public/images')));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '../frontend/dist/index.html'));
});
export default app;

View File

@@ -0,0 +1,43 @@
import { getMessages as getMessagesService, findMatch, registerUser as registerUserService, addMessage, endChat } from '../services/chatService.js';
export const getMessages = (req, res) => {
const { to, from } = req.body;
const messages = getMessagesService(to, from);
res.status(200).json(messages);
};
export const findRandomChatMatch = (req, res) => {
const { genders, age, id } = req.body;
const match = findMatch(genders, age, id);
if (match) {
res.status(200).json({ status: 'matched', user: match });
} else {
res.status(200).json({ status: 'waiting' });
}
};
export const registerUser = (req, res) => {
const { gender, age } = req.body;
const userId = registerUserService(gender, age);
res.status(200).json({ id: userId });
};
export const sendMessage = (req, res) => {
const from = req.body.from;
const to = req.body.to;
const text = req.body.text;
const message = addMessage(from, to, text);
res.status(200).json(message);
};
export const removeUser = (req, res) => {
const { id } = req.body;
removeUserService(id);
res.sendStatus(200);
};
export const stopChat = (req, res) => {
const { id } = req.body;
endChat(id);
res.sendStatus(200);
}

1
backend/dist/index.html vendored Normal file
View File

@@ -0,0 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>YourPart</title><script defer="defer" src="/js/chunk-vendors.e0723df7.js"></script><script defer="defer" src="/js/app.989c1f98.js"></script></head><body><div id="app"></div></body></html>

2
backend/dist/js/app.989c1f98.js vendored Normal file
View File

@@ -0,0 +1,2 @@
(()=>{"use strict";var e={855:(e,t,n)=>{var s=n(756),r=n(641),o=n(33),a=n(751);function i(e,t,n,s,i,u){return(0,r.uX)(),(0,r.CE)("div",null,[((0,r.uX)(!0),(0,r.CE)(r.FK,null,(0,r.pI)(i.messages,(e=>((0,r.uX)(),(0,r.CE)("div",{key:e.id},(0,o.v_)(e.text),1)))),128)),(0,r.bo)((0,r.Lk)("input",{"onUpdate:modelValue":t[0]||(t[0]=e=>i.newMessage=e),onKeyup:t[1]||(t[1]=(0,a.jR)(((...e)=>u.sendMessage&&u.sendMessage(...e)),["enter"]))},null,544),[[a.Jo,i.newMessage]])])}var u=n(373);const l={data(){return{socket:null,messages:[],newMessage:""}},created(){this.socket=(0,u.Ay)("http://localhost:3001"),this.socket.on("newMessage",(e=>{this.messages.push(e)})),fetch("/api/chat/messages").then((e=>e.json())).then((e=>{this.messages=e}))},methods:{sendMessage(){if(""!==this.newMessage.trim()){const e={id:Date.now(),text:this.newMessage};this.socket.emit("newMessage",e),this.newMessage=""}}}};var d=n(262);const c=(0,d.A)(l,[["render",i]]),f=c;s["default"].config.productionTip=!1,new s["default"]({render:e=>e(f)}).$mount("#app")}},t={};function n(s){var r=t[s];if(void 0!==r)return r.exports;var o=t[s]={exports:{}};return e[s](o,o.exports,n),o.exports}n.m=e,(()=>{var e=[];n.O=(t,s,r,o)=>{if(!s){var a=1/0;for(d=0;d<e.length;d++){for(var[s,r,o]=e[d],i=!0,u=0;u<s.length;u++)(!1&o||a>=o)&&Object.keys(n.O).every((e=>n.O[e](s[u])))?s.splice(u--,1):(i=!1,o<a&&(a=o));if(i){e.splice(d--,1);var l=r();void 0!==l&&(t=l)}}return t}o=o||0;for(var d=e.length;d>0&&e[d-1][2]>o;d--)e[d]=e[d-1];e[d]=[s,r,o]}})(),(()=>{n.d=(e,t)=>{for(var s in t)n.o(t,s)&&!n.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})}})(),(()=>{n.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"===typeof window)return window}}()})(),(()=>{n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t)})(),(()=>{n.r=e=>{"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}})(),(()=>{var e={524:0};n.O.j=t=>0===e[t];var t=(t,s)=>{var r,o,[a,i,u]=s,l=0;if(a.some((t=>0!==e[t]))){for(r in i)n.o(i,r)&&(n.m[r]=i[r]);if(u)var d=u(n)}for(t&&t(s);l<a.length;l++)o=a[l],n.o(e,o)&&e[o]&&e[o][0](),e[o]=0;return n.O(d)},s=self["webpackChunkfrontend"]=self["webpackChunkfrontend"]||[];s.forEach(t.bind(null,0)),s.push=t.bind(null,s.push.bind(s))})();var s=n.O(void 0,[504],(()=>n(855)));s=n.O(s)})();
//# sourceMappingURL=app.989c1f98.js.map

1
backend/dist/js/app.989c1f98.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1026
backend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
backend/package.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "backend",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"amqplib": "^0.10.4",
"express": "^4.19.2",
"socket.io": "^4.7.5",
"uuid": "^10.0.0"
}
}

View File

@@ -0,0 +1,14 @@
import { Router } from 'express';
import { getMessages, findRandomChatMatch, registerUser, sendMessage, stopChat, removeUser } from '../controllers/chatController.js';
const router = Router();
router.get('/messages', getMessages);
router.post('/findMatch', findRandomChatMatch);
router.post('/register', registerUser);
router.post('/sendMessage', sendMessage);
router.post('/getMessages', getMessages);
router.post('/leave', stopChat);
router.post('/exit', removeUser);
export default router;

55
backend/server.js Normal file
View File

@@ -0,0 +1,55 @@
import http from 'http';
import { Server } from 'socket.io';
import amqp from 'amqplib/callback_api.js';
import app from './app.js';
import path from 'path';
import express from 'express';
const server = http.createServer(app);
const io = new Server(server);
const RABBITMQ_URL = 'amqp://localhost';
const QUEUE = 'chat_messages';
const __dirname = path.resolve();
const frontendPath = path.join(__dirname, 'path/to/your/frontend/build/folder');
app.use(express.static(frontendPath));
app.get('*', (req, res) => {
res.sendFile(path.join(frontendPath, 'index.html'));
});
amqp.connect(RABBITMQ_URL, (err, connection) => {
if (err) {
throw err;
}
connection.createChannel((err, channel) => {
if (err) {
throw err;
}
channel.assertQueue(QUEUE, { durable: false });
io.on('connection', (socket) => {
console.log('A user connected');
channel.consume(QUEUE, (msg) => {
const message = JSON.parse(msg.content.toString());
io.emit('newMessage', message);
}, { noAck: true });
socket.on('newMessage', (message) => {
channel.sendToQueue(QUEUE, Buffer.from(JSON.stringify(message)));
});
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
server.listen(3001, () => {
console.log('Server is running on port 3001');
});
});
});

View File

@@ -0,0 +1,76 @@
import { v4 as uuidv4 } from 'uuid';
let messages = [];
let searchQueue = [];
let users = [];
let currentChats = [];
export const getMessages = (toId, fromId) => {
const userChats = currentChats.filter(chat => chat.includes(toId) && chat.includes(fromId));
if (userChats.length === 0) {
fromId = '';
}
const userMessages = messages.filter(message => message.to = toId && ["system", fromId].includes(message.from));
messages = messages.filter(message => message.to === toId && ["system", fromId].includes(message.from));
return userMessages;
};
export const addMessage = (from, to, text) => {
const userChats = currentChats.filter(chat => chat.includes(from) && chat.includes(to));
if (userChats.length === 0) {
return;
}
messages.push({ from: from, to: to, text: text });
return { text: text };
};
export const findMatch = (genders, age, id) => {
const currentUsersChat = currentChats.filter(chat => chat.includes(id));
if (currentUsersChat.length > 0) {
return findUser(currentUsersChat[0][0] === id ? currentUsersChat[0][1] : currentUsersChat[0][0]);
}
let filteredSearchQueue = users.filter(user =>
searchQueue.some(sq => sq.id === user.id) && user.id !== id
&& currentChats.filter(chat => chat.includes(user.id)).length === 0
).sort(() => Math.random() - 0.5);
for (let i = 0; i < filteredSearchQueue.length; i++) {
const user = filteredSearchQueue[i];
const ageMatch = user.age >= age.min && user.age <= age.max;
const genderMatch = genders.includes(user.gender);
if (ageMatch && genderMatch) {
for (let j = searchQueue.length - 1; j >= 0; j--) {
if ([id, user.id].includes(searchQueue[j].id)) {
searchQueue.splice(j, 1);
}
}
currentChats.push([user.id, id]);
return user;
}
}
if (!searchQueue.find(user => user.id === id)) {
searchQueue.push({ id, genders, age });
}
return null;
};
const findUser = (id) => {
return users.find(user => user.id === id);
};
export const registerUser = (gender, age) => {
const id = uuidv4();
users.push({ gender, age, id });
return id;
};
export const removeUser = (id) => {
searchQueue = searchQueue.filter(user => user.id !== id);
users = users.filter(user => user.id !== id);
currentChats = currentChats.filter(pair => pair[0] === id || pair[1] === id);
messages = messages.filter(message => message.from === id || message.to === id);
};
export const endChat = (userId) => {
currentChats = currentChats.filter(chat => !chat.includes(userId));
messages.push({ to: userId, from: 'system', activity: 'otheruserleft'})
}