diff --git a/backend/src/controllers/SchedulingNotifyController.ts b/backend/src/controllers/SchedulingNotifyController.ts index 6ca142b..11cb315 100644 --- a/backend/src/controllers/SchedulingNotifyController.ts +++ b/backend/src/controllers/SchedulingNotifyController.ts @@ -1,18 +1,11 @@ import { Request, Response } from "express"; import AppError from "../errors/AppError"; -import { getIO } from "../libs/socket"; -import DeleteSchedulingNotifyService from "../services/SchedulingNotifyServices/DeleteSchedulingNotifyService"; -import ListSchedulingNotifyContactService from "../services/SchedulingNotifyServices/ListSchedulingNotifyContactService"; -import CreateSchedulingNotifyService from "../services/SchedulingNotifyServices/CreateSchedulingNotifyService"; - -// const test = await ListSchedulingNotifyContactService('5517988310949','2022-03-18','2022-03-19'); -// const test = await ListSchedulingNotifyContactService('','2022-03-18','2022-03-19'); -// const test = await ListSchedulingNotifyContactService('5517988310949'); -// - - - - +import { getIO } from "../libs/socket"; +import DeleteSchedulingNotifyService from "../services/SchedulingNotifyServices/DeleteSchedulingNotifyService"; +import ListSchedulingNotifyContactService from "../services/SchedulingNotifyServices/ListSchedulingNotifyContactService"; +import CreateSchedulingNotifyService from "../services/SchedulingNotifyServices/CreateSchedulingNotifyService"; +import ShowSchedulingNotifyService from "../services/SchedulingNotifyServices/ShowSchedulingNotifyService"; +import { deleteScheduleByTicketIdCache } from "../helpers/SchedulingNotifyCache"; type IndexQuery = { @@ -21,13 +14,13 @@ type IndexQuery = { endDate: string; }; - -export const reportScheduleNotifyByDateStartDateEnd = async (req: Request, res: Response): Promise => { - - const { contactNumber, startDate, endDate } = req.query as IndexQuery - const data_query = await ListSchedulingNotifyContactService(contactNumber, startDate, endDate); +export const reportScheduleNotifyByDateStartDateEnd = async (req: Request, res: Response): Promise => { + + const { contactNumber, startDate, endDate } = req.query as IndexQuery + + const data_query = await ListSchedulingNotifyContactService(contactNumber, startDate, endDate); // console.group('DATA QUERY SCHEDULE:\n',data_query) @@ -36,23 +29,23 @@ export const reportScheduleNotifyByDateStartDateEnd = async (req: Request, res: }; -export const createOrUpdateScheduleNotify = async (req: Request, res: Response): Promise => { - - const scheduleData = req.body; +export const createOrUpdateScheduleNotify = async (req: Request, res: Response): Promise => { + + const scheduleData = req.body; + - const schedulingNotifyCreate = await CreateSchedulingNotifyService( { schedulingNotifyId: scheduleData.schedulingNotifyId, ticketId: scheduleData.ticketId, - statusChatEndId: scheduleData.statusChatEndId, - schedulingDate: scheduleData.schedulingDate, + statusChatEndId: scheduleData.statusChatEndId, + schedulingDate: scheduleData.schedulingDate, schedulingTime: scheduleData.schedulingTime, - message: scheduleData.message + message: scheduleData.message } - ) - + ) + // console.group(':::::::::::::::::: DATA schedulingNotifyCreate:\n',schedulingNotifyCreate) // const io = getIO(); // io.emit("schedulingNotify", {action: "update", schedulingNotifyCreate }); @@ -61,13 +54,17 @@ export const createOrUpdateScheduleNotify = async (req: Request, res: Response): }; -export const remove = async ( req: Request, res: Response ): Promise => { +export const remove = async (req: Request, res: Response): Promise => { + - const { scheduleId } = req.params; - await DeleteSchedulingNotifyService(scheduleId); + let schedule: any = await ShowSchedulingNotifyService(scheduleId) + + await deleteScheduleByTicketIdCache(schedule.ticketId) + + await DeleteSchedulingNotifyService(scheduleId); return res.status(200).send(); }; diff --git a/backend/src/helpers/SchedulingNotifyCache.ts b/backend/src/helpers/SchedulingNotifyCache.ts new file mode 100644 index 0000000..b95ef36 --- /dev/null +++ b/backend/src/helpers/SchedulingNotifyCache.ts @@ -0,0 +1,221 @@ + +import Redis from 'ioredis' +import { type } from 'os' +const unflatten = require('flat').unflatten +var flatten = require('flat') +import ListContactsServiceCache from "../services/ContactServices/ListContactsServiceCache" +import { redisConn } from './TicketCache' + +import SchedulingNotify from '../models/SchedulingNotify' + +import { format } from "date-fns"; +import ptBR from 'date-fns/locale/pt-BR'; + +import { escapeCharCache } from './ContactsCache' + + +const deleteScheduleByTicketIdCache = async (ticketId: string | number) => { + + const redis: any = await redisConn(); + + if (!redis) return + + if (redis.status !== 'connect') return + + const schedule_cache: any = await redis.hgetall(`schedule:${ticketId}`) + + try { + if (schedule_cache && Object.keys(schedule_cache).length > 0) { + + await redis.del(`schedule:${ticketId}`) + + console.log(`Schedule cache ticketId ${schedule_cache.ticketId} deleted!`) + } + else { + console.log('SCHEDULE CACHE NOT FOUND!') + } + } catch (error) { + console.log(`There was an error on deleteScheduleByTicketIdCache: ${error}`) + } + + redis.quit() +} + + + + + +const updateScheduleCacheByTicketId = async (scheduleNotify: any) => { + + const redis: any = await redisConn(); + + if (!redis) return + + if (redis.status !== 'connect') return + + const pipeline = redis.pipeline() + + let entries = Object.entries(scheduleNotify) + + entries.forEach((e: any) => { + pipeline.hset(`schedule:${scheduleNotify.ticketId}`, e[0], e[1]) + }) + + await pipeline.exec(() => { console.log("schedule Key/value inserted/updated") }); + + redis.quit() + +} + + + + +const createSchedulingNotifyCache = async (scheduleNotify: any) => { + + const redis: any = await redisConn(); + + if (!redis) return + + if (redis.status !== 'connect') return + + let date_time: any = format(new Date(scheduleNotify.schedulingTime), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR }).split(' ') + + delete scheduleNotify.schedulingTime + delete scheduleNotify.updatedAt + delete scheduleNotify.createdAt + delete scheduleNotify.schedulingDate + + console.log('created date_time: ', date_time) + + scheduleNotify.date = date_time[0] + scheduleNotify.date_escaped = escapeCharCache(date_time[0]) + scheduleNotify.hour = date_time[1].split(':')[0] + scheduleNotify.minute = date_time[1].split(':')[1] + + await redis.hmset(`schedule:${scheduleNotify.ticketId}`, scheduleNotify); + + console.log(`${scheduleNotify.length} SCHEDULE NOTIFY INSERTED IN CACHE!`) + + redis.quit() + +} + + +async function searchScheduleCache(date: string, hour: number | string, minute: number | string) { + + const redis: any = await redisConn(); + + if (!redis) return + + if (redis.status !== 'connect') return null + + date = escapeCharCache(date).trim() + + console.log('kkkkkkkkkkk date: ', date) + + const response: any = await redis.call('FT.SEARCH', 'idx_schedule', `(@date_escaped:${date}) (@hour:${hour}) (@minute:${minute})`) + redis.quit() + + + if (response.length === 1) { + return [] + } + + const results: any = [] + + for (let n = 2; n < response.length; n += 2) { + const result: any = {} + const fieldNamesAndValues = response[n] + + for (let m = 0; m < fieldNamesAndValues.length; m += 2) { + const k = fieldNamesAndValues[m] + const v = fieldNamesAndValues[m + 1] + result[k] = v + } + + results.push(result) + } + + return results +} + +const loadSchedulesCache = async () => { + + await createScheduleIndexCache('idx_schedule') + + const redis: any = await redisConn(); + + if (!redis) return + + if (redis.status !== 'connect') return + + let schedules: any = await SchedulingNotify.findAll({ raw: true, attributes: ["id", "statusChatEndId", "ticketId", "schedulingTime", "message"] }); + + // console.log('SCHEDULE NOTIFY CACHE2: ', schedules) + + + const pipeline = redis.pipeline() + + for (let i = 0; i < schedules.length; i++) { + + let date_time: any = format(new Date(schedules[i].schedulingTime), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR }).split(' ') + + delete schedules[i].schedulingTime + + console.log('date_time: ', date_time) + + schedules[i].date = date_time[0] + schedules[i].date_escaped = escapeCharCache(date_time[0]) + + schedules[i].hour = date_time[1].split(':')[0] + schedules[i].minute = date_time[1].split(':')[1] + + pipeline.hmset(`schedule:${schedules[i].ticketId}`, schedules[i]); + } + + await pipeline.exec(() => { console.log(`${schedules.length} SCHEDULES NOTIFY INSERTED IN CACHE!`) }); + + redis.quit() + + + // let test = await searchScheduleCache('2022-12-16', '18', '30') + + // console.log('--------------> TEST: ', test) + +} + +const createScheduleIndexCache = async (hashIndex: string) => { + + const redis: any = await redisConn(); + + if (!redis) return + + if (redis.status !== 'connect') return + + try { + + const lst_index_redis: any = await redis.call('FT._LIST') + + if (lst_index_redis.includes(hashIndex)) { + console.log('entrou...') + await redis.call('FT.DROPINDEX', hashIndex) + } + + const response = await redis.call('FT.CREATE', hashIndex, 'ON', 'HASH', 'PREFIX', '1', 'schedule:', 'SCHEMA', 'id', 'TEXT', 'SORTABLE', 'date_escaped', 'TEXT', 'SORTABLE', 'hour', 'TEXT', 'SORTABLE', 'minute', 'TEXT', 'SORTABLE') + + console.log('Schedule index created: ', response) + + } catch (error) { + console.log('There was an error on createScheduleIndexCache: ', error) + } + + redis.quit() +} + +export { + loadSchedulesCache, + searchScheduleCache, + updateScheduleCacheByTicketId, + createSchedulingNotifyCache, + deleteScheduleByTicketIdCache +} \ No newline at end of file diff --git a/backend/src/helpers/SchedulingNotifySendMessage.ts b/backend/src/helpers/SchedulingNotifySendMessage.ts index 44c8b54..ea64dae 100644 --- a/backend/src/helpers/SchedulingNotifySendMessage.ts +++ b/backend/src/helpers/SchedulingNotifySendMessage.ts @@ -8,6 +8,8 @@ import { getIO } from "../libs/socket"; import ListWhatsAppsService from "../services/WhatsappService/ListWhatsAppsService"; import path from "path"; import { convertBytes } from "./ConvertBytes"; +import { deleteScheduleByTicketIdCache } from "./SchedulingNotifyCache"; +import SchedulingNotify from "../models/SchedulingNotify"; const fastFolderSize = require('fast-folder-size') const { promisify } = require('util') @@ -15,6 +17,8 @@ const fs = require('fs') const { exec } = require("child_process"); +let _fifo: any + let scheduler_monitor: any; let timeInterval = 5 @@ -36,23 +40,46 @@ const monitor = async () => { try { - // const { schedulingNotifies, count, hasMore } = await ListSchedulingNotifyService({ searchParam: dateParm, pageNumber: "1" }); + const { schedulingNotifies, count, hasMore } = await ListSchedulingNotifyService({ searchParam: dateParm, pageNumber: "1" }); - // // console.log('schedulingNotifies: ',schedulingNotifies) + // console.log('schedulingNotifies: ',schedulingNotifies) - // if (schedulingNotifies && schedulingNotifies.length > 0) { + if (schedulingNotifies && schedulingNotifies.length > 0) { - // const ticket = await ShowTicketService(schedulingNotifies[0].ticketId); + console.log('ENTROU NA DATA schedulingNotifies: ', schedulingNotifies) - // SetTicketMessagesAsRead(ticket); - // await SendWhatsAppMessage({ - // body: schedulingNotifies[0].message, ticket - // }); + for (let i = 0; i < schedulingNotifies.length; i++) { - // DeleteSchedulingNotifyService(schedulingNotifies[0].id) - // } + const ticket = await ShowTicketService(schedulingNotifies[i].ticketId); + + SetTicketMessagesAsRead(ticket); + + await SendWhatsAppMessage({ + body: schedulingNotifies[i].message, ticket + }); + + await deleteScheduleByTicketIdCache(schedulingNotifies[i].ticketId) + + await DeleteSchedulingNotifyService(schedulingNotifies[i].id) + + + } + + // const ticket = await ShowTicketService(schedulingNotifies[0].ticketId); + + // SetTicketMessagesAsRead(ticket); + + // await SendWhatsAppMessage({ + // body: schedulingNotifies[0].message, ticket + // }); + + // await deleteScheduleByTicketIdCache(schedulingNotifies[0].ticketId) + + // await DeleteSchedulingNotifyService(schedulingNotifies[0].id) + + } exec("df -h /", (error: any, stdout: any, stderr: any) => { @@ -66,9 +93,9 @@ const monitor = async () => { return; } - stdout = stdout.split(/\r?\n/) - stdout = stdout[1].trim().split(/\s+/) - + stdout = stdout.split(/\r?\n/) + stdout = stdout[1].trim().split(/\s+/) + // DISK SPACE MONITORING const io = getIO(); io.emit("diskSpaceMonit", { @@ -90,20 +117,20 @@ const monitor = async () => { whatsapps.forEach(async whats => { - + const sourcePath = path.join(__dirname, `../../.wwebjs_auth/`, `session-bd_${whats.id}`) if (fs.existsSync(sourcePath)) { try { - + const fastFolderSizeAsync = promisify(fastFolderSize) let size = await fastFolderSizeAsync(sourcePath) size = convertBytes(size) - + // SESSION MONITORING const io = getIO(); @@ -132,27 +159,46 @@ const monitor = async () => { } catch (error) { console.log('>>> SchedulingNotifiySendMessage.ts error: ', error) - stopSchedulingMonitor() - startSchedulingMonitor(timeInterval) } }; -export const startSchedulingMonitor = async (mileseconds: number) => { +const SchedulingNotifySendMessage = async () => { - timeInterval = mileseconds + try { + clearInterval(_fifo); - scheduler_monitor = setInterval(monitor, mileseconds) + await monitor() + } catch (error) { + console.log('error on SchedulingNotifySendMessage: ', error) + } + finally { + _fifo = setInterval(SchedulingNotifySendMessage, 5000); + } } +_fifo = setInterval(SchedulingNotifySendMessage, 5000); -export const stopSchedulingMonitor = async () => { - clearInterval(scheduler_monitor) +module.exports = SchedulingNotifySendMessage -} + +// export const startSchedulingMonitor = async (mileseconds: number) => { + +// timeInterval = mileseconds + +// scheduler_monitor = setInterval(monitor, mileseconds) + +// } + + +// export const stopSchedulingMonitor = async () => { + +// clearInterval(scheduler_monitor) + +// } diff --git a/backend/src/server.ts b/backend/src/server.ts index 4602c3d..86b2cb4 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -4,14 +4,15 @@ import { initIO } from "./libs/socket"; import { logger } from "./utils/logger"; import { StartAllWhatsAppsSessions } from "./services/WbotServices/StartAllWhatsAppsSessions"; -import { startSchedulingMonitor } from "./helpers/SchedulingNotifySendMessage" -import { startWhoIsOnlineMonitor } from "./helpers/WhoIsOnlineMonitor" +import "./helpers/SchedulingNotifySendMessage" +import { startWhoIsOnlineMonitor } from "./helpers/WhoIsOnlineMonitor" import { loadTicketsCache, flushCache, cacheSize } from './helpers/TicketCache' import { loadContactsCache } from './helpers/ContactsCache' import { loadWhatsappCache } from './helpers/WhatsCache' import { delRestoreControllFile } from "./helpers/RestoreControll"; import { createSessionDir } from "./helpers/CreateSessionDir"; +import { loadSchedulesCache, } from "./helpers/SchedulingNotifyCache"; const server = app.listen(process.env.PORT, () => { logger.info(`Server started on port: ${process.env.PORT}`); @@ -33,6 +34,7 @@ gracefulShutdown(server); await loadContactsCache() await loadTicketsCache() await loadWhatsappCache() + await loadSchedulesCache() } @@ -40,6 +42,6 @@ gracefulShutdown(server); createSessionDir() delRestoreControllFile() -startSchedulingMonitor(5000) + startWhoIsOnlineMonitor(3000) diff --git a/backend/src/services/SchedulingNotifyServices/CreateSchedulingNotifyService.ts b/backend/src/services/SchedulingNotifyServices/CreateSchedulingNotifyService.ts index 1315d5b..6c9d0e8 100644 --- a/backend/src/services/SchedulingNotifyServices/CreateSchedulingNotifyService.ts +++ b/backend/src/services/SchedulingNotifyServices/CreateSchedulingNotifyService.ts @@ -1,4 +1,5 @@ import AppError from "../../errors/AppError"; +import { createSchedulingNotifyCache } from "../../helpers/SchedulingNotifyCache"; import SchedulingNotify from "../../models/SchedulingNotify"; @@ -55,10 +56,11 @@ const CreateSchedulingNotifyService = async ({ schedulingTime, message - }) - + }) } + await createSchedulingNotifyCache(JSON.parse(JSON.stringify(schedulingNotify))) + return schedulingNotify } diff --git a/backend/src/services/SchedulingNotifyServices/ListSchedulingNotifyService.ts b/backend/src/services/SchedulingNotifyServices/ListSchedulingNotifyService.ts index 1c42641..c88fd3f 100644 --- a/backend/src/services/SchedulingNotifyServices/ListSchedulingNotifyService.ts +++ b/backend/src/services/SchedulingNotifyServices/ListSchedulingNotifyService.ts @@ -1,68 +1,83 @@ import { Op, Sequelize } from "sequelize"; +import { searchScheduleCache } from "../../helpers/SchedulingNotifyCache"; import SchedulingNotify from "../../models/SchedulingNotify"; interface Request { - searchParam?: string; - pageNumber?: string; - } - - interface Response { - schedulingNotifies: SchedulingNotify[]; - count: number; - hasMore: boolean; - } - - const ListSchedulingNotifyService = async ({ - searchParam = "", - pageNumber = "1" - }: Request): Promise => { - // const whereCondition = { - // message: Sequelize.where( - - // Sequelize.fn("date", Sequelize.col("schedulingDate")), `${searchParam.toLowerCase().trim()}`, - - // ), - - // }; + searchParam?: string; + pageNumber?: string; +} - let date = searchParam.split(' ')[0] - let hour = searchParam.split(' ')[1].split(':')[0] - let minute = searchParam.split(' ')[1].split(':')[1] - - const whereCondition = { - [Op.and]: [ - { - "$schedulingTime$": Sequelize.where(Sequelize.fn("date", Sequelize.col("schedulingTime")), `${date.trim()}`) - }, - { - "$schedulingTime$": Sequelize.where(Sequelize.fn("hour", Sequelize.col("schedulingTime")), `${hour.trim()}`) - }, - { - "$schedulingTime$": Sequelize.where(Sequelize.fn("minute", Sequelize.col("schedulingTime")), `${minute.trim()}`) - } - ] - }; +interface Response { + schedulingNotifies: SchedulingNotify[]; + count: number; + hasMore: boolean; +} +const ListSchedulingNotifyService = async ({ + searchParam = "", + pageNumber = "1" +}: Request): Promise => { + // const whereCondition = { + // message: Sequelize.where( + + // Sequelize.fn("date", Sequelize.col("schedulingDate")), `${searchParam.toLowerCase().trim()}`, + + // ), + + // }; + + let date = searchParam.split(' ')[0] + let hour = searchParam.split(' ')[1].split(':')[0] + let minute = searchParam.split(' ')[1].split(':')[1] + + let fromCache = null + + fromCache = await searchScheduleCache(date, hour, minute) + + if (fromCache) { - const limit = 1; - const offset = limit * (+pageNumber - 1); - - const { count, rows: schedulingNotifies } = await SchedulingNotify.findAndCountAll({ - raw: true, - where: whereCondition, - limit, - offset, - order: [["id", "ASC"]] - }); - - const hasMore = count > offset + schedulingNotifies.length; - return { - schedulingNotifies, - count, - hasMore + schedulingNotifies: fromCache, + count: 0, + hasMore: false, }; + + } + + + const whereCondition = { + [Op.and]: [ + { + "$schedulingTime$": Sequelize.where(Sequelize.fn("date", Sequelize.col("schedulingTime")), `${date.trim()}`) + }, + { + "$schedulingTime$": Sequelize.where(Sequelize.fn("hour", Sequelize.col("schedulingTime")), `${hour.trim()}`) + }, + { + "$schedulingTime$": Sequelize.where(Sequelize.fn("minute", Sequelize.col("schedulingTime")), `${minute.trim()}`) + } + ] }; - - export default ListSchedulingNotifyService; - \ No newline at end of file + + + const limit = 1; + const offset = limit * (+pageNumber - 1); + + const { count, rows: schedulingNotifies } = await SchedulingNotify.findAndCountAll({ + raw: true, + where: whereCondition, + limit, + offset, + order: [["id", "ASC"]] + }); + + const hasMore = count > offset + schedulingNotifies.length; + + return { + schedulingNotifies, + count, + hasMore + }; +}; + +export default ListSchedulingNotifyService; diff --git a/frontend/src/components/DashboardUser/TableUser.jsx b/frontend/src/components/DashboardUser/TableUser.jsx index e744d46..66fc804 100644 --- a/frontend/src/components/DashboardUser/TableUser.jsx +++ b/frontend/src/components/DashboardUser/TableUser.jsx @@ -92,7 +92,7 @@ const TableUser = ({ classes, usersOnlineInfo, logout }) => { {i18n.t("dashboard.table_users.column2")} {i18n.t("dashboard.table_users.column3")} {i18n.t("dashboard.table_users.column4")} - Ações + {i18n.t("dashboard.table_users.column5")} diff --git a/frontend/src/translate/languages/en.js b/frontend/src/translate/languages/en.js index 2ec83fa..7410d89 100644 --- a/frontend/src/translate/languages/en.js +++ b/frontend/src/translate/languages/en.js @@ -58,7 +58,7 @@ const messages = { column2: 'Open by Queue', column3: 'Closed by Queue', column4: 'Online time', - column4: 'Actions', + column5: 'Actions', } }, connections: { diff --git a/frontend/src/translate/languages/es.js b/frontend/src/translate/languages/es.js index caad541..6e047b2 100644 --- a/frontend/src/translate/languages/es.js +++ b/frontend/src/translate/languages/es.js @@ -60,7 +60,7 @@ const messages = { column2: 'Abrir por cola', column3: 'Cerrado por cola', column4: 'Tiempo Online', - column4: 'Actions', + column5: 'Actions', } }, connections: { diff --git a/frontend/src/translate/languages/pt.js b/frontend/src/translate/languages/pt.js index c6e6934..ca12b50 100644 --- a/frontend/src/translate/languages/pt.js +++ b/frontend/src/translate/languages/pt.js @@ -58,7 +58,7 @@ const messages = { column2: 'Abertos Por Fila', column3: 'Fechados Por Fila', column4: 'Tempo Online', - column4: 'Ações', + column5: 'Ações', } }, connections: {