Spaces:
Sleeping
Sleeping
| const express = require('express'); | |
| const multer = require('multer'); | |
| const archiver = require('archiver'); | |
| const fs = require('fs'); | |
| const fsPromises = require('fs/promises'); | |
| const path = require('path'); | |
| const os = require('os'); | |
| const cors = require('cors'); | |
| const { convertFile, findODAConverter, AUTOCAD_VERSIONS } = require('./oda-converter'); | |
| const app = express(); | |
| const port = process.env.PORT || 7860; | |
| app.use(cors()); | |
| app.use(express.json()); | |
| const upload = multer({ dest: os.tmpdir() }); | |
| app.get('/', (req, res) => { | |
| res.json({ message: 'DWG/DXF Conversion Microservice is running.' }); | |
| }); | |
| app.get('/api/check-oda', async (req, res) => { | |
| try { | |
| const odaPath = await findODAConverter(); | |
| res.json({ | |
| installed: !!odaPath, | |
| path: odaPath, | |
| versions: AUTOCAD_VERSIONS, | |
| }); | |
| } catch (error) { | |
| res.status(500).json({ installed: false, error: 'Failed to check ODA installation' }); | |
| } | |
| }); | |
| app.post('/api/convert', upload.array('files'), async (req, res) => { | |
| const files = req.files; | |
| const targetVersion = req.body.targetVersion; | |
| const outputFormat = req.body.outputFormat || 'DWG'; | |
| const targetCRS = req.body.targetCRS; // e.g. "EPSG:4326" | |
| if (!files || files.length === 0) { | |
| return res.status(400).json({ error: 'No files uploaded' }); | |
| } | |
| if (!targetVersion || !AUTOCAD_VERSIONS.find(v => v.code === targetVersion)) { | |
| return res.status(400).json({ error: 'Invalid target version' }); | |
| } | |
| const tempDir = path.join(os.tmpdir(), 'convert_' + Date.now()); | |
| await fsPromises.mkdir(tempDir, { recursive: true }); | |
| const outputDir = path.join(tempDir, 'output'); | |
| await fsPromises.mkdir(outputDir, { recursive: true }); | |
| try { | |
| const results = []; | |
| for (const file of files) { | |
| const originalName = file.originalname.replace(/[^a-zA-Z0-9._-]/g, '_'); | |
| const sourceFilePath = path.join(tempDir, originalName); | |
| await fsPromises.rename(file.path, sourceFilePath); | |
| const result = await convertFile({ | |
| sourceFilePath: sourceFilePath, | |
| outputDir: outputDir, | |
| targetVersion: targetVersion, | |
| outputFormat: outputFormat, | |
| targetCRS: targetCRS, | |
| audit: true, | |
| }); | |
| results.push({ | |
| name: file.originalname, | |
| success: result.success, | |
| outputPath: result.outputFilePath, | |
| error: result.error, | |
| duration: result.duration, | |
| }); | |
| } | |
| const successResults = results.filter(r => r.success && r.outputPath); | |
| if (successResults.length === 0) { | |
| await fsPromises.rm(tempDir, { recursive: true, force: true }).catch(() => {}); | |
| return res.status(500).json({ error: 'All conversions failed', details: results }); | |
| } | |
| if (successResults.length === 1 && files.length === 1) { | |
| const outputPath = successResults[0].outputPath; | |
| const fileName = path.basename(outputPath); | |
| res.set({ | |
| 'Content-Type': 'application/octet-stream', | |
| 'Content-Disposition': `attachment; filename="${fileName}"`, | |
| 'X-Conversion-Results': JSON.stringify(results), | |
| }); | |
| const fileStream = fs.createReadStream(outputPath); | |
| fileStream.pipe(res); | |
| fileStream.on('close', () => { | |
| fsPromises.rm(tempDir, { recursive: true, force: true }).catch(() => {}); | |
| }); | |
| return; | |
| } | |
| const zipPath = path.join(tempDir, 'converted_files.zip'); | |
| const output = fs.createWriteStream(zipPath); | |
| const archive = archiver('zip', { zlib: { level: 6 } }); | |
| output.on('close', () => { | |
| res.set({ | |
| 'Content-Type': 'application/zip', | |
| 'Content-Disposition': `attachment; filename="converted_${targetVersion}_${outputFormat}.zip"`, | |
| 'X-Conversion-Results': JSON.stringify(results), | |
| }); | |
| const zipStream = fs.createReadStream(zipPath); | |
| zipStream.pipe(res); | |
| zipStream.on('close', () => { | |
| fsPromises.rm(tempDir, { recursive: true, force: true }).catch(() => {}); | |
| }); | |
| }); | |
| archive.on('error', (err) => { | |
| res.status(500).json({ error: err.message }); | |
| }); | |
| archive.pipe(output); | |
| for (const result of successResults) { | |
| if (result.outputPath) { | |
| archive.file(result.outputPath, { name: path.basename(result.outputPath) }); | |
| } | |
| } | |
| archive.finalize(); | |
| } catch (error) { | |
| await fsPromises.rm(tempDir, { recursive: true, force: true }).catch(() => {}); | |
| res.status(500).json({ error: error.message || 'Internal server error' }); | |
| } | |
| }); | |
| app.listen(port, () => { | |
| console.log(`Conversion microservice listening on port ${port}`); | |
| }); | |