Skip to content

Commit 7213459

Browse files
Thomas Fuchsseveneleven
authored andcommitted
Extend file system with owner keys
1 parent 83c5cf1 commit 7213459

File tree

5 files changed

+239
-9
lines changed

5 files changed

+239
-9
lines changed

docs/articles/Core/FileSystem.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
uid: FileSystem
3+
---
4+
# FileSystem
5+
6+
````mermaid
7+
classDiagram
8+
MoryxFile <|-- Blob
9+
MoryxFile <|-- Tree
10+
Tree --> MoryxFile
11+
OwnerFile --> Tree
12+
class MoryxFileSystem{
13+
-string Directory
14+
+WriteBlob()
15+
+WriteTree()
16+
+ReadBlob()
17+
+ReadTree()
18+
}
19+
class MoryxFile {
20+
+String Hash
21+
}
22+
````

src/Moryx.Runtime.Kernel/FileSystem/MoryxFileSystem.cs

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using Microsoft.Extensions.Logging;
22
using Moryx.FileSystem;
3+
using Moryx.Logging;
34
using System;
45
using System.Collections.Generic;
56
using System.IO;
7+
using System.Linq;
68
using System.Text;
79
using System.Threading.Tasks;
810

@@ -11,6 +13,7 @@ namespace Moryx.Runtime.Kernel.FileSystem
1113
internal class MoryxFileSystem : IMoryxFileSystem
1214
{
1315
private string _fsDirectory;
16+
private string _ownerFilesDirectory;
1417
private readonly ILogger _logger;
1518

1619
public MoryxFileSystem(ILoggerFactory loggerFactory)
@@ -21,15 +24,10 @@ public MoryxFileSystem(ILoggerFactory loggerFactory)
2124
public void SetBasePath(string basePath = "fs")
2225
{
2326
_fsDirectory = Path.Combine(Directory.GetCurrentDirectory(), basePath);
27+
_ownerFilesDirectory = Path.Combine(_fsDirectory, "owners");
2428
}
2529

26-
public Stream ReadFile(string hash)
27-
{
28-
var path = HashPath.FromHash(hash).FilePath(_fsDirectory);
29-
return File.Exists(path) ? new FileStream(path, FileMode.Open, FileAccess.Read) : null;
30-
}
31-
32-
public async Task<string> WriteFile(Stream stream)
30+
public async Task<string> WriteBlob(Stream stream)
3331
{
3432
var hashPath = HashPath.FromStream(stream);
3533

@@ -64,6 +62,139 @@ public async Task<string> WriteFile(Stream stream)
6462

6563
return hashPath.Hash;
6664
}
65+
public Task<string> WriteTree(IReadOnlyList<MoryxFileMetadata> metadata)
66+
{
67+
// Convert metadata to lines
68+
var lines = metadata.Select(md => md.ToString()).ToList();
69+
var stream = new MemoryStream();
70+
using (var sw = new StreamWriter(stream))
71+
{
72+
foreach (var line in lines)
73+
sw.WriteLine(line);
74+
sw.Flush();
75+
}
76+
77+
return WriteBlob(stream);
78+
}
79+
80+
public async Task<string> WriteBlob(Stream fileStream, string ownerKey, MoryxFileMetadata metadata)
81+
{
82+
// Create file first
83+
var hash = await WriteBlob(fileStream);
84+
metadata.Hash = hash;
85+
86+
// Read current owner tree
87+
var ownerFile = Path.Combine(_ownerFilesDirectory, ownerKey);
88+
var ownerTree = File.ReadAllText(ownerFile);
89+
var tree = ReadExtensibleTree(ownerTree);
90+
91+
// Add to owner tree and write new
92+
tree.Add(metadata);
93+
var treeHash = WriteTree(tree);
94+
95+
// Update owner file
96+
var ownerFilePath = Path.Combine(_ownerFilesDirectory, ownerKey);
97+
if (File.Exists(ownerFilePath))
98+
await File.WriteAllLinesAsync(ownerFilePath, new[] { hash });
99+
else
100+
await File.AppendAllLinesAsync(ownerFilePath, new[] { hash });
101+
102+
return hash;
103+
}
104+
105+
public Stream ReadBlob(string hash)
106+
{
107+
var path = HashPath.FromHash(hash).FilePath(_fsDirectory);
108+
return File.Exists(path) ? new FileStream(path, FileMode.Open, FileAccess.Read) : null;
109+
}
110+
111+
public IReadOnlyList<MoryxFileMetadata> ReadTree(string hash) => ReadExtensibleTree(hash);
112+
113+
114+
public IReadOnlyList<MoryxFileMetadata> ReadTreeByOwner(string ownerKey)
115+
{
116+
// read hash from owner file
117+
var ownerFile = Path.Combine(_ownerFilesDirectory, ownerKey);
118+
var ownerTree = File.ReadAllText(ownerFile);
119+
120+
return ReadExtensibleTree(ownerTree);
121+
}
122+
123+
private List<MoryxFileMetadata> ReadExtensibleTree(string hash)
124+
{
125+
// Read tree from hash
126+
var stream = ReadBlob(hash);
127+
var metadata = new List<MoryxFileMetadata>();
128+
using (var sr = new StreamReader(stream))
129+
{
130+
var line = sr.ReadLine();
131+
metadata.Add(MoryxFileMetadata.FromLine(line));
132+
}
133+
134+
return metadata;
135+
}
136+
137+
public bool RemoveFile(string hash, string ownerKey)
138+
{
139+
if (!IsOwner(hash, ownerKey))
140+
return false;
141+
142+
// Delete file if found
143+
var hashPath = HashPath.FromHash(hash);
144+
var filePath = hashPath.FilePath(_fsDirectory);
145+
if (!File.Exists(filePath))
146+
return false;
147+
RemoveFile(filePath, _logger);
148+
149+
// Check if subdirectory is empty and remove
150+
var directory = hashPath.DirectoryPath(_fsDirectory);
151+
CleanUpDirectory(directory, _logger);
152+
153+
// TODO: Remove file from owner list
154+
155+
return true;
156+
}
157+
158+
private bool IsOwner(string hash, string ownerFile)
159+
{
160+
var ownerFilePath = Path.Combine(_ownerFilesDirectory, ownerFile);
161+
using (var reader = new StreamReader(ownerFilePath))
162+
{
163+
string line;
164+
while ((line = reader.ReadLine()) != null)
165+
{
166+
if (line.Contains(searchLine))
167+
return true;
168+
}
169+
}
170+
return false;
171+
}
172+
173+
private void RemoveFile(string filePath, ILogger logger)
174+
{
175+
try
176+
{
177+
File.Delete(filePath);
178+
}
179+
catch (Exception e)
180+
{
181+
throw LoggedException(e, logger, filePath);
182+
}
183+
}
184+
185+
private void CleanUpDirectory(string directoryPath, ILogger logger)
186+
187+
{
188+
try
189+
{
190+
if (Directory.GetFiles(directoryPath).Length == 0)
191+
Directory.Delete(directoryPath);
192+
}
193+
catch (Exception e)
194+
{
195+
throw LoggedException(e, logger, directoryPath);
196+
}
197+
}
67198

68199
private Exception LoggedException(Exception e, ILogger logger, string cause)
69200
{

src/Moryx/FileSystem/IMoryxFileSystem.cs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,41 @@ public interface IMoryxFileSystem
1414
/// <summary>
1515
/// Write a file to the file system and receive the hash to access it later
1616
/// </summary>
17-
Task<string> WriteFile(Stream fileStream);
17+
Task<string> WriteBlob(Stream fileStream);
18+
19+
/// <summary>
20+
/// Write a file to the file system and receive the hash to access it later
21+
/// </summary>
22+
Task<string> WriteBlob(Stream fileStream, string ownerKey, MoryxFileMetadata metadata);
23+
24+
/// <summary>
25+
/// Write a file to the file system and receive the hash to access it later
26+
/// </summary>
27+
Task<string> WriteTree(IReadOnlyList<MoryxFileMetadata> metadata);
1828

1929
/// <summary>
2030
/// Read the file by passing the file system hash
2131
/// </summary>
2232
/// <param name="hash"></param>
2333
/// <returns></returns>
24-
Stream ReadFile(string hash);
34+
Stream ReadBlob(string hash);
35+
36+
/// <summary>
37+
/// Read a tree file and return the listed files
38+
/// </summary>
39+
IReadOnlyList<MoryxFileMetadata> ReadTree(string hash);
40+
41+
/// <summary>
42+
/// Return all files stored under
43+
/// </summary>
44+
/// <param name="ownerKey"></param>
45+
/// <returns></returns>
46+
IReadOnlyList<MoryxFileMetadata> ReadTreeByOwner(string ownerKey);
47+
48+
/// <summary>
49+
/// Remove a file by hash and provided owner key.
50+
/// Files without owner key can not be removed
51+
/// </summary>
52+
bool RemoveFile(string hash, string ownerKey);
2553
}
2654
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace Moryx.FileSystem
7+
{
8+
public class MoryxFileMetadata
9+
{
10+
public int Mode { get; set; }
11+
12+
public FileType FileType { get; set; }
13+
14+
public string MimeType { get; set; }
15+
16+
public string Hash { get; set; }
17+
18+
public string FileName { get; set; }
19+
20+
public string ToLine()
21+
{
22+
return $"{Mode} {FileType.ToString().ToLower()} {MimeType} {Hash} {FileName}";
23+
}
24+
25+
public static MoryxFileMetadata FromLine(string line)
26+
{
27+
var parts = line.Split(' ');
28+
return new MoryxFileMetadata
29+
{
30+
Mode = int.Parse(parts[0]),
31+
FileType = (FileType)Enum.Parse(typeof(FileType), parts[1]),
32+
MimeType = parts[2],
33+
Hash = parts[3],
34+
FileName = string.Join(" ", parts.Skip(4))
35+
};
36+
}
37+
}
38+
39+
/// <summary>
40+
/// Moryx file types in owner tree file
41+
/// </summary>
42+
public enum FileType
43+
{
44+
Blob = 0,
45+
46+
Tree = 1,
47+
}
48+
}

src/StartProject.Asp/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public static void Main(string[] args)
2727
webBuilder.UseStartup<Startup>();
2828
}).Build();
2929

30+
host.Services.UseMoryxFileSystem("fs");
3031
host.Services.UseMoryxConfigurations("Config");
3132

3233
var moduleManager = host.Services.GetRequiredService<IModuleManager>();

0 commit comments

Comments
 (0)