import { Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ExportTarget } from '../database/entities/export-target.entity'; import * as ftp from 'basic-ftp'; import { createClient, type WebDAVClient } from 'webdav'; @Injectable() export class ExportService { private readonly logger = new Logger(ExportService.name); constructor( @InjectRepository(ExportTarget) private readonly targetRepo: Repository, ) {} async exportFile(targetId: number, filename: string, content: Buffer): Promise { const target = await this.targetRepo.findOneByOrFail({ Id: targetId }); if (!target.IsActive) { throw new Error(`Export-Ziel "${target.Name}" ist deaktiviert.`); } switch (target.Protocol) { case 'ftp': await this.uploadFtp(target, filename, content); break; case 'webdav': await this.uploadWebDav(target, filename, content); break; default: throw new Error(`Unbekanntes Protokoll: ${target.Protocol}`); } } async testConnection(targetId: number): Promise<{ success: boolean; message: string }> { const target = await this.targetRepo.findOneByOrFail({ Id: targetId }); try { switch (target.Protocol) { case 'ftp': await this.testFtp(target); break; case 'webdav': await this.testWebDav(target); break; default: return { success: false, message: `Unbekanntes Protokoll: ${target.Protocol}` }; } return { success: true, message: 'Verbindung erfolgreich.' }; } catch (err: any) { return { success: false, message: err.message }; } } private async uploadFtp(target: ExportTarget, filename: string, content: Buffer): Promise { const client = new ftp.Client(); try { await client.access({ host: target.Host, port: target.Port || 21, user: target.Username || 'anonymous', password: target.Password || '', secure: false, }); const remotePath = `${target.RemotePath || '/'}/${filename}`; const { Readable } = await import('stream'); const stream = Readable.from(content); await client.uploadFrom(stream, remotePath); this.logger.log(`FTP Upload: ${remotePath} → ${target.Name}`); } finally { client.close(); } } private async testFtp(target: ExportTarget): Promise { const client = new ftp.Client(); try { await client.access({ host: target.Host, port: target.Port || 21, user: target.Username || 'anonymous', password: target.Password || '', secure: false, }); await client.list(target.RemotePath || '/'); } finally { client.close(); } } private async uploadWebDav(target: ExportTarget, filename: string, content: Buffer): Promise { const client = this.createWebDavClient(target); const remotePath = `${target.RemotePath || '/'}/${filename}`; await client.putFileContents(remotePath, content); this.logger.log(`WebDAV Upload: ${remotePath} → ${target.Name}`); } private async testWebDav(target: ExportTarget): Promise { const client = this.createWebDavClient(target); await client.getDirectoryContents(target.RemotePath || '/'); } private createWebDavClient(target: ExportTarget): WebDAVClient { const protocol = target.Port === 443 ? 'https' : 'http'; const port = target.Port ? `:${target.Port}` : ''; const url = `${protocol}://${target.Host}${port}`; return createClient(url, { username: target.Username || undefined, password: target.Password || undefined, }); } }