158 lines
5.3 KiB
C#
158 lines
5.3 KiB
C#
/*
|
|
A simple Backup Client / Server
|
|
Copyright (C) 2023 Mike Nolan
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Net.Http;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Tesses.Backup.Models;
|
|
using Tesses.VirtualFilesystem;
|
|
|
|
namespace Tesses.Backup
|
|
{
|
|
public class BackupContext
|
|
{
|
|
IVirtualFilesystem fs;
|
|
string key;
|
|
|
|
HttpClient clt;
|
|
long device;
|
|
internal BackupContext(string key,HttpClient clt,IVirtualFilesystem fs,CreateBackupResponse resp,long device)
|
|
{
|
|
this.key=key;
|
|
this.clt =clt;
|
|
this.fs = fs;
|
|
this.BackupResponse = resp;
|
|
this.device =device;
|
|
|
|
CalculateLength(this.BackupResponse.BackupData,Special.Root);
|
|
}
|
|
|
|
public CreateBackupResponse BackupResponse {get;set;}
|
|
|
|
public List<(UnixPath Path,string Hash)> FilesToBackup {get;set;}=new List<(UnixPath Path,string Hash)>();
|
|
|
|
public long TotalBytes {get;set;}=0;
|
|
private void CalculateLength(List<BackupFileEntry> files,UnixPath path)
|
|
{
|
|
|
|
foreach(var file in files)
|
|
{
|
|
if(file.IsFile)
|
|
{
|
|
FilesToBackup.Add((path / file.Name,file.Hash));
|
|
TotalBytes += file.Length;
|
|
}else{
|
|
CalculateLength(file.SubEntries,path / file.Name);
|
|
}
|
|
}
|
|
}
|
|
|
|
private class CallbackStrm : Stream
|
|
{
|
|
Stream strm;
|
|
Action<int> read;
|
|
public CallbackStrm(Stream strm,Action<int> read)
|
|
{
|
|
this.strm = strm;
|
|
this.read=read;
|
|
}
|
|
public override bool CanRead => strm.CanRead;
|
|
|
|
public override bool CanSeek => strm.CanSeek;
|
|
|
|
public override bool CanWrite => false;
|
|
|
|
public override long Length => strm.Length;
|
|
|
|
public override long Position { get => strm.Position; set => strm.Position=value; }
|
|
|
|
public override void Flush()
|
|
{
|
|
strm.Flush();
|
|
}
|
|
public override async Task FlushAsync(CancellationToken cancellationToken)
|
|
{
|
|
await strm.FlushAsync(cancellationToken);
|
|
}
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
int outCount= strm.Read(buffer,offset,count);
|
|
this?.read(outCount);
|
|
return outCount;
|
|
}
|
|
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
|
{
|
|
int outCount= await strm.ReadAsync(buffer,offset,count);
|
|
this?.read(outCount);
|
|
return outCount;
|
|
}
|
|
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
{
|
|
return strm.Seek(offset,origin);
|
|
}
|
|
|
|
public override void SetLength(long value)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public async Task PerformBackupAsync(IProgress<BackupProgress> progress=null)
|
|
{
|
|
BackupProgress p=new BackupProgress();
|
|
var files = FilesToBackup;
|
|
p.FileCount = files.Count;
|
|
p.BackupBytesWriten = 0;
|
|
p.BackupTotalBytes = TotalBytes;
|
|
for(int i = 0;i<files.Count;i++)
|
|
{
|
|
var file = files[i];
|
|
p.FileName = file.Path;
|
|
p.Hash = file.Hash;
|
|
p.FileIndex = i;
|
|
p.FileBytesWriten = 0;
|
|
progress?.Report(p);
|
|
try{
|
|
using(var srcStrm = await fs.OpenAsync(file.Path,System.IO.FileMode.Open,System.IO.FileAccess.Read,System.IO.FileShare.Read))
|
|
{
|
|
p.FileTotalBytes = srcStrm.Length;
|
|
using(CallbackStrm strm = new CallbackStrm(srcStrm,(ctx)=>{
|
|
p.FileBytesWriten += ctx;
|
|
p.BackupBytesWriten += ctx;
|
|
progress?.Report(p);
|
|
}))
|
|
await clt.PutAsync($"/api/v1/File?key={key}&hash={p.Hash}&device={device}",new StreamContent(strm));
|
|
}}catch(Exception ex)
|
|
{
|
|
_=ex;
|
|
}
|
|
progress?.Report(p);
|
|
}
|
|
progress?.Report(p);
|
|
}
|
|
}
|
|
} |