-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DataFileService.cs
136 lines (127 loc) · 5.04 KB
/
DataFileService.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
namespace Serval.DataFiles.Services;
public class DataFileService : EntityServiceBase<DataFile>, IDataFileService
{
private readonly IOptionsMonitor<DataFileOptions> _options;
private readonly IDataAccessContext _dataAccessContext;
private readonly IScopedMediator _mediator;
private readonly IRepository<DeletedFile> _deletedFiles;
private readonly IFileSystem _fileSystem;
public DataFileService(
IRepository<DataFile> dataFiles,
IDataAccessContext dataAccessContext,
IOptionsMonitor<DataFileOptions> options,
IScopedMediator mediator,
IRepository<DeletedFile> deletedFiles,
IFileSystem fileSystem
)
: base(dataFiles)
{
_dataAccessContext = dataAccessContext;
_options = options;
_mediator = mediator;
_deletedFiles = deletedFiles;
_fileSystem = fileSystem;
_fileSystem.CreateDirectory(_options.CurrentValue.FilesDirectory);
}
public async Task<DataFile> GetAsync(string id, string owner, CancellationToken cancellationToken = default)
{
DataFile? dataFile = await Entities.GetAsync(f => f.Id == id && f.Owner == owner, cancellationToken);
if (dataFile is null)
throw new EntityNotFoundException($"Could not find the DataFile '{id}' with owner '{owner}'.");
return dataFile;
}
public async Task<IEnumerable<DataFile>> GetAllAsync(string owner, CancellationToken cancellationToken = default)
{
return await Entities.GetAllAsync(c => c.Owner == owner, cancellationToken);
}
public async Task CreateAsync(DataFile dataFile, Stream stream, CancellationToken cancellationToken = default)
{
string filename = Path.GetRandomFileName();
string path = GetDataFilePath(filename);
try
{
using Stream fileStream = _fileSystem.OpenWrite(path);
await stream.CopyToAsync(fileStream, cancellationToken);
await Entities.InsertAsync(dataFile with { Filename = filename }, cancellationToken);
}
catch
{
_fileSystem.DeleteFile(path);
throw;
}
}
public async Task<Stream> ReadAsync(string id, CancellationToken cancellationToken = default)
{
DataFile? dataFile = await GetAsync(id, cancellationToken);
if (dataFile is null)
throw new EntityNotFoundException($"Could not find the DataFile '{id}'.");
string path = GetDataFilePath(dataFile.Filename);
return _fileSystem.OpenRead(path);
}
public async Task<DataFile> UpdateAsync(string id, Stream stream, CancellationToken cancellationToken = default)
{
string filename = Path.GetRandomFileName();
string path = GetDataFilePath(filename);
bool deleteFile = false;
try
{
using (Stream fileStream = _fileSystem.OpenWrite(path))
await stream.CopyToAsync(fileStream, cancellationToken);
await _dataAccessContext.WithTransactionAsync(
async (ct) =>
{
DataFile? originalDataFile = await Entities.UpdateAsync(
id,
u => u.Set(f => f.Filename, filename),
returnOriginal: true,
cancellationToken: ct
);
if (originalDataFile is null)
{
throw new EntityNotFoundException($"Could not find the DataFile '{id}'.");
}
else
{
await _deletedFiles.InsertAsync(
new DeletedFile { Filename = originalDataFile.Filename, DeletedAt = DateTime.UtcNow },
cancellationToken: ct
);
}
},
cancellationToken: cancellationToken
);
return await GetAsync(id, cancellationToken);
}
catch
{
deleteFile = true;
throw;
}
finally
{
if (deleteFile)
_fileSystem.DeleteFile(path);
}
}
public override async Task DeleteAsync(string id, CancellationToken cancellationToken = default)
{
await _dataAccessContext.WithTransactionAsync(
async (ct) =>
{
DataFile? dataFile = await Entities.DeleteAsync(id, ct);
if (dataFile is null)
throw new EntityNotFoundException($"Could not find the DataFile '{id}'.");
await _deletedFiles.InsertAsync(
new DeletedFile { Filename = dataFile.Filename, DeletedAt = DateTime.UtcNow },
ct
);
await _mediator.Publish(new DataFileDeleted { DataFileId = id }, ct);
},
cancellationToken: cancellationToken
);
}
private string GetDataFilePath(string filename)
{
return Path.Combine(_options.CurrentValue.FilesDirectory, filename);
}
}