| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 | 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')const root = require('./hotconi/proto/market.v2.trade')// Static code + Reflection + .proto parserconst timeout = 9999999async 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 storage = {}            try {                storage = JSON.parse(`${localStorage}`) ||{}            } catch (e) {                console.error(e)            }            // let script = `            //     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)        //这个网站连接了3个wss,不同的wss的数据结构不一样。        // "wss://wsw.spentr.com/trade/multiple",        //"wss://wcws.spentr.com/",        const requestInfo = {}        const decodeWsw = (data) => {            let res = inflate(data/* , { to: 'string' } */)            console.info('解压缩结果:', res)            switch (res) {                case 'pong':                    return res                default: {                    let root = require('./hotconi/proto/market.v2.trade')                    let response = root.market.v2.trade.Response.decode(res)                    let object = response.toJSON()                    console.info('=decodeWsw==>', object)                }            }        }        const decodeWsws = (data) => {            let res = inflate(data/* , { to: 'string' } */)            //字符串中有2个隐藏字符 DCC EM            let regex = new RegExp('(\\n|' + String.fromCharCode(18) + '|' + String.fromCharCode(30)+ '|' + String.fromCharCode(31) + ')', 'g')            let keys = inflate(data, { to: 'string' }).split(regex).filter(s => (s || '').includes('type.googleapis.com')).flatMap(s => (s || '').split('/'))            // CommonPbMsg            console.info('解压缩结果:', res)            switch (res) {                case 'pong':                    return res                default: {                    let root = require('./hotconi/proto/' + (keys.join('.') || '').replaceAll('"', ''))                    let response = root.type.googleapis.com[keys[1]].Response.decode(res)                    let object = response.toJSON()                    console.info('=decodeWsws==>', object)                }            }        }        // 一个二进制数据流还原        // 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 = {            requestId: '',            timestamp: '',            response: {                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')                let res = {}                if ((requestInfo[params.requestId].url || '').includes('wsw.spentr.com')) {                    res = decodeWsw(binaryData)                } else if ((requestInfo[params.requestId].url || '').includes('wcws.spentr.com')) {                    res = decodeWsws(binaryData)                }                console.info('结果解析:', res)            } catch (e) {                console.error(e)            }        }        Network.requestWillBeSent((params) => {            console.log('Request Headers:', params.request.headers);        });        Network.webSocketCreated(params => {            console.log('WebSocket created:', params.url)            requestInfo[params.requestId] = {                url: params.url,            }        })        // 订阅 Network.webSocketFrameSent 和 Network.webSocketFrameReceived 事件,监听 WebSocket 帧的发送和接收:        // 订阅 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()    })})
 |