using Blog3000.Shared; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Caching.Memory; using System.Text; using System.IO; using Microsoft.AspNetCore.StaticFiles; using Microsoft.CodeAnalysis.CSharp.Syntax; using Blog3000.Client; using System.Text.Json; using System.Xml.Linq; using System.Threading; namespace Blog3000.Server.Controllers { [ApiController] [Route("[controller]")] public class ViewStatsController : ControllerBase { private readonly ILogger logger; private readonly BlogPostRepo blogPostRepo; private readonly string statsFile; private static readonly SemaphoreSlim myLock = new SemaphoreSlim(1); public ViewStatsController(ILogger logger, BlogPostRepo blogPostRepo) { this.logger = logger; this.blogPostRepo = blogPostRepo; statsFile = System.IO.Path.Combine( (string)AppDomain.CurrentDomain.GetData("AppDataPath"), "stats.json"); } [HttpGet] public async Task>> GetAsync() { logger.LogInformation($"ViewStats|{HttpContext.Connection.RemoteIpAddress}|GetAsync"); await myLock.WaitAsync(); try { var res = await LoadAsync(); return res; } finally { myLock.Release(); } } [HttpPost] public async Task >> PostAsync(Dictionary newStats) { // Only add 1 view for each read post to prevent user manipulating stats to much // Ignoew unknwon posts logger.LogInformation($"ViewStats|{HttpContext.Connection.RemoteIpAddress}|PostAsync"); await myLock.WaitAsync(); try { var stats = await LoadAsync(); foreach (var k in newStats.Keys) { if (blogPostRepo.GetHeaders().FirstOrDefault(p => p.Id.Equals(k)) != null) { int nv; stats.TryGetValue(k, out nv); nv++; stats.Remove(k); stats.Add(k, nv); } } await SaveAsync(stats); return stats; } finally { myLock.Release(); } } private async Task> LoadAsync() { Dictionary res = null; try { if (System.IO.File.Exists(statsFile)) { var text = await System.IO.File.ReadAllTextAsync(statsFile); res = JsonSerializer.Deserialize>(text); } } catch(Exception ex) { logger.LogWarning(ex, $"Error reading stats file ${statsFile}"); } return res ?? new Dictionary(); } private async Task SaveAsync(Dictionary stats) { stats ??= new Dictionary(); try { var text = JsonSerializer.Serialize(stats); await System.IO.File.WriteAllTextAsync(statsFile, text); return true; } catch (Exception ex) { logger.LogWarning(ex, $"Error writing stats file ${statsFile}"); } return false; } } }