216 lines
6.5 KiB
JavaScript
216 lines
6.5 KiB
JavaScript
import { v4 as uuidv4 } from 'uuid';
|
|
import amqp from 'amqplib/callback_api.js';
|
|
import User from '../models/community/user.js';
|
|
import Room from '../models/chat/room.js';
|
|
|
|
const RABBITMQ_URL = 'amqp://localhost';
|
|
const QUEUE = 'oneToOne_messages';
|
|
|
|
class ChatService {
|
|
constructor() {
|
|
this.messages = [];
|
|
this.searchQueue = [];
|
|
this.users = [];
|
|
this.randomChats = [];
|
|
this.oneToOneChats = [];
|
|
amqp.connect(RABBITMQ_URL, (err, connection) => {
|
|
if (err) throw err;
|
|
connection.createChannel((err, channel) => {
|
|
if (err) throw err;
|
|
this.channel = channel;
|
|
channel.assertQueue(QUEUE, { durable: false });
|
|
});
|
|
});
|
|
}
|
|
|
|
getMessages(toId, fromId) {
|
|
const userChats = this.randomChats.filter(chat => chat.includes(toId) && chat.includes(fromId));
|
|
if (userChats.length === 0) {
|
|
fromId = '';
|
|
}
|
|
const userMessages = this.messages.filter(message => message.to === toId && ["system", fromId].includes(message.from));
|
|
this.messages = this.messages.filter(message => message.to === toId && ["system", fromId].includes(message.from));
|
|
return userMessages;
|
|
}
|
|
|
|
async addMessage(from, to, text) {
|
|
const userChats = this.randomChats.filter(chat => chat.includes(from) && chat.includes(to));
|
|
if (userChats.length === 0) {
|
|
return;
|
|
}
|
|
this.messages.push({ from: from, to: to, text: text });
|
|
return { text: text };
|
|
}
|
|
|
|
findMatch(genders, age, id) {
|
|
const currentUsersChat = this.randomChats.filter(chat => chat.includes(id));
|
|
if (currentUsersChat.length > 0) {
|
|
return this.findUser(currentUsersChat[0][0] === id ? currentUsersChat[0][1] : currentUsersChat[0][0]);
|
|
}
|
|
let filteredSearchQueue = this.users.filter(user =>
|
|
this.searchQueue.some(sq => sq.id === user.id) && user.id !== id
|
|
&& this.randomChats.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 = this.searchQueue.length - 1; j >= 0; j--) {
|
|
if ([id, user.id].includes(this.searchQueue[j].id)) {
|
|
this.searchQueue.splice(j, 1);
|
|
}
|
|
}
|
|
this.randomChats.push([user.id, id]);
|
|
return user;
|
|
}
|
|
}
|
|
if (!this.searchQueue.find(user => user.id === id)) {
|
|
this.searchQueue.push({ id, genders, age });
|
|
}
|
|
return null;
|
|
}
|
|
|
|
findUser(id) {
|
|
return this.users.find(user => user.id === id);
|
|
}
|
|
|
|
async registerUser(gender, age) {
|
|
const id = uuidv4();
|
|
this.users.push({ gender, age, id });
|
|
return id;
|
|
}
|
|
|
|
async removeUser(id) {
|
|
this.searchQueue = this.searchQueue.filter(user => user.id !== id);
|
|
this.users = this.users.filter(user => user.id !== id);
|
|
this.randomChats = this.randomChats.filter(pair => pair[0] === id || pair[1] === id);
|
|
this.messages = this.messages.filter(message => message.from === id || message.to === id);
|
|
}
|
|
|
|
async endChat(userId) {
|
|
this.randomChats = this.randomChats.filter(chat => !chat.includes(userId));
|
|
this.messages.push({ to: userId, from: 'system', activity: 'otheruserleft' });
|
|
}
|
|
|
|
async initOneToOne(user1HashId, user2HashId) {
|
|
const chat = this.searchOneToOneChat(user1HashId, user2HashId);
|
|
if (!chat) {
|
|
this.oneToOneChats.push({ user1Id: user1HashId, user2Id: user2HashId, history: [] });
|
|
}
|
|
}
|
|
|
|
async sendOneToOneMessage(user1HashId, user2HashId, message) {
|
|
const messageBundle = {
|
|
timestamp: Date.now(),
|
|
sender: user1HashId,
|
|
recipient: user2HashId,
|
|
message: message,
|
|
};
|
|
const chat = this.searchOneToOneChat(user1HashId, user2HashId);
|
|
if (chat) {
|
|
chat.history.push(messageBundle);
|
|
} else {
|
|
this.oneToOneChats.push({
|
|
user1Id: user1HashId,
|
|
user2Id: user2HashId,
|
|
history: [messageBundle],
|
|
});
|
|
}
|
|
if (this.channel) {
|
|
this.channel.sendToQueue(QUEUE, Buffer.from(JSON.stringify(messageBundle)));
|
|
}
|
|
}
|
|
|
|
async getOneToOneMessageHistory(user1HashId, user2HashId) {
|
|
const chat = this.searchOneToOneChat(user1HashId, user2HashId);
|
|
return chat ? chat.history : [];
|
|
}
|
|
|
|
searchOneToOneChat(user1HashId, user2HashId) {
|
|
return this.oneToOneChats.find(chat =>
|
|
(chat.user1Id === user1HashId && chat.user2Id === user2HashId) ||
|
|
(chat.user1Id === user2HashId && chat.user2Id === user1HashId)
|
|
);
|
|
}
|
|
|
|
async getRoomList() {
|
|
// Nur öffentliche Räume, keine sensiblen Felder
|
|
const { default: Room } = await import('../models/chat/room.js');
|
|
const { default: RoomType } = await import('../models/chat/room_type.js');
|
|
return Room.findAll({
|
|
attributes: [
|
|
'id', 'title', 'roomTypeId', 'isPublic', 'genderRestrictionId',
|
|
'minAge', 'maxAge', 'friendsOfOwnerOnly', 'requiredUserRightId'
|
|
],
|
|
where: { isPublic: true },
|
|
include: [
|
|
{ model: RoomType, as: 'roomType' }
|
|
]
|
|
});
|
|
}
|
|
|
|
async getRoomCreateOptions() {
|
|
const { default: UserRightType } = await import('../models/type/user_right.js');
|
|
const { default: InterestType } = await import('../models/type/interest.js');
|
|
|
|
const [rights, interests] = await Promise.all([
|
|
UserRightType.findAll({
|
|
attributes: ['id', 'title'],
|
|
order: [['id', 'ASC']]
|
|
}),
|
|
InterestType.findAll({
|
|
attributes: ['id', 'name'],
|
|
order: [['id', 'ASC']]
|
|
})
|
|
]);
|
|
|
|
return {
|
|
rights: rights.map((r) => ({ id: r.id, title: r.title })),
|
|
roomTypes: interests.map((i) => ({ id: i.id, name: i.name }))
|
|
};
|
|
}
|
|
|
|
async getOwnRooms(hashedUserId) {
|
|
const user = await User.findOne({
|
|
where: { hashedId: hashedUserId },
|
|
attributes: ['id']
|
|
});
|
|
if (!user) {
|
|
throw new Error('user_not_found');
|
|
}
|
|
|
|
return Room.findAll({
|
|
where: { ownerId: user.id },
|
|
attributes: ['id', 'title', 'isPublic', 'roomTypeId', 'ownerId'],
|
|
order: [['title', 'ASC']]
|
|
});
|
|
}
|
|
|
|
async deleteOwnRoom(hashedUserId, roomId) {
|
|
const user = await User.findOne({
|
|
where: { hashedId: hashedUserId },
|
|
attributes: ['id']
|
|
});
|
|
if (!user) {
|
|
throw new Error('user_not_found');
|
|
}
|
|
|
|
const deleted = await Room.destroy({
|
|
where: {
|
|
id: roomId,
|
|
ownerId: user.id
|
|
}
|
|
});
|
|
|
|
if (!deleted) {
|
|
throw new Error('room_not_found_or_not_owner');
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export default new ChatService();
|