/* Adapted and rewritten to Node based on ading2210/poe-api ading2210/poe-api: a reverse engineered Python API wrapper for Quora's Poe Copyright (C) 2023 ading2210 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ const WebSocket = require('ws'); const axios = require('axios'); const fs = require('fs'); const path = require('path'); const http = require('http'); const https = require('https'); const parent_path = path.resolve(__dirname); const queries_path = path.join(parent_path, "poe_graphql"); let queries = {}; const logger = console; const user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0"; function load_queries() { const files = fs.readdirSync(queries_path); for (const filename of files) { const ext = path.extname(filename); if (ext !== '.graphql') { continue; } const queryName = path.basename(filename, ext); const query = fs.readFileSync(path.join(queries_path, filename), 'utf-8'); queries[queryName] = query; } } function generate_payload(query_name, variables) { return { query: queries[query_name], variables: variables, } } async function request_with_retries(method, attempts = 10) { const url = ''; for (let i = 0; i < attempts; i++) { try { const response = await method(); if (response.status === 200) { return response; } logger.warn(`Server returned a status code of ${response.status} while downloading ${url}. Retrying (${i + 1}/${attempts})...`); } catch (err) { console.log(err); } } throw new Error(`Failed to download ${url} too many times.`); } class Client { gql_url = "https://poe.com/api/gql_POST"; gql_recv_url = "https://poe.com/api/receive_POST"; home_url = "https://poe.com"; settings_url = "https://poe.com/api/settings"; formkey = ""; next_data = {}; bots = {}; active_messages = {}; message_queues = {}; bot_names = []; ws = null; ws_connected = false; auto_reconnect = false; constructor(auto_reconnect = false) { this.auto_reconnect = auto_reconnect; } async init(token, proxy = null) { this.proxy = proxy; this.session = axios.default.create({ timeout: 60000, httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }), }); if (proxy) { this.session.defaults.proxy = { "http": proxy, "https": proxy, }; logger.info(`Proxy enabled: ${proxy}`); } const cookies = `p-b=${token}; Domain=poe.com`; this.headers = { "User-Agent": user_agent, "Referrer": "https://poe.com/", "Origin": "https://poe.com", "Cookie": cookies, }; this.ws_domain = `tch${Math.floor(Math.random() * 1e6)}`; this.session.defaults.headers.common = this.headers; this.next_data = await this.get_next_data(); this.channel = await this.get_channel_data(); await this.connect_ws(); this.bots = await this.get_bots(); this.bot_names = this.get_bot_names(); this.gql_headers = { "poe-formkey": this.formkey, "poe-tchannel": this.channel["channel"], ...this.headers, }; await this.subscribe(); } async get_next_data() { logger.info('Downloading next_data...'); const r = await request_with_retries(() => this.session.get(this.home_url)); const jsonRegex = /