110 lines
3.6 KiB
JavaScript
110 lines
3.6 KiB
JavaScript
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}`);
|
||
}); |