@droppii-org/chat-sdk
Version:
Droppii React Chat SDK
289 lines (288 loc) • 12.3 kB
JavaScript
import { MessageStatus, } from "@openim/wasm-client-sdk";
import { DChatSDK } from "../../constants/sdk";
import { v4 as uuidv4 } from "uuid";
import { useChatContext } from "../../context/ChatContext";
import { useCallback } from "react";
import { pushNewMessage, updateOneMessage } from "./useMessage";
import { emit } from "../../utils/events";
import useConversationStore from "../../store/conversation";
import useAuthStore from "../../store/auth";
import { extractLinks, generateContentBasedOnMessageType, } from "../../utils/common";
export const createTextMessage = async (text) => {
let textMessage = await DChatSDK.createTextMessage(text, new Date().getTime().toString())
.then(({ data }) => {
return data;
})
.catch(({ errCode, errMsg }) => {
console.error("createTextMessage", errCode, errMsg);
return null;
});
return textMessage;
};
export const createImageMessageByFile = async (file) => {
let imageMessage = await DChatSDK.createImageMessageByFile(file, new Date().getTime().toString())
.then(({ data }) => {
return data;
})
.catch(({ errCode, errMsg }) => {
console.error("createImageMessageByFile", errCode, errMsg);
return null;
});
return imageMessage;
};
export const createMergerMessage = async (mergerMsgParams) => {
let mergerMessage = await DChatSDK.createMergerMessage(mergerMsgParams, new Date().getTime().toString())
.then(({ data }) => {
return data;
})
.catch(({ errCode, errMsg }) => {
console.error("createMergerMessage", errCode, errMsg);
return null;
});
return mergerMessage;
};
export const createVideoMessageByFile = async (file) => {
let videoMessage = await DChatSDK.createVideoMessageByFile(file, new Date().getTime().toString())
.then(({ data }) => {
return data;
})
.catch(({ errCode, errMsg }) => {
console.error("createVideoMessageByFile", errCode, errMsg);
return null;
});
return videoMessage;
};
export const createFileMessageByFile = async (file) => {
let fileMessage = await DChatSDK.createFileMessageByFile(file, new Date().getTime().toString())
.then(({ data }) => {
return data;
})
.catch(({ errCode, errMsg }) => {
console.error("createFileMessageByFile", errCode, errMsg);
return null;
});
return fileMessage;
};
export const createUrlTextMessage = async (text, urls) => {
let textMessage = await DChatSDK.createUrlTextMessage(text, JSON.stringify(urls), new Date().getTime().toString())
.then(({ data }) => {
return data;
})
.catch(({ errCode, errMsg }) => {
console.error("createUrlTextMessage", errCode, errMsg);
return null;
});
return textMessage;
};
export const useSendMessage = () => {
const { user } = useChatContext();
const conversationData = useConversationStore((state) => state.conversationData);
const { userID: recvID, groupID } = conversationData || {};
const sendMessage = useCallback(async (message) => {
var _a, _b;
try {
pushNewMessage(message);
emit("CHAT_LIST_SCROLL_TO_BOTTOM");
const { data: successMessage } = await DChatSDK.sendMessage({
recvID: recvID || "",
groupID: groupID || "",
message: message,
offlinePushInfo: {
title: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "Droppii Chat",
desc: `${generateContentBasedOnMessageType(message.contentType, ((_a = message === null || message === void 0 ? void 0 : message.textElem) === null || _a === void 0 ? void 0 : _a.content) || "")}` || "Bạn có tin nhắn mới",
ex: JSON.stringify({
icon: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL) || "",
conversationId: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID) || "",
title: (conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName) || "Droppii Chat",
desc: `${generateContentBasedOnMessageType(message.contentType, ((_b = message === null || message === void 0 ? void 0 : message.textElem) === null || _b === void 0 ? void 0 : _b.content) || "")}` || "Bạn có tin nhắn mới",
}),
iOSPushSound: "default",
iOSBadgeCount: true,
},
});
updateOneMessage(successMessage);
}
catch (error) {
updateOneMessage(Object.assign(Object.assign({}, message), { status: MessageStatus.Failed }));
}
}, [recvID, groupID]);
const sendTextMessage = useCallback(async ({ plainText, richText, currentSession, }) => {
if (!recvID && !groupID)
return;
const urls = extractLinks(plainText);
const isUrlMessage = urls.length > 0;
let message = null;
if (isUrlMessage) {
message = await createUrlTextMessage(plainText, urls);
}
else {
message = await createTextMessage(plainText);
}
if (!message)
return;
const extendMessageInfo = generateExtendMessageInfo({
richText,
currentSession,
});
let messageItem = Object.assign(Object.assign({}, message), { ex: JSON.stringify(extendMessageInfo) || "{}" });
sendMessage(messageItem);
}, [recvID, groupID, user, sendMessage]);
const sendMergeMessage = useCallback(async ({ richText, plainText, files, currentSession, }) => {
if (!recvID && !groupID)
return;
const messageList = [];
for (const fileWrapper of files) {
const file = fileWrapper.originFileObj;
if (!file)
continue;
const isImage = file.type.startsWith("image/");
const isVideo = file.type.startsWith("video/");
const isDocument = file.type.startsWith("application/");
try {
if (isImage) {
const picInfo = await createPicBaseInfoFromFile(file);
const baseInfo = {
uuid: uuidv4(),
type: file.type,
size: file.size,
width: picInfo.width,
height: picInfo.height,
url: URL.createObjectURL(file),
};
const parsedImage = {
sourcePicture: baseInfo,
bigPicture: baseInfo,
snapshotPicture: baseInfo,
sourcePath: "",
file: file,
};
const imageMessage = await createImageMessageByFile(parsedImage);
if (!imageMessage)
continue;
messageList.push(imageMessage);
}
else if (isVideo) {
const videoBaseInfo = await createVideoInfoWithThumbnail(file);
const thumbFile = new File([videoBaseInfo.thumbnail], file.name + "-thumb.jpg", {
type: "image/jpeg",
});
const videoMessage = await createVideoMessageByFile({
videoPath: "",
duration: videoBaseInfo.duration,
videoType: file.type,
snapshotPath: "",
videoUUID: uuidv4(),
videoUrl: "",
videoSize: file.size,
snapshotUUID: "",
snapshotSize: file.size,
snapshotUrl: "",
snapshotWidth: videoBaseInfo.width,
snapshotHeight: videoBaseInfo.height,
snapShotType: file.type,
videoFile: file,
snapshotFile: thumbFile,
});
if (!videoMessage)
continue;
messageList.push(videoMessage);
}
else if (isDocument) {
const fileMessage = await createFileMessageByFile({
filePath: "",
fileName: file.name,
uuid: uuidv4(),
sourceUrl: "",
fileSize: file.size,
fileType: file.type,
file: file,
});
if (!fileMessage)
continue;
messageList.push(fileMessage);
}
}
catch (err) {
console.error("Lỗi xử lý tin nhắn:", err);
}
}
if (!!plainText && plainText.trim() !== "") {
const textMessage = await createTextMessage(plainText);
if (!textMessage)
return;
messageList.push(textMessage);
}
for (const message of messageList) {
const extendMessageInfo = generateExtendMessageInfo({
richText,
currentSession,
});
const mMessage = Object.assign(Object.assign({}, message), { ex: JSON.stringify(extendMessageInfo) || "{}" });
await sendMessage(mMessage);
}
}, [recvID, groupID, sendMessage]);
return {
sendTextMessage,
sendMergeMessage,
};
};
export const generateExtendMessageInfo = ({ richText, currentSession, }) => {
return {
messageInfo: {
type: "MESSAGE_INFO",
data: {
type: "rich_text",
content: richText || "",
},
},
sessionId: (currentSession === null || currentSession === void 0 ? void 0 : currentSession.id) || "",
applicationType: useAuthStore.getState().applicationType,
};
};
const createPicBaseInfoFromFile = (file) => new Promise((resolve, reject) => {
const _URL = window.URL || window.webkitURL;
const img = new Image();
img.onload = function () {
resolve(img);
};
img.src = _URL.createObjectURL(file);
});
function createVideoInfoWithThumbnail(file) {
return new Promise((resolve, reject) => {
try {
const video = document.createElement("video");
video.preload = "metadata";
video.src = URL.createObjectURL(file);
video.onloadedmetadata = () => {
const duration = Math.floor(video.duration * 1000);
const width = video.videoWidth;
const height = video.videoHeight;
// Seek tới giây 1 (nếu video dài hơn 1s) để lấy frame đẹp hơn
video.currentTime = Math.min(1, video.duration / 2);
};
video.onseeked = () => {
const canvas = document.createElement("canvas");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const ctx = canvas.getContext("2d");
if (!ctx)
return reject("Canvas not supported");
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
canvas.toBlob((blob) => {
if (!blob)
return reject("Thumbnail capture failed");
resolve({
duration: Math.floor(video.duration * 1000),
width: video.videoWidth,
height: video.videoHeight,
thumbnail: blob,
});
}, "image/jpeg", 0.85);
};
video.onerror = (err) => reject(err);
}
catch (e) {
reject(e);
}
});
}