feature/IO-3000-messaging-sockets-migrations2 - Base cleanup

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-11-20 11:35:30 -08:00
parent 299a675a9c
commit 261353b511
9 changed files with 145 additions and 305 deletions

View File

@@ -11,7 +11,6 @@ const logger = require("../utils/logger");
const InstanceManager = require("../utils/instanceMgr").default;
exports.receive = async (req, res) => {
// Perform request validation
const {
ioRedis,
ioHelpers: { getBodyshopRoom, getBodyshopConversationRoom }
@@ -50,20 +49,17 @@ exports.receive = async (req, res) => {
};
if (response.bodyshops[0]) {
if (response.bodyshops[0].conversations.length === 0) {
// No conversation found, create one
const bodyshop = response.bodyshops[0];
if (bodyshop.conversations.length === 0) {
newMessage.conversation = {
data: {
bodyshopid: response.bodyshops[0].id,
bodyshopid: bodyshop.id,
phone_num: phone(req.body.From).phoneNumber
}
};
try {
// Insert new conversation and message
const insertresp = await client.request(queries.RECEIVE_MESSAGE, { msg: newMessage });
// Safely access conversation and message
const createdConversation = insertresp?.insert_messages?.returning?.[0]?.conversation || null;
const message = insertresp?.insert_messages?.returning?.[0];
@@ -71,12 +67,12 @@ exports.receive = async (req, res) => {
throw new Error("Conversation data is missing from the response.");
}
const broadcastRoom = getBodyshopRoom(r2.insert_messages.returning[0].conversation.bodyshop.id);
const broadcastRoom = getBodyshopRoom(createdConversation.bodyshop.id);
const conversationRoom = getBodyshopConversationRoom({
bodyshopId: message.conversation.bodyshop.id,
conversationId: message.conversation.id
});
// Broadcast new message to the conversation room
ioRedis.to(broadcastRoom).emit("new-message-summary", {
isoutbound: false,
existingConversation: false,
@@ -86,6 +82,7 @@ exports.receive = async (req, res) => {
msid: message.sid,
summary: true
});
ioRedis.to(conversationRoom).emit("new-message-detailed", {
newMessage: message,
isoutbound: false,
@@ -103,24 +100,12 @@ exports.receive = async (req, res) => {
res.status(200).send("");
return;
} catch (e) {
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
messagingServiceSid: req.body.MessagingServiceSid,
error: e
});
res.status(500).json(e);
handleError(req, e, res, "RECEIVE_MESSAGE");
return;
}
} else if (response.bodyshops[0].conversations.length === 1) {
// Add to the existing conversation
// conversation UPDATED
newMessage.conversationid = response.bodyshops[0].conversations[0].id;
} else if (bodyshop.conversations.length === 1) {
newMessage.conversationid = bodyshop.conversations[0].id;
} else {
// Duplicate phone error
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
@@ -134,7 +119,6 @@ exports.receive = async (req, res) => {
}
try {
// Insert message into an existing conversation
const insertresp = await client.request(queries.INSERT_MESSAGE, {
msg: newMessage,
conversationid: newMessage.conversationid
@@ -167,52 +151,36 @@ exports.receive = async (req, res) => {
fcmresp
});
const broadcastRoom = getBodyshopRoom(r2.insert_messages.returning[0].conversation.bodyshop.id);
const broadcastRoom = getBodyshopRoom(message.conversation.bodyshop.id);
const conversationRoom = getBodyshopConversationRoom({
bodyshopId: message.conversation.bodyshop.id,
conversationId: message.conversation.id
});
// Broadcast new message to the conversation room
ioRedis.to(broadcastRoom).emit("new-message-summary", {
isoutbound: false,
existingConversation: true,
conversationId: conversationid,
conversationId: message.conversationid,
updated_at: message.updated_at,
msid: message.sid,
summary: true
});
ioRedis.to(conversationRoom).emit("new-message-detailed", {
newMessage: message,
isoutbound: false,
existingConversation: true,
conversationId: conversationid,
conversationId: message.conversationid,
summary: false
});
res.status(200).send("");
} catch (e) {
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
messagingServiceSid: req.body.MessagingServiceSid,
error: e
});
res.status(500).json(e);
handleError(req, e, res, "INSERT_MESSAGE");
}
}
} catch (e) {
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
messagingServiceSid: req.body.MessagingServiceSid,
error: e
});
res.status(500).json(e);
handleError(req, e, res, "FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID");
}
};
@@ -228,3 +196,17 @@ const generateMediaArray = (body) => {
return null;
}
};
const handleError = (req, error, res, context) => {
logger.log("sms-inbound-error", "ERROR", "api", null, {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: generateMediaArray(req.body),
messagingServiceSid: req.body.MessagingServiceSid,
context,
error
});
res.status(500).json({ error: error.message || "Internal Server Error" });
};

View File

@@ -8,10 +8,9 @@ const { phone } = require("phone");
const queries = require("../graphql-client/queries");
const logger = require("../utils/logger");
const client = twilio(process.env.TWILIO_AUTH_TOKEN, process.env.TWILIO_AUTH_KEY);
const { admin } = require("../firebase/firebase-handler");
const gqlClient = require("../graphql-client/graphql-client").client;
exports.send = (req, res) => {
exports.send = async (req, res) => {
const { to, messagingServiceSid, body, conversationid, selectedMedia, imexshopid } = req.body;
const {
ioRedis,
@@ -19,7 +18,7 @@ exports.send = (req, res) => {
} = req;
logger.log("sms-outbound", "DEBUG", req.user.email, null, {
messagingServiceSid: messagingServiceSid,
messagingServiceSid,
to: phone(to).phoneNumber,
mediaUrl: selectedMedia.map((i) => i.src),
text: body,
@@ -30,85 +29,10 @@ exports.send = (req, res) => {
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
});
if (!!to && !!messagingServiceSid && (!!body || !!selectedMedia.length > 0) && !!conversationid) {
client.messages
.create({
body: body,
messagingServiceSid: messagingServiceSid,
to: phone(to).phoneNumber,
mediaUrl: selectedMedia.map((i) => i.src)
})
.then((message) => {
let newMessage = {
msid: message.sid,
text: body,
conversationid,
isoutbound: true,
userid: req.user.email,
image: req.body.selectedMedia.length > 0,
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
};
gqlClient
.request(queries.INSERT_MESSAGE, { msg: newMessage, conversationid })
.then((r2) => {
//console.log("Responding GQL Message ID", JSON.stringify(r2));
logger.log("sms-outbound-success", "DEBUG", req.user.email, null, {
msid: message.sid,
conversationid
});
const data = {
type: "messaging-outbound",
conversationid: newMessage.conversationid || ""
};
// TODO Verify
// const messageData = response.insert_messages.returning[0];
// Broadcast new message to conversation room
const broadcastRoom = getBodyshopRoom(r2.insert_messages.returning[0].conversation.bodyshop.id);
const conversationRoom = getBodyshopConversationRoom({
bodyshopId: r2.insert_messages.returning[0].conversation.bodyshop.id,
conversationId: r2.insert_messages.returning[0].conversation.id
});
ioRedis.to(broadcastRoom).emit("new-message-summary", {
isoutbound: true,
conversationId: conversationid,
updated_at: r2.insert_messages.returning[0].updated_at,
msid: message.sid,
summary: true
});
ioRedis.to(conversationRoom).emit("new-message-detailed", {
newMessage: r2.insert_messages.returning[0],
conversationId: conversationid,
summary: false
});
res.sendStatus(200);
})
.catch((e2) => {
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
msid: message.sid,
conversationid,
error: e2.message,
stack: e2.stack
});
//res.json({ success: false, message: e2 });
});
})
.catch((e1) => {
//res.json({ success: false, message: error });
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
conversationid,
error: e1.message,
stack: e1.stack
});
});
} else {
if (!to || !messagingServiceSid || (!body && selectedMedia.length === 0) || !conversationid) {
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
type: "missing-parameters",
messagingServiceSid: messagingServiceSid,
messagingServiceSid,
to: phone(to).phoneNumber,
text: body,
conversationid,
@@ -118,5 +42,72 @@ exports.send = (req, res) => {
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
});
res.status(400).json({ success: false, message: "Missing required parameter(s)." });
return;
}
try {
const message = await client.messages.create({
body,
messagingServiceSid,
to: phone(to).phoneNumber,
mediaUrl: selectedMedia.map((i) => i.src)
});
const newMessage = {
msid: message.sid,
text: body,
conversationid,
isoutbound: true,
userid: req.user.email,
image: req.body.selectedMedia.length > 0,
image_path: req.body.selectedMedia.length > 0 ? selectedMedia.map((i) => i.src) : []
};
try {
const gqlResponse = await gqlClient.request(queries.INSERT_MESSAGE, { msg: newMessage, conversationid });
logger.log("sms-outbound-success", "DEBUG", req.user.email, null, {
msid: message.sid,
conversationid
});
const insertedMessage = gqlResponse.insert_messages.returning[0];
const broadcastRoom = getBodyshopRoom(insertedMessage.conversation.bodyshop.id);
const conversationRoom = getBodyshopConversationRoom({
bodyshopId: insertedMessage.conversation.bodyshop.id,
conversationId: insertedMessage.conversation.id
});
ioRedis.to(broadcastRoom).emit("new-message-summary", {
isoutbound: true,
conversationId: conversationid,
updated_at: insertedMessage.updated_at,
msid: message.sid,
summary: true
});
ioRedis.to(conversationRoom).emit("new-message-detailed", {
newMessage: insertedMessage,
conversationId: conversationid,
summary: false
});
res.sendStatus(200);
} catch (gqlError) {
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
msid: message.sid,
conversationid,
error: gqlError.message,
stack: gqlError.stack
});
res.status(500).json({ success: false, message: "Failed to insert message into database." });
}
} catch (twilioError) {
logger.log("sms-outbound-error", "ERROR", req.user.email, null, {
conversationid,
error: twilioError.message,
stack: twilioError.stack
});
res.status(500).json({ success: false, message: "Failed to send message through Twilio." });
}
};

View File

@@ -1,12 +1,4 @@
const { admin } = require("../firebase/firebase-handler");
const { MARK_MESSAGES_AS_READ, GET_CONVERSATIONS, GET_CONVERSATION_DETAILS } = require("../graphql-client/queries");
const { phone } = require("phone");
const { client: gqlClient } = require("../graphql-client/graphql-client");
const queries = require("../graphql-client/queries");
const twilio = require("twilio");
const client = require("../graphql-client/graphql-client").client;
const twilioClient = twilio(process.env.TWILIO_AUTH_TOKEN, process.env.TWILIO_AUTH_KEY);
const redisSocketEvents = ({
io,
@@ -84,6 +76,7 @@ const redisSocketEvents = ({
};
socket.on("update-token", updateToken);
};
// Room Broadcast Events
const registerRoomAndBroadcastEvents = (socket) => {
const joinBodyshopRoom = (bodyshopUUID) => {
@@ -138,6 +131,7 @@ const redisSocketEvents = ({
socket.on("disconnect", disconnect);
};
// Messaging Events
const registerMessagingEvents = (socket) => {
const joinConversationRoom = async ({ bodyshopId, conversationId }) => {
@@ -145,19 +139,26 @@ const redisSocketEvents = ({
const room = getBodyshopConversationRoom({ bodyshopId, conversationId });
socket.join(room);
} catch (error) {
logger.log("error", "Failed to join conversation", error);
logger.log("Failed to Join Conversation Room", "error", "io-redis", null, {
bodyshopId,
conversationId,
error: error.message,
stack: error.stack
});
socket.emit("error", { message: "Failed to join conversation" });
}
};
const leaveConversationRoom = ({ bodyshopId, conversationId }) => {
try {
const room = getBodyshopConversationRoom({ bodyshopId, conversationId });
socket.leave(room);
// Optionally notify the client
//socket.emit("conversation-left", { conversationId });
} catch (error) {
socket.emit("error", { message: "Failed to leave conversation" });
logger.log("Failed to Leave Conversation Room", "error", "io-redis", null, {
bodyshopId,
conversationId,
error: error.message,
stack: error.stack
});
}
};