- Backend NestJS orchestrant CloudCompare CLI (stats, decimation x2 sur 5 etapes, volume, assemblage .bin) - Scripts Python (laspy, scipy, matplotlib) pour la conversion LAS/LAZ et la generation d'images - Frontend web simple (Tailwind CDN) avec historique des runs - Image Docker (debian:trixie-slim + cloudcompare apt + xvfb) prete pour deploiement Coolify - Lint/typecheck/tests unitaires integres comme portes de qualite au build Docker - CLAUDE.md documentant les comportements CloudCompare CLI verifies empiriquement
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import { Injectable, OnModuleInit } from '@nestjs/common';
|
|
import Database from 'better-sqlite3';
|
|
import * as fs from 'fs';
|
|
import { config, dbPath } from '../config';
|
|
|
|
export interface RunRow {
|
|
id: string;
|
|
original_filename: string;
|
|
status: 'pending' | 'running' | 'done' | 'error';
|
|
created_at: string;
|
|
finished_at: string | null;
|
|
params_json: string | null;
|
|
report_json: string | null;
|
|
log: string;
|
|
error: string | null;
|
|
}
|
|
|
|
@Injectable()
|
|
export class DatabaseService implements OnModuleInit {
|
|
private db!: Database.Database;
|
|
|
|
onModuleInit() {
|
|
fs.mkdirSync(config.dataDir, { recursive: true });
|
|
this.db = new Database(dbPath());
|
|
this.db.pragma('journal_mode = WAL');
|
|
this.db.exec(`
|
|
CREATE TABLE IF NOT EXISTS runs (
|
|
id TEXT PRIMARY KEY,
|
|
original_filename TEXT NOT NULL,
|
|
status TEXT NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
finished_at TEXT,
|
|
params_json TEXT,
|
|
report_json TEXT,
|
|
log TEXT NOT NULL DEFAULT '',
|
|
error TEXT
|
|
);
|
|
`);
|
|
}
|
|
|
|
insert(row: Pick<RunRow, 'id' | 'original_filename' | 'status' | 'created_at' | 'params_json'>) {
|
|
this.db
|
|
.prepare(
|
|
`INSERT INTO runs (id, original_filename, status, created_at, params_json, log) VALUES (?, ?, ?, ?, ?, '')`,
|
|
)
|
|
.run(row.id, row.original_filename, row.status, row.created_at, row.params_json);
|
|
}
|
|
|
|
updateStatus(id: string, status: RunRow['status']) {
|
|
this.db.prepare(`UPDATE runs SET status = ? WHERE id = ?`).run(status, id);
|
|
}
|
|
|
|
appendLog(id: string, line: string) {
|
|
this.db.prepare(`UPDATE runs SET log = log || ? WHERE id = ?`).run(`[${new Date().toISOString()}] ${line}\n`, id);
|
|
}
|
|
|
|
complete(id: string, reportJson: string) {
|
|
this.db
|
|
.prepare(`UPDATE runs SET status = 'done', report_json = ?, finished_at = ? WHERE id = ?`)
|
|
.run(reportJson, new Date().toISOString(), id);
|
|
}
|
|
|
|
fail(id: string, error: string) {
|
|
this.db.prepare(`UPDATE runs SET status = 'error', error = ?, finished_at = ? WHERE id = ?`).run(error, new Date().toISOString(), id);
|
|
}
|
|
|
|
get(id: string): RunRow | undefined {
|
|
return this.db.prepare(`SELECT * FROM runs WHERE id = ?`).get(id) as RunRow | undefined;
|
|
}
|
|
|
|
list(): RunRow[] {
|
|
return this.db.prepare(`SELECT * FROM runs ORDER BY created_at DESC`).all() as RunRow[];
|
|
}
|
|
|
|
remove(id: string) {
|
|
this.db.prepare(`DELETE FROM runs WHERE id = ?`).run(id);
|
|
}
|
|
}
|