uniugm/admin/apps/game/domain/comm_resource.go
2025-05-15 17:30:33 +08:00

366 lines
13 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package domain
import (
"admin/apps/game/api"
"admin/apps/game/domain/entity"
"admin/apps/game/domain/projects"
"admin/apps/game/domain/repo"
"admin/apps/game/model"
"admin/apps/game/model/dto"
"admin/internal/consts"
"admin/internal/errcode"
"admin/internal/event"
"admin/lib/xlog"
"database/sql"
"encoding/json"
"fmt"
"gorm.io/gorm"
"reflect"
"strings"
"time"
)
type CommonResourceService struct {
projectRepo repo.IProjectRepo
}
func initCommonResourcesRepo(db *gorm.DB) {
r(consts.ResourcesName_Project, "项目管理", repo.NewCommonResourceRepo(db, &model.Project{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
{
serverRepo := r(consts.ResourcesName_Server, "服务器管理", repo.NewCommonResourceRepo(db, &model.Server{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
serverRepo.GlobalBtns = []*api.ResourceBtnInfo{
{Key: consts.BtnKeyGlobal_Server_DownAll, Name: "一键停服", BtnColorType: "info"},
{Key: consts.BtnKeyGlobal_Server_UpAll, Name: "一键起服", BtnColorType: "warning"},
}
serverRepo.RowBtns = []*api.ResourceBtnInfo{
{Key: consts.BtnKeyRow_Server_Down, Name: "停服", BtnColorType: "info"},
{Key: consts.BtnKeyRow_Server_Up, Name: "起服", BtnColorType: "warning"},
}
}
r(consts.ResourcesName_Account, "账号列表", repo.NewCommonResourceRepo(db, &model.Account{}), ShowMethod_Get) // 账号管理不需要在后台读写数据都是通过项目api拉
r(consts.ResourcesName_SupportAccount, "扶持账号", repo.NewCommonResourceRepo(db, &model.SupportAccount{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Delete) // 扶持账号,只是标记哪些账号是扶持好
r(consts.ResourcesName_Role, "角色列表", repo.NewCommonResourceRepo(db, &model.Role{}), ShowMethod_Get) // 角色管理不需要在后台读写数据都是通过项目api拉
r(consts.ResourcesName_WhiteList, "白名单", repo.NewCommonResourceRepo(db, &model.WhiteList{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Delete)
r(consts.ResourcesName_Ban, "封禁管理", repo.NewCommonResourceRepo(db, &model.Ban{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
r(consts.ResourcesName_MailRole, "个人邮件", repo.NewCommonResourceRepo(db, &model.RoleMail{}), ShowMethod_Get|ShowMethod_Post) // 个人邮件发放就没法撤回?
{
globalMailRepo := r(consts.ResourcesName_MailGlobal, "全服邮件", repo.NewCommonResourceRepo(db, &model.GlobalMail{}), ShowMethod_Get|ShowMethod_Post)
globalMailRepo.HasDelayInvokeCreateHook = true
} // 直接删除,别修改了,玩家收到的更乱
r(consts.ResourcesName_CDKey, "礼包码", repo.NewCommonResourceRepo(db, &model.CDKey{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
r(consts.ResourcesName_ItemBag, "道具礼包", repo.NewCommonResourceRepo(db, &model.ItemBag{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
r(consts.ResourcesName_Notice, "公告(暂无)", repo.NewCommonResourceRepo(db, &model.Notice{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
r(consts.ResourcesName_DevicePush, "设备推送(暂无)", repo.NewCommonResourceRepo(db, &model.DevicePush{}), ShowMethod_Get)
}
func NewCommonResourceService(db *gorm.DB) *CommonResourceService {
initCommonResourcesRepo(db)
svc := &CommonResourceService{
projectRepo: repo.NewProjectRepo(db),
}
svc.startEventSubscriber()
svc.startLoadAllDelayInvokeDbData()
return svc
}
func (svc *CommonResourceService) startLoadAllDelayInvokeDbData() {
for _, repo := range commResourcesRepo {
if repo.HasDelayInvokeCreateHook {
repo.Repo.ListPagination("`delay_invoke_create_hook` is not NULL and `delay_invoke_create_hook` > ?", []any{time.Now()}, func(po model.IModel) {
var projectId int
var resource string = repo.Resource
var delayAt time.Time
//xlog.Infof("过滤数据:%+v", po)
switch repo.Resource {
case consts.ResourcesName_MailGlobal:
dbData := po.(*model.GlobalMail)
projectId = dbData.ProjectId
if !dbData.DelayInvokeCreateHook.Valid || dbData.DelayInvokeCreateHook.Time.Before(time.Now()) {
return
}
delayAt = dbData.DelayInvokeCreateHook.Time
default:
return
}
// 延迟执行钩子调用
xlog.Infof("起服查看全局邮件:%+v延迟到%v发送添加到全局定时器。。", po, delayAt.Format(time.DateTime))
objBin, _ := json.Marshal(po)
payload := &event.EventPayload_DelayInvokeCreateHook{
ProjectId: projectId,
Resource: resource,
DelayAt: delayAt,
Obj: objBin,
}
event.GetMgrInstance().Publish(event.EventTopic_DelayInvokeCreateHook, payload)
return
})
}
}
}
func (svc *CommonResourceService) List(projectId int, resource string, listParams *dto.CommonListReq) (int, []*dto.CommonDtoFieldDesc, []dto.CommonDtoValues, error) {
_, projectEt, find, err := svc.projectRepo.GetById(projectId)
if err != nil {
return 0, nil, nil, err
}
if resource != consts.ResourcesName_Project && !find {
return 0, nil, nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId)
}
rRepo := findCommResourceRepo(resource)
totalCount, fieldsDescInfo, etList, err := rRepo.Repo.List(projectEt, listParams)
if err != nil {
return 0, nil, nil, err
}
retList := make([]dto.CommonDtoValues, 0, len(etList))
for _, v := range etList {
retList = append(retList, v.ToCommonDto())
}
// 执行各个项目特定的钩子方法
if hook, ok := projects.GetProjectResourceHook(projectEt, resource).(projects.IPostResourceOpListHook); ok {
totalCount1, fieldsDescInfo1, retList1, err1 := hook.List(projectEt, resource, listParams, fieldsDescInfo, totalCount, retList)
if err1 != nil {
xlog.Warnf("list resource %v, hook return error:%v", resource, err1)
return totalCount, fieldsDescInfo, retList, nil
}
return totalCount1, fieldsDescInfo1, retList1, nil
}
return totalCount, fieldsDescInfo, retList, nil
}
func (svc *CommonResourceService) GetById(projectId int, resource string, id int) ([]*dto.CommonDtoFieldDesc, dto.CommonDtoValues, *entity.CommonResource, bool, error) {
_, projectEt, find, err := svc.projectRepo.GetById(projectId)
if err != nil {
return nil, nil, nil, false, err
}
if resource != consts.ResourcesName_Project && !find {
return nil, nil, nil, false, errcode.New(errcode.ServerError, "not found project %v db data", projectId)
}
fieldsDescInfo, et, find, err := findCommResourceRepo(resource).Repo.GetById(projectEt, id)
if err != nil {
return nil, nil, nil, false, err
}
return fieldsDescInfo, et.ToCommonDto(), et, find, nil
}
func (svc *CommonResourceService) Create(projectId int, resource string, dtoObj dto.CommonDtoValues) (dto.CommonDtoValues, error) {
_, projectEt, find, err := svc.projectRepo.GetById(projectId)
if err != nil {
return nil, err
}
if resource != consts.ResourcesName_Project && !find {
return nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId)
}
createOne := func(obj dto.CommonDtoValues) (dto.CommonDtoValues, error) {
resourceRepo := findCommResourceRepo(resource)
et, err := resourceRepo.Repo.Create(projectEt, resource, obj)
if err != nil {
return nil, err
}
// 返回新的实体插入数据库之后会填入数据库id所以要返给前端刷新id数据
// 这里转换一次新的数据传输对象因为上一步走了创建会给dto分配id
newObj := et.ToCommonDto()
// 执行各个项目特定的钩子方法
if resourceRepo.HasDelayInvokeCreateHook {
field := reflect.ValueOf(et.Po).Elem().FieldByName("DelayInvokeCreateHook")
delayAt := field.Interface().(sql.NullTime)
if delayAt.Valid && delayAt.Time.After(time.Now()) {
// 延迟执行钩子调用
objBin, _ := json.Marshal(et.Po)
payload := &event.EventPayload_DelayInvokeCreateHook{
ProjectId: projectId,
Resource: resource,
DelayAt: delayAt.Time,
Obj: objBin,
}
event.GetMgrInstance().Publish(event.EventTopic_DelayInvokeCreateHook, payload)
return newObj, nil
}
}
if hook, ok := projects.GetProjectResourceHook(projectEt, resource).(projects.IPostResourceOpCreateHook); ok {
err = hook.Create(projectEt, resource, newObj)
if err != nil {
return nil, err
}
return newObj, nil
}
return newObj, nil
}
var newDtoObj dto.CommonDtoValues
if resource == consts.ResourcesName_SupportAccount {
account, findAccount := dtoObj["Account"]
if findAccount {
for _, ac := range strings.Split(account.(string), ",") {
dtoObj["Account"] = ac
tmpObj, err := createOne(dtoObj)
if err != nil {
xlog.Errorf("create support account %v db error:%v", ac, err)
err = nil // 忽略多个插入的报错
} else {
newDtoObj = tmpObj
}
}
} else {
return nil, errcode.New(errcode.ParamsInvalid, "account empty:%+v", dtoObj)
}
} else {
newDtoObj, err = createOne(dtoObj)
}
return newDtoObj, err
}
func (svc *CommonResourceService) Edit(projectId int, resource string, dtoObj dto.CommonDtoValues) error {
_, projectEt, find, err := svc.projectRepo.GetById(projectId)
if err != nil {
return err
}
if resource != consts.ResourcesName_Project && !find {
return errcode.New(errcode.ServerError, "not found project %v db data", projectId)
}
err = findCommResourceRepo(resource).Repo.Edit(projectEt, dtoObj)
if err != nil {
return err
}
// 执行各个项目特定的钩子方法
if hook, ok := projects.GetProjectResourceHook(projectEt, resource).(projects.IPostResourceOpEditHook); ok {
err = hook.Edit(projectEt, resource, dtoObj)
if err != nil {
return err
}
return nil
}
return nil
}
func (svc *CommonResourceService) Delete(projectId int, resource string, id int) (*entity.CommonResource, error) {
_, projectEt, find, err := svc.projectRepo.GetById(projectId)
if err != nil {
return nil, err
}
if resource != consts.ResourcesName_Project && !find {
return nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId)
}
oldEt, find, err := findCommResourceRepo(resource).Repo.Delete(projectEt, id)
if err != nil {
return nil, err
}
// 执行各个项目特定的钩子方法
if find {
if hook, ok := projects.GetProjectResourceHook(projectEt, resource).(projects.IPostResourceOpDeleteHook); ok {
err = hook.Delete(projectEt, resource, oldEt.ToCommonDto())
if err != nil {
return oldEt, err
}
return oldEt, nil
}
}
return oldEt, nil
}
func (svc *CommonResourceService) RowsSelection(projectId int, resourceName string, params *dto.CommonRowsSelectionReq) (*dto.CommonRowsSelectionRsp, error) {
_, projectEt, find, err := svc.projectRepo.GetById(projectId)
if err != nil {
return nil, err
}
if resourceName != consts.ResourcesName_Project && !find {
return nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId)
}
if hook, ok := projects.GetProjectResourceHook(projectEt, resourceName).(projects.IPostResourceOpRowsHook); ok {
return hook.RowsSelection(projectEt, resourceName, params.BtnKey, params.Rows)
}
return nil, nil
}
func (svc *CommonResourceService) GetSupportResourcesList(permissions []string) []*api.ResourceInitInfo {
list := make([]*api.ResourceInitInfo, 0, len(commResourcesRepo))
for _, v := range commResourcesRepo {
list = append(list, &api.ResourceInitInfo{
Resource: v.Resource,
Desc: v.Desc,
ShowMethods: v.ShowMethods,
GlobalBtns: v.GlobalBtns,
RowBtns: v.RowBtns,
})
}
return list
}
const (
ShowMethod_Get = 1
ShowMethod_Post = 1 << 1
ShowMethod_Put = 1 << 2
ShowMethod_Delete = 1 << 3
)
type resourceRepoInfo struct {
Resource string
Desc string
Repo repo.ICommonResourceRepo
ShowMethods []string
showMethods int
GlobalBtns []*api.ResourceBtnInfo
RowBtns []*api.ResourceBtnInfo
HasDelayInvokeCreateHook bool
}
var commResourcesRepo = make([]*resourceRepoInfo, 0)
func r(resource, desc string, repo repo.ICommonResourceRepo, showMethods int) *resourceRepoInfo {
curRepo := &resourceRepoInfo{
Resource: resource,
Desc: desc,
Repo: repo,
ShowMethods: make([]string, 0),
}
if showMethods&ShowMethod_Get == ShowMethod_Get {
curRepo.ShowMethods = append(curRepo.ShowMethods, "get")
}
if showMethods&ShowMethod_Post == ShowMethod_Post {
curRepo.ShowMethods = append(curRepo.ShowMethods, "post")
}
if showMethods&ShowMethod_Put == ShowMethod_Put {
curRepo.ShowMethods = append(curRepo.ShowMethods, "put")
}
if showMethods&ShowMethod_Delete == ShowMethod_Delete {
curRepo.ShowMethods = append(curRepo.ShowMethods, "delete")
}
commResourcesRepo = append(commResourcesRepo, curRepo)
return curRepo
}
func findCommResourceRepo(resource string) *resourceRepoInfo {
for _, v := range commResourcesRepo {
if v.Resource == resource {
return v
}
}
panic(fmt.Errorf("not found Resource:%v", resource))
return nil
}