const fs = require('fs'); const path = require('path'); const { execFile } = require('child_process'); const express = require('express'); const { v4: uuidv4 } = require('uuid'); const https = require('https'); const cors = require('cors'); const app = express(); app.use(express.json({ limit: '20mb' })); // 大きなファイルにも対応 app.use(cors({ origin: [ 'https://neo999.next-hd.net', 'https://nextoffice.next-hd.co.jp', ], // 許可するオリジン optionsSuccessStatus: 200 })); // CORS対応 const API_KEY = 'pgqhLFWbDFu4Byz#4afNYX2F6Fa1&$KPjved$8%sUdTQV52caip#EpIKxYUkdd4S'; // 任意のAPIキーを設定 // LibreOffice AppImageのパス const libreofficeAppImage = './LibreOffice-still.standard-x86_64.AppImage'; // PDF変換処理 async function convertExcelBase64ToPdf(base64Data, originalFileName) { const tempId = uuidv4(); const ext = path.extname(originalFileName) || '.xlsx'; const excelPath = path.join(__dirname, `${tempId}${ext}`); const pdfPath = path.join(__dirname, `${tempId}.pdf`); // base64データをファイルに保存 fs.writeFileSync(excelPath, Buffer.from(base64Data, 'base64')); // LibreOfficeでPDF変換(タイムアウト60秒) await new Promise((resolve, reject) => { const child = execFile( libreofficeAppImage, [ '--headless', '--convert-to', 'pdf', '--outdir', __dirname, excelPath ], (error, stdout, stderr) => { if (error) { console.error('stderr:', stderr); reject(error); } else { resolve(); } } ); // 60秒タイムアウト const timeout = setTimeout(() => { child.kill('SIGKILL'); reject(new Error('PDF変換がタイムアウトしました(60秒経過)')); }, 60000); child.on('exit', () => clearTimeout(timeout)); }); // PDFファイルを読み込む if (!fs.existsSync(pdfPath)) { // cleanup fs.unlinkSync(excelPath); throw new Error('PDF変換に失敗しました'); } const pdfBuffer = fs.readFileSync(pdfPath); // cleanup fs.unlinkSync(excelPath); fs.unlinkSync(pdfPath); return pdfBuffer; } // POSTエンドポイント app.post('/XlsxToPdfconvert', async (req, res) => { try { // APIキーの検証 const apiKey = req.headers['x-api-key']; if (!apiKey || apiKey !== API_KEY) { return res.status(401).json({ error: 'APIキーが不正です' }); } const { base64, fileName } = req.body; if (!base64 || !fileName) { return res.status(400).json({ error: 'base64とfileNameは必須です' }); } const pdfBuffer = await convertExcelBase64ToPdf(base64, fileName); res.set({ 'Content-Type': 'application/pdf', 'Content-Disposition': `attachment; filename="${path.parse(fileName).name}.pdf"` }); res.send(pdfBuffer); } catch (err) { console.error('変換エラー:', err.message); res.status(500).json({ error: err.message }); } }); // HTTPSサーバ起動 const PORT = 30308; // HTTPS用証明書・秘密鍵のパス const sslOptions = { cert: fs.readFileSync('/etc/letsencrypt/live/neo999.next-hd.net/fullchain.pem'), key: fs.readFileSync('/etc/letsencrypt/live/neo999.next-hd.net/privkey.pem') }; https.createServer(sslOptions, app).listen(PORT, () => { console.log(`HTTPSサーバー起動: https://localhost:${PORT}`); });