98 lines
3.6 KiB
JavaScript
98 lines
3.6 KiB
JavaScript
const fs = require('fs');
|
||
const path = require('path');
|
||
const { execFile } = require('child_process');
|
||
const { v4: uuidv4 } = require('uuid');
|
||
const express = require('express'); // JSON解析用にexpressをインポート
|
||
const { API_KEY } = require('../config.js'); // API_KEYをインポート
|
||
|
||
// tmpディレクトリのパス
|
||
const tmpDir = path.join(__dirname, 'tmp');
|
||
|
||
// tmpディレクトリが存在しない場合は作成
|
||
if (!fs.existsSync(tmpDir)) {
|
||
fs.mkdirSync(tmpDir);
|
||
}
|
||
|
||
// POSTエンドポイント
|
||
module.exports = (app) => {
|
||
app.post('/pdfMerge', express.json({ limit: '30mb' }), async (req, res) => {
|
||
try {
|
||
// APIキーのチェック
|
||
const apiKey = req.headers['x-api-key'];
|
||
if (!apiKey || apiKey !== API_KEY) {
|
||
console.log('APIキーが不正です');
|
||
return res.status(401).json({ error: 'APIキーが不正です' });
|
||
}
|
||
|
||
// base64_1, base64_2, fileName の3つをチェック
|
||
const { base64_1, base64_2, fileName } = req.body;
|
||
if (!base64_1 || !base64_2 || !fileName) {
|
||
return res.status(400).json({ error: 'base64_1, base64_2, fileNameは必須です' });
|
||
}
|
||
|
||
const pdfBuffer = await mergeBase64ToPdf(base64_1, base64_2, fileName);
|
||
const safeFileName = encodeURIComponent(path.parse(fileName).name); // ファイル名をエスケープ
|
||
res.set({
|
||
'Content-Type': 'application/pdf',
|
||
'Content-Disposition': `attachment; filename="${safeFileName}.pdf"`
|
||
});
|
||
res.send(pdfBuffer);
|
||
} catch (err) {
|
||
console.error('変換エラー:', err.message);
|
||
res.status(500).json({ error: err.message });
|
||
}
|
||
});
|
||
};
|
||
|
||
// PDF結合処理
|
||
async function mergeBase64ToPdf(base64Data1, base64Data2) {
|
||
const tempId = uuidv4(); // 一意のIDを生成
|
||
const orgPath1 = path.join(tmpDir, `${tempId}_1.pdf`);
|
||
const orgPath2 = path.join(tmpDir, `${tempId}_2.pdf`);
|
||
const mergedPath = path.join(tmpDir, `${tempId}_merged.pdf`);
|
||
|
||
// base64データをファイルに保存
|
||
fs.writeFileSync(orgPath1, Buffer.from(base64Data1, 'base64'));
|
||
fs.writeFileSync(orgPath2, Buffer.from(base64Data2, 'base64'));
|
||
|
||
// pdfuniteでPDF結合
|
||
await new Promise((resolve, reject) => {
|
||
const child = execFile(
|
||
'pdfunite',
|
||
[orgPath1, orgPath2, mergedPath],
|
||
(error, stdout, stderr) => {
|
||
if (error) {
|
||
console.error('stderr:', stderr);
|
||
reject(new Error(`pdfuniteエラー: ${stderr}`));
|
||
} else {
|
||
resolve();
|
||
}
|
||
}
|
||
);
|
||
const timeout = setTimeout(() => {
|
||
child.kill('SIGTERM'); // SIGTERMを使用してプロセスを終了
|
||
reject(new Error('PDF変換がタイムアウトしました(60秒経過)'));
|
||
}, 60000);
|
||
child.on('exit', () => clearTimeout(timeout));
|
||
});
|
||
|
||
// 結合されたPDFを読み込む
|
||
if (!fs.existsSync(mergedPath)) {
|
||
throw new Error('PDF結合に失敗しました');
|
||
}
|
||
const pdfBuffer = fs.readFileSync(mergedPath);
|
||
|
||
// cleanup
|
||
try {
|
||
if (fs.existsSync(orgPath1)) fs.unlinkSync(orgPath1);
|
||
if (fs.existsSync(orgPath2)) fs.unlinkSync(orgPath2);
|
||
if (fs.existsSync(mergedPath)) fs.unlinkSync(mergedPath);
|
||
} catch (cleanupError) {
|
||
console.error('クリーンアップエラー:', cleanupError.message);
|
||
}
|
||
|
||
return pdfBuffer;
|
||
}
|
||
|
||
|