add multi-account logic
This commit is contained in:
+217
-140
@@ -13,6 +13,7 @@ import {detectBrowser} from '../utils/browserDetector.mjs';
|
|||||||
import {insertGarbledText} from './garbledText.mjs';
|
import {insertGarbledText} from './garbledText.mjs';
|
||||||
import * as imageStorage from "../imageStorage.mjs";
|
import * as imageStorage from "../imageStorage.mjs";
|
||||||
import Logger from './logger.mjs';
|
import Logger from './logger.mjs';
|
||||||
|
import {clientState} from "../index.mjs";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@@ -28,16 +29,11 @@ class YouProvider {
|
|||||||
this.rotationEnabled = true;
|
this.rotationEnabled = true;
|
||||||
this.uploadFileFormat = process.env.UPLOAD_FILE_FORMAT || 'docx';
|
this.uploadFileFormat = process.env.UPLOAD_FILE_FORMAT || 'docx';
|
||||||
this.currentMode = this.isCustomModeEnabled ? 'custom' : 'default';
|
this.currentMode = this.isCustomModeEnabled ? 'custom' : 'default';
|
||||||
this.modeStatus = {
|
|
||||||
default: true,
|
|
||||||
custom: true,
|
|
||||||
}; // 记录可用状态
|
|
||||||
this.switchCounter = 0;
|
this.switchCounter = 0;
|
||||||
this.requestsInCurrentMode = 0;
|
this.requestsInCurrentMode = 0;
|
||||||
this.lastDefaultThreshold = 0; // 记录上一次default的阈值
|
this.lastDefaultThreshold = 0; // 记录上一次default的阈值
|
||||||
this.switchThreshold = this.getRandomSwitchThreshold();
|
this.switchThreshold = this.getRandomSwitchThreshold();
|
||||||
this.networkMonitor = new NetworkMonitor();
|
this.networkMonitor = new NetworkMonitor();
|
||||||
this.isTeamAccount = false; // 是否为Team账号
|
|
||||||
this.logger = new Logger();
|
this.logger = new Logger();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,9 +70,31 @@ class YouProvider {
|
|||||||
|
|
||||||
// 检测Chrome和Edge浏览器
|
// 检测Chrome和Edge浏览器
|
||||||
const browserPath = detectBrowser(this.preferredBrowser);
|
const browserPath = detectBrowser(this.preferredBrowser);
|
||||||
|
|
||||||
this.sessions = {};
|
this.sessions = {};
|
||||||
const timeout = 120000; // 120 秒超时
|
const timeout = 120000;
|
||||||
|
// 创建共享浏览器用户数据
|
||||||
|
const sharedProfilePath = path.join(__dirname, "browser_profiles", "shared_profile");
|
||||||
|
createDirectoryIfNotExists(sharedProfilePath);
|
||||||
|
// 创建浏览器
|
||||||
|
const response = await connect({
|
||||||
|
headless: "auto",
|
||||||
|
turnstile: true,
|
||||||
|
customConfig: {
|
||||||
|
userDataDir: sharedProfilePath,
|
||||||
|
executablePath: browserPath,
|
||||||
|
args: [
|
||||||
|
'--no-sandbox',
|
||||||
|
'--disable-setuid-sandbox',
|
||||||
|
'--remote-debugging-address=::',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {page, browser} = response;
|
||||||
|
this.browser = browser;
|
||||||
|
this.page = page;
|
||||||
|
|
||||||
|
this.skipAccountValidation = process.env.SKIP_ACCOUNT_VALIDATION !== "true";
|
||||||
|
|
||||||
if (process.env.USE_MANUAL_LOGIN === "true") {
|
if (process.env.USE_MANUAL_LOGIN === "true") {
|
||||||
this.sessions['manual_login'] = {
|
this.sessions['manual_login'] = {
|
||||||
@@ -84,6 +102,36 @@ class YouProvider {
|
|||||||
valid: false,
|
valid: false,
|
||||||
};
|
};
|
||||||
console.log("当前使用手动登录模式,跳过config.mjs文件中的 cookie 验证");
|
console.log("当前使用手动登录模式,跳过config.mjs文件中的 cookie 验证");
|
||||||
|
|
||||||
|
// 手动登录
|
||||||
|
console.log(`请在打开的浏览器窗口中手动登录 You.com`);
|
||||||
|
await page.goto("https://you.com", {timeout: timeout});
|
||||||
|
await sleep(3000); // 等待页面加载完毕
|
||||||
|
|
||||||
|
// 等待手动登录完成
|
||||||
|
const {loginInfo, sessionCookie} = await this.waitForManualLogin(page);
|
||||||
|
if (sessionCookie) {
|
||||||
|
const email = loginInfo || sessionCookie.email || 'manual_login';
|
||||||
|
this.sessions[email] = {
|
||||||
|
...this.sessions['manual_login'],
|
||||||
|
...sessionCookie,
|
||||||
|
valid: true,
|
||||||
|
// 添加 modeStatus 属性
|
||||||
|
modeStatus: {
|
||||||
|
default: true,
|
||||||
|
custom: true,
|
||||||
|
},
|
||||||
|
isTeamAccount: false,
|
||||||
|
};
|
||||||
|
delete this.sessions['manual_login'];
|
||||||
|
console.log(`成功获取 ${email} 登录的 cookie (${sessionCookie.isNewVersion ? '新版' : '旧版'})`);
|
||||||
|
|
||||||
|
// 设置隐身模式 cookie
|
||||||
|
await page.setCookie(...sessionCookie);
|
||||||
|
} else {
|
||||||
|
console.error(`未能获取有效的登录 cookie`);
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 使用配置文件中的 cookie
|
// 使用配置文件中的 cookie
|
||||||
for (let index = 0; index < config.sessions.length; index++) {
|
for (let index = 0; index < config.sessions.length; index++) {
|
||||||
@@ -93,13 +141,20 @@ class YouProvider {
|
|||||||
// 旧版cookie处理
|
// 旧版cookie处理
|
||||||
try {
|
try {
|
||||||
const jwt = JSON.parse(Buffer.from(jwtToken.split(".")[1], "base64").toString());
|
const jwt = JSON.parse(Buffer.from(jwtToken.split(".")[1], "base64").toString());
|
||||||
this.sessions[jwt.user.name] = {
|
const username = jwt.user.name;
|
||||||
|
this.sessions[username] = {
|
||||||
configIndex: index,
|
configIndex: index,
|
||||||
jwtSession,
|
jwtSession,
|
||||||
jwtToken,
|
jwtToken,
|
||||||
valid: false,
|
valid: false,
|
||||||
|
// 添加 modeStatus 属性
|
||||||
|
modeStatus: {
|
||||||
|
default: true,
|
||||||
|
custom: true,
|
||||||
|
},
|
||||||
|
isTeamAccount: false,
|
||||||
};
|
};
|
||||||
console.log(`已添加 #${index} ${jwt.user.name} (旧版cookie)`);
|
console.log(`已添加 #${index} ${username} (旧版cookie)`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`解析第${index}个旧版cookie失败: ${e.message}`);
|
console.error(`解析第${index}个旧版cookie失败: ${e.message}`);
|
||||||
}
|
}
|
||||||
@@ -107,13 +162,20 @@ class YouProvider {
|
|||||||
// 新版cookie处理
|
// 新版cookie处理
|
||||||
try {
|
try {
|
||||||
const jwt = JSON.parse(Buffer.from(ds.split(".")[1], "base64").toString());
|
const jwt = JSON.parse(Buffer.from(ds.split(".")[1], "base64").toString());
|
||||||
this.sessions[jwt.email] = {
|
const username = jwt.email;
|
||||||
|
this.sessions[username] = {
|
||||||
configIndex: index,
|
configIndex: index,
|
||||||
ds,
|
ds,
|
||||||
dsr,
|
dsr,
|
||||||
valid: false,
|
valid: false,
|
||||||
|
// 添加 modeStatus 属性
|
||||||
|
modeStatus: {
|
||||||
|
default: true,
|
||||||
|
custom: true,
|
||||||
|
},
|
||||||
|
isTeamAccount: false,
|
||||||
};
|
};
|
||||||
console.log(`已添加 #${index} ${jwt.email} (新版cookie)`);
|
console.log(`已添加 #${index} ${username} (新版cookie)`);
|
||||||
if (!dsr) {
|
if (!dsr) {
|
||||||
console.warn(`警告: 第${index}个cookie缺少DSR字段。`);
|
console.warn(`警告: 第${index}个cookie缺少DSR字段。`);
|
||||||
}
|
}
|
||||||
@@ -125,56 +187,16 @@ class YouProvider {
|
|||||||
console.error(`未检测到有效的DS或stytch_session字段。`);
|
console.error(`未检测到有效的DS或stytch_session字段。`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(`已添加 ${Object.keys(this.sessions).length} 个 cookie,开始验证有效性`);
|
console.log(`已添加 ${Object.keys(this.sessions).length} 个 cookie`);
|
||||||
}
|
}
|
||||||
|
if (this.skipAccountValidation) {
|
||||||
|
console.log(`开始验证cookie有效性...`);
|
||||||
for (const originalUsername of Object.keys(this.sessions)) {
|
for (const originalUsername of Object.keys(this.sessions)) {
|
||||||
let currentUsername = originalUsername;
|
let currentUsername = originalUsername;
|
||||||
let session = this.sessions[currentUsername];
|
let session = this.sessions[currentUsername];
|
||||||
createDirectoryIfNotExists(path.join(__dirname, "browser_profiles", currentUsername));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await connect({
|
// 设置账户的Cookie
|
||||||
headless: "auto",
|
|
||||||
turnstile: true,
|
|
||||||
customConfig: {
|
|
||||||
userDataDir: path.join(__dirname, "browser_profiles", currentUsername),
|
|
||||||
executablePath: browserPath,
|
|
||||||
args: [
|
|
||||||
'--no-sandbox',
|
|
||||||
'--disable-setuid-sandbox',
|
|
||||||
'--remote-debugging-address=::',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const {page, browser} = response;
|
|
||||||
if (process.env.USE_MANUAL_LOGIN === "true") {
|
|
||||||
console.log(`正在为 session #${session.configIndex} 进行手动登录...`);
|
|
||||||
await page.goto("https://you.com", {timeout: timeout});
|
|
||||||
// 等待页面加载完毕
|
|
||||||
await sleep(3000);
|
|
||||||
console.log(`请在打开的浏览器窗口中手动登录 You.com (session #${session.configIndex})`);
|
|
||||||
const {loginInfo, sessionCookie} = await this.waitForManualLogin(page);
|
|
||||||
if (sessionCookie) {
|
|
||||||
const email = loginInfo || sessionCookie.email;
|
|
||||||
this.sessions[email] = {
|
|
||||||
...session,
|
|
||||||
...sessionCookie,
|
|
||||||
};
|
|
||||||
delete this.sessions[currentUsername];
|
|
||||||
currentUsername = email;
|
|
||||||
session = this.sessions[currentUsername];
|
|
||||||
console.log(`成功获取 ${email} 登录的 cookie (${sessionCookie.isNewVersion ? '新版' : '旧版'})`);
|
|
||||||
|
|
||||||
// 兼容设置隐身模式
|
|
||||||
await page.setCookie(...sessionCookie);
|
|
||||||
} else {
|
|
||||||
console.error(`未能获取到 session #${session.configIndex} 有效登录的 cookie`);
|
|
||||||
await browser.close();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await page.setCookie(...getSessionCookie(
|
await page.setCookie(...getSessionCookie(
|
||||||
session.jwtSession,
|
session.jwtSession,
|
||||||
session.jwtToken,
|
session.jwtToken,
|
||||||
@@ -183,10 +205,9 @@ class YouProvider {
|
|||||||
));
|
));
|
||||||
await page.goto("https://you.com", {timeout: timeout});
|
await page.goto("https://you.com", {timeout: timeout});
|
||||||
await sleep(5000); // 等待加载完毕
|
await sleep(5000); // 等待加载完毕
|
||||||
}
|
|
||||||
|
|
||||||
// 检测是否为 team 账号
|
// 检测是否为 team 账号
|
||||||
this.isTeamAccount = await page.evaluate(() => {
|
session.isTeamAccount = await page.evaluate(() => {
|
||||||
const teamElement = document.querySelector('div._16bctla1 p._16bctla2');
|
const teamElement = document.querySelector('div._16bctla1 p._16bctla2');
|
||||||
return teamElement && teamElement.textContent === 'Your Team';
|
return teamElement && teamElement.textContent === 'Your Team';
|
||||||
});
|
});
|
||||||
@@ -209,11 +230,9 @@ class YouProvider {
|
|||||||
const json = JSON.parse(content);
|
const json = JSON.parse(content);
|
||||||
const allowNonPro = process.env.ALLOW_NON_PRO === "true";
|
const allowNonPro = process.env.ALLOW_NON_PRO === "true";
|
||||||
|
|
||||||
if (this.isTeamAccount) {
|
if (session.isTeamAccount) {
|
||||||
console.log(`${currentUsername} 有效 (Team 计划)`);
|
console.log(`${currentUsername} 有效 (Team 计划)`);
|
||||||
session.valid = true;
|
session.valid = true;
|
||||||
session.browser = browser;
|
|
||||||
session.page = page;
|
|
||||||
session.isTeam = true;
|
session.isTeam = true;
|
||||||
|
|
||||||
// 获取 Team 订阅信息
|
// 获取 Team 订阅信息
|
||||||
@@ -224,8 +243,6 @@ class YouProvider {
|
|||||||
} else if (json.subscriptions && json.subscriptions.length > 0) {
|
} else if (json.subscriptions && json.subscriptions.length > 0) {
|
||||||
console.log(`${currentUsername} 有效 (Pro 计划)`);
|
console.log(`${currentUsername} 有效 (Pro 计划)`);
|
||||||
session.valid = true;
|
session.valid = true;
|
||||||
session.browser = browser;
|
|
||||||
session.page = page;
|
|
||||||
session.isPro = true;
|
session.isPro = true;
|
||||||
|
|
||||||
// 获取 Pro 订阅信息
|
// 获取 Pro 订阅信息
|
||||||
@@ -237,27 +254,28 @@ class YouProvider {
|
|||||||
console.log(`${currentUsername} 有效 (非Pro)`);
|
console.log(`${currentUsername} 有效 (非Pro)`);
|
||||||
console.warn(`警告: ${currentUsername} 没有Pro或Team订阅,功能受限。`);
|
console.warn(`警告: ${currentUsername} 没有Pro或Team订阅,功能受限。`);
|
||||||
session.valid = true;
|
session.valid = true;
|
||||||
session.browser = browser;
|
|
||||||
session.page = page;
|
|
||||||
session.isPro = false;
|
session.isPro = false;
|
||||||
session.isTeam = false;
|
session.isTeam = false;
|
||||||
} else {
|
} else {
|
||||||
console.log(`${currentUsername} 无有效订阅`);
|
console.log(`${currentUsername} 无有效订阅`);
|
||||||
console.warn(`警告: ${currentUsername} 可能没有有效的订阅。请检查You是否有有效的Pro或Team订阅。`);
|
console.warn(`警告: ${currentUsername} 可能没有有效的订阅。请检查You是否有有效的Pro或Team订阅。`);
|
||||||
await this.clearYouCookies(page);
|
await this.clearYouCookies(page);
|
||||||
await browser.close();
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`${currentUsername} 已失效`);
|
console.log(`${currentUsername} 已失效`);
|
||||||
console.warn(`警告: ${currentUsername} 验证失败。请检查cookie是否有效。`);
|
console.warn(`警告: ${currentUsername} 验证失败。请检查cookie是否有效。`);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
await this.clearYouCookies(page);
|
await this.clearYouCookies(page);
|
||||||
await browser.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentUsername !== Object.keys(this.sessions)[Object.keys(this.sessions).length - 1]) {
|
||||||
|
await this.clearYouCookies(page);
|
||||||
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`初始化浏览器失败 (${currentUsername})`);
|
console.error(`验证账户 ${currentUsername} 时出错:`, e);
|
||||||
console.error(e);
|
session.valid = false;
|
||||||
await browser?.close();
|
await this.clearYouCookies(page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,9 +303,19 @@ class YouProvider {
|
|||||||
console.log('}');
|
console.log('}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(`验证完毕,有效cookie数量 ${Object.keys(this.sessions).filter((username) => this.sessions[username].valid).length}`);
|
} else {
|
||||||
|
console.warn('\x1b[33m%s\x1b[0m', '警告: 已跳过账号验证。可能存在账号信息不正确或无效。');
|
||||||
|
for (const username in this.sessions) {
|
||||||
|
this.sessions[username].valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 开始网络监控
|
// 开始网络监控
|
||||||
await this.networkMonitor.startMonitoring();
|
await this.networkMonitor.startMonitoring();
|
||||||
|
const validSessionsCount = Object.keys(this.sessions).filter(username => this.sessions[username].valid).length;
|
||||||
|
this.isSingleSession = (validSessionsCount === 1) || (process.env.USE_MANUAL_LOGIN === "true");
|
||||||
|
console.log(`验证完毕,有效cookie数量 ${validSessionsCount}`);
|
||||||
|
console.log(`开启 ${this.isSingleSession ? "单账号模式" : "多账号模式"}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTeamSubscriptionInfo(subscription) {
|
async getTeamSubscriptionInfo(subscription) {
|
||||||
@@ -532,11 +560,11 @@ class YouProvider {
|
|||||||
return result + '.' + this.uploadFileFormat;
|
return result + '.' + this.uploadFileFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAndSwitchMode() {
|
checkAndSwitchMode(session) {
|
||||||
// 如果当前模式不可用
|
// 如果当前模式不可用
|
||||||
if (!this.modeStatus[this.currentMode]) {
|
if (!session.modeStatus[this.currentMode]) {
|
||||||
|
|
||||||
const availableModes = Object.keys(this.modeStatus).filter(mode => this.modeStatus[mode]);
|
const availableModes = Object.keys(session.modeStatus).filter(mode => session.modeStatus[mode]);
|
||||||
|
|
||||||
if (availableModes.length === 0) {
|
if (availableModes.length === 0) {
|
||||||
console.warn("两种模式都达到请求上限。");
|
console.warn("两种模式都达到请求上限。");
|
||||||
@@ -555,25 +583,32 @@ class YouProvider {
|
|||||||
if (!session || !session.valid) {
|
if (!session || !session.valid) {
|
||||||
throw new Error(`用户 ${username} 的会话无效`);
|
throw new Error(`用户 ${username} 的会话无效`);
|
||||||
}
|
}
|
||||||
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒
|
|
||||||
//刷新页面
|
|
||||||
await session.page.goto("https://you.com", {waitUntil: 'domcontentloaded'});
|
|
||||||
|
|
||||||
const {page, browser} = session;
|
|
||||||
const emitter = new EventEmitter();
|
const emitter = new EventEmitter();
|
||||||
|
let page = this.page;
|
||||||
|
let browser = this.browser;
|
||||||
|
|
||||||
|
if (!this.isSingleSession) {
|
||||||
|
// 设置账号Cookie
|
||||||
|
await page.setCookie(...getSessionCookie(
|
||||||
|
session.jwtSession,
|
||||||
|
session.jwtToken,
|
||||||
|
session.ds,
|
||||||
|
session.dsr
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.goto("https://you.com", {waitUntil: 'domcontentloaded'});
|
||||||
|
|
||||||
//打印messages完整结构
|
//打印messages完整结构
|
||||||
// console.log(messages);
|
// console.log(messages);
|
||||||
|
|
||||||
// 检查
|
// 检查
|
||||||
if (this.isRotationEnabled) {
|
if (this.isRotationEnabled) {
|
||||||
this.checkAndSwitchMode();
|
this.checkAndSwitchMode(session);
|
||||||
if (!Object.values(this.modeStatus).some(status => status)) {
|
if (!Object.values(session.modeStatus).some(status => status)) {
|
||||||
this.modeStatus.default = true;
|
session.modeStatus.default = true;
|
||||||
this.modeStatus.custom = true;
|
session.modeStatus.custom = true;
|
||||||
this.currentMode = "default";
|
console.warn(`账号 ${username} 的两种模式都达到请求上限,重置记录状态。`);
|
||||||
console.log("两种模式都达到请求上限,重置记录状态。");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 处理模式轮换逻辑
|
// 处理模式轮换逻辑
|
||||||
@@ -887,7 +922,6 @@ class YouProvider {
|
|||||||
let startTime = null; // 开始时间
|
let startTime = null; // 开始时间
|
||||||
const customEndMarker = (process.env.CUSTOM_END_MARKER || '').replace(/^"|"$/g, '').trim(); // 自定义终止符
|
const customEndMarker = (process.env.CUSTOM_END_MARKER || '').replace(/^"|"$/g, '').trim(); // 自定义终止符
|
||||||
let isEnding = false; // 是否正在结束
|
let isEnding = false; // 是否正在结束
|
||||||
let clientClosed = false; // 客户端是否已关闭
|
|
||||||
const requestTime = new Date().toLocaleString('zh-CN', {timeZone: 'Asia/Shanghai'}); // 请求时间
|
const requestTime = new Date().toLocaleString('zh-CN', {timeZone: 'Asia/Shanghai'}); // 请求时间
|
||||||
|
|
||||||
let unusualQueryVolumeTriggered = false; // 是否触发了异常请求量提示
|
let unusualQueryVolumeTriggered = false; // 是否触发了异常请求量提示
|
||||||
@@ -904,17 +938,26 @@ class YouProvider {
|
|||||||
const cleanup = async () => {
|
const cleanup = async () => {
|
||||||
clearTimeout(responseTimeout);
|
clearTimeout(responseTimeout);
|
||||||
clearTimeout(customEndMarkerTimer);
|
clearTimeout(customEndMarkerTimer);
|
||||||
|
if (heartbeatInterval) {
|
||||||
|
clearInterval(heartbeatInterval);
|
||||||
|
heartbeatInterval = null;
|
||||||
|
}
|
||||||
await page.evaluate((traceId) => {
|
await page.evaluate((traceId) => {
|
||||||
if (window["exit" + traceId]) {
|
if (window["exit" + traceId]) {
|
||||||
window["exit" + traceId]();
|
window["exit" + traceId]();
|
||||||
}
|
}
|
||||||
}, traceId);
|
}, traceId);
|
||||||
|
|
||||||
|
if (!this.isSingleSession) {
|
||||||
|
await this.clearYouCookies(page);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 缓存
|
// 缓存
|
||||||
let buffer = '';
|
let buffer = '';
|
||||||
let clientPointer = 0; // 客户端指针
|
let clientPointer = 0; // 客户端指针
|
||||||
let proxyPointer = 0; // 反代指针
|
let proxyPointer = 0; // 反代指针
|
||||||
|
let heartbeatInterval = null;
|
||||||
const self = this;
|
const self = this;
|
||||||
page.exposeFunction("callback" + traceId, async (event, data) => {
|
page.exposeFunction("callback" + traceId, async (event, data) => {
|
||||||
if (isEnding) return;
|
if (isEnding) return;
|
||||||
@@ -923,7 +966,7 @@ class YouProvider {
|
|||||||
case "resetProxyPointer":
|
case "resetProxyPointer":
|
||||||
proxyPointer = 0; // 重置反代指针
|
proxyPointer = 0; // 重置反代指针
|
||||||
break;
|
break;
|
||||||
case "youChatToken":
|
case "youChatToken": {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
let tokenContent = data.youChatToken;
|
let tokenContent = data.youChatToken;
|
||||||
buffer += tokenContent;
|
buffer += tokenContent;
|
||||||
@@ -944,6 +987,12 @@ class YouProvider {
|
|||||||
customEndMarkerTimer = setTimeout(() => {
|
customEndMarkerTimer = setTimeout(() => {
|
||||||
customEndMarkerEnabled = true;
|
customEndMarkerEnabled = true;
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
|
// 停止
|
||||||
|
if (heartbeatInterval) {
|
||||||
|
clearInterval(heartbeatInterval);
|
||||||
|
heartbeatInterval = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测 'unusual query volume'
|
// 检测 'unusual query volume'
|
||||||
@@ -953,17 +1002,20 @@ class YouProvider {
|
|||||||
unusualQueryVolumeTriggered = true; // 更新标志位
|
unusualQueryVolumeTriggered = true; // 更新标志位
|
||||||
|
|
||||||
if (self.isRotationEnabled) {
|
if (self.isRotationEnabled) {
|
||||||
self.modeStatus[self.currentMode] = false;
|
session.modeStatus[self.currentMode] = false;
|
||||||
self.checkAndSwitchMode();
|
self.checkAndSwitchMode();
|
||||||
if (Object.values(self.modeStatus).some(status => status)) {
|
if (Object.values(session.modeStatus).some(status => status)) {
|
||||||
console.log(`模式达到请求上限,已切换模式 ${self.currentMode},请重试请求。`);
|
console.log(`模式达到请求上限,已切换模式 ${self.currentMode},请重试请求。`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("检测到请求量异常提示,请求终止。");
|
console.log("检测到请求量异常提示,请求终止。");
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnding = true;
|
isEnding = true;
|
||||||
|
// 终止
|
||||||
|
setTimeout(async () => {
|
||||||
|
await cleanup();
|
||||||
|
emitter.emit("end", traceId);
|
||||||
|
}, 1000);
|
||||||
self.logger.logRequest({
|
self.logger.logRequest({
|
||||||
email: username,
|
email: username,
|
||||||
time: requestTime,
|
time: requestTime,
|
||||||
@@ -972,13 +1024,6 @@ class YouProvider {
|
|||||||
completed: true,
|
completed: true,
|
||||||
unusualQueryVolume: true,
|
unusualQueryVolume: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 终止
|
|
||||||
setTimeout(async () => {
|
|
||||||
await cleanup();
|
|
||||||
emitter.emit("end", traceId);
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1003,29 +1048,10 @@ class YouProvider {
|
|||||||
if (customEndMarkerEnabled && customEndMarker && checkEndMarker(responseAfter20Seconds, customEndMarker)) {
|
if (customEndMarkerEnabled && customEndMarker && checkEndMarker(responseAfter20Seconds, customEndMarker)) {
|
||||||
isEnding = true;
|
isEnding = true;
|
||||||
console.log("检测到自定义终止,关闭请求");
|
console.log("检测到自定义终止,关闭请求");
|
||||||
self.logger.logRequest({
|
|
||||||
email: username,
|
|
||||||
time: requestTime,
|
|
||||||
mode: self.currentMode,
|
|
||||||
model: proxyModel,
|
|
||||||
completed: true,
|
|
||||||
unusualQueryVolume: unusualQueryVolumeTriggered,
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
await cleanup();
|
await cleanup();
|
||||||
emitter.emit(stream ? "end" : "completion", traceId, stream ? undefined : finalResponse);
|
emitter.emit(stream ? "end" : "completion", traceId, stream ? undefined : finalResponse);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "customEndMarkerEnabled":
|
|
||||||
customEndMarkerEnabled = true;
|
|
||||||
break;
|
|
||||||
case "done":
|
|
||||||
clientClosed = true;
|
|
||||||
if (isEnding) return;
|
|
||||||
console.log("请求结束");
|
|
||||||
self.logger.logRequest({
|
self.logger.logRequest({
|
||||||
email: username,
|
email: username,
|
||||||
time: requestTime,
|
time: requestTime,
|
||||||
@@ -1034,14 +1060,41 @@ class YouProvider {
|
|||||||
completed: true,
|
completed: true,
|
||||||
unusualQueryVolume: unusualQueryVolumeTriggered,
|
unusualQueryVolume: unusualQueryVolumeTriggered,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "customEndMarkerEnabled":
|
||||||
|
customEndMarkerEnabled = true;
|
||||||
|
break;
|
||||||
|
case "done":
|
||||||
|
if (isEnding) return;
|
||||||
|
console.log("请求结束");
|
||||||
isEnding = true;
|
isEnding = true;
|
||||||
await cleanup();
|
await cleanup(); // 清理
|
||||||
emitter.emit(stream ? "end" : "completion", traceId, stream ? undefined : finalResponse);
|
emitter.emit(stream ? "end" : "completion", traceId, stream ? undefined : finalResponse);
|
||||||
|
self.logger.logRequest({
|
||||||
|
email: username,
|
||||||
|
time: requestTime,
|
||||||
|
mode: self.currentMode,
|
||||||
|
model: proxyModel,
|
||||||
|
completed: true,
|
||||||
|
unusualQueryVolume: unusualQueryVolumeTriggered,
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case "error": {
|
case "error": {
|
||||||
if (isEnding) return; // 如果已经结束,则忽略错误
|
if (isEnding) return; // 如果已经结束,则忽略错误
|
||||||
console.error("请求发生错误", data);
|
console.error("请求发生错误", data);
|
||||||
|
const errorMessage = data.message || "未知错误";
|
||||||
|
const clientErrorMessage = `请求发生错误: ${errorMessage} (错误详情已记录到日志中)`;
|
||||||
|
emitter.emit("completion", traceId, clientErrorMessage);
|
||||||
|
finalResponse += ` (${errorMessage})`;
|
||||||
|
isEnding = true;
|
||||||
|
setTimeout(async () => {
|
||||||
|
``
|
||||||
|
await cleanup();
|
||||||
|
emitter.emit("end", traceId);
|
||||||
|
}, 1000);
|
||||||
self.logger.logRequest({
|
self.logger.logRequest({
|
||||||
email: username,
|
email: username,
|
||||||
time: requestTime,
|
time: requestTime,
|
||||||
@@ -1050,19 +1103,6 @@ class YouProvider {
|
|||||||
completed: false,
|
completed: false,
|
||||||
unusualQueryVolume: unusualQueryVolumeTriggered,
|
unusualQueryVolume: unusualQueryVolumeTriggered,
|
||||||
});
|
});
|
||||||
|
|
||||||
const errorMessage = data.message || "未知错误";
|
|
||||||
const clientErrorMessage = `请求发生错误: ${errorMessage} (错误详情已记录到日志中)`;
|
|
||||||
|
|
||||||
emitter.emit("completion", traceId, clientErrorMessage);
|
|
||||||
|
|
||||||
finalResponse += ` (${errorMessage})`;
|
|
||||||
|
|
||||||
isEnding = true;
|
|
||||||
setTimeout(async () => {
|
|
||||||
await cleanup();
|
|
||||||
emitter.emit("end", traceId);
|
|
||||||
}, 1000);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1219,7 +1259,6 @@ class YouProvider {
|
|||||||
let retryCount = 0;
|
let retryCount = 0;
|
||||||
const maxRetries = 5;
|
const maxRetries = 5;
|
||||||
let customEndMarkerTimer = null;
|
let customEndMarkerTimer = null;
|
||||||
clientClosed = false; // 重置客户端关闭状态
|
|
||||||
|
|
||||||
function connect() {
|
function connect() {
|
||||||
// 重置反代指针
|
// 重置反代指针
|
||||||
@@ -1234,6 +1273,7 @@ class YouProvider {
|
|||||||
if (retryCount < maxRetries) {
|
if (retryCount < maxRetries) {
|
||||||
retryCount++;
|
retryCount++;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
console.log(`连接断开,尝试重新连接 (${retryCount}/${maxRetries})`);
|
||||||
connect();
|
connect();
|
||||||
}, 500 * retryCount); // 指数退避
|
}, 500 * retryCount); // 指数退避
|
||||||
} else {
|
} else {
|
||||||
@@ -1270,6 +1310,7 @@ class YouProvider {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
connect();
|
connect();
|
||||||
// 注册退出函数
|
// 注册退出函数
|
||||||
window["exit" + traceId] = () => {
|
window["exit" + traceId] = () => {
|
||||||
@@ -1287,6 +1328,7 @@ class YouProvider {
|
|||||||
customEndMarker
|
customEndMarker
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重新发送请求
|
// 重新发送请求
|
||||||
async function resendPreviousRequest() {
|
async function resendPreviousRequest() {
|
||||||
try {
|
try {
|
||||||
@@ -1309,6 +1351,14 @@ class YouProvider {
|
|||||||
console.log("重试请求后仍未收到响应,终止请求");
|
console.log("重试请求后仍未收到响应,终止请求");
|
||||||
emitter.emit("warning", new Error("在重试后仍未收到响应"));
|
emitter.emit("warning", new Error("在重试后仍未收到响应"));
|
||||||
emitter.emit("end", traceId);
|
emitter.emit("end", traceId);
|
||||||
|
self.logger.logRequest({
|
||||||
|
email: username,
|
||||||
|
time: requestTime,
|
||||||
|
mode: self.currentMode,
|
||||||
|
model: proxyModel,
|
||||||
|
completed: false,
|
||||||
|
unusualQueryVolume: unusualQueryVolumeTriggered,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
@@ -1335,21 +1385,48 @@ class YouProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
responseTimeout = setTimeout(async () => {
|
responseTimeout = setTimeout(async () => {
|
||||||
if (!responseStarted && !clientClosed) {
|
if (!responseStarted && !clientState.isClosed()) {
|
||||||
console.log("60秒内没有收到响应,尝试重新发送请求");
|
console.log("60秒内没有收到响应,尝试重新发送请求");
|
||||||
const retrySuccess = await resendPreviousRequest();
|
const retrySuccess = await resendPreviousRequest();
|
||||||
if (!retrySuccess) {
|
if (!retrySuccess) {
|
||||||
console.log("重试请求时发生错误,终止请求");
|
console.log("重试请求时发生错误,终止请求");
|
||||||
emitter.emit("warning", new Error("重试请求时发生错误"));
|
emitter.emit("warning", new Error("重试请求时发生错误"));
|
||||||
emitter.emit("end", traceId);
|
emitter.emit("end", traceId);
|
||||||
|
self.logger.logRequest({
|
||||||
|
email: username,
|
||||||
|
time: requestTime,
|
||||||
|
mode: self.currentMode,
|
||||||
|
model: proxyModel,
|
||||||
|
completed: false,
|
||||||
|
unusualQueryVolume: unusualQueryVolumeTriggered,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else if (clientClosed) {
|
} else if (clientState.isClosed()) {
|
||||||
console.log("客户端已关闭连接,停止重试");
|
console.log("客户端已关闭连接,停止重试");
|
||||||
await cleanup();
|
await cleanup();
|
||||||
emitter.emit("end", traceId);
|
emitter.emit("end", traceId);
|
||||||
|
self.logger.logRequest({
|
||||||
|
email: username,
|
||||||
|
time: requestTime,
|
||||||
|
mode: self.currentMode,
|
||||||
|
model: proxyModel,
|
||||||
|
completed: false,
|
||||||
|
unusualQueryVolume: unusualQueryVolumeTriggered,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
|
if (stream) {
|
||||||
|
heartbeatInterval = setInterval(() => {
|
||||||
|
if (!isEnding && !clientState.isClosed()) {
|
||||||
|
emitter.emit("completion", traceId, "");
|
||||||
|
} else {
|
||||||
|
clearInterval(heartbeatInterval);
|
||||||
|
heartbeatInterval = null;
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
// 初始执行 setupEventSource
|
// 初始执行 setupEventSource
|
||||||
await setupEventSource(page, url, traceId, customEndMarker);
|
await setupEventSource(page, url, traceId, customEndMarker);
|
||||||
|
|
||||||
@@ -1362,8 +1439,8 @@ class YouProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = async () => {
|
||||||
page?.evaluate((traceId) => {
|
await page?.evaluate((traceId) => {
|
||||||
if (window["exit" + traceId]) {
|
if (window["exit" + traceId]) {
|
||||||
window["exit" + traceId]();
|
window["exit" + traceId]();
|
||||||
}
|
}
|
||||||
@@ -1378,12 +1455,12 @@ export default YouProvider;
|
|||||||
|
|
||||||
function unescapeContent(content) {
|
function unescapeContent(content) {
|
||||||
// 将 \" 替换为 "
|
// 将 \" 替换为 "
|
||||||
content = content.replace(/\\"/g, '"');
|
// content = content.replace(/\\"/g, '"');
|
||||||
|
|
||||||
content = content.replace(/\\n/g, '');
|
// content = content.replace(/\\n/g, '');
|
||||||
|
|
||||||
// 将 \r 替换为空字符
|
// 将 \r 替换为空字符
|
||||||
content = content.replace(/\\r/g, '');
|
// content = content.replace(/\\r/g, '');
|
||||||
|
|
||||||
// 将 「 和 」 替换为 "
|
// 将 「 和 」 替换为 "
|
||||||
// content = content.replace(/[「」]/g, '"');
|
// content = content.replace(/[「」]/g, '"');
|
||||||
|
|||||||
Reference in New Issue
Block a user