using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using StackExchange.Redis; using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { public class RedisBasketRepository : IBasketRepository { private ILogger _logger; private BasketSettings _settings; private ConnectionMultiplexer _redis; public RedisBasketRepository(IOptionsSnapshot options, ILoggerFactory loggerFactory) { _settings = options.Value; _logger = loggerFactory.CreateLogger(); } public async Task DeleteBasketAsync(string id) { var database = await GetDatabase(); return await database.KeyDeleteAsync(id.ToString()); } public async Task> GetUsersAsync() { var server = await GetServer(); IEnumerable data = server.Keys(); if (data == null) { return null; } return data.Select(k => k.ToString()); } public async Task GetBasketAsync(string customerId) { var database = await GetDatabase(); var data = await database.StringGetAsync(customerId.ToString()); if (data.IsNullOrEmpty) { return null; } return JsonConvert.DeserializeObject(data); } public async Task UpdateBasketAsync(CustomerBasket basket) { var database = await GetDatabase(); var created = await database.StringSetAsync(basket.BuyerId, JsonConvert.SerializeObject(basket)); if (!created) { _logger.LogInformation("Problem occur persisting the item."); return null; } _logger.LogInformation("Basket item persisted succesfully."); return await GetBasketAsync(basket.BuyerId); } private async Task GetDatabase() { if (_redis == null) { await ConnectToRedisAsync(); } return _redis.GetDatabase(); } private async Task GetServer() { if (_redis == null) { await ConnectToRedisAsync(); } var endpoint = _redis.GetEndPoints(); return _redis.GetServer(endpoint.First()); } private async Task ConnectToRedisAsync() { // TODO: Need to make this more robust. ConnectionMultiplexer.ConnectAsync doesn't like domain names or IPv6 addresses. if (IPAddress.TryParse(_settings.ConnectionString, out var ip)) { _redis = await ConnectionMultiplexer.ConnectAsync(ip.ToString()); _logger.LogInformation($"Connecting to database at {_settings.ConnectionString}"); } else { // workaround for https://github.com/StackExchange/StackExchange.Redis/issues/410 var ips = await Dns.GetHostAddressesAsync(_settings.ConnectionString); _logger.LogInformation($"Connecting to database {_settings.ConnectionString} at IP {ips.First().ToString()}"); _redis = await ConnectionMultiplexer.ConnectAsync(ips.First().ToString()); } } } }