blog3000/Blog3000/Server/Controllers/ViewStatsController.cs

137 lines
3.8 KiB
C#

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<BlogPostsController> logger;
private readonly BlogPostRepo blogPostRepo;
private readonly string statsFile;
private static readonly SemaphoreSlim myLock = new SemaphoreSlim(1);
public ViewStatsController(ILogger<BlogPostsController> 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<ActionResult<Dictionary<string, int>>> 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 <ActionResult<Dictionary<string, int>>> PostAsync(Dictionary<string, int> 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<Dictionary<String, int>> LoadAsync()
{
Dictionary<string, int> res = null;
try
{
if (System.IO.File.Exists(statsFile))
{
var text = await System.IO.File.ReadAllTextAsync(statsFile);
res = JsonSerializer.Deserialize<Dictionary<string, int>>(text);
}
}
catch(Exception ex)
{
logger.LogWarning(ex, $"Error reading stats file ${statsFile}");
}
return res ?? new Dictionary<string, int>();
}
private async Task<bool> SaveAsync(Dictionary<string, int> stats)
{
stats ??= new Dictionary<string, int>();
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;
}
}
}