refactor: 枚举移入Models目录,命名空间更新为Rainbow.Entity.Models
大石头 authored at 2026-07-02 12:54:58
3.11 KiB
RainbowBridge
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 { }
        });
    }
}