You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

212 lines
7.1 KiB

const {jsdomFromText, browser} = require("sdenv");
const JsUtil = require("../../utils/JsUtil");
const {Script} = require("node:vm");
const Store = require("../../utils/Store");
let TimeUtil = require("../../utils/TimeUtil");
class Rs6Service {
store = new Store();
// service handle
async handle(url, uuid, areaName, htmlStr, cookie, userAgent) {
// 获取 origin
let baseUrl = new URL(url).origin;
// 初始化 jsDom 和 cookieJar
const [jsDom, cookieJar] = jsdomFromText({
url: url, referrer: url, userAgent: userAgent, contentType: "text/html", runScripts: "outside-only", // runScripts: 'dangerously'/'outside-only'
})
// 加载dom
let dom = await jsDom(htmlStr);
console.log(`${uuid};html 加载长度--->`, dom.serialize().length)
window = dom.window
// ------------------------------------------------ param ----------------------------------------------------------
// 标志判断cookie是否生成
window[uuid] = false
// ------------------------------------------------ function -------------------------------------------------------
// js执行成功后会跳转页面 会触发onbeforeunload钩子
window.onbeforeunload = async (url) => {
console.debug(`${url} 页面回调完成`);
window[uuid] = true
}
// 设置 cookie
if (cookie != null) {
let cookieList = this.CookieStr2List(cookie);
console.log(`${uuid};cookie 加载长度--->`, cookieList.length, baseUrl)
for (let i = 0; i < cookieList.length; i++) {
cookieJar.setCookieSync(cookieList[i], baseUrl);
}
}
// 方案1 通过监听cookie 判断cookie是否生成
const superSetCookie = cookieJar.setCookie;
let generateCookieKey = null;
// 设置 setCookie 代理
cookieJar.setCookie = function (cookie, currentUrl, options, callback) {
console.debug(`${uuid};正在设置 Cookie:`, cookie, currentUrl);
let call = superSetCookie.call(this, cookie, currentUrl, options, callback);
// 根据瑞树6 cookie 特性 截取 `enable_XXXXXXXXXXXX=true` XXXXXXXX 为即将生成的 cookie key
if (generateCookieKey != null && cookie.includes(generateCookieKey)) {
window[uuid] = true
console.debug('匹配---->', cookie)
}
let match = cookie.match(/enable_(.*?)=true/);
if (match) {
generateCookieKey = match[1];
console.debug('设置 匹配---->', generateCookieKey)
}
return call;
};
// ------------------------------------------------ 实例化浏览器 -----------------------------------------------------
browser(window, 'chrome');
// 加载js
let js = await JsUtil.loadJs(window.document, areaName, cookie);
console.log(`${uuid};js 加载长度--->`, js.length)
// 执行 js
let script = new Script(js);
let internalVMContext = dom.getInternalVMContext();
script.runInContext(internalVMContext, {timeout: 1000});
// 等待 cookie 被设置
for (let i = 0; i < 10; i++) {
if (window[uuid]) {
break;
}
await TimeUtil.sleep(100)
}
// 获取cookie
let resCookie = cookieJar.getCookieStringSync(baseUrl);
// 关闭
dom.window.close()
return resCookie;
}
// 将 cookie 转为 list
CookieStr2List(cookies) {
let list = []
for (let cookie of cookies.trim().split("; ")) {
list.push(cookie);
}
return list
}
/**
* 方案1
* 利用rs特性 js加载完成后会刷新页面
* 利用 window.onbeforeunload 判断页面是否执行完毕
* @param window
* @param cookieJar
* @param uuid
* @returns {Promise<*|null>}
*/
scheme1_before(window, cookieJar, uuid) {
window.onbeforeunload = async (url) => {
let baseUrl = new URL(url).origin;
const cookies = cookieJar.getCookieStringSync(baseUrl);
console.debug(`${url} 页面回调生成cookie:`, cookies);
this.store.set(uuid, cookies)
// window.close();
}
}
/**
* 方案1
* @param window
* @param cookieJar
* @param uuid
* @returns {Promise<*|null>}
*/
async scheme1_after(window, cookieJar, uuid) {
// 等待 onbeforeunload 钩子触发后的回掉
let val = await this.store.waitGetAndDelete(uuid, 100, 10)
if (val != null) {
return val;
}
return null;
}
/**
* 监听cookie出现指定cookie
* @param window
* @param cookieJar
* @param uuid
* @returns {Promise<null|string>}
*/
scheme2_before(window, cookieJar, uuid) {
// window[uuid] = false;
const superSetCookie = cookieJar.setCookie;
// 设置 setCookie 代理
cookieJar.setCookie = function (cookie, currentUrl, options, callback) {
console.log(`${uuid};正在设置 Cookie:`, cookie, currentUrl);
return superSetCookie.call(this, cookie, currentUrl, options, callback);
// let cookieStringSync = super.getCookieStringSync();
// console.log(cookieStringSync)
// if (cookie.includes(key)) {
// // 设置标志可取标志
// window[uuid] = true
// }
// return call;
};
}
/**
* 方案2
* @param window
* @param cookieJar
* @param key
* @param uuid
* @returns {Promise<null|string>}
*/
async scheme2_after(window, cookieJar, key, uuid) {
for (let i = 0; i < 10; i++) {
let cookieStringSync = cookieJar.getCookieStringSync();
if (cookieStringSync.includes(key)) {
return cookieStringSync;
}
await TimeUtil.sleep(100)
}
return null;
}
/**
* 方案3 根据cookie现有的数量判断
* @param window
* @param cookieJar
* @param baseUrl
* @param uuid
*/
scheme3_before(window, cookieJar, baseUrl, uuid) {
const initCookie = cookieJar.getCookieStringSync(baseUrl);
window[uuid + 'CookieSize'] = initCookie != null ? initCookie.trim().split("; ").length : 0;
}
/**
* 方案3
* @param window
* @param cookieJar
* @param baseUrl
* @param uuid
* @returns {Promise<null|string>}
*/
async scheme3_after(window, cookieJar, baseUrl, uuid) {
let initCookieLength = window[uuid + 'CookieSize']
for (let i = 0; i < 10; i++) {
let cookieStringSync = cookieJar.getCookieStringSync(baseUrl);
let cookies = cookieStringSync != null ? cookieStringSync.trim().split("; ").length : 0;
if (cookies > initCookieLength) {
return cookieStringSync;
}
await TimeUtil.sleep(100)
}
return null;
}
}
module.exports = Rs6Service