const os = require('os'); const fs = require('fs'); const path = require('path'); const { chromium } = require('playwright'); const sharp = require('sharp'); let globalBrowser; const queue = []; let isProcessing = false; // Ініціалізація браузера (один раз на весь життєвий цикл додатка) async function getBrowser() { if (!globalBrowser) { globalBrowser = await chromium.launch({ executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu', '--disable-dev-shm-usage' ] }); } return globalBrowser; } // Функція обробки черги async function processQueue() { if (isProcessing || queue.length === 0) return; isProcessing = true; const { task, resolve, reject } = queue.shift(); try { const result = await runGeneration(task); resolve(result); } catch (err) { reject(err); } finally { isProcessing = false; processQueue(); // беремо наступне завдання } } // Основна логіка генерації async function runGeneration({ id, type }) { const { DOMAIN, ADMIN_TOKEN, CARDS_PATH } = process.env; const name = type === 'homestead' ? `H${id}` : `T${id}`; const URL = `https://${DOMAIN}/api/${type}/${id}`; const baseDir = path.resolve(CARDS_PATH); const cacheDir = path.join(baseDir, 'cache', type); const outputDir = path.join(baseDir, type); fs.mkdirSync(cacheDir, { recursive: true }); fs.mkdirSync(outputDir, { recursive: true }); const SCREENSHOT_FILE = path.join(cacheDir, `${name}.png`); const OUTPUT_FILE = path.join(outputDir, `${name}.webp`); // 1. Отримання даних const res = await fetch(URL, { headers: { 'Authorization': ADMIN_TOKEN, 'Accept': 'application/json' } }); if (!res.ok) throw new Error(`API Error: ${res.status}`); const data = await res.json(); // 2. Підготовка HTML const tmpFile = path.join(os.tmpdir(), `map_${type}_${id}_${Date.now()}.html`); const html = `