done chat

This commit is contained in:
leca 2025-02-06 15:22:32 +03:00
parent 60e093f123
commit 37c170b265
9 changed files with 90 additions and 11 deletions

View File

@ -97,13 +97,14 @@ canvas {
} }
.chat-container { .chat-container {
overflow: scroll;
border: black solid border: black solid
} }
.messages-container { .messages-container {
width: 100%; width: 100%;
height: 75%; height: 75%;
overflow: scroll;
overflow-wrap: anywhere;
border: gray solid; border: gray solid;
} }
@ -125,4 +126,11 @@ canvas {
font-size: 15pt; font-size: 15pt;
margin: 0; margin: 0;
padding: 0 padding: 0
}
.chat-message {
margin-top: 8px;
margin-bottom: 8px;
margin-left: 8px;
margin-right: 16px;
} }

View File

@ -4,21 +4,50 @@ function getCookie(name) {
if (parts.length === 2) return parts.pop().split(';').shift(); if (parts.length === 2) return parts.pop().split(';').shift();
} }
$(document).ready(() => { $(document).ready(async () => {
//prod const wsConnectionString = (await fetch(`/api/websocketConnection`)).text()
// const socket = new WebSocket('wss://auth.foxarmy.org'); const socket = new WebSocket(wsConnectionString);
//dev let lastMessageNumber = 0;
const socket = new WebSocket('ws://localhost:3000'); let page = 20;
const fetchMoreMessages = async () => {
if (lastMessageNumber < 0 ) return [];
let messages = await (await fetch(`/api/getChatMessages/${lastMessageNumber}/${page}`)).json();
lastMessageNumber = messages.length < page? -1 : lastMessageNumber + messages.length
return messages
}
const appendMessageToChat = (author, content) => { const appendMessageToChat = (author, content) => {
const messageDiv = document.createElement('div')//`<div class="chat-message" ><${message.author}> ${message.content}</div><br/>` const messageDiv = document.createElement('div')
messageDiv.className = "chat-message" messageDiv.className = "chat-message"
messageDiv.textContent = `<${author}> ${content}` messageDiv.textContent = `<${author}> ${content}`
document.getElementsByClassName("messages-container")[0].appendChild(messageDiv) document.getElementsByClassName("messages-container")[0].appendChild(messageDiv)
} }
socket.onmessage = message => { const prependMessageToChat = (author, content) => {
const messageDiv = document.createElement('div')
messageDiv.className = "chat-message"
messageDiv.textContent = `<${author}> ${content}`
const messageContainer = document.getElementsByClassName("messages-container")[0]
messageContainer.firstChild.insertAdjacentElement('afterend', messageDiv)
}
const onFetchMessageButtonClick = async () => {
let messages = await fetchMoreMessages(lastMessageNumber, page);
if (messages.length == 0) return;
messages.forEach(message => {
prependMessageToChat(message.author, message.content);
});
}
$("#fetch-messages-button").click(onFetchMessageButtonClick);
await onFetchMessageButtonClick();
socket.onmessage = message => {
try { try {
message = JSON.parse(message.data) message = JSON.parse(message.data)
} catch(e) { } catch(e) {
@ -40,6 +69,8 @@ $(document).ready(() => {
socket.send(JSON.stringify(message)); socket.send(JSON.stringify(message));
appendMessageToChat(message.author, message.content) appendMessageToChat(message.author, message.content)
$("#chat-input").val("") $("#chat-input").val("")
let messageContainer = $(".messages-container")
messageContainer.animate({ scrollTop: messageContainer.prop("scrollHeight")}, 1000);
} }
$("#send-message-button").click(sendData); $("#send-message-button").click(sendData);

View File

@ -6,4 +6,5 @@ DBPORT=5432
DBPASS=GENERATE_A_STRONG_PASSWORD_HERE DBPASS=GENERATE_A_STRONG_PASSWORD_HERE
PORT=3000 PORT=3000
REQUIRE_TOKEN=false REQUIRE_TOKEN=false
DELETE_TOKEN_ON_USE=true DELETE_TOKEN_ON_USE=true
WS_CONNECTION_STRING=wss://auth.foxarmy.org

20
src/controllers/api.js Normal file
View File

@ -0,0 +1,20 @@
import ApiService from "../services/api.js";
import dotenv from 'dotenv';
dotenv.config({path: ".env"});
class ApiController {
async getChatMessages(req, res) {
const {limit, offset} = req.params;
const messages = await ApiService.getChatMessages(limit, offset);
return res.status(200).send(messages);
}
async getWebsocketConnection(req, res) {
return res.status(200).send(process.env.WS_CONNECTION_STRING)
}
}
export default new ApiController();

View File

@ -91,6 +91,8 @@ const startChat = async () => {
origin: "website" origin: "website"
}) })
}] }]
}).catch(e => {
console.log(e)
}); });
// we are not sending this message to all websockets right now, because plugin will emit // we are not sending this message to all websockets right now, because plugin will emit
// a chat event once it'll catch this message from kafka, triggering a new message // a chat event once it'll catch this message from kafka, triggering a new message

View File

@ -26,7 +26,6 @@ const validateInviteToken = async (req, res, next) => {
let tokenValid = false; let tokenValid = false;
inviteTokens.forEach((token) => { inviteTokens.forEach((token) => {
console.log(`${token} == ${inviteToken}`)
if (token == inviteToken) tokenValid = true; if (token == inviteToken) tokenValid = true;
}); });

View File

@ -6,6 +6,7 @@ import auth from '../middlewares/auth.js';
import utils from '../utils.js'; import utils from '../utils.js';
import UserController from '../controllers/user.js'; import UserController from '../controllers/user.js';
import ApiController from '../controllers/api.js';
const ApiRouter = new Router(); const ApiRouter = new Router();
@ -16,5 +17,7 @@ ApiRouter.post('/changepassword', auth.authenticate, existance.userExist, UserCo
ApiRouter.post('/uploadSkin', existance.userExist, auth.authenticate, utils.upload.single('file'), requiredParameters.requireFile, UserController.uploadSkin); ApiRouter.post('/uploadSkin', existance.userExist, auth.authenticate, utils.upload.single('file'), requiredParameters.requireFile, UserController.uploadSkin);
ApiRouter.post('/uploadCape', existance.userExist, auth.authenticate, auth.canHaveCloak, utils.upload.single('file'), requiredParameters.requireFile, UserController.uploadCape); ApiRouter.post('/uploadCape', existance.userExist, auth.authenticate, auth.canHaveCloak, utils.upload.single('file'), requiredParameters.requireFile, UserController.uploadCape);
ApiRouter.get('/getUsername', existance.userExist, auth.authenticate, UserController.getUsername); ApiRouter.get('/getUsername', existance.userExist, auth.authenticate, UserController.getUsername);
ApiRouter.get('/getChatMessages/:offset/:limit', auth.authenticate, ApiController.getChatMessages);
ApiRouter.get('/webSocketConnection', auth.authenticate, ApiController.getWebsocketConnection)
export default ApiRouter; export default ApiRouter;

15
src/services/api.js Normal file
View File

@ -0,0 +1,15 @@
import db from '../db.js';
class ApiService {
async getChatMessages(limit, offset) {
try {
const messages = (await db.query("SELECT * FROM chat_messages ORDER BY ID DESC LIMIT $1 OFFSET $2", [limit, offset])).rows
return messages
} catch(e) {
console.log(e)
}
}
}
export default new ApiService();

View File

@ -15,7 +15,7 @@ html
h1 Чат h1 Чат
div(class="chat-container") div(class="chat-container")
div(class="messages-container") div(class="messages-container")
button(id="fetch-messages-button") Загрузить ещё
div(class="input-container") div(class="input-container")
input(type="text" id="chat-input") input(type="text" id="chat-input")
button(id="send-message-button") Отправить button(id="send-message-button") Отправить