225 lines
6.2 KiB
Go
225 lines
6.2 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"gorm.io/gorm"
|
|
|
|
"gitee.ltd/lxh/wechat-robot/internal/config"
|
|
"gitee.ltd/lxh/wechat-robot/internal/docker"
|
|
"gitee.ltd/lxh/wechat-robot/internal/model"
|
|
)
|
|
|
|
// ListRobots 列出所有机器人
|
|
func ListRobots(c *fiber.Ctx) error {
|
|
db := model.GetDB()
|
|
var robots []model.Robot
|
|
|
|
if err := db.Find(&robots).Error; err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "获取机器人列表失败")
|
|
}
|
|
|
|
return c.Render("robot/index", fiber.Map{
|
|
"Title": "机器人列表",
|
|
"Robots": robots,
|
|
})
|
|
}
|
|
|
|
// NewRobotForm 显示创建机器人表单
|
|
func NewRobotForm(c *fiber.Ctx) error {
|
|
return c.Render("robot/new", fiber.Map{
|
|
"Title": "新建机器人",
|
|
})
|
|
}
|
|
|
|
// CreateRobot 创建新机器人
|
|
func CreateRobot(c *fiber.Ctx) error {
|
|
robotName := c.FormValue("name")
|
|
if robotName == "" {
|
|
return fiber.NewError(fiber.StatusBadRequest, "机器人名称不能为空")
|
|
}
|
|
|
|
// 加载配置
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "加载配置失败")
|
|
}
|
|
|
|
// 创建Docker容器
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
containerID, err := docker.CreateRobotContainer(ctx, &cfg.Docker, robotName)
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "创建容器失败: "+err.Error())
|
|
}
|
|
|
|
// 创建机器人数据库记录
|
|
robot := model.Robot{
|
|
ContainerID: containerID,
|
|
Nickname: robotName,
|
|
Status: model.RobotStatusOffline,
|
|
}
|
|
|
|
db := model.GetDB()
|
|
if err := db.Create(&robot).Error; err != nil {
|
|
// 如果数据库创建失败,尝试删除容器
|
|
docker.RemoveContainer(ctx, containerID, true)
|
|
return fiber.NewError(fiber.StatusInternalServerError, "保存机器人信息失败: "+err.Error())
|
|
}
|
|
|
|
// 添加到监控器
|
|
// 注意:这里假设有一个全局可访问的监控器实例,实际中可能需要通过依赖注入或其他方式获取
|
|
monitor := docker.NewContainerMonitor(db, time.Minute)
|
|
monitor.AddRobot(containerID)
|
|
|
|
return c.Redirect("/admin/robots/" + strconv.Itoa(int(robot.ID)))
|
|
}
|
|
|
|
// ShowRobot 显示机器人详情
|
|
func ShowRobot(c *fiber.Ctx) error {
|
|
id, err := strconv.Atoi(c.Params("id"))
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "无效的ID")
|
|
}
|
|
|
|
var robot model.Robot
|
|
db := model.GetDB()
|
|
|
|
if err := db.First(&robot, id).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return fiber.NewError(fiber.StatusNotFound, "机器人不存在")
|
|
}
|
|
return fiber.NewError(fiber.StatusInternalServerError, "查询数据库失败")
|
|
}
|
|
|
|
return c.Render("robot/show", fiber.Map{
|
|
"Title": robot.Nickname,
|
|
"Robot": robot,
|
|
})
|
|
}
|
|
|
|
// DeleteRobot 删除机器人
|
|
func DeleteRobot(c *fiber.Ctx) error {
|
|
id, err := strconv.Atoi(c.Params("id"))
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "无效的ID")
|
|
}
|
|
|
|
var robot model.Robot
|
|
db := model.GetDB()
|
|
|
|
if err := db.First(&robot, id).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return fiber.NewError(fiber.StatusNotFound, "机器人不存在")
|
|
}
|
|
return fiber.NewError(fiber.StatusInternalServerError, "查询数据库失败")
|
|
}
|
|
|
|
// 首先尝试登出微信
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
if robot.Status == model.RobotStatusOnline {
|
|
if err := docker.LogoutWechatBot(ctx, robot.ContainerID); err != nil {
|
|
log.Printf("登出机器人失败: %v", err)
|
|
// 继续删除流程,不因登出失败而中断
|
|
}
|
|
}
|
|
|
|
// 删除容器
|
|
if err := docker.RemoveContainer(ctx, robot.ContainerID, true); err != nil {
|
|
log.Printf("删除容器失败: %v", err)
|
|
// 继续删除流程,不因容器删除失败而中断
|
|
}
|
|
|
|
// 从监控器移除
|
|
monitor := docker.NewContainerMonitor(db, time.Minute)
|
|
monitor.RemoveRobot(robot.ContainerID)
|
|
|
|
// 删除数据库记录
|
|
if err := db.Delete(&robot).Error; err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "删除机器人失败: "+err.Error())
|
|
}
|
|
|
|
return c.Redirect("/admin/robots")
|
|
}
|
|
|
|
// RobotLogin 显示微信登录二维码
|
|
func RobotLogin(c *fiber.Ctx) error {
|
|
id, err := strconv.Atoi(c.Params("id"))
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "无效的ID")
|
|
}
|
|
|
|
var robot model.Robot
|
|
db := model.GetDB()
|
|
|
|
if err := db.First(&robot, id).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return fiber.NewError(fiber.StatusNotFound, "机器人不存在")
|
|
}
|
|
return fiber.NewError(fiber.StatusInternalServerError, "查询数据库失败")
|
|
}
|
|
|
|
// 获取登录二维码
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
qrcode, err := docker.GetLoginQRCode(ctx, robot.ContainerID)
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "获取登录二维码失败: "+err.Error())
|
|
}
|
|
|
|
// 保存二维码路径到数据库
|
|
robot.QRCodePath = qrcode
|
|
if err := db.Save(&robot).Error; err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "保存二维码路径失败")
|
|
}
|
|
|
|
return c.Render("robot/login", fiber.Map{
|
|
"Title": "微信登录",
|
|
"Robot": robot,
|
|
"QRCode": qrcode,
|
|
})
|
|
}
|
|
|
|
// RobotLogout 机器人退出微信登录
|
|
func RobotLogout(c *fiber.Ctx) error {
|
|
id, err := strconv.Atoi(c.Params("id"))
|
|
if err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "无效的ID")
|
|
}
|
|
|
|
var robot model.Robot
|
|
db := model.GetDB()
|
|
|
|
if err := db.First(&robot, id).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return fiber.NewError(fiber.StatusNotFound, "机器人不存在")
|
|
}
|
|
return fiber.NewError(fiber.StatusInternalServerError, "查询数据库失败")
|
|
}
|
|
|
|
// 登出微信
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
if err := docker.LogoutWechatBot(ctx, robot.ContainerID); err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "登出微信失败: "+err.Error())
|
|
}
|
|
|
|
// 更新机器人状态
|
|
robot.Status = model.RobotStatusOffline
|
|
robot.QRCodePath = ""
|
|
if err := db.Save(&robot).Error; err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "更新状态失败")
|
|
}
|
|
|
|
return c.Redirect("/admin/robots/" + c.Params("id"))
|
|
}
|