Table des Matières
🖥️ API CLI (Ligne de Commande)
L'outil en ligne de commande utilise System.CommandLine pour le parsing des arguments.
CLI Commande Principale
Syntaxe
sftp-copy-tool [options]
Options Obligatoires
| Option | Type | Description |
|---|---|---|
--host |
string | Adresse du serveur SFTP |
--username |
string | Nom d'utilisateur SFTP |
--password |
string | Mot de passe SFTP |
--remote-path |
string | Chemin du fichier/dossier distant |
--local-path |
string | Répertoire de destination local |
Options Facultatives
| Option | Type | Défaut | Description |
|---|---|---|---|
--port |
int | 22 | Port du serveur SFTP |
--recursive |
flag | false | Active la copie récursive |
--log-level |
enum | Information | Niveau de journalisation (Verbose, Debug, Information, Warning, Error, Fatal) |
Exemple
sftp-copy-tool \
--host sftp.example.com \
--port 22 \
--username admin \
--password "secret123" \
--remote-path /data/backup \
--local-path /mnt/nas/backup \
--recursive \
--log-level Debug
Code de Retour
| Code | Signification |
|---|---|
0 |
Succès |
1 |
Erreur générale ou exception |
🌐 Services Web
L'application Blazor expose plusieurs services pour gérer les opérations SFTP et l'interface utilisateur.
SftpExecutionService
Service principal pour exécuter les opérations SFTP avec suivi de progression.
ExecuteAsync
Description: Exécute une opération SFTP (fichier unique ou récursif)
Signature
public async Task ExecuteAsync(
string host,
int port,
string username,
string password,
string remotePath,
string localPath,
bool recursive,
IProgressReporter progressReporter,
CancellationToken cancellationToken
)
Paramètres
| Paramètre | Type | Description |
|---|---|---|
host |
string | Adresse du serveur SFTP |
port |
int | Port SFTP (généralement 22) |
username |
string | Nom d'utilisateur |
password |
string | Mot de passe |
remotePath |
string | Chemin distant (absolu) |
localPath |
string | Chemin local de destination |
recursive |
bool | True pour copie récursive |
progressReporter |
IProgressReporter | Interface de rapport de progression |
cancellationToken |
CancellationToken | Token d'annulation |
Exceptions
ArgumentException: Paramètres invalidesInvalidOperationException: Tentative de copie d'un dossier sans --recursiveIOException: Erreur d'E/S (lecture/écriture)UnauthorizedAccessException: Permissions insuffisantes
📡 SftpService
Service bas niveau pour les opérations SFTP utilisant la bibliothèque Tmds.Ssh.
CopyFileAsync
Description: Copie un fichier unique depuis le serveur SFTP
public async Task CopyFileAsync(
string host,
int port,
string username,
string password,
string remotePath,
string localPath,
IProgress<ProgressInfo>? progress = null
)
ProgressInfo Structure
public class ProgressInfo
{
public long BytesTransferred { get; set; }
public long TotalBytes { get; set; }
public double Percentage { get; set; }
public double SpeedBytesPerSecond { get; set; }
public TimeSpan Elapsed { get; set; }
public TimeSpan? EstimatedRemaining { get; set; }
public string CurrentFile { get; set; }
}
CopyDirectoryRecursiveAsync
Description: Copie récursivement un répertoire complet
public async Task CopyDirectoryRecursiveAsync(
string host,
int port,
string username,
string password,
string remotePath,
string localPath,
IProgress<ProgressInfo>? progress = null
)
. et ..) sont ignorées.
TestConnectionAsync
Description: Teste la connexion SFTP sans effectuer de transfert
public async Task<bool> TestConnectionAsync(
string host,
int port,
string username,
string password
)
Retour
true: Connexion réussiefalse: Échec de connexion (exception levée)
📊 Suivi de Progression
IProgressReporter Interface
public interface IProgressReporter
{
void Report(ProgressInfo info);
void AddLog(string message);
IReadOnlyList<string> GetRecentLogs();
}
ProgressReporter (Implémentation)
Propriétés Publiques
| Propriété | Type | Description |
|---|---|---|
CurrentProgress |
ProgressInfo | Informations de progression actuelles |
OnProgressChanged |
Action<ProgressInfo> | Callback appelé lors des mises à jour |
Méthodes
| Méthode | Description |
|---|---|
Report(ProgressInfo info) |
Met à jour la progression et déclenche le callback |
AddLog(string message) |
Ajoute un message au journal (max 50 entrées) |
GetRecentLogs() |
Récupère les 50 derniers logs |
Clear() |
Réinitialise la progression et les logs |
Exemple d'Utilisation
var progressReporter = new ProgressReporter();
progressReporter.OnProgressChanged = (info) =>
{
Console.WriteLine($"Progression: {info.Percentage:F1}%");
Console.WriteLine($"Vitesse: {info.SpeedBytesPerSecond / 1024:F2} KB/s");
};
await sftpService.CopyFileAsync(
"sftp.example.com", 22, "user", "pass",
"/remote/file.zip", "/local/dest/",
new Progress<ProgressInfo>(progressReporter.Report)
);
📁 Explorateur de Fichiers
FileExplorerService
ListRemoteDirectoryAsync
Description: Liste les fichiers et dossiers d'un répertoire distant SFTP
public async Task<List<FileEntry>> ListRemoteDirectoryAsync(
string host,
int port,
string username,
string password,
string remotePath
)
FileEntry Structure
public class FileEntry
{
public string Name { get; set; }
public string FullPath { get; set; }
public bool IsDirectory { get; set; }
public long Size { get; set; }
public DateTime? LastModified { get; set; }
}
Retour
Liste d'objets FileEntry représentant les fichiers et dossiers
ListLocalDirectoryAsync
Description: Liste les fichiers et dossiers d'un répertoire local
public async Task<List<FileEntry>> ListLocalDirectoryAsync(
string localPath
)
⚠️ Gestion des Erreurs
Types d'Exceptions
| Exception | Contexte | Solution |
|---|---|---|
SshException |
Erreur de connexion SSH/SFTP | Vérifier host, port, identifiants, firewall |
ArgumentException |
Paramètres invalides | Valider les entrées utilisateur |
InvalidOperationException |
Opération invalide (ex: dossier sans --recursive) | Ajouter le flag --recursive pour les dossiers |
UnauthorizedAccessException |
Permissions insuffisantes (local) | Vérifier les permissions du dossier local |
IOException |
Erreur lecture/écriture fichier | Vérifier espace disque, permissions, chemin valide |
TaskCanceledException |
Opération annulée par l'utilisateur | Normal, pas d'action requise |
Messages d'Erreur Courants
"Connection refused"
- Serveur SFTP inaccessible ou hors ligne
- Port incorrect (vérifier si c'est bien 22)
- Firewall bloquant la connexion
"Authentication failed"
- Nom d'utilisateur ou mot de passe incorrect
- Compte verrouillé après trop de tentatives
- Authentification par clé requise (non supporté actuellement)
"Path not found"
- Le chemin distant n'existe pas
- Permissions insuffisantes sur le serveur SFTP
- Chemin relatif au lieu d'absolu
Gestion des Erreurs dans le Code
try
{
await sftpService.CopyFileAsync(
host, port, username, password,
remotePath, localPath, progress
);
Console.WriteLine("✅ Transfert réussi");
}
catch (SshException ex)
{
Console.WriteLine($"❌ Erreur SFTP: {ex.Message}");
// Vérifier connexion réseau, identifiants
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine($"❌ Permissions refusées: {ex.Message}");
// Vérifier permissions du dossier local
}
catch (IOException ex)
{
Console.WriteLine($"❌ Erreur E/S: {ex.Message}");
// Vérifier espace disque, chemin valide
}
catch (Exception ex)
{
Console.WriteLine($"❌ Erreur inattendue: {ex.Message}");
// Logger pour investigation
}
📖 Exemples Complets
Exemple 1: Transfert Simple avec Progression
using SftpCopyTool;
var sftpService = new SftpService();
var progress = new Progress<ProgressInfo>(info =>
{
Console.WriteLine($"📊 {info.Percentage:F1}% | " +
$"⚡ {info.SpeedBytesPerSecond / 1024:F2} KB/s | " +
$"📁 {info.CurrentFile}");
});
try
{
await sftpService.CopyFileAsync(
"sftp.example.com",
22,
"admin",
"password123",
"/remote/file.tar.gz",
"/local/backup/",
progress
);
Console.WriteLine("✅ Transfert terminé avec succès!");
}
catch (Exception ex)
{
Console.WriteLine($"❌ Erreur: {ex.Message}");
}
Exemple 2: Interface Web - Composant Blazor
@page "/copy"
@inject SftpExecutionService SftpService
<h3>SFTP Copy Tool</h3>
<EditForm Model="@model" OnValidSubmit="@StartCopy">
<InputText @bind-Value="model.Host" placeholder="Host" />
<InputNumber @bind-Value="model.Port" placeholder="Port" />
<InputText @bind-Value="model.Username" placeholder="Username" />
<InputText type="password" @bind-Value="model.Password" placeholder="Password" />
<InputText @bind-Value="model.RemotePath" placeholder="Remote Path" />
<InputText @bind-Value="model.LocalPath" placeholder="Local Path" />
<InputCheckbox @bind-Value="model.Recursive" /> Recursive
<button type="submit">Start Copy</button>
</EditForm>
@if (progress != null)
{
<div>
<p>Progression: @progress.Percentage.ToString("F1")%</p>
<p>Vitesse: @(progress.SpeedBytesPerSecond / 1024).ToString("F2") KB/s</p>
<p>Fichier: @progress.CurrentFile</p>
</div>
}
@code {
private SftpModel model = new();
private ProgressInfo? progress;
private CancellationTokenSource? cts;
private async Task StartCopy()
{
cts = new CancellationTokenSource();
var progressReporter = new ProgressReporter();
progressReporter.OnProgressChanged = (info) =>
{
progress = info;
StateHasChanged();
};
try
{
await SftpService.ExecuteAsync(
model.Host, model.Port, model.Username, model.Password,
model.RemotePath, model.LocalPath, model.Recursive,
progressReporter, cts.Token
);
}
catch (Exception ex)
{
// Handle error
}
}
}