Merge pull request 'fix something idon't no' (#1) from zelda.fix-some-i-dont-no into main

Reviewed-on: #1
This commit is contained in:
zelda 2026-04-24 16:57:08 +10:00
commit 45bbf1f65f
9 changed files with 173 additions and 109 deletions

BIN
.DS_Store vendored

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,23 +1,26 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { globalIgnores } from 'eslint/config'
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
import { globalIgnores } from "eslint/config";
export default tseslint.config([
globalIgnores(['dist']),
globalIgnores(["dist"]),
{
files: ['**/*.{ts,tsx}'],
files: ["**/*.{ts,tsx}"],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs['recommended-latest'],
reactHooks.configs["recommended-latest"],
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
"@typescript-eslint/no-unused-vars": ["off"],
},
])
},
]);

View File

@ -42,7 +42,7 @@ function initSocket() {
// Socket.IO events
socket.on("connect", () => {
console.log("✅ Socket.IO connected");
console.log("✅ Socket.IO connectedd");
broadcastToPorts({
type: "socket",
event: "connect",
@ -60,6 +60,7 @@ function initSocket() {
eventsToListen.forEach((event) => {
socket?.on(event, (data: any) => {
console.log({ event });
broadcastToPorts({
type: "socket",
event,
@ -143,7 +144,7 @@ chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === "reloadEvery4Hours") {
console.log(
"🔄 Reloading all tabs (every 4 hours)",
new Date().toLocaleString()
new Date().toLocaleString(),
);
// Reload tất cả các tab đang mở

View File

@ -44,11 +44,3 @@ contentService.startSyncConversations();
// AUTO SYNC MESAGE PREFIX (INTERNAL)
contentService.autoSyncConversationPrefixMessages();
// setTimeout(async () => {
// const a = new TeamsChatService();
// const conversations = await a.handleGetConversations();
// console.log({ conversations });
// }, 10000);

View File

@ -23,7 +23,7 @@ export class ContentService {
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
null,
).singleNodeValue;
}
@ -74,7 +74,7 @@ export class ContentService {
}
private async _waitForMessagesToAppear(
timeoutMs = 10000
timeoutMs = 10000,
): Promise<HTMLElement[]> {
return new Promise((resolve, reject) => {
const chatPaneList = document.getElementById("chat-pane-list");
@ -114,46 +114,46 @@ export class ContentService {
});
}
private async _waitForNewMessages(
existingItems: HTMLElement[],
timeoutMs = 10000
): Promise<HTMLElement[]> {
return new Promise((resolve, reject) => {
const chatPaneList = document.getElementById("chat-pane-list");
// private async _waitForNewMessages(
// existingItems: HTMLElement[],
// timeoutMs = 10000
// ): Promise<HTMLElement[]> {
// return new Promise((resolve, reject) => {
// const chatPaneList = document.getElementById("chat-pane-list");
if (!chatPaneList) {
return reject(new Error("#chat-pane-list not found"));
}
// if (!chatPaneList) {
// return reject(new Error("#chat-pane-list not found"));
// }
const getChildren = () =>
Array.from(chatPaneList.children) as HTMLElement[];
// const getChildren = () =>
// Array.from(chatPaneList.children) as HTMLElement[];
const existingSet = new Set(existingItems);
// const existingSet = new Set(existingItems);
let timeoutHandle: any = null;
// let timeoutHandle: any = null;
const observer = new MutationObserver(() => {
const currentChildren = getChildren();
const newItems = currentChildren.filter((el) => !existingSet.has(el));
// const observer = new MutationObserver(() => {
// const currentChildren = getChildren();
// const newItems = currentChildren.filter((el) => !existingSet.has(el));
if (newItems.length > 0) {
observer.disconnect();
if (timeoutHandle) clearTimeout(timeoutHandle);
resolve(newItems);
}
});
// if (newItems.length > 0) {
// observer.disconnect();
// if (timeoutHandle) clearTimeout(timeoutHandle);
// resolve(newItems);
// }
// });
observer.observe(chatPaneList, {
childList: true,
subtree: true,
});
// observer.observe(chatPaneList, {
// childList: true,
// subtree: true,
// });
timeoutHandle = setTimeout(() => {
observer.disconnect();
reject(new Error("Timeout waiting for new messages"));
}, timeoutMs);
});
}
// timeoutHandle = setTimeout(() => {
// observer.disconnect();
// reject(new Error("Timeout waiting for new messages"));
// }, timeoutMs);
// });
// }
private async _waitToloadMessages(stableTime = 300): Promise<any> {
return new Promise((resolve) => {
@ -189,24 +189,24 @@ export class ContentService {
});
}
private _getTypeGeo() {
const el = document.querySelector(".ck-placeholder");
// private _getTypeGeo() {
// const el = document.querySelector(".ck-placeholder");
if (el) {
const rect = el.getBoundingClientRect();
// if (el) {
// const rect = el.getBoundingClientRect();
return {
top: rect.top,
left: rect.left,
right: rect.right,
bottom: rect.bottom,
width: rect.width,
height: rect.height,
};
}
// return {
// top: rect.top,
// left: rect.left,
// right: rect.right,
// bottom: rect.bottom,
// width: rect.width,
// height: rect.height,
// };
// }
return null;
}
// return null;
// }
private async _rightClickMessage(date_time: number) {
const selector = this.service.elTags.container_chat;
@ -234,7 +234,7 @@ export class ContentService {
scrollContainer.scrollTop = Math.max(
0,
scrollContainer.scrollTop - scrollStep
scrollContainer.scrollTop - scrollStep,
);
await delay(200); // Đợi scroll và DOM render lại
@ -385,6 +385,8 @@ export class ContentService {
initialMessages = await this._waitForMessagesToAppear(); // Đợi có item đầu tiên
await this._waitToloadMessages();
console.log({ initialMessages });
}
await this._clickIfExists(this.service.elTags.close_reply_btn);
@ -392,7 +394,7 @@ export class ContentService {
await this._rightClickMessage(time);
const replyBtn: any = document.querySelector(
this.service.elTags.reply_btn
this.service.elTags.reply_btn,
);
if (replyBtn) {
@ -410,7 +412,7 @@ export class ContentService {
fixedHeightChatInput(retry = 20, interval = 2000) {
const tryFind = () => {
const el = document.querySelector(
this.service.elTags.chat_input
this.service.elTags.chat_input,
) as HTMLElement;
if (el) {
@ -419,7 +421,7 @@ export class ContentService {
} else if (retry > 0) {
setTimeout(
() => this.fixedHeightChatInput(retry - 1, interval),
interval
interval,
);
} else {
console.warn("✘ Element not found with provided XPath after retries");
@ -448,7 +450,7 @@ export class ContentService {
// Lấy attribute aria-labelledby
const ariaValue = document
.querySelector(
'[aria-labelledby^="cn-normal-notification-main-content-"]'
'[aria-labelledby^="cn-normal-notification-main-content-"]',
)
?.getAttribute("aria-labelledby");
@ -478,7 +480,7 @@ export class ContentService {
if (!roomId) {
console.warn(
"[Monitor] Could not extract room_id from aria-labelledby"
"[Monitor] Could not extract room_id from aria-labelledby",
);
return;
}
@ -563,7 +565,7 @@ export class ContentService {
() => {
this.getConversations();
},
120000
120000,
);
console.log("✅ startSyncConversations running");
} else {
@ -572,13 +574,73 @@ export class ContentService {
}
// Interval chạy, chỉ add task vào queue
autoSyncConversationPrefixMessages() {
(window as any)._chatIntervals = (window as any)?._chatIntervals || {};
// autoSyncConversationPrefixMessages() {
// (window as any)._chatIntervals = (window as any)?._chatIntervals || {};
// if (!(window as any)._chatIntervals.syncPrefixMessages) {
// (window as any)._chatIntervals.syncPrefixMessages = (
// window as any
// ).setInterval(() => {
// (window as any)["is_sync_conversation_prefix"] = true;
// queue.add(async () => {
// try {
// const { data } =
// (await conversationApi.getConversationByPrefix()) as {
// data: ChatItem[];
// };
// if (!data) return;
// for (const chat of data) {
// this._clickToConversation(chat.id as string);
// await delay(5000);
// const currentRoom = this.service.getCurrentRoomInfo();
// if (!currentRoom || currentRoom.room_id !== chat.id) return;
// const filesMessages = this.filesMessages();
// if (filesMessages.length) {
// await this.clickToRefreshToken(filesMessages);
// }
// const messages = this.service.extractAllMessages();
// await messageApi.createAndSendToZulip(messages);
// await delay(5000);
// }
// } catch (err) {
// console.error(
// "❌ autoSyncConversationPrefixMessages error:",
// (err as any)?.message,
// );
// messageApi.sendLog({
// type: "error",
// message: `auto_to_sync_conersations: ${(err as any)?.message}`,
// });
// }
// });
// }, 60000);
// console.log("✅ autoSyncConversationPrefixMessages running with PQueue");
// } else {
// console.log(" autoSyncConversationPrefixMessages already running");
// }
// }
autoSyncConversationPrefixMessages() {
(window as any)._chatIntervals = (window as any)._chatIntervals || {};
if ((window as any)._chatIntervals.syncPrefixMessages) {
console.log("autoSyncConversationPrefixMessages already running");
return;
}
let isRunning = false;
(window as any)._chatIntervals.syncPrefixMessages = window.setInterval(
() => {
if (isRunning) {
console.log("syncPrefixMessages skipped (still running)");
return;
}
isRunning = true;
if (!(window as any)._chatIntervals.syncPrefixMessages) {
(window as any)._chatIntervals.syncPrefixMessages = (
window as any
).setInterval(() => {
queue.add(async () => {
try {
const { data } =
@ -586,7 +648,7 @@ export class ContentService {
data: ChatItem[];
};
if (!data) return;
if (!data?.length) return;
for (const chat of data) {
this._clickToConversation(chat.id as string);
@ -594,37 +656,39 @@ export class ContentService {
await delay(5000);
const currentRoom = this.service.getCurrentRoomInfo();
if (!currentRoom || currentRoom.room_id !== chat.id) return;
if (!currentRoom || currentRoom.room_id !== chat.id) {
console.warn("room mismatch, skip:", chat.id);
continue;
}
const filesMessages = this.filesMessages();
if (filesMessages.length) {
await this.clickToRefreshToken(filesMessages);
}
const messages = this.service.extractAllMessages();
await messageApi.createAndSendToZulip(messages);
await delay(5000);
}
} catch (err) {
console.error(
"autoSyncConversationPrefixMessages error:",
(err as any)?.message
"autoSyncConversationPrefixMessages error:",
(err as any)?.message,
);
messageApi.sendLog({
type: "error",
message: `auto_to_sync_conersations: ${(err as any)?.message}`,
});
} finally {
isRunning = false; // 🔑 cực kỳ quan trọng
}
});
}, 40000);
},
60000,
);
console.log("✅ autoSyncConversationPrefixMessages running with PQueue");
} else {
console.log(" autoSyncConversationPrefixMessages already running");
}
console.log("autoSyncConversationPrefixMessages running safely");
}
}

View File

@ -11,12 +11,13 @@ import * as fs from 'fs';
import { SocketIoAdapter } from './socket-adapter';
async function bootstrap() {
const httpsOptions = {
key: fs.readFileSync('ssl/localhost+1-key.pem'),
cert: fs.readFileSync('ssl/localhost+1.pem'),
};
// const httpsOptions = {
// key: fs.readFileSync('ssl/localhost+1-key.pem'),
// cert: fs.readFileSync('ssl/localhost+1.pem'),
// };
const app = await NestFactory.create(AppModule, { httpsOptions });
const app = await NestFactory.create(AppModule);
// const app = await NestFactory.create(AppModule, { httpsOptions });
const prefix_version = process.env.PREFIX_VERSION;
@ -54,12 +55,14 @@ async function bootstrap() {
useContainer(app.select(AppModule), { fallbackOnErrors: true });
app.useWebSocketAdapter(new SocketIoAdapter(app));
await app.listen(Number(process.env.APP_API_PORT));
// ===== App cho WebSocket (WS hoặc WSS) =====
const wsApp = await NestFactory.create(AppModule);
wsApp.useWebSocketAdapter(new SocketIoAdapter(wsApp));
await wsApp.listen(Number(process.env.APP_SOCKET_PORT));
// // ===== App cho WebSocket (WS hoặc WSS) =====
// const wsApp = await NestFactory.create(AppModule);
// wsApp.useWebSocketAdapter(new SocketIoAdapter(wsApp));
// await wsApp.listen(Number(process.env.APP_SOCKET_PORT));
}
bootstrap();

View File

@ -30,6 +30,7 @@ export class MessagesGateway implements OnGatewayConnection {
for (const event of eventsToForward) {
this.event.on(event, (data) => {
console.log({ event, data });
this.server.emit(event, data);
});
}