Files
cad-data-router/sop.md

5.2 KiB
Raw Permalink Blame History

SOP CadRoute MVP

Obiettivo

Realizzare un'app desktop (.exe) che:

  • accetti una cartella o uno ZIP
  • legga file CAD (.prt .asm .dwr)
  • analizzi nome file ed estensione
  • applichi regole di routing
  • copi i file verso destinazioni configurate (anche share di rete)

Tecnologie:

  • Node.js
  • Electron
  • unzipper
  • fs-extra

1. Prerequisiti

Installare:

  • Node.js LTS
  • Git
  • Visual Studio Code / VSCodium

Verifica:

node -v
npm -v

2. Creazione progetto

mkdir cadroute
cd cadroute
npm init -y

Installare dipendenze:

npm install electron unzipper fs-extra
npm install electron-builder --save-dev

3. Struttura progetto

cadroute
│
├── package.json
├── main.js
├── preload.js
│
├── renderer
│   ├── index.html
│   └── renderer.js
│
├── services
│   ├── router.js
│   ├── zipProcessor.js
│   └── folderProcessor.js

4. Configurazione runtime

La destinazione viene gestita in memoria in main.js e modificata dalla UI durante l'esecuzione.


5. Motore di routing

services/router.js

const path = require("path")

function findDestination(filename, config){

    const ext = path.extname(filename).slice(1)

    for(const rule of config.rules){

        if(rule.ext !== ext)
            continue

        if(!rule.pattern)
            return rule.destination

        const regex = new RegExp(rule.pattern)

        if(regex.test(filename))
            return rule.destination
    }

    return null
}

module.exports = { findDestination }

7. Processare una cartella

services/folderProcessor.js

const fs = require("fs-extra")
const path = require("path")
const { findDestination } = require("./router")

async function processFolder(folder, config){

    const files = await fs.readdir(folder)

    for(const file of files){

        const src = path.join(folder,file)

        const destDir = findDestination(file, config)

        if(!destDir) continue

        const dest = path.join(destDir,file)

        await fs.copy(src,dest)
    }
}

module.exports = { processFolder }

8. Processare ZIP

services/zipProcessor.js

const unzipper = require("unzipper")
const fs = require("fs-extra")
const path = require("path")
const { findDestination } = require("./router")

async function processZip(zipPath, config){

    const stream = fs.createReadStream(zipPath)
        .pipe(unzipper.Parse())

    for await (const entry of stream){

        const file = entry.path

        const destDir = findDestination(file, config)

        if(!destDir){
            entry.autodrain()
            continue
        }

        const dest = path.join(destDir,path.basename(file))

        entry.pipe(fs.createWriteStream(dest))
    }
}

module.exports = { processZip }

9. Main Electron

main.js

const { app, BrowserWindow, dialog, ipcMain } = require("electron")
const path = require("path")

const { processFolder } = require("./services/folderProcessor")
const { processZip } = require("./services/zipProcessor")
const CAD_EXTENSIONS = ["prt", "asm", "dwr"]
const DEFAULT_DESTINATION = "./output/cad"

let config = {
    destination: DEFAULT_DESTINATION,
    rules: CAD_EXTENSIONS.map((ext) => ({ ext, destination: DEFAULT_DESTINATION }))
}

function createWindow(){

    const win = new BrowserWindow({
        width:800,
        height:600,
        webPreferences:{
            preload: path.join(__dirname,"preload.js")
        }
    })

    win.loadFile("renderer/index.html")
}

app.whenReady().then(createWindow)

ipcMain.handle("select-folder", async () => {

    const result = await dialog.showOpenDialog({
        properties:["openDirectory"]
    })

    if(result.canceled) return

    await processFolder(result.filePaths[0], config)

})

ipcMain.handle("select-zip", async () => {

    const result = await dialog.showOpenDialog({
        filters:[{ name:"Zip", extensions:["zip"] }]
    })

    if(result.canceled) return

    await processZip(result.filePaths[0], config)

})

10. Preload

preload.js

const { contextBridge, ipcRenderer } = require("electron")

contextBridge.exposeInMainWorld("api", {

    selectFolder: () => ipcRenderer.invoke("select-folder"),

    selectZip: () => ipcRenderer.invoke("select-zip")

})

11. UI minima

renderer/index.html

<h2>CadRoute</h2>

<button onclick="window.api.selectFolder()">
Process Folder
</button>

<button onclick="window.api.selectZip()">
Process ZIP
</button>

12. Avvio applicazione

Nel package.json aggiungere:

"scripts": {
  "start": "electron ."
}

Avviare:

npm start

13. Build .exe

Aggiungere nel package.json:

"build": {
  "appId": "com.cadroute",
  "win": {
    "target": "nsis"
  }
}

Build:

npx electron-builder

Output:

dist/
   CadRoute Setup.exe

MVP completato quando

  • l'app si avvia
  • si seleziona ZIP o cartella
  • i file .prt .asm .dwr vengono analizzati
  • i file vengono copiati nelle destinazioni configurate

Migliorie future

  • progress bar
  • drag and drop ZIP
  • modifica regole avanzate da UI
  • logging operazioni
  • parallelismo file
  • watch folder automatico