using Microsoft.AspNetCore.Mvc;
using NewLife;
using Rainbow.Entity;
using Rainbow.Services;
using XCode;
namespace Rainbow.Web.Controllers;
/// <summary>DNS 黑名单管理 API</summary>
[ApiController]
[Route("api/dns/blacklist")]
public class DnsBlacklistController : ControllerBase
{
private readonly DnsmasqManager _dnsmasqManager;
/// <summary>构造 DNS 黑名单控制器</summary>
/// <param name="dnsmasqManager">Dnsmasq 配置管理器</param>
public DnsBlacklistController(DnsmasqManager dnsmasqManager) => _dnsmasqManager = dnsmasqManager;
[HttpGet]
public ActionResult<IList<DnsBlacklist>> GetList([FromQuery] String category = null, [FromQuery] String source = null)
{
var exp = new WhereExpression();
if (!category.IsNullOrEmpty()) exp &= DnsBlacklist._.Category == category;
if (!source.IsNullOrEmpty()) exp &= DnsBlacklist._.Source == source;
exp &= DnsBlacklist._.Enable == true;
return Ok(DnsBlacklist.FindAll(exp, DnsBlacklist._.Id.Asc(), null, 0, 500));
}
/// <summary>获取拦截分类统计(含命中次数)</summary>
[HttpGet("categories")]
public ActionResult GetCategories()
{
var all = DnsBlacklist.FindAllWithCache();
return Ok(all.GroupBy(b => b.Category).Select(g => new { category = g.Key, count = g.Count(), totalHits = g.Sum(b => (Int64)b.Hits) }));
}
/// <summary>获取拦截详细统计(总览 + Top 域名 + 趋势)</summary>
[HttpGet("stats")]
public ActionResult GetStats([FromQuery] Int32 top = 10)
{
var all = DnsBlacklist.FindAllWithCache().Where(b => b.Enable).ToList();
var totalHits = all.Sum(b => (Int64)b.Hits);
var totalRules = all.Count;
// 按分类汇总
var categories = all.GroupBy(b => b.Category)
.Select(g => new { category = g.Key, ruleCount = g.Count(), hitCount = g.Sum(b => (Int64)b.Hits) })
.OrderByDescending(g => g.hitCount)
.ToList();
// Top 命中域名
var topDomains = all.Where(b => b.Hits > 0)
.OrderByDescending(b => b.Hits)
.Take(top)
.Select(b => new { domain = b.Domain, category = b.Category, hits = b.Hits })
.ToList();
return Ok(new
{
totalHits,
totalRules,
categories,
topDomains
});
}
[HttpPost]
public ActionResult Add([FromBody] DnsBlacklist item)
{
item.Source = "User";
item.Insert();
TryApplyDnsmasq();
return Ok(new { success = true });
}
[HttpDelete("{id}")]
public ActionResult Delete(Int32 id)
{
var e = DnsBlacklist.FindById(id);
if (e == null) return NotFound();
e.Delete();
TryApplyDnsmasq();
return Ok(new { success = true });
}
/// <summary>尝试应用 dnsmasq 配置(最佳努力)</summary>
private void TryApplyDnsmasq()
{
_ = Task.Run(async () =>
{
try
{
await _dnsmasqManager.ApplyAsync();
}
catch { }
});
}
}
|