From bc368e96cf54235c0c534f393367ab25298ed36c Mon Sep 17 00:00:00 2001 From: likun <906102152@qq.com> Date: Wed, 7 May 2025 15:03:19 +0800 Subject: [PATCH] optimize and add cdkey --- admin/apps/game/domain/comm_resource.go | 2 +- admin/apps/game/domain/entity/cdkey.go | 22 ++ admin/apps/game/domain/projects/projects.go | 1 + admin/apps/game/domain/projects/smdl/items.go | 12 +- .../game/domain/projects/smdl/whitelist.go | 63 ++++ admin/apps/game/model/account.go | 2 +- admin/apps/game/model/cdkey.go | 41 +++ admin/apps/game/model/cdkey_used.go | 29 ++ admin/apps/game/model/globalmail.go | 4 +- admin/apps/game/model/notice.go | 4 +- admin/apps/game/model/rewardcode.go | 27 -- admin/apps/game/model/rolemail.go | 4 +- admin/apps/game/model/whitelist.go | 13 +- admin/apps/game/server/ctl_common_rest.go | 20 +- admin/apps/user/model/history.go | 16 +- admin/apps/user/server/server.go | 5 +- admin/internal/context/ctx_web.go | 2 +- admin/lib/cdkey/bitmap.go | 57 ++++ admin/lib/cdkey/cdkey.go | 124 +++++++ admin/lib/cdkey/cdkey_test.go | 19 ++ admin/lib/cdkey/utils.go | 311 ++++++++++++++++++ ui/.env.development | 2 +- ui/src/components/restful/table.vue | 26 +- ui/src/permission.js | 2 +- ui/src/views/Home.vue | 2 +- ui/todo.md | 10 +- 26 files changed, 749 insertions(+), 71 deletions(-) create mode 100644 admin/apps/game/domain/entity/cdkey.go create mode 100644 admin/apps/game/domain/projects/smdl/whitelist.go create mode 100644 admin/apps/game/model/cdkey.go create mode 100644 admin/apps/game/model/cdkey_used.go delete mode 100644 admin/apps/game/model/rewardcode.go create mode 100644 admin/lib/cdkey/bitmap.go create mode 100644 admin/lib/cdkey/cdkey.go create mode 100644 admin/lib/cdkey/cdkey_test.go create mode 100644 admin/lib/cdkey/utils.go diff --git a/admin/apps/game/domain/comm_resource.go b/admin/apps/game/domain/comm_resource.go index 2c430a5..1a22a93 100644 --- a/admin/apps/game/domain/comm_resource.go +++ b/admin/apps/game/domain/comm_resource.go @@ -27,7 +27,7 @@ func initCommonResourcesRepo(db *gorm.DB) { r(consts.ResourcesName_MailRole, "个人邮件", repo.NewCommonResourceRepo(db, &model.RoleMail{}), ShowMethod_Get|ShowMethod_Post) // 个人邮件发放就没法撤回? r(consts.ResourcesName_MailGlobal, "全服邮件", repo.NewCommonResourceRepo(db, &model.GlobalMail{}), ShowMethod_Get|ShowMethod_Post) // 直接删除,别修改了,玩家收到的更乱 r(consts.ResourcesName_Notice, "公告", repo.NewCommonResourceRepo(db, &model.Notice{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete) - r(consts.ResourcesName_RewardCode, "奖励码", repo.NewCommonResourceRepo(db, &model.RewardCode{}), ShowMethod_Get) + r(consts.ResourcesName_RewardCode, "奖励码", repo.NewCommonResourceRepo(db, &model.CDKey{}), ShowMethod_Get) r(consts.ResourcesName_DevicePush, "设备推送", repo.NewCommonResourceRepo(db, &model.DevicePush{}), ShowMethod_Get) } diff --git a/admin/apps/game/domain/entity/cdkey.go b/admin/apps/game/domain/entity/cdkey.go new file mode 100644 index 0000000..7ea991b --- /dev/null +++ b/admin/apps/game/domain/entity/cdkey.go @@ -0,0 +1,22 @@ +package entity + +import ( + "admin/apps/game/model" + "admin/lib/cdkey" +) + +var MaxKeyNum = 100000 // 每个批次直接搞10w个,不然运营想补加码,算法又要一开始定好数量 + +type CDKey struct { + Po *model.CDKey +} + +func NewCDKey(po *model.CDKey) *CDKey { + return &CDKey{ + Po: po, + } +} + +func (c *CDKey) GenerateKeys() []string { + return cdkey.GenerateAll(c.Po.ID, MaxKeyNum)[:c.Po.CodeNum] +} diff --git a/admin/apps/game/domain/projects/projects.go b/admin/apps/game/domain/projects/projects.go index adc22c5..c261377 100644 --- a/admin/apps/game/domain/projects/projects.go +++ b/admin/apps/game/domain/projects/projects.go @@ -16,6 +16,7 @@ var projectsResourceHookMgr = map[string]map[string]any{ consts.ResourcesName_Ban: &smdl.BanHook{}, // 所有角色走神魔大陆api直接获取 consts.ResourcesName_MailGlobal: &smdl.MailGlobalHook{}, // 所有角色走神魔大陆api直接获取 consts.ResourcesName_MailRole: &smdl.MailRoleHook{}, // 所有角色走神魔大陆api直接获取 + consts.ResourcesName_WhiteList: &smdl.WhitelistHook{}, // 所有角色走神魔大陆api直接获取 }, } diff --git a/admin/apps/game/domain/projects/smdl/items.go b/admin/apps/game/domain/projects/smdl/items.go index a8e4cdb..23d6db6 100644 --- a/admin/apps/game/domain/projects/smdl/items.go +++ b/admin/apps/game/domain/projects/smdl/items.go @@ -11,12 +11,12 @@ type Items struct { } func (items *Items) GetItems(projectInfo *entity.Project) ([]*dto.CommonDtoFieldChoice, error) { - return []*dto.CommonDtoFieldChoice{ - {Desc: "黄金战甲", Value: 123, Type: 1}, - {Desc: "黄金头盔", Value: 234, Type: 1}, - {Desc: "黄金大刀", Value: 346, Type: 1}, - {Desc: "白银大刀", Value: 346, Type: 1}, - }, nil + //return []*dto.CommonDtoFieldChoice{ + // {Desc: "黄金战甲", Value: 123, Type: 1}, + // {Desc: "黄金头盔", Value: 234, Type: 1}, + // {Desc: "黄金大刀", Value: 346, Type: 1}, + // {Desc: "白银大刀", Value: 346, Type: 1}, + //}, nil alisrvAddr := projectInfo.GetApiAddr() if alisrvAddr == "" { return nil, errcode.New(errcode.ServerError, "项目%v没有配置api服务器地址", projectInfo.Po.Name) diff --git a/admin/apps/game/domain/projects/smdl/whitelist.go b/admin/apps/game/domain/projects/smdl/whitelist.go new file mode 100644 index 0000000..833414d --- /dev/null +++ b/admin/apps/game/domain/projects/smdl/whitelist.go @@ -0,0 +1,63 @@ +package smdl + +import ( + "admin/apps/game/domain/entity" + "admin/apps/game/model" + "admin/apps/game/model/dto" + "admin/internal/errcode" + "admin/lib/httpclient" + "net/url" +) + +type WhitelistHook struct { +} + +func (hook *WhitelistHook) Create(projectInfo *entity.Project, resource string, dtoObj dto.CommonDtoValues) error { + alisrvAddr := projectInfo.GetApiAddr() + if alisrvAddr == "" { + return errcode.New(errcode.ServerError, "项目%v没有配置api服务器地址", projectInfo.Po.Name) + } + + et := (&entity.CommonResource{}).FromPo(&model.RoleMail{}).FromDto(dtoObj) + whiteInfo := et.ToPo().(*model.WhiteList) + + params := &url.Values{} + params.Add("cmd_data", "OpWhitelist") + params.Add("type", whiteInfo.WType) + params.Add("value", whiteInfo.Value) + params.Add("op", "add") + params.Add("server", whiteInfo.ServerConfID) + + rsp := make(map[string]any) + err := httpclient.Request(alisrvAddr+"/gm", "get", params, &rsp) + if err != nil { + return errcode.New(errcode.ServerError, "发送新增白名单请求:%+v错误:%v", whiteInfo, err) + } + + return nil +} + +func (hook *WhitelistHook) Delete(projectInfo *entity.Project, resource string, dtoObj dto.CommonDtoValues) error { + alisrvAddr := projectInfo.GetApiAddr() + if alisrvAddr == "" { + return errcode.New(errcode.ServerError, "项目%v没有配置api服务器地址", projectInfo.Po.Name) + } + + et := (&entity.CommonResource{}).FromPo(&model.RoleMail{}).FromDto(dtoObj) + whiteInfo := et.ToPo().(*model.WhiteList) + + params := &url.Values{} + params.Add("cmd_data", "OpWhitelist") + params.Add("type", whiteInfo.WType) + params.Add("value", whiteInfo.Value) + params.Add("op", "remove") + params.Add("server", whiteInfo.ServerConfID) + + rsp := make(map[string]any) + err := httpclient.Request(alisrvAddr+"/gm", "get", params, &rsp) + if err != nil { + return errcode.New(errcode.ServerError, "发送删除白名单请求:%+v错误:%v", whiteInfo, err) + } + + return nil +} diff --git a/admin/apps/game/model/account.go b/admin/apps/game/model/account.go index b34312e..bc48b4d 100644 --- a/admin/apps/game/model/account.go +++ b/admin/apps/game/model/account.go @@ -11,7 +11,7 @@ func init() { // Account 空表,就是用来兼容资源增删改查公共操作的,实际列举账号等都是走各个项目api拉取 type Account struct { - ProjectId int + ProjectId int `gorm:"index:idx_project_id"` Account string `name:"账号" json:"account" where:"eq"` ServerConfId string `name:"区服id" json:"serveId" where:"eq"` RoleIds []string `gorm:"type:json;serializer:json" name:"角色id列表" json:"roleIds"` diff --git a/admin/apps/game/model/cdkey.go b/admin/apps/game/model/cdkey.go new file mode 100644 index 0000000..a063622 --- /dev/null +++ b/admin/apps/game/model/cdkey.go @@ -0,0 +1,41 @@ +package model + +import ( + "admin/apps/game/model/dto" + "admin/internal/db" + "time" +) + +func init() { + db.RegisterTableModels(CDKey{}) +} + +type CDKey struct { + ID int `gorm:"primarykey" readonly:"true"` + ProjectId int `gorm:"index:idx_project_id"` + Desc string `name:"礼包说明" required:"true"` + ServerIDs []string `gorm:"type:json;serializer:json" name:"区服" type:"[]string" choices:"GetChoiceServers" multi_choice:"true"` + CodeType int `name:"礼包类型" required:"true" choices:"GetCodeTypeChoices"` + Code string `name:"礼包码" desc:"一码通用才配置"` + CodeNum int `name:"礼包数量" desc:"一码一用才配置"` + ValidStartTime time.Time `name:"生效起始时间"` + ValidEndTime time.Time `name:"生效结束时间"` + RewardList []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" desc:"搜索道具并点击添加"` + + CreatedAt time.Time `readonly:"true"` +} + +func (lm *CDKey) TableName() string { + return "cdkey" +} + +func (m *CDKey) GetId() int { + return m.ID +} + +func (m *CDKey) GetCodeTypeChoices() []*dto.CommonDtoFieldChoice { + return []*dto.CommonDtoFieldChoice{ + {Desc: "一码通用", Value: 0}, + {Desc: "一码一用", Value: 1}, + } +} diff --git a/admin/apps/game/model/cdkey_used.go b/admin/apps/game/model/cdkey_used.go new file mode 100644 index 0000000..6434421 --- /dev/null +++ b/admin/apps/game/model/cdkey_used.go @@ -0,0 +1,29 @@ +package model + +import ( + "admin/internal/db" + "time" +) + +func init() { + db.RegisterTableModels(CDKeyUsed{}) +} + +type CDKeyUsed struct { + ID int `gorm:"primarykey" readonly:"true"` + ProjectId int `gorm:"index:idx_project_id"` + ServerID string `name:"所属区服" choices:"GetChoiceServers" required:"true" where:"eq"` + Account string `gorm:"type:varchar(255);index:idx_account"` + RoleID string `gorm:"type:varchar(255);index:idx_role_id"` + RoleName string `gorm:"type:varchar(255)"` + Key string `gorm:"type:varchar(255);index:idx_key"` + CreatedAt time.Time `readonly:"true"` +} + +func (lm *CDKeyUsed) TableName() string { + return "cdkey_used" +} + +func (m *CDKeyUsed) GetId() int { + return m.ID +} diff --git a/admin/apps/game/model/globalmail.go b/admin/apps/game/model/globalmail.go index cdc05d2..577251f 100644 --- a/admin/apps/game/model/globalmail.go +++ b/admin/apps/game/model/globalmail.go @@ -11,8 +11,8 @@ func init() { } type GlobalMail struct { - ID int `gorm:"primarykey" readonly:"true"` - ProjectId int + ID int `gorm:"primarykey" readonly:"true"` + ProjectId int `gorm:"index:idx_project_id"` ServerIDs []string `gorm:"type:json;serializer:json" name:"区服" type:"[]string" choices:"GetChoiceServers" multi_choice:"true"` Title string `name:"邮件标题" required:"true"` Content string `name:"邮件内容" required:"true"` diff --git a/admin/apps/game/model/notice.go b/admin/apps/game/model/notice.go index 00cb493..82ec4a5 100644 --- a/admin/apps/game/model/notice.go +++ b/admin/apps/game/model/notice.go @@ -11,8 +11,8 @@ func init() { } type Notice struct { - ID int `gorm:"primarykey" readonly:"true"` - ProjectId int + ID int `gorm:"primarykey" readonly:"true"` + ProjectId int `gorm:"index:idx_project_id"` ServerIDs []int `gorm:"type:json;serializer:json" name:"公告生效服务器" desc:"为空表示所有服" choices:"GetChoiceServers"` Content string `name:"公告内容" required:"true"` StartAt time.Time `name:"开始时间" required:"true"` diff --git a/admin/apps/game/model/rewardcode.go b/admin/apps/game/model/rewardcode.go deleted file mode 100644 index d68aa87..0000000 --- a/admin/apps/game/model/rewardcode.go +++ /dev/null @@ -1,27 +0,0 @@ -package model - -import ( - "admin/internal/db" - "time" -) - -func init() { - db.RegisterTableModels(RewardCode{}) -} - -type RewardCode struct { - ID int `gorm:"primarykey" readonly:"true"` - ProjectId int - Group int `name:"奖励码组"` - Code int `name:"奖励码"` - - CreatedAt time.Time `readonly:"true"` -} - -func (lm *RewardCode) TableName() string { - return "reward_code" -} - -func (m *RewardCode) GetId() int { - return m.ID -} diff --git a/admin/apps/game/model/rolemail.go b/admin/apps/game/model/rolemail.go index 3a6ae88..ebc5a84 100644 --- a/admin/apps/game/model/rolemail.go +++ b/admin/apps/game/model/rolemail.go @@ -17,8 +17,8 @@ type MailAttachItem struct { } type RoleMail struct { - ID int `gorm:"primarykey" readonly:"true"` - ProjectId int + ID int `gorm:"primarykey" readonly:"true"` + ProjectId int `gorm:"index:idx_project_id"` RoleIDs []string `gorm:"type:json;serializer:json" name:"生效的角色id" desc:"生效的角色id,逗号分隔多个" required:"true"` ServerID string `name:"所属区服" choices:"GetChoiceServers" required:"true" where:"eq"` Title string `name:"邮件标题" required:"true"` diff --git a/admin/apps/game/model/whitelist.go b/admin/apps/game/model/whitelist.go index 27d8fd9..3706d2a 100644 --- a/admin/apps/game/model/whitelist.go +++ b/admin/apps/game/model/whitelist.go @@ -13,9 +13,9 @@ func init() { type WhiteList struct { ID int `gorm:"primarykey" readonly:"true"` ProjectId int `gorm:"uniqueIndex:idx_whitelist"` - ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers" where:"eq"` - Account string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist" name:"账户" required:"true"` - Desc string `name:"描述"` + ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_whitelist;index:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers" where:"eq"` + WType string `name:"白名单类型" desc:"账号或者ip" required:"true" choices:"GetWhitelistTypeChoices"` + Value string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist" name:"账户" required:"true"` CreatedAt time.Time `readonly:"true" where:"range"` } @@ -31,3 +31,10 @@ func (m *WhiteList) GetId() int { func (m *WhiteList) GetChoiceServers(project *Project) []*dto.CommonDtoFieldChoice { return getChoiceServers(project) } + +func (m *WhiteList) GetWhitelistTypeChoices(project *Project) []*dto.CommonDtoFieldChoice { + return []*dto.CommonDtoFieldChoice{ + {Desc: "IP", Value: "ip"}, + {Desc: "账号", Value: "account"}, + } +} diff --git a/admin/apps/game/server/ctl_common_rest.go b/admin/apps/game/server/ctl_common_rest.go index f3185a4..3b32ba0 100644 --- a/admin/apps/game/server/ctl_common_rest.go +++ b/admin/apps/game/server/ctl_common_rest.go @@ -8,7 +8,11 @@ import ( func (ctl *controller) CommonList(ctx *context.WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error { projectId, resource := getCtxURIProjectIdAndResource(ctx) - list, err := ctl.svc.CommonList(ctx, projectId, resource, params) + + ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId) + ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserName) + + list, err := ctl.svc.CommonList(ctx1, projectId, resource, params) if err != nil { return err } @@ -20,7 +24,7 @@ func (ctl *controller) CommonPost(ctx *context.WebContext, params *dto.CommonPos projectId, resource := getCtxURIProjectIdAndResource(ctx) ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId) - ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserId) + ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserName) newObj, err := ctl.svc.CommonPost(ctx1, projectId, resource, *params.Dto) if err != nil { @@ -32,7 +36,11 @@ func (ctl *controller) CommonPost(ctx *context.WebContext, params *dto.CommonPos func (ctl *controller) CommonPut(ctx *context.WebContext, params *dto.CommonPutReq, rsp *dto.CommonPutRsp) error { projectId, resource := getCtxURIProjectIdAndResource(ctx) - err := ctl.svc.CommonPut(ctx, projectId, resource, *params.Dto) + + ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId) + ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserName) + + err := ctl.svc.CommonPut(ctx1, projectId, resource, *params.Dto) if err != nil { return err } @@ -42,7 +50,11 @@ func (ctl *controller) CommonPut(ctx *context.WebContext, params *dto.CommonPutR func (ctl *controller) CommonDelete(ctx *context.WebContext, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error { projectId, resource := getCtxURIProjectIdAndResource(ctx) - err := ctl.svc.CommonDelete(ctx, projectId, resource, params.Id) + + ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId) + ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserName) + + err := ctl.svc.CommonDelete(ctx1, projectId, resource, params.Id) if err != nil { return err } diff --git a/admin/apps/user/model/history.go b/admin/apps/user/model/history.go index 6436e4a..9725828 100644 --- a/admin/apps/user/model/history.go +++ b/admin/apps/user/model/history.go @@ -12,14 +12,14 @@ func init() { // History 用户执行历史 type History struct { - ID int `gorm:"primarykey" readonly:"true"` - UserId int - UserName string - ProjectId int - Resource string - Method string - Data string `gorm:"type:longtext"` - CreateTime time.Time + ID int `gorm:"primarykey" readonly:"true"` + UserId int + UserName string + ProjectId int + Resource string + Method string + Data string `gorm:"type:longtext"` + CreatedAt time.Time } func (m *History) TableName() string { diff --git a/admin/apps/user/server/server.go b/admin/apps/user/server/server.go index 2adad5c..7cdc2a1 100644 --- a/admin/apps/user/server/server.go +++ b/admin/apps/user/server/server.go @@ -14,10 +14,12 @@ type Server struct { } func New(svc *service.Service) *Server { - return &Server{ + srv := &Server{ svc: svc, ctl: newController(svc), } + srv.jobsSubscribe() + return srv } func (srv *Server) jobsSubscribe() { @@ -30,6 +32,7 @@ func (srv *Server) subscriberHandlerUserExecute(msg *event.Msg) { err := json.Unmarshal(msg.Payload, msgHistory) if err != nil { xlog.Errorf("unmarshal msg(%+v) err:%v", string(msg.Payload), err) + return } po.UserId = msgHistory.UserId diff --git a/admin/internal/context/ctx_web.go b/admin/internal/context/ctx_web.go index 8bf413f..75fbf65 100644 --- a/admin/internal/context/ctx_web.go +++ b/admin/internal/context/ctx_web.go @@ -23,7 +23,7 @@ type WebContext struct { } func NewWebContext(rawCtx *gin.Context) web.IContext { - return &WebContext{rawCtx: rawCtx} + return &WebContext{Context: context.Background(), rawCtx: rawCtx} } func (ctx *WebContext) ExtractHeader() error { diff --git a/admin/lib/cdkey/bitmap.go b/admin/lib/cdkey/bitmap.go new file mode 100644 index 0000000..c184182 --- /dev/null +++ b/admin/lib/cdkey/bitmap.go @@ -0,0 +1,57 @@ +package cdkey + +import "fmt" + +type bitmap struct { + size int + set int64 +} + +func newBitmap(size int, set int64) *bitmap { + if size < 0 || size > 63 { + panic("size must be between 0 and 63") + } + if size == 0 { + size = 32 + } + m := &bitmap{size: size, set: set} + return m +} + +func (m *bitmap) Get(index int) bool { + return m.GetInt(index) != 0 +} + +func (m *bitmap) GetInt(index int) int64 { + if index < 0 || index >= m.size { + panic(fmt.Errorf("index out of range:%v", index)) + } + + if m.set&(1<= m.size { + panic(fmt.Errorf("index out of range:%v", index)) + } + if value { + m.set |= 1 << uint(index) + } else { + m.set &^= 1 << uint(index) + } +} + +func (m *bitmap) Clear() { + m.set = 0 +} + +func (m *bitmap) toInt64() int64 { + return m.set +} + +func (m *bitmap) GetSize() int { + return m.size +} diff --git a/admin/lib/cdkey/cdkey.go b/admin/lib/cdkey/cdkey.go new file mode 100644 index 0000000..f1e3077 --- /dev/null +++ b/admin/lib/cdkey/cdkey.go @@ -0,0 +1,124 @@ +package cdkey + +/* + * 奖励码模块,从神魔大陆java代码移植过来的 + */ + +func GenerateAll(batch int, totalCount int) []string { + keyList := make([]string, 0, totalCount) + for i := 0; i < totalCount; i++ { + codeKey := GenerateOne(batch, totalCount, i) + keyList = append(keyList, codeKey) + } + return keyList +} + +func GenerateOne(batch int, totalCount int, curNo int) string { + base := MAXNUM / totalCount + numId := curNo + num := base + numId*base + mainKeyBitSet := newBitmap(MAIN_KEY_LENGTH, 0) + numKeyIndex := int((num + batch) % NUM_KEY_LENGTH_BINARY) + temp := newEncode(int64(num), numKeyIndex) + for i := 0; i < MAIN_KEY_NUM_LENGTH; i++ { + mainKeyBitSet.Set(i, (temp&1) == 1) + temp >>= 1 + } + for i := 0; i < NUM_KEY_LENGTH; i++ { + mainKeyBitSet.Set(i+MAIN_KEY_NUM_LENGTH, toNumBitSet[numKeyIndex].Get(i)) + } + + var beCheckNum int64 + if mainKeyBitSet.toInt64() > 0 { + beCheckNum = mainKeyBitSet.toInt64() + } else { + beCheckNum = -mainKeyBitSet.toInt64() + } + checkNum := int32(beCheckNum % 32) + checkNumBitSet := toBitSet32[checkNum] + for i := 0; i < CHECK_LENGTH; i++ { + mainKeyBitSet.Set(i+MAIN_KEY_NUM_LENGTH+NUM_KEY_LENGTH, checkNumBitSet.Get(i)) + } + batchBitSet := newBitmap(BATCH_LENGTH, 0) + temp = int64(batch) + for i := 0; i < BATCH_LENGTH; i++ { + batchBitSet.Set(i, (temp&1) == 1) + temp >>= 1 + } + batchKeyIndex := (num + batch) % BATCH_KEY_LENGTH_BINARY + batchStr := base32Encode(fakeRC4Encode(batchBitSet, batchKey[batchKeyIndex])) + temp1 := fakeRC4Encode(mainKeyBitSet, getMainKey(batchBitSet)) + mainKeyStr := base32Encode(temp1) + + cdKeyType := 1 + typeIndex := (num + cdKeyType) % TYPE_LENGTH_BINARY + + codeKey := mainKeyStr + batchStr + string(toBase32[batchKeyIndex]) + string(toBase32[typeIndex]) + return shuffleCDKey(codeKey, batchKeyIndex) +} + +type CDKeyInfo struct { + Batch int + Num int64 +} + +func DecodeCDKey(cdKey string) (*CDKeyInfo, bool) { + if len(cdKey) != CDKEY_LENGTH { + return nil, false + } + index := toBase32CToI[rune(cdKey[SHUFFLE_INDEX])] + cdKey1 := recoverCDKey(cdKey[0:SHUFFLE_INDEX], index) + if cdKey1 == "" { + return nil, false + } + typeCheck, find := toBase32CToI[rune(cdKey1[TYPE_INDEX])] + if !find { + return nil, false + } + batchKeyIndex, find := toBase32CToI[rune(cdKey1[BATCH_NUM_BEGIN])] + if !find { + return nil, false + } + if !(batchKeyIndex == index) { + return nil, false + } + batch := base32Decode(cdKey1[BATCH_BEGIN:BATCH_END]) + if batch == nil { + return nil, false + } + batchBitSet := fakeRC4Encode(batch, batchKey[batchKeyIndex]) + if batchBitSet == nil { + return nil, false + } + mainKey := base32Decode(cdKey1[MAIN_KEY_BEGIN:MAIN_KEY_END]) + if mainKey == nil { + return nil, false + } + mainKey2 := getMainKey(batchBitSet) + if mainKey2 == nil { + return nil, false + } + mainKeyBitSet := fakeRC4Encode(mainKey, mainKey2) + if mainKeyBitSet == nil { + return nil, false + } + if !(check(mainKeyBitSet)) { + return nil, false + } + numKeyIndex := getNumKeyIndex(mainKeyBitSet) + numInt := numEncode(mainKeyBitSet.toInt64()&intFormat, numKeyIndex) + batchInt := int(batchBitSet.toInt64() & intFormat) + if !(checkIndex(numInt, batchInt, batchKeyIndex, numKeyIndex)) { + return nil, false + } + + cdkeyInfo := &CDKeyInfo{ + Batch: batchInt, + Num: numInt, + // Type: typeCheck, + } + if typeCheck > 0 { + + } + return cdkeyInfo, true +} diff --git a/admin/lib/cdkey/cdkey_test.go b/admin/lib/cdkey/cdkey_test.go new file mode 100644 index 0000000..07a4203 --- /dev/null +++ b/admin/lib/cdkey/cdkey_test.go @@ -0,0 +1,19 @@ +package cdkey + +import ( + "fmt" + "testing" +) + +func TestCDKey(t *testing.T) { + for i, key := range GenerateAll(2, 100000) { + if i > 10 { + continue + } + info, ok := DecodeCDKey(key) + if !ok { + panic(key) + } + fmt.Printf("%s, info:%+v\n", key, info) + } +} diff --git a/admin/lib/cdkey/utils.go b/admin/lib/cdkey/utils.go new file mode 100644 index 0000000..b67c37c --- /dev/null +++ b/admin/lib/cdkey/utils.go @@ -0,0 +1,311 @@ +package cdkey + +import ( + "math" + "math/rand" +) + +const ( + MAXNUM = math.MaxInt32 - 20000000 + CDKEY_LENGTH = 15 + MAIN_KEY_LENGTH = 40 + NUM_KEY_LENGTH_BINARY = 8 + MAIN_KEY_NUM_LENGTH = 32 + NUM_KEY_LENGTH = 3 + CHECK_LENGTH = 5 + BATCH_LENGTH = 20 + BATCH_KEY_LENGTH_BINARY = 32 + TYPE_LENGTH_BINARY = 32 + shuffleLength = 32 + exceptShuffleSeedTotalLength = 70 + SHUFFLE_INDEX = 14 + TYPE_INDEX = 13 + BATCH_NUM_BEGIN = 12 + BATCH_BEGIN = 8 + BATCH_END = 12 + MAIN_KEY_BEGIN = 0 + MAIN_KEY_END = 8 + mainKeyFormat int64 = 34359738367 + checkNumFormat int64 = 1065151889408 + CHECK_LENGTH_BINARY = 32 +) + +var toBase32 = []rune{'2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'} +var toBase32CToI map[rune]int + +var mainKeyBatchKey = newBitmap(20, 1918215104086) + +var intFormat int64 = 4294967295 +var key = newBitmap(20, 1209617303503) +var shuffleMap = make(map[int][]int) + +var numKey = []int64{ + 3000669867, + 3671239387, + 2526368469, + 2493864681, + 3604110165, + 3567998377, + 2763216037, + 2863360677, +} + +var batchKey = []*bitmap{ + newBitmap(20, 31511741981182095), + newBitmap(20, 3664122353341979125), + newBitmap(20, 3024789513220408272), + newBitmap(20, 7614911559402769357), + newBitmap(20, 2108459002177461007), + newBitmap(20, -3779584974404014377), + newBitmap(20, -4708816669881919040), + newBitmap(20, -6362362468306307184), + newBitmap(20, 5237470582631498811), + newBitmap(20, 5507680150663927504), + newBitmap(20, -533592023685287698), + newBitmap(20, 5175063634818869382), + newBitmap(20, -8744795741519816883), + newBitmap(20, -4080090257317771786), + newBitmap(20, -8036132546007449313), + newBitmap(20, 202953352259602475), + newBitmap(20, 1095317292689077154), + newBitmap(20, 2991873574004670411), + newBitmap(20, -6707239314758981218), + newBitmap(20, 7712241472074747715), + newBitmap(20, -8133590642362246474), + newBitmap(20, -4968343163714505661), + newBitmap(20, -6905628074578549760), + newBitmap(20, 5195681389062354029), + newBitmap(20, -5910830154906229288), + newBitmap(20, -1676518468791541432), + newBitmap(20, -7994149653806568719), + newBitmap(20, -7378005837432330374), + newBitmap(20, 1068884024847281324), + newBitmap(20, 1945505497196485942), + newBitmap(20, -3492268017556027220), + newBitmap(20, 7364928014934311923), +} + +var toNumBitSet [NUM_KEY_LENGTH_BINARY]*bitmap +var toBitSet32 [32]*bitmap + +func init() { + for i := 0; i < 32; i++ { + temp := i + toBitSet32[i] = newBitmap(5, 0) + for j := 0; j < 5; j++ { + toBitSet32[i].Set(j, (temp&1) == 1) + temp >>= 1 + } + } + for i := 0; i < NUM_KEY_LENGTH_BINARY; i++ { + temp := i + toNumBitSet[i] = newBitmap(NUM_KEY_LENGTH, 0) + for j := 0; j < NUM_KEY_LENGTH; j++ { + toNumBitSet[i].Set(j, (temp&1) == 1) + temp >>= 1 + } + } + + toBase32CToI = make(map[rune]int) + for i := 0; i < len(toBitSet32); i++ { + toBase32CToI[toBase32[i]] = i + } + for seed := 0; seed < shuffleLength; seed++ { + array := make([]int, exceptShuffleSeedTotalLength) + for i := 0; i < exceptShuffleSeedTotalLength; i++ { + array[i] = i + } + shuffle(array, rand.New(rand.NewSource(int64(seed)))) + shuffleMap[seed] = array + } +} + +func checkIndex(num int64, batch int, batchKeyIndex int, numKeyIndex int) bool { + return (num+int64(batch))%BATCH_KEY_LENGTH_BINARY == int64(batchKeyIndex) && (num+int64(batch))%NUM_KEY_LENGTH_BINARY == int64(numKeyIndex) +} + +func numEncode(num int64, index int) int64 { + return numKey[index] ^ num +} + +func getNumKeyIndex(mainKeyBitSet *bitmap) int { + bitset := newBitmap(NUM_KEY_LENGTH, 0) + for i := 0; i < bitset.GetSize(); i++ { + bitset.Set(i, mainKeyBitSet.Get(MAIN_KEY_NUM_LENGTH+i)) + } + return int(bitset.toInt64()) +} + +func check(mainkeyBitSet *bitmap) bool { + mainkey := mainkeyBitSet.toInt64() + if mainkey <= 0 { + mainkey = -mainkey + } + beCheckNum := mainkey & mainKeyFormat + checkNum := mainkey & checkNumFormat + checkNum >>= (MAIN_KEY_NUM_LENGTH + NUM_KEY_LENGTH) + return beCheckNum%CHECK_LENGTH_BINARY == checkNum +} + +func base32Decode(data string) *bitmap { + if len(data) > 63/5 { + return nil + } + bitset := newBitmap(len(data)*5, 0) + i := 0 + for _, c := range data { + if _, find := toBase32CToI[c]; !find { + return nil + } + index := toBase32CToI[c] + letterBitSet := toBitSet32[index] + for j := 0; j < 5; j++ { + bitset.Set(i, letterBitSet.Get(j)) + i++ + } + } + return bitset +} + +func recoverCDKey(cdKey string, index int) string { + array := shuffleMap[index] + if array == nil { + return "" + } + bytes := base32DecodeReturnByteArray(cdKey) + if bytes == nil { + return "" + } + if len(array) != len(bytes) { + return "" + } + resultByte := make([]byte, len(bytes)) + for i := 0; i < len(array); i++ { + resultByte[array[i]] = bytes[i] + } + return base32Encode1(resultByte) +} + +func shuffleCDKey(key string, index int) string { + array := shuffleMap[index] + bytes := base32DecodeReturnByteArray(key) + resultByte := make([]byte, len(bytes)) + for i := 0; i < len(array); i++ { + resultByte[i] = bytes[array[i]] + } + return base32Encode1(resultByte) + string(toBase32[index]) +} + +func shuffle(array []int, rander *rand.Rand) { + for i := len(array); i > 1; i-- { + swap(array, i-1, rander.Intn(i)) + } +} + +func swap(array []int, i, j int) { + array[i], array[j] = array[j], array[i] +} + +func newEncode(num int64, index int) int64 { + return numKey[index] ^ num +} + +func base32Encode(m *bitmap) string { + if m.GetSize()%5 != 0 { + return "" + } + + stringBuilder := "" + + for i := 0; i < m.GetSize(); i += 5 { + bitset1 := newBitmap(5, 0) + for j := 0; j < 5; j++ { + bitset1.Set(j, m.Get(i+j)) + } + if bitset1.toInt64() >= int64(len(toBase32)) { + return "" + } + letter := toBase32[int(bitset1.toInt64())] + stringBuilder += string(letter) + } + + return stringBuilder +} + +func base32Encode1(bytes []byte) string { + if len(bytes)%5 != 0 { + return "" + } + + stringBuilder := "" + + for i := 0; i < len(bytes); i += 5 { + bitset1 := newBitmap(5, 0) + for j := 0; j < 5; j++ { + bitset1.Set(j, bytes[i+j] > 0) + } + if bitset1.toInt64() >= int64(len(toBase32)) { + return "" + } + letter := toBase32[int(bitset1.toInt64())] + stringBuilder += string(letter) + } + + return stringBuilder +} + +func fakeRC4Encode(data, key *bitmap) *bitmap { + if data.GetSize() != key.GetSize() { + return nil + } + bitSet := newBitmap(data.GetSize(), 0) + for i := 0; i < data.GetSize(); i++ { + bitSet.Set(i, data.GetInt(i)^key.GetInt(i) == 1) + } + return bitSet +} + +func getMainKey(batch *bitmap) *bitmap { + bitSet := newBitmap(MAIN_KEY_LENGTH, 0) + batchKey := fakeRC4Encode(batch, mainKeyBatchKey) + if batchKey == nil { + return nil + } + index := (int)(batchKey.toInt64()&intFormat) % key.GetSize() + count := 0 + for i := 0; i < index; i++ { + bitSet.Set(count, key.Get(i)) + count++ + } + for i := 0; i < batchKey.GetSize(); i++ { + bitSet.Set(count, batchKey.Get(i)) + count++ + } + for i := index; i < key.GetSize(); i++ { + bitSet.Set(count, key.Get(i)) + count++ + } + return bitSet +} + +func base32DecodeReturnByteArray(data string) []byte { + bytes := make([]byte, len(data)*5) + i := 0 + for _, c := range data { + if _, find := toBase32CToI[c]; !find { + return nil + } + index := toBase32CToI[c] + letterBitSet := toBitSet32[index] + for j := 0; j < 5; j++ { + bitValue := letterBitSet.Get(j) + if bitValue { + bytes[i] = 1 + } else { + bytes[i] = 0 + } + i++ + } + } + return bytes +} diff --git a/ui/.env.development b/ui/.env.development index 1683d70..ff54252 100644 --- a/ui/.env.development +++ b/ui/.env.development @@ -1,2 +1,2 @@ VITE_APP_BASE_API = '/api' -VITE_APP_BASE_URL = 'http://localhost:8080/api' \ No newline at end of file +VITE_APP_BASE_URL = 'http://192.168.78.128:8080/api' \ No newline at end of file diff --git a/ui/src/components/restful/table.vue b/ui/src/components/restful/table.vue index 7804e0d..baed9ee 100644 --- a/ui/src/components/restful/table.vue +++ b/ui/src/components/restful/table.vue @@ -98,7 +98,7 @@ const listData = async () => { calcElColSpan.value = 0 // 计算el-col占用24格子的span数量 - let calcElColSpanTmp = 1 + let calcElColSpanTmp = 2 whereFieldsDescInfo.value.forEach((field) => { if (field.where === "range") { calcElColSpanTmp += 2 @@ -106,9 +106,9 @@ const listData = async () => { calcElColSpanTmp += 1 } }) - calcElColSpan.value = 24/calcElColSpanTmp + calcElColSpan.value = 24 / calcElColSpanTmp - console.log("where fields:", whereFieldsDescInfo.value) + // console.log("where fields:", whereFieldsDescInfo.value) // console.log('await list rsp:', listRsp.value, fieldsDescInfo.value, toRaw(rows.value), toRaw(rules.value)) listDataOK.value = true @@ -270,7 +270,7 @@ const handleQueryItem = (itemQueryStr) => { itemQueryStr = itemQueryStr.replace(/[\s\u3000]/g, "") resourceGetAllItems(projectId).then((res) => { console.log("获取所有道具返回:", res.data) - console.log("查询字符串:[" + itemQueryStr + "]") + console.log("查询字符串:[" + itemQueryStr + "]") itemChoices.value = res.data.items.filter((item) => { return item.desc.includes(itemQueryStr) }) @@ -280,6 +280,14 @@ const handleQueryItem = (itemQueryStr) => { }) } +const resetConditionSearch = () => { + for (let i = 0; i < whereFieldsDescInfo.value.length; i++) { + let field = whereFieldsDescInfo.value[i] + field.value1 = null + field.value2 = null + } +} +