Initial commit
This commit is contained in:
20
backend/app.js
Normal file
20
backend/app.js
Normal 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;
|
||||
43
backend/controllers/chatController.js
Normal file
43
backend/controllers/chatController.js
Normal 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
1
backend/dist/index.html
vendored
Normal 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
2
backend/dist/js/app.989c1f98.js
vendored
Normal 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
1
backend/dist/js/app.989c1f98.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
23
backend/dist/js/chunk-vendors.e0723df7.js
vendored
Normal file
23
backend/dist/js/chunk-vendors.e0723df7.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
backend/dist/js/chunk-vendors.e0723df7.js.map
vendored
Normal file
1
backend/dist/js/chunk-vendors.e0723df7.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1026
backend/package-lock.json
generated
Normal file
1026
backend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
backend/package.json
Normal file
19
backend/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
14
backend/routers/chatRouter.js
Normal file
14
backend/routers/chatRouter.js
Normal 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
55
backend/server.js
Normal 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');
|
||||
});
|
||||
});
|
||||
});
|
||||
76
backend/services/chatService.js
Normal file
76
backend/services/chatService.js
Normal 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'})
|
||||
}
|
||||
Reference in New Issue
Block a user