DreamineVMS 1.0.0.0
Windows PC의 RTSP·USB 카메라 영상을 HLS로 변환해 원격 CCTV Viewer에 전달하는 데스크톱 에이전트입니다.
로딩중...
검색중...
일치하는것 없음
SqliteCameraRepository.cs
이 파일의 문서화 페이지로 가기
1using System.IO;
4using Microsoft.Data.Sqlite;
5
7
17{
26 private readonly VmsDatabase _db;
35 private readonly SemaphoreSlim _lock = new(1, 1);
44 private List<CameraDevice> _cache;
45
54 public event EventHandler<CameraRepositoryChangedEventArgs>? Changed;
55
73 {
74 _db = db;
75 _cache = LoadAll();
77 }
78
95 public IReadOnlyList<CameraDevice> GetAll() => _cache.AsReadOnly();
96
121 public IReadOnlyList<CameraDevice> GetByTenant(string tenantId) =>
122 _cache.Where(c => c.TenantId == tenantId).ToList().AsReadOnly();
123
148 public async Task<CameraDevice> AddAsync(CameraDevice camera)
149 {
150 await _lock.WaitAsync();
151 try
152 {
153 using var conn = _db.Open();
154 using var cmd = conn.CreateCommand();
155 cmd.CommandText = """
156 INSERT INTO cameras (id, tenant_id, name, host, rtsp_url, display_order, enabled, auto_reconnect, is_public)
157 VALUES ($id, $tid, $name, $host, $rtsp, $order, $enabled, $ar, $pub)
158 """;
159 BindCamera(cmd, camera);
160 await cmd.ExecuteNonQueryAsync();
161 _cache = LoadAll();
162 }
163 finally { _lock.Release(); }
164
166 {
167 CameraId = camera.Id, Kind = CameraRepositoryChangeKind.Added, Camera = camera
168 });
169 return camera;
170 }
171
196 public async Task UpdateAsync(CameraDevice camera)
197 {
198 await _lock.WaitAsync();
199 try
200 {
201 using var conn = _db.Open();
202 using var cmd = conn.CreateCommand();
203 cmd.CommandText = """
204 UPDATE cameras
205 SET tenant_id=$tid, name=$name, host=$host, rtsp_url=$rtsp,
206 display_order=$order, enabled=$enabled, auto_reconnect=$ar, is_public=$pub
207 WHERE id=$id
208 """;
209 BindCamera(cmd, camera);
210 await cmd.ExecuteNonQueryAsync();
211 _cache = LoadAll();
212 }
213 finally { _lock.Release(); }
214
216 {
217 CameraId = camera.Id, Kind = CameraRepositoryChangeKind.Updated, Camera = camera
218 });
219 }
220
245 public async Task DeleteAsync(string id)
246 {
247 await _lock.WaitAsync();
248 try
249 {
250 using var conn = _db.Open();
251 using var cmd = conn.CreateCommand();
252 cmd.CommandText = "DELETE FROM cameras WHERE id = $id";
253 cmd.Parameters.AddWithValue("$id", id);
254 await cmd.ExecuteNonQueryAsync();
255 _cache = LoadAll();
256 }
257 finally { _lock.Release(); }
258
260 {
261 CameraId = id, Kind = CameraRepositoryChangeKind.Deleted
262 });
263 }
264
265 // ── private ──────────────────────────────────────────────────────────────
266
283 private List<CameraDevice> LoadAll()
284 {
285 var list = new List<CameraDevice>();
286 using var conn = _db.Open();
287 using var cmd = conn.CreateCommand();
288 cmd.CommandText = "SELECT * FROM cameras ORDER BY display_order";
289 using var reader = cmd.ExecuteReader();
290 while (reader.Read())
291 list.Add(ReadCamera(reader));
292 return list;
293 }
294
319 private static void BindCamera(SqliteCommand cmd, CameraDevice c)
320 {
321 cmd.Parameters.AddWithValue("$id", c.Id);
322 cmd.Parameters.AddWithValue("$tid", c.TenantId);
323 cmd.Parameters.AddWithValue("$name", c.Name);
324 cmd.Parameters.AddWithValue("$host", c.Host);
325 cmd.Parameters.AddWithValue("$rtsp", c.RtspUrl);
326 cmd.Parameters.AddWithValue("$order", c.DisplayOrder);
327 cmd.Parameters.AddWithValue("$enabled", c.Enabled ? 1 : 0);
328 cmd.Parameters.AddWithValue("$ar", c.AutoReconnect ? 1 : 0);
329 cmd.Parameters.AddWithValue("$pub", c.IsPublic ? 1 : 0);
330 }
331
356 private static CameraDevice ReadCamera(SqliteDataReader r) => new()
357 {
358 Id = r.GetString(r.GetOrdinal("id")),
359 TenantId = r.GetString(r.GetOrdinal("tenant_id")),
360 Name = r.GetString(r.GetOrdinal("name")),
361 Host = r.GetString(r.GetOrdinal("host")),
362 RtspUrl = r.GetString(r.GetOrdinal("rtsp_url")),
363 DisplayOrder = r.GetInt32(r.GetOrdinal("display_order")),
364 Enabled = r.GetInt32(r.GetOrdinal("enabled")) == 1,
365 AutoReconnect = r.GetInt32(r.GetOrdinal("auto_reconnect")) == 1,
366 IsPublic = r.GetInt32(r.GetOrdinal("is_public")) == 1
367 };
368
377 private void MigrateFromJson()
378 {
379 var jsonPath = Path.Combine(AppContext.BaseDirectory, "cameras.json");
380 if (!File.Exists(jsonPath) || _cache.Count > 0) return;
381
382 try
383 {
384 var json = File.ReadAllText(jsonPath);
385 var stored = System.Text.Json.JsonSerializer.Deserialize<List<JsonCam>>(json) ?? [];
386 foreach (var cam in stored)
387 {
388 using var conn = _db.Open();
389 using var cmd = conn.CreateCommand();
390 cmd.CommandText = """
391 INSERT OR IGNORE INTO cameras (id, tenant_id, name, host, rtsp_url, display_order, enabled, auto_reconnect, is_public)
392 VALUES ($id, '', $name, $host, $rtsp, $order, $enabled, $ar, 0)
393 """;
394 cmd.Parameters.AddWithValue("$id", cam.Id ?? Guid.NewGuid().ToString("N"));
395 cmd.Parameters.AddWithValue("$name", cam.Name ?? "");
396 cmd.Parameters.AddWithValue("$host", cam.Host ?? "");
397 cmd.Parameters.AddWithValue("$rtsp", cam.RtspUrl ?? "");
398 cmd.Parameters.AddWithValue("$order", cam.DisplayOrder);
399 cmd.Parameters.AddWithValue("$enabled", cam.Enabled ? 1 : 0);
400 cmd.Parameters.AddWithValue("$ar", cam.AutoReconnect ? 1 : 0);
401 cmd.ExecuteNonQuery();
402 }
403 _cache = LoadAll();
404 File.Move(jsonPath, jsonPath + ".migrated");
405 }
406 catch { /* 마이그레이션 실패 시 무시 */ }
407 }
408
417 private sealed class JsonCam
418 {
427 public string? Id { get; set; }
436 public string? Name { get; set; }
445 public string? Host { get; set; }
454 public string? RtspUrl { get; set; }
463 public int DisplayOrder { get; set; }
472 public bool Enabled { get; set; } = true;
481 public bool AutoReconnect { get; set; } = true;
482 }
483}
async Task< CameraDevice > AddAsync(CameraDevice camera)
IReadOnlyList< CameraDevice > GetByTenant(string tenantId)
static void BindCamera(SqliteCommand cmd, CameraDevice c)
EventHandler< CameraRepositoryChangedEventArgs >? Changed
static CameraDevice ReadCamera(SqliteDataReader r)