generated from toakiryu/repository-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.js
186 lines (158 loc) · 5.17 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
const express = require("express");
const path = require("path");
const multer = require("multer");
const sharp = require("sharp");
const fs = require("fs");
const { exec } = require("child_process");
const icoToPng = require("ico-to-png");
const archiver = require("archiver");
const app = express();
const decodeFilename = (filename) => {
try {
return decodeURIComponent(filename);
} catch (e) {
console.error("Filename decoding failed:", e);
return filename; // デコード失敗した場合はそのまま返す
}
};
const encodeFilename = (filename) => {
try {
return encodeURIComponent(filename);
} catch (e) {
console.error("Filename encoding failed:", e);
return filename;
}
};
// アップロード先の設定
const upload = multer({
storage: multer.diskStorage({
destination: path.join(__dirname, "uploads"),
filename: (req, file, cb) => {
const decodedName = decodeFilename(file.originalname);
cb(null, decodedName);
},
}),
});
// ダウンロードディレクトリのパス
const downloadDir = path.join(__dirname, "downloads");
// ダウンロードディレクトリが存在しない場合は作成
if (!fs.existsSync(downloadDir)) {
fs.mkdirSync(downloadDir);
}
// 静的ファイルの提供
app.use(express.static(path.join(__dirname, "public")));
app.use(express.json());
function removeLastExtension(filename) {
return filename.replace(/\.[a-zA-Z0-9]+$/, "");
}
// 複数ファイルの画像変換API
app.post("/convert", upload.array("images"), async (req, res) => {
try {
const { format } = req.body;
const convertedFiles = [];
// アップロードされたファイルごとに処理
for (const file of req.files) {
const newFilename = removeLastExtension(file.filename);
// const originalName = path.parse(file.originalname).name;
const inputPath = file.path;
const outputPath = path.resolve(
__dirname,
`uploads/${newFilename}.${format}`
);
// .ico ファイルの場合、最初に PNG に変換
if (file.mimetype === "image/vnd.microsoft.icon") {
const pngBuffer = await icoToPng(inputPath);
await sharp(pngBuffer).toFormat(format).toFile(outputPath);
} else {
await sharp(inputPath).toFormat(format).toFile(outputPath);
}
convertedFiles.push(`${newFilename}.${format}`);
}
res.json({
message: "Images converted!",
files: convertedFiles,
});
} catch (error) {
res.status(500).send(error.message);
}
});
app.post("/download", (req, res) => {
const filesToDownload = req.body.files; // クライアントから送信されたダウンロードファイルリスト
const archive = archiver("zip", {
zlib: { level: 9 }, // 最大圧縮
});
const output = fs.createWriteStream(
path.join(downloadDir, "converted_files.zip")
);
archive.pipe(output);
filesToDownload.forEach((file) => {
const filePath = path.resolve(__dirname, "uploads", file);
archive.file(filePath, { name: file });
});
output.on("close", () => {
res.download(
path.join(__dirname, "downloads", "converted_files.zip"),
"converted_files.zip"
);
});
archive.finalize();
});
// サーバー終了時に変換済みファイルを削除
const deleteFiles = async () => {
const publicDir = path.resolve(__dirname, "uploads");
const downloadsDir = path.resolve(__dirname, "downloads");
const logFiles = async (dir) => {
const files = await fs.promises.readdir(dir);
console.log(`Files in ${dir}:`, files);
return files;
};
const deleteFromDir = async (dir) => {
const files = await logFiles(dir); // ファイルリストをログ
const unlinkPromises = files.map(async (file) => {
const filePath = path.join(dir, file);
try {
if (fs.existsSync(filePath)) {
await fs.promises.unlink(filePath);
console.log(`Deleted file: ${file}`);
} else {
console.warn(`File not found: ${file}`);
}
} catch (err) {
console.error(`Failed to delete file ${file}:`, err.message);
}
});
await Promise.all(unlinkPromises);
};
await deleteFromDir(publicDir);
await deleteFromDir(downloadsDir);
};
// サーバー起動
const server = app.listen(0, () => {
const PORT = server.address().port; // 自動で割り当てられたポート番号を取得
console.log(`Server is running at http://localhost:${PORT}`);
exec(`open http://localhost:${PORT}`, (err) => {
if (err) {
console.error("Failed to open browser:", err);
}
});
// サーバーのcloseイベントをリスンして終了時のログを表示
server.on("close", () => {
console.log("Server has been shut down.");
});
// SIGINT (Ctrl+C) をリスンしてサーバーを終了
process.on("SIGINT", async () => {
console.log("SIGINT received");
try {
console.log("Deleting files...");
await deleteFiles();
console.log("Files deleted.");
} catch (error) {
console.error("Error during file deletion:", error);
}
console.log("Closing server...");
server.close(() => {
console.log("Server closed.");
process.exit();
});
});
});