refactor: 枚举移入Models目录,命名空间更新为Rainbow.Entity.Models
大石头 authored at 2026-07-02 12:54:58
3.80 KiB
RainbowBridge
using Microsoft.AspNetCore.Mvc;
using NewLife;
using Rainbow.Services;
using TimerX = NewLife.Threading.TimerX;

namespace Rainbow.Web.Controllers;

/// <summary>家庭管控 API。定时断网、上网时长、设备策略</summary>
[ApiController]
[Route("api/family")]
public class FamilyController : ControllerBase
{
    private readonly ShellExecutor _shell;
    private static readonly Dictionary<String, TimerX?> _timers = new();

    public FamilyController(ShellExecutor shell) => _shell = shell;

    /// <summary>设置定时断网(每日多时间段)</summary>
    [HttpPost("schedule")]
    public ActionResult SetSchedule([FromBody] FamilyScheduleDto dto)
    {
        if (dto.DeviceMac.IsNullOrEmpty())
            return BadRequest(new { error = "设备 MAC 为必填" });

        // 存储到内存配置(后续可持久化到数据库)
        var key = $"schedule_{dto.DeviceMac}";
        _timers[key] = null; // 占位,实际 TimerX 调度在 Linux 环境启用

        return Ok(new { success = true, message = "定时断网已设置", deviceMac = dto.DeviceMac, schedule = dto.Schedule });
    }

    /// <summary>获取定时断网配置</summary>
    [HttpGet("schedule/{mac}")]
    public ActionResult GetSchedule(String mac)
    {
        var key = $"schedule_{mac}";
        return Ok(new { deviceMac = mac, hasSchedule = _timers.ContainsKey(key) });
    }

    /// <summary>立即断网(指定 MAC)</summary>
    [HttpPost("block")]
    public async Task<ActionResult> BlockDevice([FromBody] FamilyBlockDto dto)
    {
        if (dto.DeviceMac.IsNullOrEmpty())
            return BadRequest(new { error = "设备 MAC 为必填" });

        // 使用 iptables 阻止 MAC 地址
        var result = await _shell.ExecuteAsync("iptables",
            $"-A FORWARD -m mac --mac-source {dto.DeviceMac} -j DROP", true);

        return Ok(new { success = result.Success, message = result.Success ? "已断网" : result.Stderr });
    }

    /// <summary>恢复网络(指定 MAC)</summary>
    [HttpPost("unblock")]
    public async Task<ActionResult> UnblockDevice([FromBody] FamilyBlockDto dto)
    {
        if (dto.DeviceMac.IsNullOrEmpty())
            return BadRequest(new { error = "设备 MAC 为必填" });

        var result = await _shell.ExecuteAsync("iptables",
            $"-D FORWARD -m mac --mac-source {dto.DeviceMac} -j DROP", true);

        return Ok(new { success = result.Success, message = result.Success ? "已恢复" : result.Stderr });
    }

    /// <summary>临时奖励(30 分钟倒计时后自动恢复断网)</summary>
    [HttpPost("reward")]
    public ActionResult Reward([FromBody] FamilyRewardDto dto)
    {
        if (dto.DeviceMac.IsNullOrEmpty())
            return BadRequest(new { error = "设备 MAC 为必填" });

        var minutes = dto.Minutes > 0 ? dto.Minutes : 30;
        var key = $"reward_{dto.DeviceMac}";

        // 取消已有定时器
        if (_timers.TryGetValue(key, out var existing) && existing != null)
            existing.Dispose();

        // 设置倒计时定时器(30 分钟后自动恢复断网)
        _timers[key] = new TimerX(s =>
        {
            // 定时器触发:恢复网络
            _shell.ExecuteAsync("iptables",
                $"-D FORWARD -m mac --mac-source {dto.DeviceMac} -j DROP", true);
            _timers.Remove(key);
        }, null, minutes * 60_000, 0);

        return Ok(new { success = true, message = $"已设置 {minutes} 分钟奖励时间", deviceMac = dto.DeviceMac });
    }
}

public class FamilyScheduleDto
{
    public String DeviceMac { get; set; } = "";
    public String Schedule { get; set; } = "";
}

public class FamilyBlockDto
{
    public String DeviceMac { get; set; } = "";
}

public class FamilyRewardDto
{
    public String DeviceMac { get; set; } = "";
    public Int32 Minutes { get; set; } = 30;
}