| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- const {
- describe,
- test,
- expect,
- } = require('@jest/globals')
- const { WebDriver } = require('../common/web_driver')
- const {
- inflate,
- deflate,
- } = require('pako')
- const fs = require('fs')
- const path = require('node:path')
- // Static code + Reflection + .proto parser
- const protobuf = require('protobufjs')
- const desc = require('./hotconi.proto')
- const timeout = 9999999
- async function sleep (ms) {
- return new Promise(resolve => setTimeout(resolve, ms))
- }
- describe('hotcoin站点测试', () => {
- let targetInfo = {
- 'targetId': '',
- 'type': '',
- 'title': '',
- 'url': '',
- 'attached': true,
- 'canAccessOpener': false,
- 'browserContextId': '',
- }
- const driver = new WebDriver({
- // port: 23035,
- })
- const init = async () => {
- // await driver.setProxy('socks://localhost:8880')
- await driver.setProxy('http://172.16.1.132:3128')
- await driver.builder()
- let target = await driver.cdp.Target
- targetInfo = await target.getTargetInfo()
- console.info('info>>>>', targetInfo)
- }
- const baseUrl = 'https://www.hotcoin.com/'
- const prefix = 'hotcoin'
- let cookiesPath = path.join(__dirname, 'tmp', prefix + '_cookies')
- let storagePath = path.join(__dirname, 'tmp', prefix + '_storage')
- test('测试打开', async (done) => {
- await init()
- const page = driver.cdp.Page
- page.navigate({ url: baseUrl })
- done()
- }, timeout)
- const login = async (Storage, Runtime) => {
- let cookie = '', localStorage = ''
- if (fs.existsSync(cookiesPath)) {
- cookie = fs.readFileSync(cookiesPath, 'utf8')
- }
- // 借助localStorage中的jwt信息登录
- if (fs.existsSync(storagePath)) {
- localStorage = fs.readFileSync(storagePath, 'utf8')
- }
- if (cookie) {
- await Storage.setCookies(JSON.parse(cookie))
- }
- if (localStorage) {
- // let script = `
- let storage = JSON.parse(`${localStorage}`) || {}
- // for (const k in storage) {
- // localStorage.setItem(k,storage[k]);
- // }
- // `
- // script=`
- // localStorage.setItem('aaa','bbb')
- // `
- // await Runtime.evaluate({
- // expression: `localStorage.setItem('aaa','>>>>>')`,
- // // awaitPromise: true,
- // });
- for (const k in storage) {
- await Runtime.evaluate({
- expression: `localStorage.setItem(\`${k}\`, \`${storage[k]}\`)`,
- // awaitPromise: true,
- })
- }
- }
- }
- test('自动登录', async (done) => {
- await init()
- const {
- Storage,
- Page,
- Runtime,
- } = driver.cdp
- await Runtime.enable()
- try {
- Page.navigate({ url: baseUrl })
- await login(Storage, Runtime)
- let t = Date.now()
- let s = setInterval(async () => {
- let cookies = await Storage.getCookies()
- fs.writeFileSync(cookiesPath, JSON.stringify(cookies), 'utf8')
- let localStorage = await Runtime.evaluate({
- expression: 'JSON.stringify(localStorage)',
- })
- fs.writeFileSync(storagePath, localStorage?.result?.value, 'utf8')
- if (Date.now() - t > 5 * 60 * 1000) {
- clearInterval(s)
- }
- }, 1000)
- } catch (e) {
- console.error(e)
- }
- await sleep(timeout)
- done()
- }, timeout)
- test('监听wss', async (done) => {
- await init()
- const {
- Storage,
- Page,
- Network,
- Runtime,
- } = driver.cdp
- Network.enable()
- Page.navigate({ url: baseUrl })
- await login(Storage, Runtime)
- const decode = (data) => {
- let res = inflate(data/* , { to: 'string' } */)
- console.info('解压缩结果:', res)
- switch (res) {
- case 'pong':
- return res
- default: {
- // function decodeProtobufToJson(buffer) {
- // try {
- // // 创建一个通用的解码器
- // const Reader = protobuf.Reader;
- // const reader = Reader.create(buffer);
- //
- // const result = {};
- //
- // while (reader.pos < reader.len) {
- // const tag = reader.uint32();
- // const fieldId = tag >>> 3;
- // const wireType = tag & 7;
- //
- // // 根据 wireType 解析数据
- // let value;
- // switch (wireType) {
- // case 0: // varint
- // value = reader.uint64();
- // break;
- // case 1: // 64-bit
- // value = reader.fixed64();
- // break;
- // case 2: // length-delimited (string, bytes, embedded messages)
- // value = reader.bytes();
- // // 尝试将 bytes 转换为字符串
- // try {
- // value = new TextDecoder().decode(value);
- // } catch(e) {}
- // break;
- // case 5: // 32-bit
- // value = reader.fixed32();
- // break;
- // default:
- // reader.skipType(wireType);
- // continue;
- // }
- //
- // result[`field${fieldId}`] = value;
- // }
- //
- // return result;
- //
- // } catch (error) {
- // console.error("解析错误:", error);
- // return null;
- // }
- // }
- //
- // let object = decodeProtobufToJson(res)
- // let root = protobuf.Root.fromJSON(desc.common)
- //
- // // 查找 Response 消息类型
- // let ResponseType = root.lookupType('Response')
- //
- // // 解码数据
- // let message = ResponseType.decode(res)
- //
- // // 转换为普通的 JavaScript 对象
- // let object = ResponseType.toObject(message, {
- // longs: String, // 将 long 转换为字符串
- // enums: String, // 将枚举转换为字符串
- // bytes: String, // 将 bytes 转换为字符串
- // defaults: true, // 包含默认值
- // objects: true,
- // arrays: true,
- // json: true,
- // oneofs: true,
- // })
- // console.info('=00==>', object)
- // let key = (object.ch || '') + '.json'
- // let key = (object.ch || '') + '.js'
- //root = protobuf.Root.fromJSON(require('./hotconi/proto/' + key))
- // root = protobuf.loadSync(path.resolve('./hotconi/proto/' + key))
- // root = require('./hotconi/proto/' + key)
- let root = require('./hotconi/proto/market.v2.trade.area.tickers')
- // Response = root.lookupType(object.ch + '.Response')
- // message = Response.decode(res)
- //
- // object = Response.toObject(message, {
- // longs: String,
- // enums: String,
- // bytes: String,
- // defaults: true,
- // arrays: true,
- // objects: true,
- // oneofs: true,
- // })
- console.info('=11==>', 'object')
- // return JSON.parse(res)
- }
- }
- }
- // 一个二进制数据流还原
- // opcode number WebSocket message opcode.
- // mask boolean WebSocket message mask.
- // payloadData string WebSocket message payload data. If the opcode is 1, this is a text message and payloadData is a UTF-8 string.
- // If the opcode isn't 1, then payloadData is a base64 encoded string representing binary data.
- const formatResponse = (params = {
- opcode: 1,
- mask: false,
- payloadData: '',
- }) => {
- try {
- if (!params.response?.opcode) {
- return params.response
- }
- if (params.response?.opcode === 1) {
- return params.response.payloadData
- }
- const binaryData = Buffer.from(params.response.payloadData, 'base64')
- console.info('结果解析:', decode(binaryData))
- } catch (e) {
- console.error(e)
- }
- }
- Network.webSocketCreated(params => {
- console.log('WebSocket created:', params.url)
- })
- // 订阅 Network.webSocketFrameSent 和 Network.webSocketFrameReceived 事件,监听 WebSocket 帧的发送和接收:
- Network.webSocketFrameSent(params => {
- console.log('WebSocket frame sent:', params.response)
- // formatResponse(params)
- })
- Network.webSocketFrameReceived(params => {
- console.log('WebSocket frame received:', params.response)
- // formatResponse(params)
- })
- // 订阅 Network.webSocketClosed 事件,监听 WebSocket 连接的关闭:
- Network.webSocketClosed(params => {
- console.log('WebSocket closed:', params.closeCode, params.closeReason)
- // formatResponse(params)
- })
- // 订阅Network.webSocketWillSendHandshakeRequest事件,拦截WebSocket连接的握手请求:
- Network.webSocketWillSendHandshakeRequest(params => {
- console.log('WebSocket handshake request:', params.request)
- // formatResponse(params)
- })
- // 订阅Network.webSocketHandshakeResponseReceived事件,拦截WebSocket连接的握手响应:
- Network.webSocketHandshakeResponseReceived(params => {
- console.log('WebSocket handshake response:', params.response)
- let data = formatResponse(params)
- console.info('webSocketHandshakeResponseReceived解析结果:', data)
- })
- // 订阅Network.webSocketFrameSent和Network.webSocketFrameReceived事件,拦截WebSocket数据帧的发送和接收:
- Network.webSocketFrameSent(params => {
- console.log('WebSocket frame sent:', params.response)
- // formatResponse(params)
- })
- Network.webSocketFrameReceived(params => {
- // console.log('WebSocket frame received:', params.response)
- console.info('webSocketFrameReceived 回复', params.response)
- let data = formatResponse(params)
- console.info('webSocketFrameReceived解析结果:', data)
- })
- Network.webSocketFrameError(params => {
- console.log('WebSocket frame error:', params.response)
- let data = formatResponse(params)
- console.info('webSocketFrameError解析结果:', data)
- })
- await sleep(timeout)
- done()
- }, timeout)
- test('拆包', done => {
- let str = `0{"sid":"b6535f35-3047-4f12-9cd3-c526b39cd019","upgrades":["websocket"],"pingInterval":30000,"pingTimeout":60000}`
- while (/^\d/.test(str)) {
- str = str.substring(1)
- }
- try {
- JSON.parse(str)
- } catch (e) {
- console.error(e)
- }
- console.info(str)
- done()
- })
- })
|