| | 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 | | } |