115 lines
3.7 KiB
TypeScript
115 lines
3.7 KiB
TypeScript
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<ExportTarget>,
|
|
) {}
|
|
|
|
async exportFile(targetId: number, filename: string, content: Buffer): Promise<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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,
|
|
});
|
|
}
|
|
}
|