diff --git a/README-NEW.md b/README-NEW.md index 8a8696d..17eadf3 100644 --- a/README-NEW.md +++ b/README-NEW.md @@ -193,6 +193,17 @@ logx.Errorf("redis init: %v", err) os.Exit(1) } +//日志队列初始化 +if err := logRedis.Init(logRedis.LogRedisConfig{ +Host: utils.GetConfigString("log-redis.host"), +Port: utils.GetConfigInt("log-redis.port"), +Password: utils.GetConfigString("log-redis.password"), +DB: utils.GetConfigInt("log-redis.db"), +}); err != nil { +logx.Errorf("log redis init: %v", err) +os.Exit(1) +} + debug := utils.GetConfigBool("mysql.debug") modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug}) diff --git a/pkg/logRedis/redis.go b/pkg/logRedis/redis.go new file mode 100644 index 0000000..856f7e4 --- /dev/null +++ b/pkg/logRedis/redis.go @@ -0,0 +1,54 @@ +package logRedis + +import ( + "context" + "fmt" + "time" + + goredis "github.com/redis/go-redis/v9" +) + +const Nil = goredis.Nil + +var LogRedisClient *goredis.Client + +type LogRedisConfig struct { + Host string + Port int + Password string + DB int +} + +func Init(c LogRedisConfig) error { + client, err := New(c) + if err != nil { + return err + } + LogRedisClient = client + return nil +} + +func New(c LogRedisConfig) (*goredis.Client, error) { + if c.Host == "" { + return nil, fmt.Errorf("redis: Host is empty") + } + if c.Port == 0 { + c.Port = 6379 + } + + client := goredis.NewClient(&goredis.Options{ + Addr: fmt.Sprintf("%s:%d", c.Host, c.Port), + Password: c.Password, + DB: c.DB, + }) + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + if err := client.Ping(ctx).Err(); err != nil { + _ = client.Close() + return nil, fmt.Errorf("redis ping: %w", err) + } + + return client, nil +} diff --git a/pkg/utils/log.go b/pkg/utils/log.go index d4e8b10..43f8fd7 100644 --- a/pkg/utils/log.go +++ b/pkg/utils/log.go @@ -1,9 +1,12 @@ package utils import ( + "context" + "lone-services/pkg/logRedis" lonelog "lone-services/rpc/lonelog/pb" jsoniter "github.com/json-iterator/go" + "github.com/zeromicro/go-zero/core/logx" ) const ( @@ -14,6 +17,7 @@ const ( LogActionTypeDown = 5 //下载 LogActionTypeStatus = 6 //状态 LogActionTypePassword = 7 //修改密码 + LogActionTypeSort = 8 //排序 //增加、删除、修改时需要改 services.log中的返回值 @@ -44,6 +48,20 @@ const ( LogActionModuleFactory = "工厂管理" ) +type ActionLog struct { + Content string `json:"content"` + AdminId int64 `json:"admin_id"` + AdminName string `json:"admin_name"` + Type int32 `json:"type"` + ModuleName string `json:"module_name"` + Ip string `json:"ip"` + BrowserInfo string `json:"browser_info"` + BrowserName string `json:"browser_name"` + BrowserVersion string `json:"browser_version"` + Reason string `json:"reason"` + CreateTime string `json:"create_time"` +} + type ActionAdd struct { NewContent interface{} `json:"new_content"` OldContent interface{} `json:"old_content"` @@ -52,15 +70,29 @@ type ActionAdd struct { ModuleName string `json:"module_name"` } -const LoginReasonOK = "OK" +type LoginLog struct { + AdminId int64 `json:"admin_id"` + Ip string `json:"ip"` + Name string `json:"name"` + BrowserInfo string `json:"browser_info"` + BrowserName string `json:"browser_name"` + BrowserVersion string `json:"browser_version"` + Status int32 `json:"status"` + CreateTime string `json:"create_time"` + Reason string `json:"reason"` +} -func GetActionStruct(adminInfo UserInfo, info ActionAdd) *lonelog.ActionLog { +const LoginReasonOK = "OK" +const LogActionQueueKey = "log:queue:action" +const LogLoginQueueKey = "log:queue:login" + +func SetActionLog(adminInfo UserInfo, info ActionAdd) { content := map[string]interface{}{ "old_content": info.OldContent, "new_content": info.NewContent, } jsonData, _ := jsoniter.Marshal(content) - return &lonelog.ActionLog{ + log := ActionLog{ Content: string(jsonData), AdminId: adminInfo.ID, AdminName: adminInfo.Name, @@ -74,18 +106,25 @@ func GetActionStruct(adminInfo UserInfo, info ActionAdd) *lonelog.ActionLog { CreateTime: Now().GoString(), } + logJson, err := jsoniter.Marshal(log) + if err != nil { + logx.Errorf("marshal ActionLog failed: %v", err) + return + } + logRedis.LogRedisClient.LPush(context.Background(), LogActionQueueKey, string(logJson)).Result() + } -func GetLogStruct(adminInfo UserInfo, status bool, reason string) *lonelog.LoginLog { +func SetLoginLog(adminInfo UserInfo, status bool, reason string) { st := 2 if status { st = 1 } - return &lonelog.LoginLog{ + log := lonelog.LoginLog{ AdminId: adminInfo.ID, - Ip: adminInfo.ClientIP, Name: adminInfo.Name, + Ip: adminInfo.ClientIP, BrowserInfo: adminInfo.UserAgent, BrowserName: adminInfo.BrowserName, BrowserVersion: adminInfo.BrowserVer, @@ -93,4 +132,11 @@ func GetLogStruct(adminInfo UserInfo, status bool, reason string) *lonelog.Login CreateTime: Now().GoString(), Reason: reason, } + + logJson, err := jsoniter.Marshal(log) + if err != nil { + logx.Errorf("marshal ActionLog failed: %v", err) + return + } + logRedis.LogRedisClient.LPush(context.Background(), LogLoginQueueKey, string(logJson)).Result() } diff --git a/pkg/utils/time.go b/pkg/utils/time.go index f389be1..8d883f1 100644 --- a/pkg/utils/time.go +++ b/pkg/utils/time.go @@ -203,3 +203,12 @@ func TimeToUnix(timeStr string, layout string) (int64, error) { // 转 11 位时间戳(秒) return t.Unix(), nil } +func ParseCustomTime(s string) (CustomTime, error) { + ct := CustomTime{} + // UnmarshalJSON 需要带双引号的json字符串,所以包装成json字符串格式 + err := ct.UnmarshalJSON([]byte(`"` + s + `"`)) + if err != nil { + return CustomTime{}, err + } + return ct, nil +} diff --git a/services/admin/admin.go b/services/admin/admin.go index 9ccd246..f3fbe1a 100644 --- a/services/admin/admin.go +++ b/services/admin/admin.go @@ -2,6 +2,7 @@ package main import ( "flag" + "lone-services/pkg/logRedis" admin "lone-services/rpc/admin/pb" "lone-services/services/admin/internal/config" "lone-services/services/admin/internal/server" @@ -125,6 +126,16 @@ func main() { os.Exit(1) } + if err := logRedis.Init(logRedis.LogRedisConfig{ + Host: utils.GetConfigString("log-redis.host"), + Port: utils.GetConfigInt("log-redis.port"), + Password: utils.GetConfigString("log-redis.password"), + DB: utils.GetConfigInt("log-redis.db"), + }); err != nil { + logx.Errorf("log redis init: %v", err) + os.Exit(1) + } + debug := utils.GetConfigBool("mysql.debug") modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug}) diff --git a/services/admin/internal/logic/admineditlogic.go b/services/admin/internal/logic/admineditlogic.go index 3fa4c11..36c7a0c 100644 --- a/services/admin/internal/logic/admineditlogic.go +++ b/services/admin/internal/logic/admineditlogic.go @@ -50,6 +50,7 @@ func (l *AdminEditLogic) AdminEdit(in *admin.AdminEditRequest) (*admin.Response, return l.fail(utils.ErrorEncryptAesError) } modelObj := model.AdminModel{}.Init() + var action = utils.ActionAdd{} if in.Id > utils.NumberZero && info.Id < utils.NumberOne { w := modelbase.Params{Eq: map[string]string{"id": strconv.Itoa(int(in.Id))}} info = dao.Admin{} @@ -80,6 +81,8 @@ func (l *AdminEditLogic) AdminEdit(in *admin.AdminEditRequest) (*admin.Response, return l.fail(utils.ErrorExistUser) } } + action.Type = utils.LogActionTypeEdit + action.OldContent = info info.AdminId = int(adminInfo.ID) info.AdminName = adminInfo.Name @@ -96,9 +99,10 @@ func (l *AdminEditLogic) AdminEdit(in *admin.AdminEditRequest) (*admin.Response, info.Email = in.Email info.Avatar = in.Avatar var err error + var row int64 if info.Id > utils.NumberZero { w := modelbase.Params{Eq: map[string]string{"id": strconv.Itoa(int(info.Id))}} - _, err = modelObj.Edit(w, info) + row, err = modelObj.Edit(w, info) } else { salt := utils.GetRandstring(utils.NumberFive) pwd := utils.GetSaltPassword(salt, in.Password) @@ -106,12 +110,20 @@ func (l *AdminEditLogic) AdminEdit(in *admin.AdminEditRequest) (*admin.Response, info.Password = pwd info.Salt = salt err = modelObj.Init().Create(&info) + row = info.Id + action.Type = utils.LogActionTypeAdd } if err != nil { l.Logger.Error(err) return l.fail(utils.Fail) } + + if row > utils.NumberZero { + action.NewContent = info + action.ModuleName = utils.LogActionModuleAdmin + utils.SetActionLog(adminInfo, action) + } return l.ok(info.Id) } diff --git a/services/admin/internal/logic/adminitemslogic.go b/services/admin/internal/logic/adminitemslogic.go index acede0b..4948009 100644 --- a/services/admin/internal/logic/adminitemslogic.go +++ b/services/admin/internal/logic/adminitemslogic.go @@ -2,8 +2,14 @@ package logic import ( "context" + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" admin "lone-services/rpc/admin/pb" + "lone-services/services/admin/internal/dao" + "lone-services/services/admin/internal/model" "lone-services/services/admin/internal/svc" + "strconv" + "strings" "github.com/zeromicro/go-zero/core/logx" ) @@ -24,7 +30,96 @@ func NewAdminItemsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminI } func (l *AdminItemsLogic) AdminItems(in *admin.AdminItemsRequest) (*admin.Response, error) { - // todo: add your logic here and delete this line + modelObj := model.AdminModel{}.Init() + w := modelbase.Params{ + Page: int(in.Page), + Size: int(in.Size), + Order: "id desc", + } - return &admin.Response{}, nil + w.Like = make(map[string]string) + eq := make(map[string]string) + if len(in.Name) > utils.NumberZero { + w.Like["name LIKE ? "] = "%%" + in.Name + "%%" + } + if len(in.Phone) > utils.NumberZero { + phone := utils.GetSearchPhone(in.Phone) + if len(phone) > utils.NumberZero { + w.Like["phone LIKE ? "] = "%%" + phone + "%%" + } + } + if len(in.Email) > utils.NumberZero { + w.Like["email LIKE ? "] = "%%" + in.Email + "%%" + } + if in.Status > utils.NumberZero { + eq["status"] = strconv.Itoa(int(in.Status)) + } + + if len(eq) > utils.NumberZero { + w.Eq = eq + } + + var data []dao.AdminInfo + var list []dao.AdminItemsRet + items, _ := modelObj.Page(w, &data) + roleInfos := l.getRoleInfos(data) + for _, item := range data { + var roles []dao.RoleNameItems + for _, role := range strings.Split(item.Roles, utils.DecollatorComma) { + if _, ok := roleInfos[role]; ok { + roles = append(roles, roleInfos[role]) + } + } + + mobile, dErr := utils.DecryptPhone(item.Phone) + if dErr == nil { + item.Phone = mobile + } + + list = append(list, dao.AdminItemsRet{ + AdminInfo: item, + RoleInfo: roles, + }) + } + items.Items = list + + return l.ok(items) +} + +func (l *AdminItemsLogic) getRoleInfos(data []dao.AdminInfo) map[string]dao.RoleNameItems { + var ids []string + for _, item := range data { + ids = append(ids, strings.Split(item.Roles, utils.DecollatorComma)...) + } + + w := modelbase.Params{In: map[string][]string{"id in ?": ids}} + var items []dao.RoleNameItems + retData := make(map[string]dao.RoleNameItems) + + err := model.RoleModel{}.Init().Items(w, &items) + if err != nil { + return retData + } + + w = modelbase.Params{} + var serversItems []dao.ServicesNames + pErr := model.ServicesModel{}.Init().Items(w, &serversItems) + serverIds := make(map[int]string) + if pErr == nil { + for _, item := range serversItems { + serverIds[int(item.Id)] = item.Name + } + } + for i := utils.NumberZero; i < len(items); i++ { + serverName := utils.StringEmpty + if _, ok := serverIds[int(items[i].ServiceId)]; ok { + serverName = serverIds[int(items[i].ServiceId)] + utils.DecollatorColon + } + retData[strconv.Itoa(int(items[i].Id))] = dao.RoleNameItems{ + Id: items[i].Id, + Name: serverName + items[i].Name, + } + } + + return retData } diff --git a/services/admin/internal/logic/adminstatuslogic.go b/services/admin/internal/logic/adminstatuslogic.go index 41bf399..fe5a2e1 100644 --- a/services/admin/internal/logic/adminstatuslogic.go +++ b/services/admin/internal/logic/adminstatuslogic.go @@ -51,18 +51,21 @@ func (l *AdminStatusLogic) AdminStatus(in *admin.StatusRequest) (*admin.Response return l.fail(utils.ErrorNotFund) } action.OldContent = info - action.Type = utils.LogActionTypeStatus - action.ModuleName = utils.LogActionModuleAdmin info.Status = uint8(in.Status) info.Reason = in.Reason info.AdminName = adminInfo.Name info.AdminId = adminInfo.ID - _, editErr := modelObj.Edit(w, info) + row, editErr := modelObj.Edit(w, info) if editErr != nil { l.Logger.Error(editErr) return l.fail(utils.Fail) } - action.NewContent = info - _ = utils.GetActionStruct(adminInfo, action) + if row > utils.NumberZero { + action.NewContent = info + action.Reason = in.Reason + action.Type = utils.LogActionTypeStatus + action.ModuleName = utils.LogActionModuleAdmin + utils.SetActionLog(adminInfo, action) + } return l.ok(utils.NumberOne) } diff --git a/services/admin/internal/logic/authorityeditlogic.go b/services/admin/internal/logic/authorityeditlogic.go index 823f2b9..bcd693c 100644 --- a/services/admin/internal/logic/authorityeditlogic.go +++ b/services/admin/internal/logic/authorityeditlogic.go @@ -2,9 +2,17 @@ package logic import ( "context" + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" admin "lone-services/rpc/admin/pb" + "lone-services/services/admin/internal/dao" + "lone-services/services/admin/internal/model" "lone-services/services/admin/internal/svc" + "lone-services/services/admin/validator" + "strconv" + "strings" + jsoniter "github.com/json-iterator/go" "github.com/zeromicro/go-zero/core/logx" ) @@ -12,6 +20,7 @@ type AuthorityEditLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger + BaseLogic } func NewAuthorityEditLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AuthorityEditLogic { @@ -23,7 +32,305 @@ func NewAuthorityEditLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Aut } func (l *AuthorityEditLogic) AuthorityEdit(in *admin.AuthorityEditRequest) (*admin.Response, error) { - // todo: add your logic here and delete this line + var v validator.AuthorityEditValidator + if fail := l.checkParams(in, &v); fail != nil { + return fail, nil + } + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return l.fail(utils.ErrorNoLoginInfo) + } + edit, dErr := l.getData(adminInfo, in) + if dErr != utils.Ok { + return l.fail(dErr) + } + modelObj := model.AuthorityModel{}.Init() + var err error + jErr, jsonData := l.getJsonData(in) + if jErr != utils.Ok { + return l.fail(jErr) + } + id := in.Id + var row int64 + var action utils.ActionAdd + if id > utils.NumberZero { + w := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(in.Id, utils.NumberTen)}} + info := dao.Authority{} + err = modelObj.GetOne(w, &info) + if err != nil { + l.Logger.Error(err) + return l.fail(utils.Fail) + } + if info.Id < utils.NumberOne { + return l.fail(utils.ErrorNotFund) + } + action.Type = utils.LogActionTypeEdit + action.OldContent = info + edit.Id = info.Id + edit.Type = info.Type + edit.Sort = info.Sort + edit.ServiceId = info.ServiceId + edit.Status = info.Status + w = modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(info.Id, utils.NumberTen)}} + if edit.Type == dao.TypeData { + edit.DataIds = info.DataIds + ids := strings.Split(info.DataIds, ",") + eId, _ := strconv.Atoi(ids[utils.NumberZero]) + eId1, _ := strconv.Atoi(ids[utils.NumberOne]) + eId2, _ := strconv.Atoi(ids[utils.NumberTwo]) + upW := modelbase.Params{Eq: map[string]string{"id": strconv.Itoa(eId)}} + l.setJsonData(&edit, int64(eId), "base", jsonData, in) + _, err = modelObj.Edit(upW, edit) + l.setJsonData(&edit, int64(eId1), "department", jsonData, in) + upW.Eq["id"] = strconv.Itoa(eId1) + _, err = modelObj.Edit(upW, edit) + l.setJsonData(&edit, int64(eId2), "oneself", jsonData, in) + upW.Eq["id"] = strconv.Itoa(eId2) + row, err = modelObj.Edit(upW, edit) - return &admin.Response{}, nil + } else { + row, err = modelObj.Edit(w, edit) + } + } else { + if edit.Type == dao.TypeData { + var ids []string + l.setJsonData(&edit, utils.NumberZero, "base", jsonData, in) + err = modelObj.Create(&edit) + ids = append(ids, strconv.FormatInt(edit.Id, utils.NumberTen)) + l.setJsonData(&edit, utils.NumberZero, "department", jsonData, in) + err = modelObj.Create(&edit) + ids = append(ids, strconv.FormatInt(edit.Id, utils.NumberTen)) + l.setJsonData(&edit, utils.NumberZero, "oneself", jsonData, in) + err = modelObj.Create(&edit) + row = edit.Id + ids = append(ids, strconv.FormatInt(edit.Id, utils.NumberTen)) + + jsonIds := dao.AuthorityUpJsonIds{ + DataIds: strings.Join(ids, ","), + } + jsonW := modelbase.Params{In: map[string][]string{"id": ids}} + modelObj.Edit(jsonW, &jsonIds) + + } else { + err = modelObj.Create(&edit) + id = edit.Id + row = id + } + action.Type = utils.LogActionTypeAdd + } + + if err != nil { + l.Logger.Error(err) + return l.fail(utils.Fail) + } + + if row > utils.NumberZero { + action.NewContent = edit + action.ModuleName = utils.LogActionModuleAuthority + utils.SetActionLog(adminInfo, action) + } + + return l.ok(id) +} + +func (l *AuthorityEditLogic) getData(adminInfo utils.UserInfo, in *admin.AuthorityEditRequest) (dao.Authority, utils.Status) { + edit := dao.Authority{ + Name: in.Name, + Type: uint8(in.Type), + Sort: l.getSort(in.ParentId, in.ServiceId), + Description: in.Description, + Icon: in.Icon, + Identification: in.Identification, + ServiceId: in.ServiceId, + ParentId: in.ParentId, + Api: dao.NoData, + ViewPath: in.ViewPath, + Path: in.Path, + IsShow: uint8(in.IsShow), + AdminId: adminInfo.ID, + AdminName: adminInfo.Name, + } + + edit.Path = "/" + strings.TrimLeft(edit.Path, "/") + + if edit.ParentId < utils.NumberOne { + edit.ParentId = utils.NumberZero + } + + check := l.checkName(in.Id, map[string]string{ + "service_id": strconv.FormatInt(edit.ServiceId, utils.NumberTen), + "name": edit.Name, + }) + if !check { + return edit, utils.SetError(utils.ErrorMissingParams, "权限名称已存在") + } + + check = l.check(edit.Id, map[string]string{ + "service_id": strconv.FormatInt(edit.ServiceId, utils.NumberTen), + "identification": edit.Identification, + }) + if !check { + return edit, utils.SetError(utils.ErrorMissingParams, "权限标识已存在") + } + + if edit.Type == dao.TypeWeb { + if len(edit.ViewPath) < utils.NumberOne { + return edit, utils.SetError(utils.ErrorMissingParams, "组件路径不能为空") + } + check := l.check(in.Id, map[string]string{"path": edit.Path, "service_id": strconv.FormatInt(edit.ServiceId, utils.NumberTen)}) + if !check { + return edit, utils.SetError(utils.ErrorMissingParams, "PATH已存在") + } + } else if edit.Type == dao.TypeButton { + edit.Icon = utils.StringEmpty + if len(edit.Api) < utils.NumberOne { + return edit, utils.SetError(utils.ErrorMissingParams, "API不能为空") + } + edit.Api = in.Api + edit.Path = dao.NoData + edit.ViewPath = dao.NoData + } else if edit.Type == dao.TypeDir { + edit.ViewPath = dao.NoData + check := l.check(in.Id, map[string]string{"path": edit.Path, "service_id": strconv.FormatInt(edit.ServiceId, utils.NumberTen)}) + if !check { + return edit, utils.SetError(utils.ErrorMissingParams, "PATH已存在") + } + } else if edit.Type == dao.TypeData { + if len(edit.Api) < utils.NumberOne { + return edit, utils.SetError(utils.ErrorMissingParams, "API不能为空") + } + edit.Icon = utils.StringEmpty + edit.Api = in.Api + edit.Path = dao.NoData + edit.ViewPath = dao.NoData + } + + if edit.ParentId == utils.NumberZero { + edit.ParentIds = utils.StringZero + } else { + w := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(edit.ParentId, utils.NumberTen)}} + info := dao.Authority{} + err := model.AuthorityModel{}.Init().GetOne(w, &info) + if err != nil { + return edit, utils.Ok + } + if info.Id < utils.NumberOne { + return edit, utils.ErrorNotFund + } + edit.ParentIds = info.ParentIds + "," + strconv.FormatInt(edit.ParentId, utils.NumberTen) + } + + idsArr := strings.SplitAfter(edit.ParentIds, ",") + edit.Level = uint8(len(idsArr)) + + return edit, utils.Ok +} + +func (l *AuthorityEditLogic) check(id int64, check map[string]string) bool { + w := modelbase.Params{Eq: check} + info := dao.AuthorityCheck{} + _ = model.AuthorityModel{}.Init().GetOne(w, &info) + if id > utils.NumberZero && info.Id == id { + return true + } + if info.Id > utils.NumberZero { + return false + } + + return true +} + +func (l *AuthorityEditLogic) checkName(id int64, check map[string]string) bool { + w := modelbase.Params{Eq: check} + info := dao.AuthorityCheck{} + _ = model.AuthorityModel{}.Init().GetOne(w, &info) + if id > utils.NumberZero && info.Id == id { + return true + } + if info.Id > utils.NumberZero { + return false + } + + return true +} + +func (l *AuthorityEditLogic) getSort(pid, serviceId int64) uint8 { + if pid < utils.NumberZero { + pid = utils.NumberZero + } + w := modelbase.Params{ + Eq: map[string]string{ + "parent_id": strconv.FormatInt(pid, utils.NumberTen), + "project_id": strconv.FormatInt(serviceId, utils.NumberTen)}, + Order: "sort DESC", + } + info := dao.Authority{} + err := model.AuthorityModel{}.Init().GetOne(w, &info) + if err != nil || info.Id < utils.NumberOne { + return utils.NumberOne + } + return info.Sort + utils.NumberOne +} + +func (l *AuthorityEditLogic) setJsonData(edit *dao.Authority, id int64, name string, data map[string]string, in *admin.AuthorityEditRequest) { + edit.Id = id + if name == "base" { + edit.Name = in.Name + "-全部" + edit.JsonDataBase = data["base"] + edit.JsonData = data["all"] + edit.JsonTreeData = data["tree_all"] + } else if name == "department" { + edit.JsonData = data["department"] + edit.Name = in.Name + "-部门" + edit.JsonTreeData = data["tree_department"] + edit.Identification = in.Identification + ":department" + } else if name == "oneself" { + edit.JsonData = data["oneself"] + edit.Name = in.Name + "-个人" + edit.JsonTreeData = data["tree_oneself"] + edit.Identification = in.Identification + ":oneself" + } + if id == utils.NumberZero { + edit.Sort += utils.NumberOne + } else { + info := dao.AuthoritySort{} + w := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(id, utils.NumberTen)}} + _ = model.AuthorityModel{}.Init().GetOne(w, &info) + edit.Sort = info.Sort + } +} +func (l *AuthorityEditLogic) getJsonData(in *admin.AuthorityEditRequest) (utils.Status, map[string]string) { + data := map[string]string{} + if in.Type != dao.TypeData { + return utils.Ok, data + } + var check map[string]interface{} + // 解析JSON字符串到map + err := jsoniter.Unmarshal([]byte(in.DataBaseStr), &check) + if err != nil { + return utils.ErrorJsonDataError, data + } + // 解析JSON字符串到map + err = jsoniter.Unmarshal([]byte(in.DataAll), &check) + if err != nil { + return utils.ErrorJsonDataError, data + } + // 解析JSON字符串到map + err = jsoniter.Unmarshal([]byte(in.DataDepartment), &check) + if err != nil { + return utils.ErrorJsonDataError, data + } + // 解析JSON字符串到map + err = jsoniter.Unmarshal([]byte(in.DataOneself), &check) + if err != nil { + return utils.ErrorJsonDataError, data + } + data["base"] = in.DataBaseStr + data["all"] = in.DataAll + data["department"] = in.DataDepartment + data["oneself"] = in.DataOneself + data["tree_all"] = in.DataTreeAll + data["tree_department"] = in.DataTreeDepartment + data["tree_oneself"] = in.DataTreeOneself + return utils.Ok, data } diff --git a/services/admin/internal/logic/authoritysortlogic.go b/services/admin/internal/logic/authoritysortlogic.go index f42fba4..c67c813 100644 --- a/services/admin/internal/logic/authoritysortlogic.go +++ b/services/admin/internal/logic/authoritysortlogic.go @@ -41,7 +41,7 @@ func (l *AuthoritySortLogic) AuthoritySort(in *admin.AuthoritySortRequest) (*adm info := dao.AuthoritySort{} modelObj := model.AuthorityModel{}.Init() w := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(in.Id, utils.NumberTen)}} - err := modelObj.Items(w, &info) + err := modelObj.GetOne(w, &info) if err != nil { l.Logger.Error(err) return l.fail(utils.Fail) @@ -61,15 +61,20 @@ func (l *AuthoritySortLogic) AuthoritySort(in *admin.AuthoritySortRequest) (*adm } w.Other = map[string]string{sortKey: strconv.Itoa(int(info.Sort))} other := dao.AuthoritySort{} - err = modelObj.Items(w, &other) + err = modelObj.GetOne(w, &other) if err != nil { l.Logger.Error(err) return l.fail(utils.Fail) } + action := utils.ActionAdd{} + action.Type = utils.LogActionTypeSort + action.ModuleName = utils.LogActionModuleAuthority + action.OldContent = info if info.Id < utils.NumberOne { return l.fail(utils.ErrorNotFund) } w = modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(info.Id, utils.NumberTen)}} + infoSort := info.Sort info.Sort = other.Sort info.AdminId = adminInfo.ID @@ -79,6 +84,9 @@ func (l *AuthoritySortLogic) AuthoritySort(in *admin.AuthoritySortRequest) (*adm l.Logger.Error(err) return l.fail(utils.Fail) } + action.NewContent = info + utils.SetActionLog(adminInfo, action) + action.OldContent = other w = modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(other.Id, utils.NumberTen)}} other.Sort = infoSort other.AdminId = info.AdminId @@ -88,6 +96,8 @@ func (l *AuthoritySortLogic) AuthoritySort(in *admin.AuthoritySortRequest) (*adm l.Logger.Error(err) return l.fail(utils.Fail) } + action.NewContent = other + utils.SetActionLog(adminInfo, action) return l.ok(utils.NumberOne) } diff --git a/services/admin/internal/logic/authoritystatuslogic.go b/services/admin/internal/logic/authoritystatuslogic.go index bc49eb4..6e7a0e3 100644 --- a/services/admin/internal/logic/authoritystatuslogic.go +++ b/services/admin/internal/logic/authoritystatuslogic.go @@ -66,15 +66,25 @@ func (l *AuthorityStatusLogic) AuthorityStatus(in *admin.StatusRequest) (*admin. return l.fail(utils.ErrorAuthorityChange) } + var action utils.ActionAdd + action.OldContent = info info.Status = uint8(in.Status) info.Reason = in.Reason info.AdminId = adminInfo.ID info.AdminName = adminInfo.Name - _, editErr := modelObj.Edit(w, info) + row, editErr := modelObj.Edit(w, info) if editErr != nil { l.Logger.Error(editErr) return l.fail(utils.Fail) } + if row > utils.NumberZero { + action.NewContent = info + action.Reason = in.Reason + action.Type = utils.LogActionTypeStatus + action.ModuleName = utils.LogActionModuleAuthority + utils.SetActionLog(adminInfo, action) + } + return l.ok(utils.NumberOne) } diff --git a/services/admin/internal/logic/loginlogic.go b/services/admin/internal/logic/loginlogic.go index 71aafae..32f0770 100644 --- a/services/admin/internal/logic/loginlogic.go +++ b/services/admin/internal/logic/loginlogic.go @@ -33,7 +33,6 @@ func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic } func (l *LoginLogic) Login(in *admin.LoginRequest) (*admin.Response, error) { - l.Logger.Error("u:", in.Username, "p:", in.Password, "|") var v validator.LoginValidator if fail := l.checkParams(in, &v); fail != nil { return fail, nil @@ -44,7 +43,8 @@ func (l *LoginLogic) Login(in *admin.LoginRequest) (*admin.Response, error) { l.Logger.Error(dErr) return l.fail(utils.Fail) } - + adminInfo := utils.GetUserFromCtx(l.ctx) + adminInfo.Name = in.Username var info dao.Admin w := modelbase.Params{Eq: map[string]string{"phone": phone}} modelObj := model.AdminModel{}.Init() @@ -54,12 +54,14 @@ func (l *LoginLogic) Login(in *admin.LoginRequest) (*admin.Response, error) { return l.fail(utils.Fail) } if info.Id < utils.NumberOne { + utils.SetLoginLog(adminInfo, false, utils.ErrorNotFund.Msg) return l.fail(utils.ErrorNotFund) } pwd := utils.GetSaltPassword(info.Salt, in.Password) eq := utils.EqualsPassword(pwd, info.Password) if !eq { + utils.SetLoginLog(adminInfo, false, utils.ErrorPwdError.Msg) return l.fail(utils.ErrorPwdError) } @@ -85,6 +87,8 @@ func (l *LoginLogic) Login(in *admin.LoginRequest) (*admin.Response, error) { retData.Refresh = utils.MD5Encrypt(data.Phone + retData.Token) l.setLogin(retData.Token, retData.Refresh, data) + adminInfo.ID = data.Id + utils.SetLoginLog(adminInfo, true, utils.StringEmpty) return l.ok(retData) } diff --git a/services/admin/internal/logic/passwordlogic.go b/services/admin/internal/logic/passwordlogic.go index fa112ff..5adcee2 100644 --- a/services/admin/internal/logic/passwordlogic.go +++ b/services/admin/internal/logic/passwordlogic.go @@ -52,13 +52,22 @@ func (l *PasswordLogic) Password(in *admin.PasswordRequest) (*admin.Response, er pwd := utils.GetSaltPassword(info.Salt, in.Password) pwd, _ = utils.EncryptPassword(pwd) + var action utils.ActionAdd + action.OldContent = info info.Password = pwd info.AdminId = int(adminInfo.ID) info.AdminName = adminInfo.Name - _, editErr := modelObj.Edit(w, info) + row, editErr := modelObj.Edit(w, info) if editErr != nil { l.Logger.Error(err) return l.fail(utils.Fail) } + + if row > utils.NumberZero { + action.NewContent = info + action.Type = utils.LogActionTypePassword + action.ModuleName = utils.LogActionModuleAdmin + utils.SetActionLog(adminInfo, action) + } return l.ok(utils.NumberOne) } diff --git a/services/admin/internal/logic/roleeditlogic.go b/services/admin/internal/logic/roleeditlogic.go index de0abf0..dc5f664 100644 --- a/services/admin/internal/logic/roleeditlogic.go +++ b/services/admin/internal/logic/roleeditlogic.go @@ -56,6 +56,8 @@ func (l *RoleEditLogic) RoleEdit(in *admin.RoleEditRequest) (*admin.Response, er modelObj := model.RoleModel{}.Init() id := in.Id var editErr error + var row int64 + var action utils.ActionAdd if id > utils.NumberZero { if check.Id > utils.NumberZero && check.Id != id { return l.fail(utils.ErrorExist) @@ -71,18 +73,21 @@ func (l *RoleEditLogic) RoleEdit(in *admin.RoleEditRequest) (*admin.Response, er if info.Id < utils.NumberOne { return l.fail(utils.ErrorNotFund) } - + action.OldContent = info edit.Id = info.Id edit.Status = info.Status w = modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(info.Id, utils.NumberTen)}} - _, editErr = modelObj.Edit(w, edit) + row, editErr = modelObj.Edit(w, edit) + action.Type = utils.LogActionTypeEdit } else { if check.Id > utils.NumberZero { return l.fail(utils.ErrorExist) } editErr = modelObj.Create(&edit) id = edit.Id + row = id + action.Type = utils.LogActionTypeAdd } if editErr != nil { @@ -90,6 +95,11 @@ func (l *RoleEditLogic) RoleEdit(in *admin.RoleEditRequest) (*admin.Response, er return l.fail(utils.Fail) } + if row > utils.NumberZero { + action.NewContent = edit + action.ModuleName = utils.LogActionModuleRole + utils.SetActionLog(adminInfo, action) + } return l.ok(id) } diff --git a/services/admin/internal/logic/rolestatuslogic.go b/services/admin/internal/logic/rolestatuslogic.go index 3310e80..0febe6a 100644 --- a/services/admin/internal/logic/rolestatuslogic.go +++ b/services/admin/internal/logic/rolestatuslogic.go @@ -50,15 +50,25 @@ func (l *RoleStatusLogic) RoleStatus(in *admin.StatusRequest) (*admin.Response, if info.Id < utils.NumberOne { return l.fail(utils.ErrorNotFund) } + + var action utils.ActionAdd + action.OldContent = info info.Status = uint8(in.Status) info.Reason = in.Reason info.AdminId = adminInfo.ID info.AdminName = adminInfo.Name - _, editErr := modelObj.Edit(w, info) + row, editErr := modelObj.Edit(w, info) if editErr != nil { l.Logger.Error(editErr) return l.fail(utils.Fail) } + if row > utils.NumberZero { + action.NewContent = info + action.Reason = in.Reason + action.Type = utils.LogActionTypeStatus + action.ModuleName = utils.LogActionModuleRole + utils.SetActionLog(adminInfo, action) + } return l.ok(utils.NumberOne) } diff --git a/services/admin/internal/logic/serviceeditlogic.go b/services/admin/internal/logic/serviceeditlogic.go index 7778f5c..d8832d0 100644 --- a/services/admin/internal/logic/serviceeditlogic.go +++ b/services/admin/internal/logic/serviceeditlogic.go @@ -47,6 +47,9 @@ func (l *ServiceEditLogic) ServiceEdit(in *admin.ServiceEditRequest) (*admin.Res modelObj := model.ServicesModel{}.Init() var err error + var row int64 + var action utils.ActionAdd + if in.Id > utils.NumberZero { w := modelbase.Params{Eq: map[string]string{"id": strconv.Itoa(int(in.Id))}} info := dao.Services{} @@ -58,10 +61,14 @@ func (l *ServiceEditLogic) ServiceEdit(in *admin.ServiceEditRequest) (*admin.Res if info.Id < utils.NumberOne { return l.fail(utils.ErrorNotFund) } + action.OldContent = info edit.Id = info.Id - _, err = modelObj.Edit(w, &edit) + row, err = modelObj.Edit(w, &edit) + action.Type = utils.LogActionTypeEdit } else { err = modelObj.Create(&edit) + row = edit.Id + action.Type = utils.LogActionTypeAdd } if err != nil { @@ -69,5 +76,10 @@ func (l *ServiceEditLogic) ServiceEdit(in *admin.ServiceEditRequest) (*admin.Res return l.fail(utils.Fail) } + if row > utils.NumberZero { + action.NewContent = edit + action.ModuleName = utils.LogActionModuleService + utils.SetActionLog(adminInfo, action) + } return l.ok(edit.Id) } diff --git a/services/admin/internal/logic/servicestatuslogic.go b/services/admin/internal/logic/servicestatuslogic.go index 952491e..1e9181a 100644 --- a/services/admin/internal/logic/servicestatuslogic.go +++ b/services/admin/internal/logic/servicestatuslogic.go @@ -50,15 +50,24 @@ func (l *ServiceStatusLogic) ServiceStatus(in *admin.StatusRequest) (*admin.Resp return l.fail(utils.ErrorNotFund) } + var action utils.ActionAdd + action.OldContent = info info.Status = uint8(in.Status) info.Reason = in.Reason info.AdminName = adminInfo.Name info.AdminId = adminInfo.ID - _, editErr := modelObj.Edit(w, info) + row, editErr := modelObj.Edit(w, info) if editErr != nil { l.Logger.Error(editErr) return l.fail(utils.Fail) } + if row > utils.NumberZero { + action.NewContent = info + action.Reason = in.Reason + action.Type = utils.LogActionTypeStatus + action.ModuleName = utils.LogActionModuleService + utils.SetActionLog(adminInfo, action) + } return l.ok(utils.NumberOne) } diff --git a/services/lonelog/internal/dao/actionLogs.go b/services/lonelog/internal/dao/actionLogs.go index 5dbd675..240cdd8 100644 --- a/services/lonelog/internal/dao/actionLogs.go +++ b/services/lonelog/internal/dao/actionLogs.go @@ -6,7 +6,7 @@ import "lone-services/pkg/utils" type ActionLog struct { Id int `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT;comment:ID" json:"id"` Content string `gorm:"column:content;type:text;comment:内容;NOT NULL" json:"content"` - AdminId int `gorm:"column:admin_id;type:int(11);comment:操作人;NOT NULL" json:"admin_id"` + AdminId int64 `gorm:"column:admin_id;type:int(11);comment:操作人;NOT NULL" json:"admin_id"` AdminName string `gorm:"column:admin_name;type:varchar(255);comment:真实姓名" json:"admin_name"` Type uint8 `gorm:"column:type;type:smallint(3);comment:类型,以常量配置文件为准,目前,1为添加,2为编辑,3为删除,4为强退,5为下载;NOT NULL" json:"type"` ModuleName string `gorm:"column:module_name;type:varchar(255);comment:操作模块名,如管理员;NOT NULL" json:"module_name"` @@ -14,7 +14,6 @@ type ActionLog struct { BrowserInfo string `gorm:"column:browser_info;type:varchar(255);comment:浏览器详细信息" json:"browser_info"` BrowserName string `gorm:"column:browser_name;type:varchar(50);comment:浏览器名称" json:"browser_name"` BrowserVersion string `gorm:"column:browser_version;type:varchar(50);comment:版本" json:"browser_version"` - ServiceId int `gorm:"column:service_id;type:int(11);default:0;comment:项目ID" json:"service_id"` Reason string `gorm:"column:reason;type:varchar(255);comment:原因" json:"reason"` CreateTime utils.CustomTime `gorm:"column:create_time;type:datetime;default:NULL;comment:添加时间;NOT NULL" json:"create_time"` } @@ -25,15 +24,6 @@ type ActionItems struct { Type []ActionType `json:"type"` } -type ActionAdd struct { - NewContent interface{} `json:"new_content"` - OldContent interface{} `json:"old_content"` - ServiceId int `json:"service_id"` - Reason string `json:"reason"` - Type uint8 `json:"type"` - ModuleName string `json:"module_name"` -} - type ActionType struct { Id int `json:"id"` Name string `json:"name"` diff --git a/services/lonelog/internal/dao/loginLogs.go b/services/lonelog/internal/dao/loginLogs.go new file mode 100644 index 0000000..58fc544 --- /dev/null +++ b/services/lonelog/internal/dao/loginLogs.go @@ -0,0 +1,25 @@ +package dao + +import "lone-services/pkg/utils" + +type LoginLog struct { + Id int64 `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT;comment:ID" json:"id"` + AdminId int64 `gorm:"column:admin_id;type:int(11);default:0;comment:登录人ID;NOT NULL" json:"admin_id"` + AdminName string `gorm:"column:admin_name;type:varchar(255);comment:登录人姓名" json:"admin_name"` + Ip string `gorm:"column:ip;type:varchar(50);comment:IP;NOT NULL" json:"ip"` + BrowserInfo string `gorm:"column:browser_info;type:varchar(255);comment:浏览器详细信息" json:"browser_info"` + BrowserName string `gorm:"column:browser_name;type:varchar(50);comment:浏览器名称" json:"browser_name"` + BrowserVersion string `gorm:"column:browser_version;type:varchar(50);comment:浏览器版本" json:"browser_version"` + Status uint8 `gorm:"column:status;type:tinyint(1);default:1;comment:状态,1为成功,2为失败" json:"status"` + CreateTime utils.CustomTime `gorm:"column:create_time;type:datetime;comment:添加时间;NOT NULL" json:"create_time"` + Reason string `gorm:"column:reason;type:varchar(50);comment:失败原因" json:"reason"` +} + +type LoginLogItems struct { + Items []LoginLog `json:"items"` + Count int64 `json:"count"` +} + +type Count struct { + Id int `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT;comment:ID" json:"id"` +} diff --git a/services/lonelog/internal/model/action.go b/services/lonelog/internal/model/action.go index 1413d3e..769f857 100644 --- a/services/lonelog/internal/model/action.go +++ b/services/lonelog/internal/model/action.go @@ -1,6 +1,9 @@ package model -import "lone-services/pkg/modelbase" +import ( + "lone-services/pkg/modelbase" + "lone-services/services/lonelog/internal/dao" +) type ActionModel struct { modelbase.Base @@ -15,6 +18,6 @@ func (m ActionModel) Init() ActionModel { return m } -//func (m ActionModel) Create(data *dao.Admin) error { -// return m.Base.Create(data) -//} +func (m ActionModel) Create(data *dao.ActionLog) error { + return m.Base.Create(data) +} diff --git a/services/lonelog/internal/model/login.go b/services/lonelog/internal/model/login.go new file mode 100644 index 0000000..db7c27e --- /dev/null +++ b/services/lonelog/internal/model/login.go @@ -0,0 +1,23 @@ +package model + +import ( + "lone-services/pkg/modelbase" + "lone-services/services/lonelog/internal/dao" +) + +type LoginModel struct { + modelbase.Base +} + +func (m LoginModel) TableName() string { + return modelbase.Prefix() + "admin_login" +} + +func (m LoginModel) Init() LoginModel { + m.Table = m.TableName() + return m +} + +func (m LoginModel) Create(data *dao.LoginLog) error { + return m.Base.Create(data) +} diff --git a/services/lonelog/internal/service/logwatcher.go b/services/lonelog/internal/service/logwatcher.go new file mode 100644 index 0000000..c567706 --- /dev/null +++ b/services/lonelog/internal/service/logwatcher.go @@ -0,0 +1,178 @@ +package service + +import ( + "context" + "encoding/json" + "lone-services/pkg/logRedis" + "lone-services/pkg/utils" + "lone-services/services/lonelog/internal/dao" + "lone-services/services/lonelog/internal/model" + "sync" + "time" + + "github.com/zeromicro/go-zero/core/logx" +) + +// LogWatcher 队列监听器,内部直接使用 logredis.LogRedisClient 包全局变量,不再传入redis参数 +type LogWatcher struct { + ctx context.Context + cancel context.CancelFunc + wg sync.WaitGroup +} + +// GlobalLogWatcher 全局单例,main初始化之后其它包直接 service.GlobalLogWatcher 访问 +var GlobalLogWatcher *LogWatcher + +// NewLogWatcher 无入参,直接使用包全局 logredis.LogRedisClient +func NewLogWatcher() *LogWatcher { + ctx, cancel := context.WithCancel(context.Background()) + return &LogWatcher{ + ctx: ctx, + cancel: cancel, + } +} + +// StartWatch 启动两个消费协程 +func (w *LogWatcher) StartWatch() { + w.wg.Add(2) + go w.loopActionLog() + go w.loopLoginLog() + logx.Infof("LogWatcher start, watch %s , %s", utils.LogActionQueueKey, utils.LogLoginQueueKey) +} + +// loopActionLog 消费action日志队列,带recover自动重启 +func (w *LogWatcher) loopActionLog() { + defer func() { + if r := recover(); r != nil { + logx.Errorf("loopActionLog panic recovered, err=%v", r) + time.Sleep(2 * time.Second) + w.wg.Add(1) + go w.loopActionLog() + } + w.wg.Done() + }() + + for { + select { + case <-w.ctx.Done(): + logx.Info("loopActionLog received exit signal, quit") + return + default: + } + + res, err := logRedis.LogRedisClient.BRPop(w.ctx, 5*time.Second, utils.LogActionQueueKey).Result() + if err != nil { + if err.Error() == "redis: nil" { + continue + } + logx.Errorf("BRPop %s redis err: %v", utils.LogActionQueueKey, err) + time.Sleep(1 * time.Second) + continue + } + + if len(res) < 2 { + continue + } + payload := res[1] + + var action utils.ActionLog + if err := json.Unmarshal([]byte(payload), &action); err != nil { + logx.Errorf("unmarshal actionlog failed payload=%s err=%v", payload, err) + continue + } + + ctxBg := context.Background() + logTime, _ := utils.ParseCustomTime(action.CreateTime) + edit := dao.ActionLog{ + Content: action.Content, + AdminId: action.AdminId, + AdminName: action.AdminName, + Type: uint8(action.Type), + ModuleName: action.ModuleName, + Ip: action.Ip, + BrowserInfo: action.BrowserInfo, + BrowserName: action.BrowserName, + BrowserVersion: action.BrowserVersion, + Reason: action.Reason, + CreateTime: logTime, + } + + err = model.ActionModel{}.Init().Create(&edit) + if err != nil { + logx.Errorf("insert actionlog mysql err=%v payload=%s", err, payload) + _ = logRedis.LogRedisClient.LPush(ctxBg, utils.LogActionQueueKey, payload).Err() + time.Sleep(500 * time.Millisecond) + } + } +} + +// loopLoginLog 消费登录日志队列,带recover自动重启 +func (w *LogWatcher) loopLoginLog() { + defer func() { + if r := recover(); r != nil { + logx.Errorf("loopLoginLog panic recovered, err=%v", r) + time.Sleep(2 * time.Second) + w.wg.Add(1) + go w.loopLoginLog() + } + w.wg.Done() + }() + + for { + select { + case <-w.ctx.Done(): + logx.Info("loopLoginLog received exit signal, quit") + return + default: + } + + res, err := logRedis.LogRedisClient.BRPop(w.ctx, 5*time.Second, utils.LogLoginQueueKey).Result() + if err != nil { + if err.Error() == "redis: nil" { + continue + } + logx.Errorf("BRPop %s redis err: %v", utils.LogLoginQueueKey, err) + time.Sleep(1 * time.Second) + continue + } + + if len(res) < 2 { + continue + } + payload := res[1] + + var login utils.LoginLog + if err := json.Unmarshal([]byte(payload), &login); err != nil { + logx.Errorf("unmarshal loginlog failed payload=%s err=%v", payload, err) + continue + } + + ctxBg := context.Background() + + logTime, _ := utils.ParseCustomTime(login.CreateTime) + edit := dao.LoginLog{ + AdminId: login.AdminId, + AdminName: login.Name, + Ip: login.Ip, + BrowserInfo: login.BrowserInfo, + BrowserName: login.BrowserName, + BrowserVersion: login.BrowserVersion, + Reason: login.Reason, + CreateTime: logTime, + Status: uint8(login.Status), + } + err = model.LoginModel{}.Init().Create(&edit) + if err != nil { + logx.Errorf("insert loginlog mysql err=%v payload=%s", err, payload) + _ = logRedis.LogRedisClient.LPush(ctxBg, utils.LogLoginQueueKey, payload).Err() + time.Sleep(500 * time.Millisecond) + } + } +} + +// StopWatch 优雅停止消费协程 +func (w *LogWatcher) StopWatch() { + w.cancel() + w.wg.Wait() + logx.Info("LogWatcher stopped complete") +} diff --git a/services/lonelog/lonelog.go b/services/lonelog/lonelog.go index 9ea7567..343c61d 100644 --- a/services/lonelog/lonelog.go +++ b/services/lonelog/lonelog.go @@ -3,14 +3,15 @@ package main import ( "flag" "lone-services/pkg/discovery" + "lone-services/pkg/logRedis" "lone-services/pkg/modelbase" "lone-services/pkg/mysql" - "lone-services/pkg/redis" "lone-services/pkg/utils" "lone-services/pkg/validate" lonelog "lone-services/rpc/lonelog/pb" "lone-services/services/lonelog/internal/config" "lone-services/services/lonelog/internal/server" + service2 "lone-services/services/lonelog/internal/service" "lone-services/services/lonelog/internal/svc" "net" "os" @@ -108,13 +109,13 @@ func main() { os.Exit(1) } - if err := redis.Init(redis.Config{ - Host: utils.GetConfigString("redis.host"), - Port: utils.GetConfigInt("redis.port"), - Password: utils.GetConfigString("redis.password"), - DB: utils.GetConfigInt("redis.db"), + if err := logRedis.Init(logRedis.LogRedisConfig{ + Host: utils.GetConfigString("log-redis.host"), + Port: utils.GetConfigInt("log-redis.port"), + Password: utils.GetConfigString("log-redis.password"), + DB: utils.GetConfigInt("log-redis.db"), }); err != nil { - logx.Errorf("redis init: %v", err) + logx.Errorf("log redis init: %v", err) os.Exit(1) } @@ -138,6 +139,10 @@ func main() { s.AddUnaryInterceptors(validate.UnaryServerInterceptor(validate.MustNew())) + watcher := service2.NewLogWatcher() + watcher.StartWatch() + defer watcher.StopWatch() + logx.Infof("Starting rpc server at %s...", listenOn) s.Start() }