|  |  | 1 |  | using LGDXRobotCloud.Data.Models.Redis; | 
|  |  | 2 |  | using LGDXRobotCloud.Protos; | 
|  |  | 3 |  | using LGDXRobotCloud.Utilities.Helpers; | 
|  |  | 4 |  | using NRedisStack; | 
|  |  | 5 |  | using NRedisStack.RedisStackCommands; | 
|  |  | 6 |  | using StackExchange.Redis; | 
|  |  | 7 |  | using static StackExchange.Redis.RedisChannel; | 
|  |  | 8 |  |  | 
|  |  | 9 |  | namespace LGDXRobotCloud.API.Repositories; | 
|  |  | 10 |  |  | 
|  |  | 11 |  | public interface ISlamDataRepository | 
|  |  | 12 |  | { | 
|  |  | 13 |  |   Task<bool> StartSlamAsync(int realmId, Guid robotId); | 
|  |  | 14 |  |   Task StopSlamAsync(int realmId, Guid robotId); | 
|  |  | 15 |  |   Task SetSlamExchangeAsync(int realmId, SlamData exchange); | 
|  |  | 16 |  |   Task<bool> AddSlamCommandAsync(int realmId, RobotClientsSlamCommands commands); | 
|  |  | 17 |  | } | 
|  |  | 18 |  |  | 
|  | 0 | 19 |  | public partial class SlamDataRepository( | 
|  | 0 | 20 |  |     IConnectionMultiplexer redisConnection, | 
|  | 0 | 21 |  |     ILogger<SlamDataRepository> logger, | 
|  | 0 | 22 |  |     IRobotDataRepository robotDataRepository | 
|  | 0 | 23 |  |   ) : ISlamDataRepository | 
|  |  | 24 |  | { | 
|  | 0 | 25 |  |   private readonly IConnectionMultiplexer _redisConnection = redisConnection ?? throw new ArgumentNullException(nameof(r | 
|  | 0 | 26 |  |   private readonly IRobotDataRepository _robotDataRepository = robotDataRepository ?? throw new ArgumentNullException(na | 
|  |  | 27 |  |  | 
|  |  | 28 |  |   [LoggerMessage(EventId = 0, Level = LogLevel.Error, Message = "Redis SlamDataRepository Exception: {Msg}")] | 
|  |  | 29 |  |   public partial void LogException(string msg); | 
|  |  | 30 |  |  | 
|  |  | 31 |  |   public async Task<bool> StartSlamAsync(int realmId, Guid robotId) | 
|  | 0 | 32 |  |   { | 
|  | 0 | 33 |  |     var db = _redisConnection.GetDatabase(); | 
|  |  | 34 |  |     try | 
|  | 0 | 35 |  |     { | 
|  | 0 | 36 |  |       bool result = await db.JSON().SetAsync(RedisHelper.GetSlamData(realmId), "$", new SlamData(), When.NotExists); | 
|  | 0 | 37 |  |       if (!result) | 
|  | 0 | 38 |  |       { | 
|  |  | 39 |  |         // Only one robot can running SLAM at a time | 
|  | 0 | 40 |  |         return false; | 
|  |  | 41 |  |       } | 
|  | 0 | 42 |  |       await db.KeyExpireAsync(RedisHelper.GetSlamData(realmId), TimeSpan.FromMinutes(5)); | 
|  | 0 | 43 |  |     } | 
|  | 0 | 44 |  |     catch (Exception ex) | 
|  | 0 | 45 |  |     { | 
|  | 0 | 46 |  |       LogException(ex.Message); | 
|  | 0 | 47 |  |       return false; | 
|  |  | 48 |  |     } | 
|  | 0 | 49 |  |     await _robotDataRepository.StartExchangeAsync(realmId, robotId); | 
|  | 0 | 50 |  |     return true; | 
|  | 0 | 51 |  |   } | 
|  |  | 52 |  |  | 
|  |  | 53 |  |   public async Task StopSlamAsync(int realmId, Guid robotId) | 
|  | 0 | 54 |  |   { | 
|  | 0 | 55 |  |     var db = _redisConnection.GetDatabase(); | 
|  |  | 56 |  |     try | 
|  | 0 | 57 |  |     { | 
|  | 0 | 58 |  |       await db.KeyDeleteAsync(RedisHelper.GetSlamData(realmId)); | 
|  | 0 | 59 |  |     } | 
|  | 0 | 60 |  |     catch (Exception ex) | 
|  | 0 | 61 |  |     { | 
|  | 0 | 62 |  |       LogException(ex.Message); | 
|  | 0 | 63 |  |     } | 
|  | 0 | 64 |  |     await _robotDataRepository.StopExchangeAsync(realmId, robotId); | 
|  | 0 | 65 |  |   } | 
|  |  | 66 |  |  | 
|  |  | 67 |  |   public async Task SetSlamExchangeAsync(int realmId, SlamData exchange) | 
|  | 0 | 68 |  |   { | 
|  | 0 | 69 |  |     var db = _redisConnection.GetDatabase(); | 
|  | 0 | 70 |  |     var pipeline = new Pipeline(db); | 
|  | 0 | 71 |  |     List<Task> tasks = []; | 
|  |  | 72 |  |     try | 
|  | 0 | 73 |  |     { | 
|  | 0 | 74 |  |       tasks.Add(pipeline.Json.SetAsync(RedisHelper.GetSlamData(realmId), "$", exchange)); | 
|  | 0 | 75 |  |       tasks.Add(db.KeyExpireAsync(RedisHelper.GetSlamData(realmId), TimeSpan.FromMinutes(5))); | 
|  | 0 | 76 |  |       pipeline.Execute(); | 
|  | 0 | 77 |  |       await Task.WhenAll(tasks); | 
|  | 0 | 78 |  |     } | 
|  | 0 | 79 |  |     catch (Exception ex) | 
|  | 0 | 80 |  |     { | 
|  | 0 | 81 |  |       LogException(ex.Message); | 
|  | 0 | 82 |  |     } | 
|  | 0 | 83 |  |   } | 
|  |  | 84 |  |  | 
|  |  | 85 |  |   public async Task<bool> AddSlamCommandAsync(int realmId, RobotClientsSlamCommands commands) | 
|  | 0 | 86 |  |   { | 
|  | 0 | 87 |  |     var db = _redisConnection.GetDatabase(); | 
|  |  | 88 |  |     try | 
|  | 0 | 89 |  |     { | 
|  | 0 | 90 |  |       if (!await db.KeyExistsAsync(RedisHelper.GetSlamData(realmId))) | 
|  | 0 | 91 |  |         return false; | 
|  | 0 | 92 |  |       var subscriber = _redisConnection.GetSubscriber(); | 
|  | 0 | 93 |  |       var base64 = SerialiserHelper.ToBase64(commands); | 
|  | 0 | 94 |  |       await subscriber.PublishAsync(new RedisChannel(RedisHelper.GetSlamExchangeQueue(realmId), PatternMode.Literal), ba | 
|  | 0 | 95 |  |     } | 
|  | 0 | 96 |  |     catch (Exception ex) | 
|  | 0 | 97 |  |     { | 
|  | 0 | 98 |  |       LogException(ex.Message); | 
|  | 0 | 99 |  |       return false; | 
|  |  | 100 |  |     } | 
|  | 0 | 101 |  |     return true; | 
|  | 0 | 102 |  |   } | 
|  |  | 103 |  | } |