using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using StackExchange.Redis; using ExcelKv.Core; namespace SchemaEditor.Services; public class GarnetClientService : IStorageWrapper, IDisposable { private ConnectionMultiplexer? _redis; private IDatabase? _db; public bool IsConnected => _redis?.IsConnected == true; public void Connect(string connectionString = "localhost:3187") { if (_redis == null || !_redis.IsConnected) { _redis = ConnectionMultiplexer.Connect(connectionString); _db = _redis.GetDatabase(); } } public async Task SetAsync(string key, string value) { if (_db == null) Connect(); if (_db != null) await _db.StringSetAsync(key, value); } public async Task SetAsync(string key, string value, int row, int col) { // For Garnet, we currently only store Key-Value string. // Traceability metadata (row, col) could be stored in a hash or side key if needed. // For now, we just proceed with standard storage. if (_db == null) Connect(); if (_db != null) await _db.StringSetAsync(key, value); } public async Task IncrementAsync(string key, double value) { if (_db == null) Connect(); if (_db != null) await _db.StringIncrementAsync(key, value); } // For Data Explorer public async Task> SearchKeysAsync(string pattern) { if (_db == null) Connect(); if (_redis == null || _db == null) return await Task.FromResult(new List()); var server = _redis.GetServer(_redis.GetEndPoints().First()); // Use Keys for simplicity in Schema Editor (low traffic) // In high production, use SCAN var keys = server.Keys(pattern: pattern).Select(k => k.ToString()).ToList(); return await Task.FromResult(keys); } public async Task GetValueAsync(string key) { if (_db == null) Connect(); if (_db == null) return string.Empty; var val = await _db.StringGetAsync(key); return val.HasValue ? val.ToString() : string.Empty; } public void Dispose() { _redis?.Dispose(); } }