重新初始化仓库

This commit is contained in:
2021-11-30 17:50:21 +08:00
commit 6c31164c37
37 changed files with 3339 additions and 0 deletions

68
manager/base.go Normal file
View File

@ -0,0 +1,68 @@
// Package manager...
//
// Description : manager...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2021-08-09 2:24 下午
package manager
import (
"time"
"git.zhangdeman.cn/zhangdeman/center-config/define/model"
"github.com/gin-gonic/gin"
)
// base 基础结构,均为通用方法
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:25 下午 2021/8/9
type base struct {
}
// ParsePostForm 解析post表单
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:25 下午 2021/8/9
func (b *base) ParsePostForm(ctx *gin.Context, form interface{}) error {
var err error
if err = ctx.ShouldBindJSON(form); nil != err {
return err
}
return nil
}
// GetLogData 获取记录日志的数据
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 6:02 下午 2021/8/9
func (b *base) GetLogData(namespaceID int64, configID int64, userID string, logType string, description string) *model.Log {
return &model.Log{
NamespaceID: namespaceID,
ConfigID: configID,
BeforeValue: "",
AfterValue: "",
Description: description,
LogType: logType,
CreateUserID: userID,
CreateTime: time.Now().Format("2006-01-02 15:04:05"),
ModifyTime: time.Now().Format("2006-01-02 15:04:05"),
}
}
// GetNamespaceIDByNamespace ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:13 下午 2021/11/30
func (b *base) GetNamespaceIDByNamespace(np string) int64 {
namespaceInfo, _ := Storage.GetNamespace(np)
if nil == namespaceInfo {
return 0
}
return namespaceInfo.ID
}

222
manager/config.go Normal file
View File

@ -0,0 +1,222 @@
// Package manager ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:46 下午 2021/8/9
package manager
import (
"errors"
"fmt"
"time"
"git.zhangdeman.cn/zhangdeman/center-config/dao"
"git.zhangdeman.cn/zhangdeman/center-config/define/model"
"git.zhangdeman.cn/zhangdeman/center-config/define/form"
"github.com/gin-gonic/gin"
)
type config struct {
base
}
// CreateOrUpdateConfig 创建或更新配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:50 下午 2021/8/9
func (c *config) CreateOrUpdateConfig(dataForm *form.CreateOrUpdateConfig) error {
var (
err error
namespaceInfo *model.Namespace
configInfo *model.Config
)
if namespaceInfo, err = Namespace.GetNamespaceDetail(dataForm.NamespaceID, dataForm.Namespace); nil != err {
return errors.New("namespace is not found : " + err.Error())
}
if err = dao.Config.Detail(dao.DBInstance, &model.Config{NamespaceID: namespaceInfo.ID, Field: dataForm.Key}, configInfo, nil); nil != err {
// 没查到,创建
return c.Create(dataForm, namespaceInfo)
} else {
// 查到更新
return c.Update(dataForm, namespaceInfo, configInfo)
}
}
// Create 创建配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:10 上午 2021/8/10
func (c *config) Create(dataForm *form.CreateOrUpdateConfig, namespaceInfo *model.Namespace) error {
var (
err error
configInfo *model.Config
)
if nil == namespaceInfo {
if namespaceInfo, err = Namespace.GetNamespaceDetail(dataForm.NamespaceID, dataForm.Namespace); nil != err {
return errors.New("namespace is not found :" + err.Error())
}
}
// 创建配置
tx := dao.Config.Begin()
if nil != tx.Error {
return err
}
// 创建配置
configInfo = &model.Config{
NamespaceID: namespaceInfo.ID,
Field: dataForm.Key,
Value: dataForm.Value,
Description: dataForm.Description,
CreateUserID: dataForm.OperateUserID,
ModifyUserID: dataForm.OperateUserID,
CreateTime: time.Now().Format("2006-01-02 15:04:05"),
ModifyTime: time.Now().Format("2006-01-02 15:04:05"),
}
if err = dao.Config.CreateNewData(tx, configInfo, nil); nil != err {
_ = dao.Config.Rollback(tx)
return err
}
// 记录日志
logData := c.GetLogData(namespaceInfo.ID, configInfo.ID, dataForm.OperateUserID, model.LogTypeCreateConfig, "新建配置")
logData.AfterValue = fmt.Sprintf(`{"field":"%s", "value":"%s"}`, dataForm.Key, dataForm.Value)
if err = dao.Log.CreateNewData(tx, logData, nil); nil != err {
_ = dao.Config.Rollback(tx)
return err
}
if err = dao.Config.Commit(tx); nil != err {
return err
}
return nil
}
// Update 更新配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:34 上午 2021/8/10
func (c *config) Update(dataForm *form.CreateOrUpdateConfig, namespaceInfo *model.Namespace, configInfo *model.Config) error {
var (
err error
)
if nil == namespaceInfo {
if namespaceInfo, err = Namespace.GetNamespaceDetail(dataForm.NamespaceID, dataForm.Namespace); nil != err {
return errors.New("namespace is not found :" + err.Error())
}
}
if nil == configInfo {
if configInfo, err = c.GetConfigInfo(namespaceInfo.ID, dataForm.Key); nil != err {
return err
}
}
// 更新配置
tx := dao.Config.Begin()
if nil != tx.Error {
return err
}
if err = dao.Config.UpdateData(tx, &model.Config{Value: dataForm.Value}, &model.Config{NamespaceID: namespaceInfo.ID, Field: dataForm.Key, Value: configInfo.Value}, nil); nil != err {
_ = dao.Config.Rollback(tx)
return err
}
// 记录日志
logData := c.GetLogData(namespaceInfo.ID, configInfo.ID, dataForm.OperateUserID, model.LogTypeUpdateConfig, "更新配置 : "+dataForm.Description)
logData.BeforeValue = fmt.Sprintf(`{"field":"%s", "value":"%s"}`, dataForm.Key, configInfo.Value)
logData.AfterValue = fmt.Sprintf(`{"field":"%s", "value":"%s"}`, dataForm.Key, dataForm.Value)
if err = dao.Log.CreateNewData(tx, logData, nil); nil != err {
_ = dao.Config.Rollback(tx)
return err
}
if err = dao.Config.Commit(tx); nil != err {
return err
}
return nil
}
// ValidateCreateOrUpdateConfigForm ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:49 下午 2021/8/9
func (c *config) ValidateCreateOrUpdateConfigForm(ctx *gin.Context) (*form.CreateOrUpdateConfig, error) {
var (
dataForm form.CreateOrUpdateConfig
err error
)
if err = c.ParsePostForm(ctx, &dataForm); nil != err {
return nil, err
}
if dataForm.NamespaceID <= 0 && len(dataForm.Namespace) == 0 {
return nil, errors.New("namespace_id or namespace is required")
}
if len(dataForm.Key) == 0 {
return nil, errors.New("key is required")
}
if len(dataForm.OperateUserID) == 0 {
return nil, errors.New("operate_user_id is required")
}
return &dataForm, nil
}
// GetConfigInfo 读取配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:59 上午 2021/8/10
func (c *config) GetConfigInfo(namespaceID int64, configKey string) (*model.Config, error) {
var (
err error
configInfo model.Config
)
if err = dao.Config.Detail(dao.DBInstance, &model.Config{NamespaceID: namespaceID, Field: configKey}, &configInfo, nil); nil != err {
return nil, errors.New("config is not found :" + err.Error())
}
return &configInfo, err
}
// GetAllConfig 获取全部配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:57 下午 2021/8/10
func (c *config) GetAllConfig() ([]*model.Config, error) {
var (
list []*model.Config
err error
)
if err = dao.Config.Select(dao.DBInstance, &model.Config{}, &list, nil); nil != err {
return make([]*model.Config, 0), err
}
return list, nil
}
// GetNamespaceConfig 获取命名空间的配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:45 上午 2021/8/11
func (c *config) GetNamespaceConfig(namespaceID int64) ([]*model.Config, error) {
var (
list []*model.Config
err error
)
if err = dao.Config.Select(dao.DBInstance, &model.Config{NamespaceID: namespaceID}, &list, nil); nil != err {
return make([]*model.Config, 0), err
}
return list, nil
}

55
manager/init.go Normal file
View File

@ -0,0 +1,55 @@
// Package manager...
//
// Description : manager...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2021-08-09 6:34 下午
package manager
import (
"git.zhangdeman.cn/zhangdeman/gopkg/easylock"
"git.zhangdeman.cn/zhangdeman/gopkg/easymap"
)
var (
// Namespace 命名空间实例
Namespace *namespace
// Config 配置管理实例
Config *config
// Storage 内存存储实例
Storage *storage
)
// Init ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 6:36 下午 2021/8/9
func Init() {
Namespace = &namespace{}
Config = &config{}
// 初始化内存存储
Storage = &storage{
lock: nil,
namespaceTable: nil,
namespaceIDTable: nil,
namespaceIDToNameTable: nil,
namespaceConfigKeyTable: nil,
configTable: nil,
}
Storage.lock, _ = easylock.NewSegment(32)
Storage.namespaceTable, _ = easymap.NewSegment(32, true)
Storage.namespaceIDTable, _ = easymap.NewSegment(32, true)
Storage.namespaceIDToNameTable, _ = easymap.NewSegment(32, true)
Storage.namespaceConfigKeyTable, _ = easymap.NewSegment(32, true)
Storage.configTable, _ = easymap.NewSegment(128, true)
if err := Storage.InitNamespace(); nil != err {
panic("memory namespace init fail")
}
if err := Storage.InitConfig(); nil != err {
panic("memory config init fail")
}
go Storage.TimerUpdate(0)
}

203
manager/namespace.go Normal file
View File

@ -0,0 +1,203 @@
// Package manager ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:39 下午 2021/8/8
package manager
import (
"errors"
"fmt"
"time"
"git.zhangdeman.cn/zhangdeman/center-config/dao"
"git.zhangdeman.cn/zhangdeman/center-config/define/model"
"git.zhangdeman.cn/zhangdeman/center-config/define/form"
"github.com/gin-gonic/gin"
)
type namespace struct {
base
}
// Create 创建命名空间
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:18 下午 2021/8/9
func (n *namespace) Create(createForm *form.CreateNamespace) error {
var (
err error
namespaceInfo *model.Namespace
)
// 查询namespace是否已经存在
if _, err = dao.Namespace.GetDetailByNamespace(createForm.Namespace); nil == err {
return errors.New("namespace " + createForm.Namespace + " is already exist!")
}
// 写库
tx := dao.Namespace.Begin()
if nil != tx.Error {
return tx.Error
}
// 创建命名空间
namespaceInfo = &model.Namespace{
Namespace: createForm.Namespace,
Name: createForm.Name,
Description: createForm.Description,
Status: model.NamespaceStatusWaitActive,
CreateUserID: createForm.CreateUserID,
ModifyUserID: createForm.CreateUserID,
CreateTime: time.Now().Format("2006-01-02 15:04:05"),
ModifyTime: time.Now().Format("2006-01-02 15:04:05"),
}
if err = dao.Namespace.CreateNewData(tx, namespaceInfo, &dao.Option{DBTable: "namespace"}); nil != err {
_ = dao.Namespace.Rollback(tx)
return err
}
// 记录日志
logData := n.GetLogData(namespaceInfo.ID, 0, namespaceInfo.CreateUserID, model.LogTypeCreateNamespace, "新建命名空间")
logData.AfterValue = namespaceInfo.Namespace
if err = dao.Log.CreateNewData(tx, logData, &dao.Option{DBTable: "log"}); nil != err {
_ = dao.Namespace.Rollback(tx)
return err
}
if err = dao.Namespace.Commit(tx); nil != err {
_ = dao.Namespace.Rollback(tx)
return err
}
return nil
}
// ValidateCreateForm 创建命名空间表单校验与预处理
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:36 下午 2021/8/9
func (n *namespace) ValidateCreateForm(ctx *gin.Context) (*form.CreateNamespace, error) {
var (
err error
createForm form.CreateNamespace
)
if err = n.ParsePostForm(ctx, &createForm); nil != err {
return nil, err
}
// 表单校验
if len(createForm.Namespace) == 0 {
return nil, errors.New("namespace field is required")
}
if len(createForm.Name) == 0 {
return nil, errors.New("name field is required")
}
if len(createForm.Description) == 0 {
createForm.Description = createForm.Name
}
if len(createForm.CreateUserID) == 0 {
return nil, errors.New("create_user_id field is required")
}
// 表单校验 end
return &createForm, nil
}
// Active 激活命名空间
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:14 下午 2021/8/9
func (n *namespace) Active(activeForm *form.ActiveNamespace) error {
if activeForm.NamespaceID <= 0 {
activeForm.NamespaceID = n.GetNamespaceIDByNamespace(activeForm.Namespace)
}
var err error
tx := dao.Namespace.Begin()
if nil != tx.Error {
return tx.Error
}
if err = dao.Namespace.UpdateData(tx, &model.Namespace{Status: model.NamespaceStatusNormal}, map[string]interface{}{"id": activeForm.NamespaceID, "status": model.NamespaceStatusWaitActive}, &dao.Option{Limit: 1, DBTable: "namespace"}); nil != err {
_ = dao.Namespace.Rollback(tx)
return err
}
logData := n.GetLogData(activeForm.NamespaceID, 0, activeForm.UpdateUserID, model.LogTypeActiveNamespace, "激活命名空间")
logData.BeforeValue = fmt.Sprintf("%v", model.NamespaceStatusWaitActive)
logData.AfterValue = fmt.Sprintf("%v", model.NamespaceStatusNormal)
if err = dao.Log.CreateNewData(tx, logData, nil); nil != err {
_ = dao.Namespace.Rollback(tx)
return err
}
if err = dao.Namespace.Commit(tx); nil != err {
_ = dao.Namespace.Rollback(tx)
return err
}
return nil
}
// ValidateActiveForm 验证激活命名空间表单
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:14 下午 2021/8/9
func (n *namespace) ValidateActiveForm(ctx *gin.Context) (*form.ActiveNamespace, error) {
var (
err error
updateForm form.ActiveNamespace
)
if err = n.ParsePostForm(ctx, &updateForm); nil != err {
return nil, err
}
if updateForm.NamespaceID <= 0 {
if namespaceDetail, err := dao.Namespace.GetDetailByNamespace(updateForm.Namespace); nil == err {
updateForm.NamespaceID = namespaceDetail.ID
}
}
if updateForm.NamespaceID <= 0 {
return nil, errors.New("namespace_id is required")
}
if len(updateForm.UpdateUserID) == 0 {
return nil, errors.New("update_user_id is required")
}
return &updateForm, nil
}
// GetNamespaceDetail 获取namespace详情
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:07 上午 2021/8/10
func (n *namespace) GetNamespaceDetail(namespaceID int64, namespaceName string) (*model.Namespace, error) {
var (
namespaceInfo model.Namespace
err error
)
// 查询namespace
if namespaceID > 0 {
err = dao.Namespace.Detail(dao.DBInstance, &model.Namespace{ID: namespaceID}, &namespaceInfo, nil)
} else {
err = dao.Namespace.Detail(dao.DBInstance, &model.Namespace{Namespace: namespaceName}, &namespaceInfo, nil)
}
return &namespaceInfo, err
}
// GetAllNormalNamespace 获取
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:51 下午 2021/8/10
func (n *namespace) GetAllNamespaceByStatus(status int) ([]*model.Namespace, error) {
var (
list []*model.Namespace
err error
)
if err = dao.Namespace.Select(dao.DBInstance, &model.Namespace{Status: status}, &list, nil); nil != err {
return make([]*model.Namespace, 0), err
}
return list, nil
}

252
manager/storage.go Normal file
View File

@ -0,0 +1,252 @@
// Package manager...
//
// Description : 内存的数据存储
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2021-08-10 9:47 下午
package manager
import (
"errors"
"fmt"
"sync"
"time"
"git.zhangdeman.cn/zhangdeman/center-config/define/model"
"git.zhangdeman.cn/zhangdeman/gopkg/easylock"
"git.zhangdeman.cn/zhangdeman/gopkg/easymap"
)
type storage struct {
// 数据锁
lock easylock.EasyLock
// 命名空间表, 唯一标识 namespace 做key
namespaceTable easymap.EasyMap
// 命名空间表, 主键 ID 做key
namespaceIDTable easymap.EasyMap
// 主键 ID 和命名空间的映射关系
namespaceIDToNameTable easymap.EasyMap
// 命名空间下有哪些配置项
namespaceConfigKeyTable easymap.EasyMap
// 全局的配置项
configTable easymap.EasyMap
}
// InitNamespace 预加载命名空间
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:48 下午 2021/8/10
func (s *storage) InitNamespace() error {
var (
namespaceList []*model.Namespace
err error
)
if namespaceList, err = Namespace.GetAllNamespaceByStatus(model.NamespaceStatusNormal); nil != err {
return err
}
// 存入内存
for _, item := range namespaceList {
s.CreateNamespace(item)
}
return nil
}
// InitConfig 预加载配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 9:49 下午 2021/8/10
func (s *storage) InitConfig() error {
var (
allConfigList []*model.Config
err error
)
if allConfigList, err = Config.GetAllConfig(); nil != err {
return err
}
// 按照namespace进行分组
groupConfig := make(map[int64][]string)
// 存入内存
for _, conf := range allConfigList {
if _, exist := groupConfig[conf.NamespaceID]; !exist {
groupConfig[conf.NamespaceID] = make([]string, 0)
}
namespaceName, _ := s.namespaceIDToNameTable.GetString(conf.NamespaceID)
configKey := s.CreateConfig(namespaceName, conf.Field, conf.Value)
groupConfig[conf.NamespaceID] = append(groupConfig[conf.NamespaceID], configKey)
}
// 维护内存中命名空间配置项集合
for namespaceID, keyList := range groupConfig {
s.namespaceConfigKeyTable.Set(namespaceID, keyList)
}
return nil
}
// CreateNamespace 创建内存的命名空间
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:23 上午 2021/8/11
func (s *storage) CreateNamespace(namespaceInfo *model.Namespace) {
s.namespaceTable.Set(namespaceInfo.Namespace, namespaceInfo)
s.namespaceIDTable.Set(namespaceInfo.ID, namespaceInfo)
s.namespaceIDToNameTable.Set(namespaceInfo.ID, namespaceInfo.Namespace)
}
// GetNamespace 获取命名空间信息
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2:16 下午 2021/11/30
func (s *storage) GetNamespace(np string) (*model.Namespace, error) {
var (
result interface{}
err error
)
if result, err = s.namespaceTable.Get(np); nil != err {
return nil, err
}
v, ok := result.(*model.Namespace)
if !ok {
return nil, errors.New("namespace info parse error")
}
return v, nil
}
// CreateConfig 创建内存配置(已存在,自动更新)
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:48 上午 2021/8/11
func (s *storage) CreateConfig(namespaceName string, field string, value string) string {
confKey := s.getConfigKey(namespaceName, field)
s.configTable.Set(confKey, value)
return confKey
}
// DeleteNamespace 删除内存的命名空间
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:22 上午 2021/8/11
func (s *storage) DeleteNamespace(namespaceName string, namespaceID int64) {
s.namespaceTable.Del(namespaceName)
s.namespaceIDToNameTable.Del(namespaceID)
s.namespaceIDTable.Del(namespaceID)
// 查询命名空间的配置
var confKeyList []string
_ = s.configTable.GetWithReceiver(namespaceID, &confKeyList)
// 删除命名空间对应内存配置
for _, key := range confKeyList {
s.configTable.Del(key)
}
}
// UpdateConfig 更新内存配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:29 上午 2021/8/11
func (s *storage) UpdateConfig(namespaceInfo *model.Namespace, wg *sync.WaitGroup) {
if nil != wg {
wg.Done()
}
// 查询命名空间的配置
var (
confKeyList []string
configList []*model.Config
err error
)
// 当前内存数据表
_ = s.namespaceConfigKeyTable.GetWithReceiver(namespaceInfo.ID, &confKeyList)
currentMemConfigTable := make(map[string]bool)
for _, confKey := range confKeyList {
currentMemConfigTable[confKey] = true
}
if configList, err = Config.GetNamespaceConfig(namespaceInfo.ID); nil != err {
// 出了异常, 不处理内存数据
return
}
newConfKeyList := make([]string, 0)
for _, item := range configList {
confKey := s.CreateConfig(namespaceInfo.Namespace, item.Field, item.Value)
newConfKeyList = append(newConfKeyList, confKey)
delete(currentMemConfigTable, confKey)
}
// 执行完 currentMemConfigTable 还有数据, 说明是已被删除数据, 从内存移除
for confKey := range currentMemConfigTable {
s.configTable.Del(confKey)
}
// 更新命名空间维护的confKey
s.namespaceConfigKeyTable.Set(namespaceInfo.ID, newConfKeyList)
}
// GetConf 读取内存配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 1:09 上午 2021/8/11
func (s *storage) GetConf(namespaceName string, field string) string {
confKey := s.getConfigKey(namespaceName, field)
// 前置已经保证写入内存的一定是字符串
confValue, err := s.configTable.GetString(confKey)
if nil != err {
return ""
}
return confValue
}
// TimerUpdate 定时更新
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 12:09 上午 2021/8/11
func (s *storage) TimerUpdate(timer int64) {
if timer <= 0 {
// 默认 10s 更新一次
timer = 10
}
for {
time.Sleep(time.Duration(timer) * time.Second)
// 计时器到期
var (
namespaceList []*model.Namespace
err error
)
if namespaceList, err = Namespace.GetAllNamespaceByStatus(model.NamespaceStatusNormal); nil != err {
break
}
namespaceTable := make(map[string]int64)
for _, item := range namespaceList {
namespaceTable[item.Namespace] = item.ID
}
// 当前内存数据
memData := s.namespaceIDToNameTable.GetAll()
for namespaceID, namespaceName := range memData {
if _, exist := namespaceTable[fmt.Sprintf("%v", namespaceID)]; !exist {
// 更新后不存在, 删除
id, _ := namespaceID.(int64)
name, _ := namespaceName.(string)
s.DeleteNamespace(name, id)
}
}
wg := &sync.WaitGroup{}
wg.Add(len(namespaceList))
for _, namespaceInfo := range namespaceList {
go s.UpdateConfig(namespaceInfo, wg)
}
}
}
// getConfigKey 获取内存配置key
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 1:08 上午 2021/8/11
func (s *storage) getConfigKey(namespaceName string, field string) string {
return fmt.Sprintf("%v_%v", namespaceName, field)
}