Families.Web 1.0.0.0
사진, 동영상, 글, 댓글과 반응을 가족끼리만 공유하는 비공개 앨범·타임라인 서비스입니다.
로딩중...
검색중...
일치하는것 없음
JsonFamilyTenantStore.cs
이 파일의 문서화 페이지로 가기
1using System.IO;
2using System.Text.Json;
3using System.Text.Json.Serialization;
5
7
17{
26 private readonly string _dataRoot;
35 private static readonly SemaphoreSlim _gate = new(1, 1);
36
45 private static readonly JsonSerializerOptions _jsonOpts = new()
46 {
47 WriteIndented = true,
48 PropertyNameCaseInsensitive = true,
49 Converters = { new JsonStringEnumConverter() }
50 };
51
69 {
71 Directory.CreateDirectory(_dataRoot);
72 }
73
98 public string GetTenantDataPath(string slug) =>
99 Path.Combine(_dataRoot, Sanitize(slug));
100
133 public async Task<FamilyConfig?> GetAsync(string slug, CancellationToken ct = default)
134 {
135 var path = ConfigPath(slug);
136 if (!File.Exists(path)) return null;
137
138 await _gate.WaitAsync(ct).ConfigureAwait(false);
139 try
140 {
141 await using var fs = File.OpenRead(path);
142 return await JsonSerializer.DeserializeAsync<FamilyConfig>(fs, _jsonOpts, ct).ConfigureAwait(false);
143 }
144 finally { _gate.Release(); }
145 }
146
171 public async Task<IReadOnlyList<FamilyConfig>> GetAllAsync(CancellationToken ct = default)
172 {
173 var list = new List<FamilyConfig>();
174 if (!Directory.Exists(_dataRoot)) return list;
175
176 foreach (var dir in Directory.GetDirectories(_dataRoot))
177 {
178 var cfg = Path.Combine(dir, "config.json");
179 if (!File.Exists(cfg)) continue;
180
181 await _gate.WaitAsync(ct).ConfigureAwait(false);
182 try
183 {
184 await using var fs = File.OpenRead(cfg);
185 var t = await JsonSerializer.DeserializeAsync<FamilyConfig>(fs, _jsonOpts, ct).ConfigureAwait(false);
186 if (t != null) list.Add(t);
187 }
188 finally { _gate.Release(); }
189 }
190 return list;
191 }
192
225 public async Task SaveAsync(FamilyConfig config, CancellationToken ct = default)
226 {
227 var dir = GetTenantDataPath(config.Slug);
228 Directory.CreateDirectory(dir);
229 Directory.CreateDirectory(Path.Combine(dir, "posts"));
230 Directory.CreateDirectory(Path.Combine(dir, "albums"));
231 Directory.CreateDirectory(Path.Combine(dir, "reactions"));
232 Directory.CreateDirectory(Path.Combine(dir, "media"));
233
234 var tmp = ConfigPath(config.Slug) + ".tmp";
235 await _gate.WaitAsync(ct).ConfigureAwait(false);
236 try
237 {
238 await using (var fs = File.Create(tmp))
239 await JsonSerializer.SerializeAsync(fs, config, _jsonOpts, ct).ConfigureAwait(false);
240
241 File.Copy(tmp, ConfigPath(config.Slug), overwrite: true);
242 File.Delete(tmp);
243 }
244 finally { _gate.Release(); }
245 }
246
279 public Task<bool> ExistsAsync(string slug, CancellationToken ct = default) =>
280 Task.FromResult(File.Exists(ConfigPath(slug)));
281
314 public Task DeleteAsync(string slug, CancellationToken ct = default)
315 {
316 var dir = GetTenantDataPath(slug);
317 if (Directory.Exists(dir))
318 Directory.Delete(dir, recursive: true);
319 return Task.CompletedTask;
320 }
321
346 private string ConfigPath(string slug) =>
347 Path.Combine(GetTenantDataPath(slug), "config.json");
348
373 private static string Sanitize(string slug) =>
374 string.Concat(slug.ToLowerInvariant().Split(Path.GetInvalidFileNameChars()));
375}
async Task< FamilyConfig?> GetAsync(string slug, CancellationToken ct=default)
async Task< IReadOnlyList< FamilyConfig > > GetAllAsync(CancellationToken ct=default)
Task DeleteAsync(string slug, CancellationToken ct=default)
Task< bool > ExistsAsync(string slug, CancellationToken ct=default)
static readonly JsonSerializerOptions _jsonOpts
async Task SaveAsync(FamilyConfig config, CancellationToken ct=default)