/* ---------------------------------------------------------------------------- Question Server GitLab: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ------------------------------------------------------------------------- */ import { Server as socket, Socket } from 'socket.io' import utils from '../../../utils/utils' import dbtools from '../../../utils/dbtools' import logger from '../../../utils/logger' import { Request, SubmoduleData, User } from '../../../types/basicTypes' import socketAuth from '../../../middlewares/socketAuth.middleware' const msgDbPath = './data/dbs/msgs.db' const msgPaginationLimit = 15 interface ExtendedSocket extends Socket { user: User } interface Message { id: number sender: number reciever: number msg: string type: string date: number unread: number } function setup(data: SubmoduleData): void { const { app, httpServer, httpsServer, userDB, publicdirs } = data const msgDB = dbtools.GetDB(msgDbPath) const publicDir = publicdirs[0] const uloadFiles = publicDir + 'chatFiles' logger.Log( `Chat: Starting Socket.io Server on ${httpsServer ? 'https' : 'http'}` ) // https://socket.io/docs/v4/handling-cors/#Configuration const io = new socket(httpsServer || httpServer, { cors: { credentials: true, origin: true, }, }) function chatMessageRead({ sender, reciever, }: { sender: number reciever: number }) { dbtools.runStatement( msgDB, `update msgs set unread = 0 where sender = ${sender} and reciever = ${reciever}`, 'run' ) io.sockets.in(sender.toString()).emit('chat message read', { userReadMsg: reciever, }) } io.use(socketAuth({ userDB: userDB })) io.on('connection', (socket: ExtendedSocket) => { const userid = socket.user.id socket.on('join', function (/*data*/) { socket.join(userid.toString()) const groups: number[] = dbtools .runStatement( msgDB, `select * from ( select sender as a from msgs where sender = ${userid} or reciever = ${userid} union select reciever from msgs where sender = ${userid} or reciever = ${userid} )t order by t.a asc` ) .reduce((acc: number[], x: { a: number }) => { if (x.a !== userid) acc.push(x.a) return acc }, []) socket.emit('prev messages', { prevMsgs: groups.map((to) => { const first: Message = dbtools.runStatement( msgDB, `select * from msgs where sender = ${userid} and reciever = ${to} or sender = ${to} and reciever = ${userid} order by date desc limit 1` )[0] return first }), }) socket.on('get chat messages', (data) => { const { chatPartner, from } = data const msgs = dbtools.runStatement( msgDB, `select * from msgs where (sender = ${userid} and reciever = ${chatPartner} or sender = ${chatPartner} and reciever = ${userid}) ${from ? `and date < ${from}` : ''} order by date desc limit ${msgPaginationLimit}` ) socket.emit('get chat messages', { requestsdMsgs: msgs, hasMore: msgs.length === msgPaginationLimit, }) // Read update chatMessageRead({ sender: chatPartner, reciever: userid }) }) socket.on('chat message read', (data) => { const { chatPartner } = data chatMessageRead({ sender: chatPartner, reciever: userid }) }) socket.on( 'chat message', (message: { reciever: string; msg: string; type: string }) => { const { reciever, msg, type } = message if (!reciever || !msg || !msg.trim() || !type) { return } const recieverUser = dbtools.Select(userDB, 'users', { id: reciever, })[0] if (!recieverUser) { socket.emit('chat message', { success: false, date: new Date().getTime(), sender: reciever, reciever: userid, type: 'text', msg: `A #${reciever} számú felhasználó nem létezik`, }) return } const msgObj = { sender: userid, reciever: parseInt(reciever), msg: dbtools.sanitizeQuery(msg), type: type || 'text', date: new Date().getTime(), unread: 1, } dbtools.Insert(msgDB, 'msgs', msgObj) if (userid !== parseInt(reciever)) { io.sockets .in(reciever.toString()) .emit('chat message', msgObj) } } ) }) // socket.on('disconnect', () => {}) // socket.on('close', () => {}) }) app.post('/postchatfile', function (req: Request, res) { logger.LogReq(req) utils .uploadFile(req, uloadFiles) .then((result) => { res.json({ success: true, path: result.filePath.replace(publicDir, ''), }) }) .catch(() => { res.json({ success: false, msg: 'error during uploading' }) return }) }) app.post('/postfeedbackfile', function (req: Request, res) { logger.LogReq(req) const user: User = req.session.user utils .uploadFile(req, uloadFiles) .then(({ filePath }) => { const fileName = filePath.replace(publicDir, '') const isImage = ['png', 'jpg', 'jpeg', 'gif'].some((ext) => { return fileName.toLowerCase().includes(ext) }) const msgObj = { sender: user.id, reciever: 1, msg: fileName, type: isImage ? 'img' : 'file', date: new Date().getTime(), unread: 1, } dbtools.Insert(msgDB, 'msgs', msgObj) res.json({ success: true }) io.sockets.in('1').emit('chat message', msgObj) }) .catch(() => { res.json({ success: false, msg: 'error during uploading' }) return }) }) app.post( '/postfeedback', function (req: Request<{ content: string }>, res) { logger.LogReq(req) const user: User = req.session.user const { content } = req.body if (!content || !content.trim()) { res.json({ success: false }) return } const msgObj = { sender: user.id, reciever: 1, msg: dbtools.sanitizeQuery(req.body.content), type: 'text', date: new Date().getTime(), unread: 1, } dbtools.Insert(msgDB, 'msgs', msgObj) res.json({ success: true }) io.sockets.in('1').emit('chat message', msgObj) } ) app.get('/hasNewMsg', (req: Request, res) => { const user: User = req.session.user const userid: number = user.id const groups = dbtools .runStatement( msgDB, `select * from ( select sender as a from msgs where sender = ${userid} or reciever = ${userid} union select reciever from msgs where sender = ${userid} or reciever = ${userid} )t order by t.a asc` ) .reduce((acc: number[], x: { a: number }) => { if (x.a !== userid) acc.push(x.a) return acc }, []) const prevMsgs = groups.map((to: number) => { const first = dbtools.runStatement( msgDB, `select * from msgs where sender = ${userid} and reciever = ${to} or sender = ${to} and reciever = ${userid} order by date desc limit 1` )[0] return first }) res.json({ unreads: prevMsgs.reduce((acc: number[], msg: Message) => { if (msg && msg.unread === 1 && msg.sender !== userid) { acc.push(msg.sender) } return acc }, []), }) }) } export default { setup: setup, }