parent
6cec904936
commit
5d37cd4cd1
5 changed files with 530 additions and 370 deletions
@ -0,0 +1,212 @@ |
|||||||
|
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 |
@ -1,151 +1,151 @@ |
|||||||
const express = require('express') |
// const express = require('express')
|
||||||
const path = require('path') |
// const path = require('path')
|
||||||
const fs = require('fs') |
// const fs = require('fs')
|
||||||
const app = express() |
// const app = express()
|
||||||
const PORT = 3000 |
// const PORT = 3000
|
||||||
|
//
|
||||||
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
|
// // process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
|
||||||
const {jsdomFromText, jsdomFromUrl, browser} = require('sdenv'); |
// const {jsdomFromText, jsdomFromUrl, browser} = require('sdenv');
|
||||||
const {Script} = require("vm"); |
// const {Script} = require("vm");
|
||||||
|
//
|
||||||
|
//
|
||||||
const baseUrl = "https://etax.hebei.chinatax.gov.cn:8443/" |
// const baseUrl = "https://etax.hebei.chinatax.gov.cn:8443/"
|
||||||
|
//
|
||||||
const store = new Map(); |
// const store = new Map();
|
||||||
|
//
|
||||||
const files = { |
// const files = {
|
||||||
html: path.resolve('../public/hubei/index.html'), |
// html: path.resolve('../public/hubei/index.html'),
|
||||||
js: path.resolve('../public/hubei/5PXGXoOF7eGJ.ed63b8f.js'), |
// js: path.resolve('../public/hubei/5PXGXoOF7eGJ.ed63b8f.js'),
|
||||||
ts: path.resolve('../public/hubei/ts.json'), |
// ts: path.resolve('../public/hubei/ts.json'),
|
||||||
} |
// }
|
||||||
|
//
|
||||||
function getFile(name) { |
// function getFile(name) {
|
||||||
const filepath = files[name]; |
// const filepath = files[name];
|
||||||
if (!filepath) throw new Error(`getFile: ${name}错误`); |
// if (!filepath) throw new Error(`getFile: ${name}错误`);
|
||||||
if (!fs.existsSync(filepath)) throw new Error(`文件${filepath}不存在,请使用rs-reverse工具先获取文件`); |
// if (!fs.existsSync(filepath)) throw new Error(`文件${filepath}不存在,请使用rs-reverse工具先获取文件`);
|
||||||
return fs.readFileSync(filepath); |
// return fs.readFileSync(filepath);
|
||||||
} |
// }
|
||||||
|
//
|
||||||
async function loadPages(key) { |
// async function loadPages(key) {
|
||||||
const htmlText = getFile('html'); |
// const htmlText = getFile('html');
|
||||||
const jsText = getFile('js'); |
// const jsText = getFile('js');
|
||||||
let tsText = getFile('ts'); |
// let tsText = getFile('ts');
|
||||||
let get = `${baseUrl}`; |
// let get = `${baseUrl}`;
|
||||||
const [jsDom, cookieJar] = jsdomFromText({ |
// const [jsDom, cookieJar] = jsdomFromText({
|
||||||
url: get, |
// url: get,
|
||||||
referrer: get, |
// referrer: get,
|
||||||
contentType: "text/html", |
// contentType: "text/html",
|
||||||
runScripts: "dangerously",//dangerously启用在页面内执行js,outside-only在外部执行js:window.eval()
|
// runScripts: "dangerously",//dangerously启用在页面内执行js,outside-only在外部执行js:window.eval()
|
||||||
}) |
// })
|
||||||
const dom = jsDom(htmlText); |
// const dom = jsDom(htmlText);
|
||||||
window = dom.window |
// window = dom.window
|
||||||
window.$_ts = JSON.parse(tsText.toString()); |
// window.$_ts = JSON.parse(tsText.toString());
|
||||||
window.onbeforeunload = async (url) => { |
// window.onbeforeunload = async (url) => {
|
||||||
const cookies = cookieJar.getCookieStringSync(baseUrl); |
// const cookies = cookieJar.getCookieStringSync(baseUrl);
|
||||||
console.debug('生成cookie:', cookies); |
// console.debug('生成cookie:', cookies);
|
||||||
store.set(key, cookies) |
// store.set(key, cookies)
|
||||||
// window.close();
|
// // window.close();
|
||||||
} |
// }
|
||||||
browser(window, 'chrome'); |
// browser(window, 'chrome');
|
||||||
|
//
|
||||||
new Script(jsText.toString()).runInContext(dom.getInternalVMContext()); |
// new Script(jsText.toString()).runInContext(dom.getInternalVMContext());
|
||||||
|
//
|
||||||
return cookieJar; |
// return cookieJar;
|
||||||
} |
// }
|
||||||
|
//
|
||||||
let sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); |
// let sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
//
|
||||||
|
//
|
||||||
function action(key, url) { |
// function action(key, url) {
|
||||||
return new Promise(async (resolve, reject) => { |
// return new Promise(async (resolve, reject) => {
|
||||||
let cookieJar = await loadPages(key, url); |
// let cookieJar = await loadPages(key, url);
|
||||||
// for (let i = 0; i < 100; i++) {
|
// // for (let i = 0; i < 100; i++) {
|
||||||
await sleep(1000) |
// await sleep(1000)
|
||||||
let cookieStringSync = cookieJar.getCookieStringSync(baseUrl); |
// let cookieStringSync = cookieJar.getCookieStringSync(baseUrl);
|
||||||
let val = store.get(key); |
// let val = store.get(key);
|
||||||
// console.log(val)
|
// // console.log(val)
|
||||||
console.log(cookieStringSync) |
// console.log(cookieStringSync)
|
||||||
// 尝试访问
|
// // 尝试访问
|
||||||
let response = await fetch(baseUrl, { |
// let response = await fetch(baseUrl, {
|
||||||
"headers": { |
|
||||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", |
|
||||||
"accept-language": "zh-CN,zh;q=0.9", |
|
||||||
"cache-control": "no-cache", |
|
||||||
"pragma": "no-cache", |
|
||||||
"priority": "u=0, i", |
|
||||||
"sec-ch-ua": "\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"", |
|
||||||
"sec-ch-ua-mobile": "?0", |
|
||||||
"sec-ch-ua-platform": "\"Linux\"", |
|
||||||
"sec-fetch-dest": "document", |
|
||||||
"sec-fetch-mode": "navigate", |
|
||||||
"sec-fetch-site": "none", |
|
||||||
"sec-fetch-user": "?1", |
|
||||||
"upgrade-insecure-requests": "1" |
|
||||||
}, |
|
||||||
"referrerPolicy": "strict-origin-when-cross-origin", |
|
||||||
"body": null, |
|
||||||
"method": "GET" |
|
||||||
}); |
|
||||||
console.log('11111111111', response.headers.get('set-cookie')); |
|
||||||
|
|
||||||
if (cookieStringSync !== undefined) { |
|
||||||
return resolve(cookieStringSync) |
|
||||||
} |
|
||||||
// }
|
|
||||||
reject('未获取到cookie') |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
action("111111", baseUrl) |
|
||||||
|
|
||||||
app.get('/getCookie', async (req, res) => { |
|
||||||
let traceId = req.query['traceId']; |
|
||||||
if (traceId === undefined) { |
|
||||||
return res.send('error') |
|
||||||
} |
|
||||||
let url = req.query['url']; |
|
||||||
try { |
|
||||||
let ac = await action(traceId, url); |
|
||||||
return res.send(ac) |
|
||||||
} catch (e) { |
|
||||||
return res.send(e) |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
//
|
|
||||||
// fetch("https://tpass.hebei.chinatax.gov.cn:8443/sys-api/v1.0/auth/oauth2/getPublicKey", {
|
|
||||||
// "headers": {
|
// "headers": {
|
||||||
// "accept": "application/json, text/plain, */*",
|
// "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||||
// "accept-language": "zh-CN,zh;q=0.9",
|
// "accept-language": "zh-CN,zh;q=0.9",
|
||||||
// "authorization": "",
|
|
||||||
// "cache-control": "no-cache",
|
// "cache-control": "no-cache",
|
||||||
// "content-type": "application/json",
|
|
||||||
// "deviceidentyno": "wrhX86TArZj82EUurHJWVBktiBVKERpy",
|
|
||||||
// "huid": "",
|
|
||||||
// "pragma": "no-cache",
|
// "pragma": "no-cache",
|
||||||
// "priority": "u=1, i",
|
// "priority": "u=0, i",
|
||||||
// "sec-ch-ua": "\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"",
|
// "sec-ch-ua": "\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"",
|
||||||
// "sec-ch-ua-mobile": "?0",
|
// "sec-ch-ua-mobile": "?0",
|
||||||
// "sec-ch-ua-platform": "\"Linux\"",
|
// "sec-ch-ua-platform": "\"Linux\"",
|
||||||
// "sec-fetch-dest": "empty",
|
// "sec-fetch-dest": "document",
|
||||||
// "sec-fetch-mode": "cors",
|
// "sec-fetch-mode": "navigate",
|
||||||
// "sec-fetch-site": "same-origin",
|
// "sec-fetch-site": "none",
|
||||||
// "x-app-clientid": "",
|
// "sec-fetch-user": "?1",
|
||||||
// "x-lang-id": "null",
|
// "upgrade-insecure-requests": "1"
|
||||||
// "x-nature-ip": "",
|
|
||||||
// "x-sm4-info": "0",
|
|
||||||
// "x-temp-info": "fffe092bceb04d32915d41c2634ed9ff",
|
|
||||||
// "x-ticket-id": "null"
|
|
||||||
// },
|
// },
|
||||||
// "referrer": "https://tpass.hebei.chinatax.gov.cn:8443/",
|
|
||||||
// "referrerPolicy": "strict-origin-when-cross-origin",
|
// "referrerPolicy": "strict-origin-when-cross-origin",
|
||||||
// "body": "{\"zipCode\":\"0\",\"encryptCode\":\"0\",\"datagram\":\"{}\",\"timestamp\":\"20240828150426\",\"access_token\":\"\",\"signtype\":\"HMacSHA256\",\"signature\":\"67848659b891af24ea9c2706e6fccbf03c2448666b719c00a49534dc536500fc\"}",
|
// "body": null,
|
||||||
// "method": "POST",
|
// "method": "GET"
|
||||||
// "mode": "cors",
|
|
||||||
// "credentials": "include"
|
|
||||||
// });
|
// });
|
||||||
|
// console.log('11111111111', response.headers.get('set-cookie'));
|
||||||
|
//
|
||||||
// app.listen(PORT, () => {
|
// if (cookieStringSync !== undefined) {
|
||||||
// console.log(`app is running on PORT ${PORT}`)
|
// return resolve(cookieStringSync)
|
||||||
|
// }
|
||||||
|
// // }
|
||||||
|
// reject('未获取到cookie')
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// action("111111", baseUrl)
|
||||||
|
//
|
||||||
|
// app.get('/getCookie', async (req, res) => {
|
||||||
|
// let traceId = req.query['traceId'];
|
||||||
|
// if (traceId === undefined) {
|
||||||
|
// return res.send('error')
|
||||||
|
// }
|
||||||
|
// let url = req.query['url'];
|
||||||
|
// try {
|
||||||
|
// let ac = await action(traceId, url);
|
||||||
|
// return res.send(ac)
|
||||||
|
// } catch (e) {
|
||||||
|
// return res.send(e)
|
||||||
|
// }
|
||||||
// })
|
// })
|
||||||
|
//
|
||||||
|
// //
|
||||||
|
// // fetch("https://tpass.hebei.chinatax.gov.cn:8443/sys-api/v1.0/auth/oauth2/getPublicKey", {
|
||||||
|
// // "headers": {
|
||||||
|
// // "accept": "application/json, text/plain, */*",
|
||||||
|
// // "accept-language": "zh-CN,zh;q=0.9",
|
||||||
|
// // "authorization": "",
|
||||||
|
// // "cache-control": "no-cache",
|
||||||
|
// // "content-type": "application/json",
|
||||||
|
// // "deviceidentyno": "wrhX86TArZj82EUurHJWVBktiBVKERpy",
|
||||||
|
// // "huid": "",
|
||||||
|
// // "pragma": "no-cache",
|
||||||
|
// // "priority": "u=1, i",
|
||||||
|
// // "sec-ch-ua": "\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"",
|
||||||
|
// // "sec-ch-ua-mobile": "?0",
|
||||||
|
// // "sec-ch-ua-platform": "\"Linux\"",
|
||||||
|
// // "sec-fetch-dest": "empty",
|
||||||
|
// // "sec-fetch-mode": "cors",
|
||||||
|
// // "sec-fetch-site": "same-origin",
|
||||||
|
// // "x-app-clientid": "",
|
||||||
|
// // "x-lang-id": "null",
|
||||||
|
// // "x-nature-ip": "",
|
||||||
|
// // "x-sm4-info": "0",
|
||||||
|
// // "x-temp-info": "fffe092bceb04d32915d41c2634ed9ff",
|
||||||
|
// // "x-ticket-id": "null"
|
||||||
|
// // },
|
||||||
|
// // "referrer": "https://tpass.hebei.chinatax.gov.cn:8443/",
|
||||||
|
// // "referrerPolicy": "strict-origin-when-cross-origin",
|
||||||
|
// // "body": "{\"zipCode\":\"0\",\"encryptCode\":\"0\",\"datagram\":\"{}\",\"timestamp\":\"20240828150426\",\"access_token\":\"\",\"signtype\":\"HMacSHA256\",\"signature\":\"67848659b891af24ea9c2706e6fccbf03c2448666b719c00a49534dc536500fc\"}",
|
||||||
|
// // "method": "POST",
|
||||||
|
// // "mode": "cors",
|
||||||
|
// // "credentials": "include"
|
||||||
|
// // });
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// // app.listen(PORT, () => {
|
||||||
|
// // console.log(`app is running on PORT ${PORT}`)
|
||||||
|
// // })
|
||||||
|
@ -0,0 +1,9 @@ |
|||||||
|
class TimeUtil { |
||||||
|
static sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); |
||||||
|
|
||||||
|
static *sleepSync(ms){ |
||||||
|
return yield new Promise(resolve => setTimeout(resolve, ms)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = TimeUtil; |
Loading…
Reference in new issue