From 0215d9ff8c6771bc398149fbaca35ae3862aa329 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Fri, 14 Jul 2023 12:40:13 +0800 Subject: [PATCH 01/10] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20server.Server?= =?UTF-8?q?=20=E9=83=A8=E5=88=86=E4=BA=8B=E4=BB=B6=E4=B8=AD=E5=8F=91?= =?UTF-8?q?=E7=94=9F=20panic=20=E5=AF=BC=E8=87=B4=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E9=80=80=E5=87=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/event.go | 89 +++++++++++++++++++++++++++++------------------ server/message.go | 12 +++++++ server/server.go | 8 +++++ 3 files changed, 75 insertions(+), 34 deletions(-) diff --git a/server/event.go b/server/event.go index 02b2402..537d472 100644 --- a/server/event.go +++ b/server/event.go @@ -6,6 +6,7 @@ import ( "github.com/kercylan98/minotaur/utils/runtimes" "go.uber.org/zap" "reflect" + "runtime/debug" "sync" "time" ) @@ -45,9 +46,11 @@ func (slf *event) RegStopEvent(handle StopEventHandle) { } func (slf *event) OnStopEvent() { - for _, handle := range slf.stopEventHandles { - handle(slf.Server) - } + PushSystemMessage(slf.Server, func() { + for _, handle := range slf.stopEventHandles { + handle(slf.Server) + } + }) } // RegConsoleCommandEvent 控制台收到指令时将立即执行被注册的事件处理函数 @@ -69,20 +72,22 @@ func (slf *event) RegConsoleCommandEvent(command string, handle ConsoleCommandEv } func (slf *event) OnConsoleCommandEvent(command string) { - handles, exist := slf.consoleCommandEventHandles[command] - if !exist { - switch command { - case "exit", "quit", "close", "shutdown", "EXIT", "QUIT", "CLOSE", "SHUTDOWN": - log.Info("Console", zap.String("Receive", command), zap.String("Action", "Shutdown")) - slf.Server.shutdown(nil) - return + PushSystemMessage(slf.Server, func() { + handles, exist := slf.consoleCommandEventHandles[command] + if !exist { + switch command { + case "exit", "quit", "close", "shutdown", "EXIT", "QUIT", "CLOSE", "SHUTDOWN": + log.Info("Console", zap.String("Receive", command), zap.String("Action", "Shutdown")) + slf.Server.shutdown(nil) + return + } + log.Warn("Server", zap.String("Command", "unregistered")) + } else { + for _, handle := range handles { + handle(slf.Server) + } } - log.Warn("Server", zap.String("Command", "unregistered")) - } else { - for _, handle := range handles { - handle(slf.Server) - } - } + }) } // RegStartBeforeEvent 在服务器初始化完成启动前立刻执行被注册的事件处理函数 @@ -92,6 +97,12 @@ func (slf *event) RegStartBeforeEvent(handle StartBeforeEventHandle) { } func (slf *event) OnStartBeforeEvent() { + defer func() { + if err := recover(); err != nil { + log.Error("Server", zap.String("OnStartBeforeEvent", fmt.Sprintf("%v", err))) + debug.PrintStack() + } + }() for _, handle := range slf.startBeforeEventHandles { handle(slf.Server) } @@ -104,9 +115,11 @@ func (slf *event) RegStartFinishEvent(handle StartFinishEventHandle) { } func (slf *event) OnStartFinishEvent() { - for _, handle := range slf.startFinishEventHandles { - handle(slf.Server) - } + PushSystemMessage(slf.Server, func() { + for _, handle := range slf.startFinishEventHandles { + handle(slf.Server) + } + }) } // RegConnectionClosedEvent 在连接关闭后将立刻执行被注册的事件处理函数 @@ -119,11 +132,13 @@ func (slf *event) RegConnectionClosedEvent(handle ConnectionClosedEventHandle) { } func (slf *event) OnConnectionClosedEvent(conn *Conn, err any) { - for _, handle := range slf.connectionClosedEventHandles { - handle(slf.Server, conn, err) - } - conn.Close() - slf.Server.online.Delete(conn.GetID()) + PushSystemMessage(slf.Server, func() { + for _, handle := range slf.connectionClosedEventHandles { + handle(slf.Server, conn, err) + } + conn.Close() + slf.Server.online.Delete(conn.GetID()) + }) } // RegConnectionOpenedEvent 在连接打开后将立刻执行被注册的事件处理函数 @@ -136,10 +151,12 @@ func (slf *event) RegConnectionOpenedEvent(handle ConnectionOpenedEventHandle) { } func (slf *event) OnConnectionOpenedEvent(conn *Conn) { - slf.Server.online.Set(conn.GetID(), conn) - for _, handle := range slf.connectionOpenedEventHandles { - handle(slf.Server, conn) - } + PushSystemMessage(slf.Server, func() { + slf.Server.online.Set(conn.GetID(), conn) + for _, handle := range slf.connectionOpenedEventHandles { + handle(slf.Server, conn) + } + }) } // RegConnectionReceivePacketEvent 在接收到数据包时将立刻执行被注册的事件处理函数 @@ -176,9 +193,11 @@ func (slf *event) RegMessageErrorEvent(handle MessageErrorEventHandle) { } func (slf *event) OnMessageErrorEvent(message *Message, err error) { - for _, handle := range slf.messageErrorEventHandles { - handle(slf.Server, message, err) - } + PushSystemMessage(slf.Server, func() { + for _, handle := range slf.messageErrorEventHandles { + handle(slf.Server, message, err) + } + }) } // RegMessageLowExecEvent 在处理消息缓慢时将立即执行被注册的事件处理函数 @@ -188,9 +207,11 @@ func (slf *event) RegMessageLowExecEvent(handle MessageLowExecEventHandle) { } func (slf *event) OnMessageLowExecEvent(message *Message, cost time.Duration) { - for _, handle := range slf.messageLowExecEventHandles { - handle(slf.Server, message, cost) - } + PushSystemMessage(slf.Server, func() { + for _, handle := range slf.messageLowExecEventHandles { + handle(slf.Server, message, cost) + } + }) } func (slf *event) check() { diff --git a/server/message.go b/server/message.go index 8c9d5cb..6bac3ae 100644 --- a/server/message.go +++ b/server/message.go @@ -21,6 +21,9 @@ const ( // MessageTypeAsync 异步消息类型 MessageTypeAsync + + // MessageTypeSystem 系统消息类型 + MessageTypeSystem ) var messageNames = map[MessageType]string{ @@ -29,6 +32,7 @@ var messageNames = map[MessageType]string{ MessageTypeCross: "MessageTypeCross", MessageTypeTicker: "MessageTypeTicker", MessageTypeAsync: "MessageTypeAsync", + MessageTypeSystem: "MessageTypeSystem", } const ( @@ -146,6 +150,14 @@ func PushAsyncMessage(srv *Server, caller func() error, callback func(err error) srv.pushMessage(msg) } +// PushSystemMessage 向特定服务器中推送 MessageTypeSystem 消息 +func PushSystemMessage(srv *Server, handle func(), mark ...any) { + msg := srv.messagePool.Get() + msg.t = MessageTypeSystem + msg.attrs = append([]any{handle}, mark...) + srv.pushMessage(msg) +} + // SetMessagePacketVisualizer 设置消息可视化函数 // - 消息可视化将在慢消息等情况用于打印,使用自定消息可视化函数可以便于开发者进行调试 // - 默认的消息可视化函数将直接返回消息的字符串表示 diff --git a/server/server.go b/server/server.go index 162aafe..e0d2c61 100644 --- a/server/server.go +++ b/server/server.go @@ -114,6 +114,7 @@ func (slf *Server) Run(addr string) error { slf.event.check() slf.addr = addr var protoAddr = fmt.Sprintf("%s://%s", slf.network, slf.addr) + var messageInitFinish = make(chan struct{}, 1) var connectionInitHandle = func(callback func()) { slf.messagePool = synchronization.NewPool[*Message](slf.messagePoolSize, func() *Message { @@ -132,6 +133,7 @@ func (slf *Server) Run(addr string) error { go callback() } go func() { + messageInitFinish <- struct{}{} for message := range slf.messageChannel { slf.dispatchMessage(message) } @@ -312,6 +314,10 @@ func (slf *Server) Run(addr string) error { return ErrCanNotSupportNetwork } + <-messageInitFinish + close(messageInitFinish) + messageInitFinish = nil + fmt.Println("messageInitFinish") if slf.multiple == nil { log.Info("Server", zap.String(serverMark, "====================================================================")) log.Info("Server", zap.String(serverMark, "RunningInfo"), @@ -568,6 +574,8 @@ func (slf *Server) dispatchMessage(msg *Message) { }); err != nil { panic(err) } + case MessageTypeSystem: + attrs[0].(func())() default: log.Warn("Server", zap.String("not support message type", msg.t.String())) } From 1b9ec9f2b69b3d2eadbca05447b4d69d1a97a232 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Fri, 14 Jul 2023 17:41:41 +0800 Subject: [PATCH 02/10] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8D=20server.PushA?= =?UTF-8?q?syncMessage=20=E6=97=A0=E6=B3=95=E6=AD=A3=E7=A1=AE=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E5=9B=9E=E8=B0=83=E5=87=BD=E6=95=B0=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/server.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/server.go b/server/server.go index e0d2c61..344f66e 100644 --- a/server/server.go +++ b/server/server.go @@ -317,7 +317,6 @@ func (slf *Server) Run(addr string) error { <-messageInitFinish close(messageInitFinish) messageInitFinish = nil - fmt.Println("messageInitFinish") if slf.multiple == nil { log.Info("Server", zap.String(serverMark, "====================================================================")) log.Info("Server", zap.String(serverMark, "RunningInfo"), @@ -566,10 +565,11 @@ func (slf *Server) dispatchMessage(msg *Message) { slf.messagePool.Release(msg) } }() - if err := handle(); err != nil { - if cb { - callback(err) - } + err := handle() + if cb { + callback(err) + } else { + log.Error("Server", zap.String("MessageType", messageNames[msg.t]), zap.Any("error", err), zap.String("stack", string(debug.Stack()))) } }); err != nil { panic(err) From c1e3c65c1cba9edd91268c99943bce64b904b428 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Fri, 14 Jul 2023 20:41:44 +0800 Subject: [PATCH 03/10] =?UTF-8?q?style:=20=E5=8E=BB=E9=99=A4=E9=83=A8?= =?UTF-8?q?=E5=88=86=E6=97=A0=E7=94=A8=E5=AD=97=E6=AE=B5=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=95=B4=E4=BD=93=E5=8F=AF=E8=AF=BB=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/builtin/attrs.go | 2 +- planner/configexport/configexport.go | 4 +++- planner/configexport/internal/errors.go | 2 -- report/reporter_strategy.go | 8 ++++---- utils/asynchronous/map.go | 2 +- utils/file/file.go | 6 +++--- utils/file/file_test.go | 2 +- utils/geometry/navmesh/navmesh_example_test.go | 2 +- utils/hash/srot_map.go | 4 ++-- utils/maths/math.go | 2 +- utils/synchronization/map.go | 2 +- utils/synchronization/map_segment.go | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-) diff --git a/game/builtin/attrs.go b/game/builtin/attrs.go index 505bf17..04b2fcd 100644 --- a/game/builtin/attrs.go +++ b/game/builtin/attrs.go @@ -272,7 +272,7 @@ func (slf *Attrs) GetAttrInt64(id int) int64 { case int32: return int64(value) case int64: - return int64(value) + return value } return 0 } diff --git a/planner/configexport/configexport.go b/planner/configexport/configexport.go index 006c283..abffe9c 100644 --- a/planner/configexport/configexport.go +++ b/planner/configexport/configexport.go @@ -11,6 +11,7 @@ import ( "go.uber.org/zap" "os/exec" "path/filepath" + "runtime/debug" "strings" "text/template" ) @@ -39,11 +40,12 @@ func New(xlsxPath string) *ConfigExport { zap.String("Info", "Excluded non-configuration table files"), ) default: - log.ErrorHideStack("ConfigExport", + log.Error("ConfigExport", zap.String("File", xlsxPath), zap.String("Sheet", sheet.Name), zap.String("Info", "Excluded non-configuration table files"), ) + debug.PrintStack() } } else { if config == nil { diff --git a/planner/configexport/internal/errors.go b/planner/configexport/internal/errors.go index 2e2472f..2e8fbf3 100644 --- a/planner/configexport/internal/errors.go +++ b/planner/configexport/internal/errors.go @@ -9,8 +9,6 @@ var ( ErrReadConfigFailedWithName = errors.New("read config name failed, can not found position") ErrReadConfigFailedWithIndexCount = errors.New("read config index count failed, can not found position") ErrReadConfigFailedWithIndexCountLessThanZero = errors.New("read config index count failed, value less than zero") - ErrReadConfigFailedWithFieldPosition = errors.New("read config index count failed, field position exception") ErrReadConfigFailedWithNameDuplicate = errors.New("read config index count failed, duplicate field names") - ErrReadConfigFailedWithExportParamException = errors.New("read config index count failed, export param must is s or c or sc or cs") ErrReadConfigFailedWithIndexTypeException = errors.New("read config index count failed, the index type is only allowed to be the basic type") ) diff --git a/report/reporter_strategy.go b/report/reporter_strategy.go index d76143b..eecaaba 100644 --- a/report/reporter_strategy.go +++ b/report/reporter_strategy.go @@ -9,9 +9,9 @@ import ( // ReporterStrategy 上报器策略 type ReporterStrategy func(reporter *Reporter) -// ReportStrategyLoop 循环上报 +// StrategyLoop 循环上报 // - 将在创建后上报一次,并且在每隔一段时间后继续上报 -func ReportStrategyLoop(t time.Duration) ReporterStrategy { +func StrategyLoop(t time.Duration) ReporterStrategy { return func(reporter *Reporter) { reporter.ticker.Loop(fmt.Sprintf("ReportStrategyLoop_%d", t.Milliseconds()), timer.Instantly, t, timer.Forever, func() { if err := reporter.Report(); err != nil && reporter.errorHandle != nil { @@ -21,8 +21,8 @@ func ReportStrategyLoop(t time.Duration) ReporterStrategy { } } -// ReportStrategyFixedTime 将在每天的固定时间上报 -func ReportStrategyFixedTime(hour, min, sec int) ReporterStrategy { +// StrategyFixedTime 将在每天的固定时间上报 +func StrategyFixedTime(hour, min, sec int) ReporterStrategy { return func(reporter *Reporter) { now := time.Now() current := now.Unix() diff --git a/utils/asynchronous/map.go b/utils/asynchronous/map.go index a852ff1..36524a4 100644 --- a/utils/asynchronous/map.go +++ b/utils/asynchronous/map.go @@ -146,7 +146,7 @@ func (slf *Map[Key, Value]) rangeFree(handle func(key Key, value Value, skip fun func (slf *Map[Key, Value]) Keys() []Key { var s = make([]Key, 0, len(slf.data)) - for k, _ := range slf.data { + for k := range slf.data { s = append(s, k) } return s diff --git a/utils/file/file.go b/utils/file/file.go index c17936c..871eeb4 100644 --- a/utils/file/file.go +++ b/utils/file/file.go @@ -102,10 +102,10 @@ func LineCount(filePath string) int { return line } -// FilePaths 获取指定目录下的所有文件路径 +// Paths 获取指定目录下的所有文件路径 // - 包括了子目录下的文件 // - 不包含目录 -func FilePaths(dir string) []string { +func Paths(dir string) []string { var paths []string abs, err := filepath.Abs(dir) if err != nil { @@ -119,7 +119,7 @@ func FilePaths(dir string) []string { for _, file := range files { fileAbs := filepath.Join(abs, file.Name()) if file.IsDir() { - paths = append(paths, FilePaths(fileAbs)...) + paths = append(paths, Paths(fileAbs)...) continue } paths = append(paths, fileAbs) diff --git a/utils/file/file_test.go b/utils/file/file_test.go index 7f24ff4..ae45998 100644 --- a/utils/file/file_test.go +++ b/utils/file/file_test.go @@ -10,7 +10,7 @@ import ( func TestFilePaths(t *testing.T) { var line int var fileCount int - for _, path := range file.FilePaths(`D:\sources\minotaur`) { + for _, path := range file.Paths(`D:\sources\minotaur`) { if !strings.HasSuffix(path, ".go") { continue } diff --git a/utils/geometry/navmesh/navmesh_example_test.go b/utils/geometry/navmesh/navmesh_example_test.go index 5075147..2571a51 100644 --- a/utils/geometry/navmesh/navmesh_example_test.go +++ b/utils/geometry/navmesh/navmesh_example_test.go @@ -69,7 +69,7 @@ func ExampleNavMesh_FindPath() { for x := sx; x <= bx; x++ { for y := sy; y <= by; y++ { - fp.Put(geometry.NewPoint[int](int(x), int(y)), '+') + fp.Put(geometry.NewPoint[int](x, y), '+') } } } diff --git a/utils/hash/srot_map.go b/utils/hash/srot_map.go index 9df2975..a913413 100644 --- a/utils/hash/srot_map.go +++ b/utils/hash/srot_map.go @@ -55,7 +55,7 @@ func (slf *SortMap[K, V]) For(handle func(key K, value V) bool) { func (slf *SortMap[K, V]) ForSort(handle func(key K, value V) bool) { var indexes []int - for i, _ := range slf.s { + for i := range slf.s { indexes = append(indexes, i) } sort.Ints(indexes) @@ -85,7 +85,7 @@ func (slf *SortMap[K, V]) ToSlice() []V { func (slf *SortMap[K, V]) ToSliceSort() []V { var indexes []int - for i, _ := range slf.s { + for i := range slf.s { indexes = append(indexes, i) } sort.Ints(indexes) diff --git a/utils/maths/math.go b/utils/maths/math.go index 03ef7f4..991ddb6 100644 --- a/utils/maths/math.go +++ b/utils/maths/math.go @@ -27,7 +27,7 @@ func Pow(a, n int) int { if n == 1 { return a } - var result int = 1 + var result = 1 factor := a for n != 0 { if n&1 != 0 { diff --git a/utils/synchronization/map.go b/utils/synchronization/map.go index 947f35a..f1b0974 100644 --- a/utils/synchronization/map.go +++ b/utils/synchronization/map.go @@ -216,7 +216,7 @@ func (slf *Map[Key, Value]) Keys() []Key { defer slf.lock.RUnlock() } var s = make([]Key, 0, len(slf.data)) - for k, _ := range slf.data { + for k := range slf.data { s = append(s, k) } return s diff --git a/utils/synchronization/map_segment.go b/utils/synchronization/map_segment.go index 853bd44..414e72e 100644 --- a/utils/synchronization/map_segment.go +++ b/utils/synchronization/map_segment.go @@ -183,7 +183,7 @@ func (slf *MapSegment[Key, Value]) RangeFree(handle func(key Key, value Value, s func (slf *MapSegment[Key, Value]) Keys() []Key { var s = make([]Key, 0, len(slf.cache)) slf.lock.RLock() - for k, _ := range slf.cache { + for k := range slf.cache { s = append(s, k) } defer slf.lock.RUnlock() From 25ed712fc9ba1f18fe2c1ce5524e2917160ae295 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Fri, 14 Jul 2023 21:24:27 +0800 Subject: [PATCH 04/10] =?UTF-8?q?feat:=20super=20=E5=8C=85=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20match=20=E6=8E=A7=E5=88=B6=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/super/match.go | 34 ++++++++++++++++++++++++++++++++++ utils/super/match_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 utils/super/match.go create mode 100644 utils/super/match_test.go diff --git a/utils/super/match.go b/utils/super/match.go new file mode 100644 index 0000000..4c83a8b --- /dev/null +++ b/utils/super/match.go @@ -0,0 +1,34 @@ +package super + +import "reflect" + +// Matcher 匹配器 +type Matcher[Value, Result any] struct { + value Value + r Result + d bool +} + +// Match 匹配 +func Match[Value, Result any](value Value) *Matcher[Value, Result] { + return &Matcher[Value, Result]{ + value: value, + } +} + +// Case 匹配 +func (slf *Matcher[Value, Result]) Case(value Value, result Result) *Matcher[Value, Result] { + if !slf.d && reflect.DeepEqual(slf.value, value) { + slf.r = result + slf.d = true + } + return slf +} + +// Default 默认 +func (slf *Matcher[Value, Result]) Default(value Result) Result { + if slf.d { + return slf.r + } + return value +} diff --git a/utils/super/match_test.go b/utils/super/match_test.go new file mode 100644 index 0000000..3f094c0 --- /dev/null +++ b/utils/super/match_test.go @@ -0,0 +1,24 @@ +package super_test + +import ( + "github.com/kercylan98/minotaur/utils/super" + . "github.com/smartystreets/goconvey/convey" + "testing" +) + +func TestMatch(t *testing.T) { + Convey("TestMatch", t, func() { + So(super.Match[int, string](1). + Case(1, "a"). + Case(2, "b"). + Default("c"), ShouldEqual, "a") + So(super.Match[int, string](2). + Case(1, "a"). + Case(2, "b"). + Default("c"), ShouldEqual, "b") + So(super.Match[int, string](3). + Case(1, "a"). + Case(2, "b"). + Default("c"), ShouldEqual, "c") + }) +} From 8e2b4ebc89ed56a3e1e091a8905641ee3461f1c2 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Sat, 15 Jul 2023 09:36:24 +0800 Subject: [PATCH 05/10] =?UTF-8?q?other:=20=E6=97=A5=E5=BF=97=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E8=B0=83=E7=94=A8=E7=94=B1=20zap.Field=20=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=20log.Field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config.go | 3 +- game/builtin/room.go | 5 ++- game/builtin/world.go | 9 +++-- notify/manager.go | 7 ++-- planner/configexport/configexport.go | 31 +++++++++-------- planner/configexport/example/config.go | 4 +-- planner/configexport/internal/template.go | 4 +-- server/cross/nats.go | 7 ++-- server/event.go | 31 +++++++++-------- server/gnet.go | 3 +- server/multiple.go | 11 +++--- server/options.go | 7 ++-- server/server.go | 41 +++++++++++------------ utils/log/field.go | 3 ++ utils/synchronization/pool.go | 3 +- 15 files changed, 80 insertions(+), 89 deletions(-) diff --git a/config/config.go b/config/config.go index a212b34..efadfd8 100644 --- a/config/config.go +++ b/config/config.go @@ -4,7 +4,6 @@ import ( jsonIter "github.com/json-iterator/go" "github.com/kercylan98/minotaur/utils/log" "github.com/kercylan98/minotaur/utils/timer" - "go.uber.org/zap" "os" "path/filepath" "sync" @@ -51,7 +50,7 @@ func Load() { return err } if err = json.Unmarshal(bytes, &config); err == nil && isInit { - log.Info("Config", zap.String("Name", filename), zap.Bool("LoadSuccess", true)) + log.Info("Config", log.String("Name", filename), log.Bool("LoadSuccess", true)) } return err }) diff --git a/game/builtin/room.go b/game/builtin/room.go index 546db04..457d5b0 100644 --- a/game/builtin/room.go +++ b/game/builtin/room.go @@ -5,7 +5,6 @@ import ( "github.com/kercylan98/minotaur/utils/asynchronous" "github.com/kercylan98/minotaur/utils/hash" "github.com/kercylan98/minotaur/utils/log" - "go.uber.org/zap" ) // NewRoom 创建一个默认的内置游戏房间 Room @@ -90,7 +89,7 @@ func (slf *Room[PlayerID, Player]) Join(player Player) error { } slf.players.Set(playerId, player) if !exist { - log.Debug("Room.Join", zap.Any("guid", slf.GetGuid()), zap.Any("player", playerId)) + log.Debug("Room.Join", log.Any("guid", slf.GetGuid()), log.Any("player", playerId)) if slf.players.Size() == 1 && !slf.noMaster { slf.owner = playerId } @@ -105,7 +104,7 @@ func (slf *Room[PlayerID, Player]) Leave(id PlayerID) { if !exist { return } - log.Debug("Room.Leave", zap.Any("guid", slf.GetGuid()), zap.Any("player", id)) + log.Debug("Room.Leave", log.Any("guid", slf.GetGuid()), log.Any("player", id)) slf.OnPlayerLeaveRoomEvent(player) slf.players.Delete(id) } diff --git a/game/builtin/world.go b/game/builtin/world.go index 34d69c9..463b76d 100644 --- a/game/builtin/world.go +++ b/game/builtin/world.go @@ -5,7 +5,6 @@ import ( "github.com/kercylan98/minotaur/utils/hash" "github.com/kercylan98/minotaur/utils/log" "github.com/kercylan98/minotaur/utils/synchronization" - "go.uber.org/zap" "sync/atomic" ) @@ -103,7 +102,7 @@ func (slf *World[PlayerID, Player]) Join(player Player) error { if slf.players.Size() >= slf.playerLimit && slf.playerLimit > 0 { return ErrWorldPlayerLimit } - log.Debug("World.Join", zap.Int64("guid", slf.GetGuid()), zap.Any("player", player.GetID())) + log.Debug("World.Join", log.Int64("guid", slf.GetGuid()), log.Any("player", player.GetID())) slf.players.Set(player.GetID(), player) if actors := slf.playerActors.Get(player.GetID()); actors == nil { actors = synchronization.NewMap[int64, game.Actor]() @@ -118,7 +117,7 @@ func (slf *World[PlayerID, Player]) Leave(id PlayerID) { if !exist { return } - log.Debug("World.Leave", zap.Int64("guid", slf.GetGuid()), zap.Any("player", player.GetID())) + log.Debug("World.Leave", log.Int64("guid", slf.GetGuid()), log.Any("player", player.GetID())) slf.OnPlayerLeaveWorldEvent(player) slf.playerActors.Get(player.GetID()).Range(func(guid int64, actor game.Actor) { slf.OnActorAnnihilationEvent(actor) @@ -170,7 +169,7 @@ func (slf *World[PlayerID, Player]) RemoveActorOwner(guid int64) { } func (slf *World[PlayerID, Player]) Reset() { - log.Debug("World", zap.Int64("Reset", slf.guid)) + log.Debug("World", log.Int64("Reset", slf.guid)) slf.players.Clear() slf.playerActors.Range(func(id PlayerID, actors hash.Map[int64, game.Actor]) { actors.Clear() @@ -184,7 +183,7 @@ func (slf *World[PlayerID, Player]) Reset() { func (slf *World[PlayerID, Player]) Release() { if !slf.released.Swap(true) { - log.Debug("World", zap.Int64("Release", slf.guid)) + log.Debug("World", log.Int64("Release", slf.guid)) slf.OnWorldReleaseEvent() slf.Reset() slf.players = nil diff --git a/notify/manager.go b/notify/manager.go index a235d98..4c4829e 100644 --- a/notify/manager.go +++ b/notify/manager.go @@ -2,7 +2,6 @@ package notify import ( "github.com/kercylan98/minotaur/utils/log" - "go.uber.org/zap" "reflect" ) @@ -20,19 +19,19 @@ func NewManager(senders ...Sender) *Manager { case <-manager.closeChannel: close(manager.closeChannel) close(manager.notifyChannel) - log.Info("Manager", zap.String("state", "release")) + log.Info("Manager", log.String("state", "release")) return case notify := <-manager.notifyChannel: for _, sender := range manager.senders { if err := sender.Push(notify); err != nil { - log.Error("Manager", zap.String("sender", reflect.TypeOf(sender).String()), zap.Error(err)) + log.Error("Manager", log.String("sender", reflect.TypeOf(sender).String()), log.Err(err)) } } } } }() - log.Info("Manager", zap.String("state", "running")) + log.Info("Manager", log.String("state", "running")) return manager } diff --git a/planner/configexport/configexport.go b/planner/configexport/configexport.go index abffe9c..8db87d5 100644 --- a/planner/configexport/configexport.go +++ b/planner/configexport/configexport.go @@ -8,7 +8,6 @@ import ( "github.com/kercylan98/minotaur/utils/log" "github.com/kercylan98/minotaur/utils/str" "github.com/tealeg/xlsx" - "go.uber.org/zap" "os/exec" "path/filepath" "runtime/debug" @@ -29,21 +28,21 @@ func New(xlsxPath string) *ConfigExport { switch err { case internal.ErrReadConfigFailedSame: log.Warn("ConfigExport", - zap.String("File", xlsxPath), - zap.String("Sheet", sheet.Name), - zap.String("Info", "A configuration with the same name exists, skipped"), + log.String("File", xlsxPath), + log.String("Sheet", sheet.Name), + log.String("Info", "A configuration with the same name exists, skipped"), ) case internal.ErrReadConfigFailedIgnore: log.Info("ConfigExport", - zap.String("File", xlsxPath), - zap.String("Sheet", sheet.Name), - zap.String("Info", "Excluded non-configuration table files"), + log.String("File", xlsxPath), + log.String("Sheet", sheet.Name), + log.String("Info", "Excluded non-configuration table files"), ) default: log.Error("ConfigExport", - zap.String("File", xlsxPath), - zap.String("Sheet", sheet.Name), - zap.String("Info", "Excluded non-configuration table files"), + log.String("File", xlsxPath), + log.String("Sheet", sheet.Name), + log.String("Info", "Excluded non-configuration table files"), ) debug.PrintStack() } @@ -55,9 +54,9 @@ func New(xlsxPath string) *ConfigExport { ce.exist[config.Name] = true log.Info("ConfigExport", - zap.String("File", xlsxPath), - zap.String("Sheet", sheet.Name), - zap.String("Info", "Export successfully"), + log.String("File", xlsxPath), + log.String("Sheet", sheet.Name), + log.String("Info", "Export successfully"), ) } } @@ -84,9 +83,9 @@ func Merge(exports ...*ConfigExport) *ConfigExport { for _, config := range ce.configs { if _, ok := export.exist[config.Name]; ok { log.Warn("ConfigExport", - zap.String("File", ce.xlsxPath), - zap.String("Sheet", config.Name), - zap.String("Info", "A configuration with the same name exists, skipped"), + log.String("File", ce.xlsxPath), + log.String("Sheet", config.Name), + log.String("Info", "A configuration with the same name exists, skipped"), ) continue } diff --git a/planner/configexport/example/config.go b/planner/configexport/example/config.go index 7fedfdc..5d33937 100644 --- a/planner/configexport/example/config.go +++ b/planner/configexport/example/config.go @@ -25,12 +25,12 @@ func LoadConfig(handle func(filename string, config any) error) { var err error _IndexConfig = make(map[int]map[string]*IndexConfigDefine) if err = handle("IndexConfig.json", &_IndexConfig); err != nil { - log.Error("Config", zap.String("Name", "IndexConfig"), zap.Bool("Invalid", true), zap.Error(err)) + log.Err("Config", log.String("Name", "IndexConfig"), log.Bool("Invalid", true), log.Err(err)) } _EasyConfig = new(EasyConfigDefine) if err = handle("EasyConfig.json", _EasyConfig); err != nil { - log.Error("Config", zap.String("Name", "EasyConfig"), zap.Bool("Invalid", true), zap.Error(err)) + log.Err("Config", log.String("Name", "EasyConfig"), log.Bool("Invalid", true), log.Err(err)) } } diff --git a/planner/configexport/internal/template.go b/planner/configexport/internal/template.go index a332fff..f4a98e9 100644 --- a/planner/configexport/internal/template.go +++ b/planner/configexport/internal/template.go @@ -59,11 +59,11 @@ func LoadConfig(handle func(filename string, config any) error) { _{{$config.Name}} = {{$config.GetVariableGen}} {{if eq $config.IndexCount 0}} if err = handle("{{$config.Prefix}}{{$config.Name}}.json", _{{$config.Name}}); err != nil { - log.Error("Config", zap.String("Name", "{{$config.Name}}"), zap.Bool("Invalid", true), zap.Error(err)) + log.Err("Config", log.String("Name", "{{$config.Name}}"), log.Bool("Invalid", true), log.Err(err)) } {{else}} if err = handle("{{$config.Prefix}}{{$config.Name}}.json", &_{{$config.Name}}); err != nil { - log.Error("Config", zap.String("Name", "{{$config.Name}}"), zap.Bool("Invalid", true), zap.Error(err)) + log.Err("Config", log.String("Name", "{{$config.Name}}"), log.Bool("Invalid", true), log.Err(err)) } {{end}} {{end}} diff --git a/server/cross/nats.go b/server/cross/nats.go index 43b2f78..8b13d21 100644 --- a/server/cross/nats.go +++ b/server/cross/nats.go @@ -7,7 +7,6 @@ import ( "github.com/kercylan98/minotaur/utils/log" "github.com/kercylan98/minotaur/utils/synchronization" "github.com/nats-io/nats.go" - "go.uber.org/zap" "time" ) @@ -47,10 +46,10 @@ func (slf *Nats) Init(server *server.Server, packetHandle func(serverId int64, p nats.ReconnectWait(time.Second*5), nats.MaxReconnects(-1), nats.DisconnectErrHandler(func(conn *nats.Conn, err error) { - log.Error(nasMark, zap.String("info", "disconnect"), zap.Error(err)) + log.Error(nasMark, log.String("info", "disconnect"), log.Err(err)) }), nats.ReconnectHandler(func(conn *nats.Conn) { - log.Info(nasMark, zap.String("info", "reconnect")) + log.Info(nasMark, log.String("info", "reconnect")) }), ) } @@ -63,7 +62,7 @@ func (slf *Nats) Init(server *server.Server, packetHandle func(serverId int64, p message := slf.messagePool.Get() defer slf.messagePool.Release(message) if err := json.Unmarshal(msg.Data, &message); err != nil { - log.Error(nasMark, zap.Error(err)) + log.Error(nasMark, log.Err(err)) return } packetHandle(message.ServerId, message.Packet) diff --git a/server/event.go b/server/event.go index 537d472..c906c2d 100644 --- a/server/event.go +++ b/server/event.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/kercylan98/minotaur/utils/log" "github.com/kercylan98/minotaur/utils/runtimes" - "go.uber.org/zap" "reflect" "runtime/debug" "sync" @@ -42,7 +41,7 @@ type event struct { // RegStopEvent 服务器停止时将立即执行被注册的事件处理函数 func (slf *event) RegStopEvent(handle StopEventHandle) { slf.stopEventHandles = append(slf.stopEventHandles, handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnStopEvent() { @@ -68,7 +67,7 @@ func (slf *event) RegConsoleCommandEvent(command string, handle ConsoleCommandEv }() }) slf.consoleCommandEventHandles[command] = append(slf.consoleCommandEventHandles[command], handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnConsoleCommandEvent(command string) { @@ -77,11 +76,11 @@ func (slf *event) OnConsoleCommandEvent(command string) { if !exist { switch command { case "exit", "quit", "close", "shutdown", "EXIT", "QUIT", "CLOSE", "SHUTDOWN": - log.Info("Console", zap.String("Receive", command), zap.String("Action", "Shutdown")) + log.Info("Console", log.String("Receive", command), log.String("Action", "Shutdown")) slf.Server.shutdown(nil) return } - log.Warn("Server", zap.String("Command", "unregistered")) + log.Warn("Server", log.String("Command", "unregistered")) } else { for _, handle := range handles { handle(slf.Server) @@ -93,13 +92,13 @@ func (slf *event) OnConsoleCommandEvent(command string) { // RegStartBeforeEvent 在服务器初始化完成启动前立刻执行被注册的事件处理函数 func (slf *event) RegStartBeforeEvent(handle StartBeforeEventHandle) { slf.startBeforeEventHandles = append(slf.startBeforeEventHandles, handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnStartBeforeEvent() { defer func() { if err := recover(); err != nil { - log.Error("Server", zap.String("OnStartBeforeEvent", fmt.Sprintf("%v", err))) + log.Error("Server", log.String("OnStartBeforeEvent", fmt.Sprintf("%v", err))) debug.PrintStack() } }() @@ -111,7 +110,7 @@ func (slf *event) OnStartBeforeEvent() { // RegStartFinishEvent 在服务器启动完成时将立刻执行被注册的事件处理函数 func (slf *event) RegStartFinishEvent(handle StartFinishEventHandle) { slf.startFinishEventHandles = append(slf.startFinishEventHandles, handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnStartFinishEvent() { @@ -128,7 +127,7 @@ func (slf *event) RegConnectionClosedEvent(handle ConnectionClosedEventHandle) { panic(ErrNetworkIncompatibleHttp) } slf.connectionClosedEventHandles = append(slf.connectionClosedEventHandles, handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnConnectionClosedEvent(conn *Conn, err any) { @@ -147,7 +146,7 @@ func (slf *event) RegConnectionOpenedEvent(handle ConnectionOpenedEventHandle) { panic(ErrNetworkIncompatibleHttp) } slf.connectionOpenedEventHandles = append(slf.connectionOpenedEventHandles, handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnConnectionOpenedEvent(conn *Conn) { @@ -165,7 +164,7 @@ func (slf *event) RegConnectionReceivePacketEvent(handle ConnectionReceivePacket panic(ErrNetworkIncompatibleHttp) } slf.connectionReceivePacketEventHandles = append(slf.connectionReceivePacketEventHandles, handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnConnectionReceivePacketEvent(conn *Conn, packet Packet) { @@ -177,7 +176,7 @@ func (slf *event) OnConnectionReceivePacketEvent(conn *Conn, packet Packet) { // RegReceiveCrossPacketEvent 在接收到跨服数据包时将立即执行被注册的事件处理函数 func (slf *event) RegReceiveCrossPacketEvent(handle ReceiveCrossPacketEventHandle) { slf.receiveCrossPacketEventHandles = append(slf.receiveCrossPacketEventHandles, handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnReceiveCrossPacketEvent(serverId int64, packet []byte) { @@ -189,7 +188,7 @@ func (slf *event) OnReceiveCrossPacketEvent(serverId int64, packet []byte) { // RegMessageErrorEvent 在处理消息发生错误时将立即执行被注册的事件处理函数 func (slf *event) RegMessageErrorEvent(handle MessageErrorEventHandle) { slf.messageErrorEventHandles = append(slf.messageErrorEventHandles, handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnMessageErrorEvent(message *Message, err error) { @@ -203,7 +202,7 @@ func (slf *event) OnMessageErrorEvent(message *Message, err error) { // RegMessageLowExecEvent 在处理消息缓慢时将立即执行被注册的事件处理函数 func (slf *event) RegMessageLowExecEvent(handle MessageLowExecEventHandle) { slf.messageLowExecEventHandles = append(slf.messageLowExecEventHandles, handle) - log.Info("Server", zap.String("RegEvent", runtimes.CurrentRunningFuncName()), zap.String("handle", reflect.TypeOf(handle).String())) + log.Info("Server", log.String("RegEvent", runtimes.CurrentRunningFuncName()), log.String("handle", reflect.TypeOf(handle).String())) } func (slf *event) OnMessageLowExecEvent(message *Message, cost time.Duration) { @@ -219,12 +218,12 @@ func (slf *event) check() { case NetworkHttp, NetworkGRPC: default: if len(slf.connectionReceivePacketEventHandles) == 0 { - log.Warn("Server", zap.String("ConnectionReceivePacketEvent", "invalid server, no packets processed")) + log.Warn("Server", log.String("ConnectionReceivePacketEvent", "invalid server, no packets processed")) } } if len(slf.receiveCrossPacketEventHandles) > 0 && slf.cross == nil { - log.Warn("Server", zap.String("ReceiveCrossPacketEvent", "invalid server, not register cross server")) + log.Warn("Server", log.String("ReceiveCrossPacketEvent", "invalid server, not register cross server")) } } diff --git a/server/gnet.go b/server/gnet.go index 73f9d57..06877eb 100644 --- a/server/gnet.go +++ b/server/gnet.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/kercylan98/minotaur/utils/log" "github.com/panjf2000/gnet" - "go.uber.org/zap" "time" ) @@ -23,7 +22,7 @@ func (slf *gNet) OnShutdown(server gnet.Server) { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() if err := gnet.Stop(ctx, fmt.Sprintf("%s://%s", slf.network, slf.addr)); err != nil { - log.Error("Server", zap.String("Minotaur GNet Server", "Shutdown"), zap.Error(err)) + log.Error("Server", log.String("Minotaur GNet Server", "Shutdown"), log.Err(err)) } } diff --git a/server/multiple.go b/server/multiple.go index e3ddad2..06a96f9 100644 --- a/server/multiple.go +++ b/server/multiple.go @@ -2,7 +2,6 @@ package server import ( "github.com/kercylan98/minotaur/utils/log" - "go.uber.org/zap" "os" "os/signal" "sync" @@ -60,14 +59,14 @@ func (slf *MultipleServer) Run() { } wait.Wait() - log.Info("Server", zap.String(serverMultipleMark, "====================================================================")) + log.Info("Server", log.String(serverMultipleMark, "====================================================================")) for _, server := range slf.servers { - log.Info("Server", zap.String(serverMultipleMark, "RunningInfo"), - zap.Any("network", server.network), - zap.String("listen", server.addr), + log.Info("Server", log.String(serverMultipleMark, "RunningInfo"), + log.Any("network", server.network), + log.String("listen", server.addr), ) } - log.Info("Server", zap.String(serverMultipleMark, "====================================================================")) + log.Info("Server", log.String(serverMultipleMark, "====================================================================")) systemSignal := make(chan os.Signal, 1) signal.Notify(systemSignal, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) diff --git a/server/options.go b/server/options.go index 610d35b..3039366 100644 --- a/server/options.go +++ b/server/options.go @@ -4,7 +4,6 @@ import ( "github.com/gin-contrib/pprof" "github.com/kercylan98/minotaur/utils/log" "github.com/kercylan98/minotaur/utils/timer" - "go.uber.org/zap" "google.golang.org/grpc" "reflect" "time" @@ -87,7 +86,7 @@ func WithDeadlockDetect(t time.Duration) Option { return func(srv *Server) { if t > 0 { srv.deadlockDetect = t - log.Info("DeadlockDetect", zap.String("Time", t.String())) + log.Info("DeadlockDetect", log.String("Time", t.String())) } } } @@ -153,11 +152,11 @@ func WithCross(crossName string, serverId int64, cross Cross) Option { srv.pushMessage(msg) }) if err != nil { - log.Info("Cross", zap.Int64("ServerID", serverId), zap.String("Cross", reflect.TypeOf(cross).String()), zap.String("State", "WaitNatsRun")) + log.Info("Cross", log.Int64("ServerID", serverId), log.String("Cross", reflect.TypeOf(cross).String()), log.String("State", "WaitNatsRun")) time.Sleep(1 * time.Second) goto start } - log.Info("Cross", zap.Int64("ServerID", serverId), zap.String("Cross", reflect.TypeOf(cross).String())) + log.Info("Cross", log.Int64("ServerID", serverId), log.String("Cross", reflect.TypeOf(cross).String())) } } } diff --git a/server/server.go b/server/server.go index 344f66e..e89b0c2 100644 --- a/server/server.go +++ b/server/server.go @@ -14,7 +14,6 @@ import ( "github.com/panjf2000/gnet" "github.com/panjf2000/gnet/pkg/logging" "github.com/xtaci/kcp-go/v5" - "go.uber.org/zap" "google.golang.org/grpc" "net" "net/http" @@ -318,12 +317,12 @@ func (slf *Server) Run(addr string) error { close(messageInitFinish) messageInitFinish = nil if slf.multiple == nil { - log.Info("Server", zap.String(serverMark, "====================================================================")) - log.Info("Server", zap.String(serverMark, "RunningInfo"), - zap.Any("network", slf.network), - zap.String("listen", slf.addr), + log.Info("Server", log.String(serverMark, "====================================================================")) + log.Info("Server", log.String(serverMark, "RunningInfo"), + log.Any("network", slf.network), + log.String("listen", slf.addr), ) - log.Info("Server", zap.String(serverMark, "====================================================================")) + log.Info("Server", log.String(serverMark, "====================================================================")) slf.OnStartFinishEvent() signal.Notify(slf.systemSignal, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) @@ -422,15 +421,15 @@ func (slf *Server) shutdown(err error) { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() if shutdownErr := slf.httpServer.Shutdown(ctx); shutdownErr != nil { - log.Error("Server", zap.Error(shutdownErr)) + log.Error("Server", log.Err(shutdownErr)) } } if err != nil { if slf.multiple != nil { slf.multiple.RegExitEvent(func() { - log.Panic("Server", zap.Any("network", slf.network), zap.String("listen", slf.addr), - zap.String("action", "shutdown"), zap.String("state", "exception"), zap.Error(err)) + log.Panic("Server", log.Any("network", slf.network), log.String("listen", slf.addr), + log.String("action", "shutdown"), log.String("state", "exception"), log.Err(err)) }) for i, server := range slf.multiple.servers { if server.addr == slf.addr { @@ -439,12 +438,12 @@ func (slf *Server) shutdown(err error) { } } } else { - log.Panic("Server", zap.Any("network", slf.network), zap.String("listen", slf.addr), - zap.String("action", "shutdown"), zap.String("state", "exception"), zap.Error(err)) + log.Panic("Server", log.Any("network", slf.network), log.String("listen", slf.addr), + log.String("action", "shutdown"), log.String("state", "exception"), log.Err(err)) } } else { - log.Info("Server", zap.Any("network", slf.network), zap.String("listen", slf.addr), - zap.String("action", "shutdown"), zap.String("state", "normal")) + log.Info("Server", log.Any("network", slf.network), log.String("listen", slf.addr), + log.String("action", "shutdown"), log.String("state", "normal")) } if slf.gServer == nil { slf.closeChannel <- struct{}{} @@ -479,7 +478,7 @@ func (slf *Server) pushMessage(message *Message) { func (slf *Server) low(message *Message, present time.Time, expect time.Duration) { cost := time.Since(present) if cost > expect { - log.Warn("Server", zap.String("type", "low-message"), zap.String("cost", cost.String()), zap.String("message", message.String()), zap.Stack("stack")) + log.Warn("Server", log.String("type", "low-message"), log.String("cost", cost.String()), log.String("message", message.String()), log.Stack("stack")) slf.OnMessageLowExecEvent(message, cost) } } @@ -496,7 +495,7 @@ func (slf *Server) dispatchMessage(msg *Message) { select { case <-ctx.Done(): if err := ctx.Err(); err == context.DeadlineExceeded { - log.Warn("Server", zap.String("MessageType", messageNames[msg.t]), zap.Any("SuspectedDeadlock", msg.attrs)) + log.Warn("Server", log.String("MessageType", messageNames[msg.t]), log.Any("SuspectedDeadlock", msg.attrs)) } } }() @@ -506,7 +505,7 @@ func (slf *Server) dispatchMessage(msg *Message) { defer func() { if err := recover(); err != nil { stack := string(debug.Stack()) - log.Error("Server", zap.String("MessageType", messageNames[msg.t]), zap.Any("MessageAttrs", msg.attrs), zap.Any("error", err), zap.String("stack", stack)) + log.Error("Server", log.String("MessageType", messageNames[msg.t]), log.Any("MessageAttrs", msg.attrs), log.Any("error", err), log.String("stack", stack)) fmt.Println(stack) if e, ok := err.(error); ok { slf.OnMessageErrorEvent(msg, e) @@ -535,11 +534,11 @@ func (slf *Server) dispatchMessage(msg *Message) { err, action := attrs[0].(error), attrs[1].(MessageErrorAction) switch action { case MessageErrorActionNone: - log.Panic("Server", zap.Error(err)) + log.Panic("Server", log.Err(err)) case MessageErrorActionShutdown: slf.shutdown(err) default: - log.Warn("Server", zap.String("not support message error action", action.String())) + log.Warn("Server", log.String("not support message error action", action.String())) } case MessageTypeCross: slf.OnReceiveCrossPacketEvent(attrs[0].(int64), attrs[1].([]byte)) @@ -552,7 +551,7 @@ func (slf *Server) dispatchMessage(msg *Message) { defer func() { if err := recover(); err != nil { stack := string(debug.Stack()) - log.Error("Server", zap.String("MessageType", messageNames[msg.t]), zap.Any("error", err), zap.String("stack", stack)) + log.Error("Server", log.String("MessageType", messageNames[msg.t]), log.Any("error", err), log.String("stack", stack)) fmt.Println(stack) if e, ok := err.(error); ok { slf.OnMessageErrorEvent(msg, e) @@ -569,7 +568,7 @@ func (slf *Server) dispatchMessage(msg *Message) { if cb { callback(err) } else { - log.Error("Server", zap.String("MessageType", messageNames[msg.t]), zap.Any("error", err), zap.String("stack", string(debug.Stack()))) + log.Error("Server", log.String("MessageType", messageNames[msg.t]), log.Any("error", err), log.String("stack", string(debug.Stack()))) } }); err != nil { panic(err) @@ -577,6 +576,6 @@ func (slf *Server) dispatchMessage(msg *Message) { case MessageTypeSystem: attrs[0].(func())() default: - log.Warn("Server", zap.String("not support message type", msg.t.String())) + log.Warn("Server", log.String("not support message type", msg.t.String())) } } diff --git a/utils/log/field.go b/utils/log/field.go index 5919e66..80ef71e 100644 --- a/utils/log/field.go +++ b/utils/log/field.go @@ -156,4 +156,7 @@ var ( // Any 接受一个键和一个任意值,并选择将它们表示为字段的最佳方式,仅在必要时才回退到基于反射的方法。 // 由于 byteuint8 和 runeint32 是别名,Any 无法区分它们。为了尽量减少意外情况,[]byte 值被视为二进制 blob,字节值被视为 uint8,而 runes 始终被视为整数 Any = zap.Any + + // Err 是常见习语 NamedError("error", err) 的简写 + Err = zap.Error ) diff --git a/utils/synchronization/pool.go b/utils/synchronization/pool.go index e8a9da4..9b2ed24 100644 --- a/utils/synchronization/pool.go +++ b/utils/synchronization/pool.go @@ -2,7 +2,6 @@ package synchronization import ( "github.com/kercylan98/minotaur/utils/log" - "go.uber.org/zap" "sync" ) @@ -42,7 +41,7 @@ func (slf *Pool[T]) Get() T { slf.mutex.Unlock() slf.warn++ if slf.warn >= 100 { - log.Warn("Pool", zap.String("Get", "the number of buffer members is insufficient, consider whether it is due to unreleased or inappropriate buffer size")) + log.Warn("Pool", log.String("Get", "the number of buffer members is insufficient, consider whether it is due to unreleased or inappropriate buffer size")) slf.warn = 0 } return slf.generator() From 7e7a504421ba430537f3b70e78334fc30a4a1681 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Mon, 17 Jul 2023 13:28:17 +0800 Subject: [PATCH 06/10] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=20config=20?= =?UTF-8?q?=E5=92=8C=20configexport=20=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 配置加载包 config 更名为 configuration - 配置导出包 configexport 更名为 pce - 重构 config 包加载方式,采用加载器的方式,并且支持多加载器 - 重构 configexport 包,支持通过实现模板的方式导出不同格式的数据文件及结构文件 --- config/config.go | 89 ---- config/doc.go | 2 - configuration/config.go | 73 +++ configuration/doc.go | 2 + {config => configuration}/event.go | 2 +- configuration/loader.go | 10 + planner/configexport/configexport.go | 213 -------- .../configexport/configexport_example_test.go | 42 -- planner/configexport/doc.go | 2 - planner/configexport/example/EasyConfig.json | 17 - planner/configexport/example/IndexConfig.json | 68 --- planner/configexport/example/config.define.go | 75 --- planner/configexport/example/config.go | 63 --- planner/configexport/internal/config.go | 423 ---------------- planner/configexport/internal/errors.go | 14 - planner/configexport/internal/field.go | 146 ------ planner/configexport/internal/field_types.go | 304 ------------ planner/configexport/internal/postion.go | 13 - planner/configexport/internal/template.go | 108 ----- planner/pce/config.go | 16 + planner/pce/config_xlsx.go | 133 +++++ planner/pce/config_xlsx_test.go | 25 + planner/pce/data_tmpl.go | 7 + planner/pce/exporter.go | 53 ++ planner/pce/field.go | 25 + planner/pce/field_test.go | 11 + planner/pce/fields.go | 456 ++++++++++++++++++ planner/pce/loader.go | 175 +++++++ planner/{configexport => pce}/template.xlsx | Bin 14963 -> 14974 bytes planner/pce/tmpl.go | 7 + planner/pce/tmpl_field.go | 105 ++++ planner/pce/tmpl_struct.go | 38 ++ planner/pce/tmpls/golang.go | 174 +++++++ planner/pce/tmpls/json.go | 29 ++ planner/pce/tmpls/tmpls.go | 19 + utils/super/parse.go | 9 + 36 files changed, 1368 insertions(+), 1580 deletions(-) delete mode 100644 config/config.go delete mode 100644 config/doc.go create mode 100644 configuration/config.go create mode 100644 configuration/doc.go rename {config => configuration}/event.go (95%) create mode 100644 configuration/loader.go delete mode 100644 planner/configexport/configexport.go delete mode 100644 planner/configexport/configexport_example_test.go delete mode 100644 planner/configexport/doc.go delete mode 100644 planner/configexport/example/EasyConfig.json delete mode 100644 planner/configexport/example/IndexConfig.json delete mode 100644 planner/configexport/example/config.define.go delete mode 100644 planner/configexport/example/config.go delete mode 100644 planner/configexport/internal/config.go delete mode 100644 planner/configexport/internal/errors.go delete mode 100644 planner/configexport/internal/field.go delete mode 100644 planner/configexport/internal/field_types.go delete mode 100644 planner/configexport/internal/postion.go delete mode 100644 planner/configexport/internal/template.go create mode 100644 planner/pce/config.go create mode 100644 planner/pce/config_xlsx.go create mode 100644 planner/pce/config_xlsx_test.go create mode 100644 planner/pce/data_tmpl.go create mode 100644 planner/pce/exporter.go create mode 100644 planner/pce/field.go create mode 100644 planner/pce/field_test.go create mode 100644 planner/pce/fields.go create mode 100644 planner/pce/loader.go rename planner/{configexport => pce}/template.xlsx (69%) create mode 100644 planner/pce/tmpl.go create mode 100644 planner/pce/tmpl_field.go create mode 100644 planner/pce/tmpl_struct.go create mode 100644 planner/pce/tmpls/golang.go create mode 100644 planner/pce/tmpls/json.go create mode 100644 planner/pce/tmpls/tmpls.go create mode 100644 utils/super/parse.go diff --git a/config/config.go b/config/config.go deleted file mode 100644 index efadfd8..0000000 --- a/config/config.go +++ /dev/null @@ -1,89 +0,0 @@ -package config - -import ( - jsonIter "github.com/json-iterator/go" - "github.com/kercylan98/minotaur/utils/log" - "github.com/kercylan98/minotaur/utils/timer" - "os" - "path/filepath" - "sync" - "time" -) - -// LoadHandle 配置加载处理函数 -type LoadHandle func(handle func(filename string, config any) error) - -// RefreshHandle 配置刷新处理函数 -type RefreshHandle func() - -const ( - tickerLoadRefresh = "_tickerLoadRefresh" -) - -var ( - cLoadDir string - cTicker *timer.Ticker - cInterval time.Duration - cLoadHandle LoadHandle - cRefreshHandle RefreshHandle - json = jsonIter.ConfigCompatibleWithStandardLibrary - mutex sync.Mutex - isInit = true -) - -// Init 配置初始化 -func Init(loadDir string, loadHandle LoadHandle, refreshHandle RefreshHandle) { - cLoadDir = loadDir - cLoadHandle = loadHandle - cRefreshHandle = refreshHandle - Load() - Refresh() -} - -// Load 加载配置 -// - 加载后并不会刷新线上配置,需要执行 Refresh 函数对线上配置进行刷新 -func Load() { - mutex.Lock() - cLoadHandle(func(filename string, config any) error { - bytes, err := os.ReadFile(filepath.Join(cLoadDir, filename)) - if err != nil { - return err - } - if err = json.Unmarshal(bytes, &config); err == nil && isInit { - log.Info("Config", log.String("Name", filename), log.Bool("LoadSuccess", true)) - } - return err - }) - isInit = false - mutex.Unlock() -} - -// WithTickerLoad 通过定时器加载配置 -// - 通过定时器加载配置后,会自动刷新线上配置 -// - 调用该函数后将会立即加载并刷新一次配置,随后每隔 interval 时间加载并刷新一次配置 -func WithTickerLoad(ticker *timer.Ticker, interval time.Duration) { - if ticker != cTicker && cTicker != nil { - cTicker.StopTimer(tickerLoadRefresh) - } - cTicker = ticker - cInterval = interval - cTicker.Loop(tickerLoadRefresh, timer.Instantly, cInterval, timer.Forever, func() { - Load() - Refresh() - }) -} - -// StopTickerLoad 停止通过定时器加载配置 -func StopTickerLoad() { - if cTicker != nil { - cTicker.StopTimer(tickerLoadRefresh) - } -} - -// Refresh 刷新配置 -func Refresh() { - mutex.Lock() - cRefreshHandle() - OnConfigRefreshEvent() - mutex.Unlock() -} diff --git a/config/doc.go b/config/doc.go deleted file mode 100644 index 09bd1ab..0000000 --- a/config/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package config 基于配置导表功能实现的配置加载及刷新功能 -package config diff --git a/configuration/config.go b/configuration/config.go new file mode 100644 index 0000000..506a72d --- /dev/null +++ b/configuration/config.go @@ -0,0 +1,73 @@ +package configuration + +import ( + "github.com/kercylan98/minotaur/utils/log" + "github.com/kercylan98/minotaur/utils/timer" + "time" +) + +const ( + tickerLoadRefresh = "_tickerLoadRefresh" +) + +var ( + cTicker *timer.Ticker + cInterval time.Duration + cLoader []Loader +) + +// Init 配置初始化 +// - 在初始化后会立即加载配置 +func Init(loader ...Loader) { + cLoader = loader + Load() + Refresh() +} + +// Load 加载配置 +// - 加载后并不会刷新线上配置,需要执行 Refresh 函数对线上配置进行刷新 +func Load() { + defer func() { + if err := recover(); err != nil { + log.Error("Config", log.String("Action", "Load"), log.Err(err.(error))) + } + }() + for _, loader := range cLoader { + loader.Load() + } +} + +// Refresh 刷新配置 +func Refresh() { + defer func() { + if err := recover(); err != nil { + log.Error("Config", log.String("Action", "Refresh"), log.Err(err.(error))) + } + OnConfigRefreshEvent() + }() + for _, loader := range cLoader { + loader.Refresh() + } +} + +// WithTickerLoad 通过定时器加载配置 +// - 通过定时器加载配置后,会自动刷新线上配置 +// - 调用该函数后不会立即刷新,而是在 interval 后加载并刷新一次配置,之后每隔 interval 加载并刷新一次配置 +func WithTickerLoad(ticker *timer.Ticker, interval time.Duration) { + if ticker != cTicker && cTicker != nil { + cTicker.StopTimer(tickerLoadRefresh) + } + cTicker = ticker + cInterval = interval + cTicker.Loop(tickerLoadRefresh, cInterval, cInterval, timer.Forever, func() { + Load() + Refresh() + }) +} + +// StopTickerLoad 停止通过定时器加载配置 +func StopTickerLoad() { + if cTicker != nil { + cTicker.StopTimer(tickerLoadRefresh) + } +} diff --git a/configuration/doc.go b/configuration/doc.go new file mode 100644 index 0000000..a1249c9 --- /dev/null +++ b/configuration/doc.go @@ -0,0 +1,2 @@ +// Package configuration 基于配置导表功能实现的配置加载及刷新功能 +package configuration diff --git a/config/event.go b/configuration/event.go similarity index 95% rename from config/event.go rename to configuration/event.go index e4d1776..5a47932 100644 --- a/config/event.go +++ b/configuration/event.go @@ -1,4 +1,4 @@ -package config +package configuration // RefreshEventHandle 配置刷新事件处理函数 type RefreshEventHandle func() diff --git a/configuration/loader.go b/configuration/loader.go new file mode 100644 index 0000000..69723ff --- /dev/null +++ b/configuration/loader.go @@ -0,0 +1,10 @@ +package configuration + +// Loader 配置加载器 +type Loader interface { + // Load 加载配置 + // - 加载后并不会刷新线上配置,需要执行 Refresh 函数对线上配置进行刷新 + Load() + // Refresh 刷新线上配置 + Refresh() +} diff --git a/planner/configexport/configexport.go b/planner/configexport/configexport.go deleted file mode 100644 index 8db87d5..0000000 --- a/planner/configexport/configexport.go +++ /dev/null @@ -1,213 +0,0 @@ -package configexport - -import ( - "bytes" - "fmt" - "github.com/kercylan98/minotaur/planner/configexport/internal" - "github.com/kercylan98/minotaur/utils/file" - "github.com/kercylan98/minotaur/utils/log" - "github.com/kercylan98/minotaur/utils/str" - "github.com/tealeg/xlsx" - "os/exec" - "path/filepath" - "runtime/debug" - "strings" - "text/template" -) - -// New 创建一个导表配置 -func New(xlsxPath string) *ConfigExport { - ce := &ConfigExport{xlsxPath: xlsxPath, exist: make(map[string]bool)} - xlsxFile, err := xlsx.OpenFile(xlsxPath) - if err != nil { - panic(err) - } - for i := 0; i < len(xlsxFile.Sheets); i++ { - sheet := xlsxFile.Sheets[i] - if config, err := internal.NewConfig(sheet, ce.exist); err != nil { - switch err { - case internal.ErrReadConfigFailedSame: - log.Warn("ConfigExport", - log.String("File", xlsxPath), - log.String("Sheet", sheet.Name), - log.String("Info", "A configuration with the same name exists, skipped"), - ) - case internal.ErrReadConfigFailedIgnore: - log.Info("ConfigExport", - log.String("File", xlsxPath), - log.String("Sheet", sheet.Name), - log.String("Info", "Excluded non-configuration table files"), - ) - default: - log.Error("ConfigExport", - log.String("File", xlsxPath), - log.String("Sheet", sheet.Name), - log.String("Info", "Excluded non-configuration table files"), - ) - debug.PrintStack() - } - } else { - if config == nil { - continue - } - ce.configs = append(ce.configs, config) - ce.exist[config.Name] = true - - log.Info("ConfigExport", - log.String("File", xlsxPath), - log.String("Sheet", sheet.Name), - log.String("Info", "Export successfully"), - ) - } - } - return ce -} - -type ConfigExport struct { - xlsxPath string - configs []*internal.Config - exist map[string]bool -} - -// Merge 合并多个导表配置 -func Merge(exports ...*ConfigExport) *ConfigExport { - if len(exports) == 0 { - return nil - } - if len(exports) == 1 { - return exports[0] - } - var export = exports[0] - for i := 1; i < len(exports); i++ { - ce := exports[i] - for _, config := range ce.configs { - if _, ok := export.exist[config.Name]; ok { - log.Warn("ConfigExport", - log.String("File", ce.xlsxPath), - log.String("Sheet", config.Name), - log.String("Info", "A configuration with the same name exists, skipped"), - ) - continue - } - export.configs = append(export.configs, config) - export.exist[config.Name] = true - } - } - return export -} - -func (slf *ConfigExport) ExportClient(prefix, outputDir string) { - for _, config := range slf.configs { - config := config - if len(prefix) > 0 { - config.Prefix = fmt.Sprintf("%s.", prefix) - } - if err := file.WriterFile(filepath.Join(outputDir, fmt.Sprintf("%s%s.json", config.Prefix, config.Name)), config.JsonClient()); err != nil { - panic(err) - } - } -} - -func (slf *ConfigExport) ExportServer(prefix, outputDir string) { - for _, config := range slf.configs { - config := config - if len(prefix) > 0 { - config.Prefix = fmt.Sprintf("%s.", prefix) - } - if err := file.WriterFile(filepath.Join(outputDir, fmt.Sprintf("%s%s.json", config.Prefix, config.Name)), config.JsonServer()); err != nil { - panic(err) - } - } -} - -func (slf *ConfigExport) ExportGo(prefix, outputDir string) { - if len(prefix) > 0 { - for _, config := range slf.configs { - config.Prefix = fmt.Sprintf("%s.", prefix) - } - } - slf.exportGoConfig(outputDir) - slf.exportGoDefine(outputDir) -} - -func (slf *ConfigExport) exportGoConfig(outputDir string) { - var v struct { - Package string - Configs []*internal.Config - } - v.Package = filepath.Base(outputDir) - - for _, config := range slf.configs { - v.Configs = append(v.Configs, config) - } - - tmpl, err := template.New("struct").Parse(internal.GenerateGoConfigTemplate) - if err != nil { - panic(err) - } - - var buf bytes.Buffer - if err = tmpl.Execute(&buf, &v); err != nil { - panic(err) - } - var result string - _ = str.RangeLine(buf.String(), func(index int, line string) error { - if len(strings.TrimSpace(line)) == 0 { - return nil - } - result += fmt.Sprintf("%s\n", strings.ReplaceAll(line, "\t\t", "\t")) - if len(strings.TrimSpace(line)) == 1 { - result += "\n" - } - return nil - }) - - filePath := filepath.Join(outputDir, "config.go") - if err := file.WriterFile(filePath, []byte(result)); err != nil { - panic(err) - } - - cmd := exec.Command("gofmt", "-w", filePath) - _ = cmd.Run() -} - -func (slf *ConfigExport) exportGoDefine(outputDir string) { - var v struct { - Package string - Configs []*internal.Config - } - v.Package = filepath.Base(outputDir) - - for _, config := range slf.configs { - v.Configs = append(v.Configs, config) - } - - tmpl, err := template.New("struct").Parse(internal.GenerateGoDefineTemplate) - if err != nil { - panic(err) - } - - var buf bytes.Buffer - if err = tmpl.Execute(&buf, &v); err != nil { - panic(err) - } - var result string - _ = str.RangeLine(buf.String(), func(index int, line string) error { - if len(strings.TrimSpace(line)) == 0 { - return nil - } - result += fmt.Sprintf("%s\n", strings.ReplaceAll(line, "\t\t", "\t")) - if len(strings.TrimSpace(line)) == 1 { - result += "\n" - } - return nil - }) - - filePath := filepath.Join(outputDir, "config.define.go") - if err := file.WriterFile(filePath, []byte(result)); err != nil { - panic(err) - } - - cmd := exec.Command("gofmt", "-w", filePath) - _ = cmd.Run() -} diff --git a/planner/configexport/configexport_example_test.go b/planner/configexport/configexport_example_test.go deleted file mode 100644 index d1d9c6b..0000000 --- a/planner/configexport/configexport_example_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package configexport_test - -import ( - "fmt" - "github.com/kercylan98/minotaur/config" - "github.com/kercylan98/minotaur/planner/configexport" - "github.com/kercylan98/minotaur/planner/configexport/example" - "os" - "path/filepath" - "strings" -) - -func ExampleNew() { - var workdir = "./" - files, err := os.ReadDir(workdir) - if err != nil { - panic(err) - } - var ces []*configexport.ConfigExport - for _, file := range files { - if file.IsDir() || !strings.HasSuffix(file.Name(), ".xlsx") || strings.HasPrefix(file.Name(), "~") { - continue - } - - ces = append(ces, configexport.New(filepath.Join(workdir, file.Name()))) - } - - c := configexport.Merge(ces...) - outDir := filepath.Join(workdir, "example") - c.ExportGo("", outDir) - c.ExportServer("", outDir) - c.ExportClient("", outDir) - - // 下方为配置加载代码 - // 使用生成的 LoadConfig 函数加载配置 - config.Init(outDir, example.LoadConfig, example.Refresh) - - fmt.Println("success") - - // Output: - // success -} diff --git a/planner/configexport/doc.go b/planner/configexport/doc.go deleted file mode 100644 index 59faff4..0000000 --- a/planner/configexport/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package configexport 提供了XLSX配置转换为JSON及Go代码的导表工具实现 -package configexport diff --git a/planner/configexport/example/EasyConfig.json b/planner/configexport/example/EasyConfig.json deleted file mode 100644 index 79f1fe2..0000000 --- a/planner/configexport/example/EasyConfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "Id": 1, - "Award": { - "0": "asd", - "1": "12" - }, - "Other": { - "0": { - "id": 1, - "name": "张飞" - }, - "1": { - "id": 2, - "name": "刘备" - } - } -} \ No newline at end of file diff --git a/planner/configexport/example/IndexConfig.json b/planner/configexport/example/IndexConfig.json deleted file mode 100644 index 1118e0e..0000000 --- a/planner/configexport/example/IndexConfig.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "0": { - "": { - "Award": null, - "Other": null, - "Id": 0, - "Count": "" - } - }, - "1": { - "b": { - "Id": 1, - "Count": "b", - "Award": { - "0": "asd", - "1": "12" - }, - "Other": { - "0": { - "id": 1, - "name": "张飞" - }, - "1": { - "name": "刘备", - "id": 2 - } - } - } - }, - "2": { - "c": { - "Id": 2, - "Count": "c", - "Award": { - "0": "asd", - "1": "12" - }, - "Other": { - "0": { - "id": 1, - "name": "张飞" - }, - "1": { - "id": 2, - "name": "刘备" - } - } - }, - "d": { - "Id": 2, - "Count": "d", - "Award": { - "0": "asd", - "1": "12" - }, - "Other": { - "0": { - "id": 1, - "name": "张飞" - }, - "1": { - "id": 2, - "name": "刘备" - } - } - } - } -} \ No newline at end of file diff --git a/planner/configexport/example/config.define.go b/planner/configexport/example/config.define.go deleted file mode 100644 index 30814af..0000000 --- a/planner/configexport/example/config.define.go +++ /dev/null @@ -1,75 +0,0 @@ -// Code generated by minotaur-config-export. DO NOT EDIT. -package example - -// IndexConfigDefine 有索引 -type IndexConfigDefine struct { - Id int // 任务ID - Count string // 次数 - Info *IndexConfigInfo // 信息 - Other map[int]*IndexConfigOther // 信息2 -} - -func (slf *IndexConfigDefine) String() string { - if data, err := json.Marshal(slf); err == nil { - return string(data) - } - - return "{}" -} - -type IndexConfigInfo struct { - Id int - Name string - Info *IndexConfigInfoInfo -} - -type IndexConfigInfoInfo struct { - Lv int - Exp *IndexConfigInfoInfoExp -} - -type IndexConfigInfoInfoExp struct { - Mux int - Count int -} - -type IndexConfigOther struct { - Id int - Name string -} - -// EasyConfigDefine 无索引 -type EasyConfigDefine struct { - Id int // 任务ID - Info *EasyConfigInfo // 信息 - Other map[int]*EasyConfigOther // 信息2 -} - -func (slf *EasyConfigDefine) String() string { - if data, err := json.Marshal(slf); err == nil { - return string(data) - } - - return "{}" -} - -type EasyConfigInfo struct { - Id int - Name string - Info *EasyConfigInfoInfo -} - -type EasyConfigInfoInfo struct { - Lv int - Exp *EasyConfigInfoInfoExp -} - -type EasyConfigInfoInfoExp struct { - Mux int - Count int -} - -type EasyConfigOther struct { - Id int - Name string -} diff --git a/planner/configexport/example/config.go b/planner/configexport/example/config.go deleted file mode 100644 index 5d33937..0000000 --- a/planner/configexport/example/config.go +++ /dev/null @@ -1,63 +0,0 @@ -// Code generated by minotaur-config-export. DO NOT EDIT. -package example - -import ( - jsonIter "github.com/json-iterator/go" - "github.com/kercylan98/minotaur/utils/log" - "go.uber.org/zap" - "os" -) - -var json = jsonIter.ConfigCompatibleWithStandardLibrary -var full map[string]any -var ( - // IndexConfig 有索引 - IndexConfigSign = "IndexConfig" - IndexConfig map[int]map[string]*IndexConfigDefine - _IndexConfig map[int]map[string]*IndexConfigDefine - // EasyConfig 无索引 - EasyConfigSign = "EasyConfig" - EasyConfig *EasyConfigDefine - _EasyConfig *EasyConfigDefine -) - -func LoadConfig(handle func(filename string, config any) error) { - var err error - _IndexConfig = make(map[int]map[string]*IndexConfigDefine) - if err = handle("IndexConfig.json", &_IndexConfig); err != nil { - log.Err("Config", log.String("Name", "IndexConfig"), log.Bool("Invalid", true), log.Err(err)) - } - - _EasyConfig = new(EasyConfigDefine) - if err = handle("EasyConfig.json", _EasyConfig); err != nil { - log.Err("Config", log.String("Name", "EasyConfig"), log.Bool("Invalid", true), log.Err(err)) - } - -} - -// Refresh 将加载后的配置刷新到线上 -func Refresh() { - full = make(map[string]any) - IndexConfig = _IndexConfig - full["IndexConfig"] = IndexConfig - EasyConfig = _EasyConfig - full["EasyConfig"] = EasyConfig -} - -// DefaultLoad 默认提供的配置加载函数 -func DefaultLoad(filepath string) { - LoadConfig(func(filename string, config any) error { - bytes, err := os.ReadFile(filepath) - if err != nil { - return err - } - - return json.Unmarshal(bytes, &config) - }) -} - -// GetFull 获取所有配置的 map 集合 -// - 通常用于前端配置通过后端接口获取的情况 -func GetFull() map[string]any { - return full -} diff --git a/planner/configexport/internal/config.go b/planner/configexport/internal/config.go deleted file mode 100644 index 218b42c..0000000 --- a/planner/configexport/internal/config.go +++ /dev/null @@ -1,423 +0,0 @@ -package internal - -import ( - "bytes" - "fmt" - jsonIter "github.com/json-iterator/go" - "github.com/kercylan98/minotaur/utils/geometry/matrix" - "github.com/kercylan98/minotaur/utils/hash" - "github.com/kercylan98/minotaur/utils/str" - "github.com/kercylan98/minotaur/utils/xlsxtool" - "github.com/tealeg/xlsx" - "strconv" - "strings" - "text/template" -) - -// NewConfig 定位为空将读取Sheet名称 -// - 表格中需要严格遵守 描述、名称、类型、导出参数、数据列的顺序 -func NewConfig(sheet *xlsx.Sheet, exist map[string]bool) (*Config, error) { - config := &Config{ - ignore: "#", - excludeFields: map[int]bool{0: true}, - Exist: exist, - } - if strings.HasPrefix(sheet.Name, config.ignore) { - return nil, ErrReadConfigFailedIgnore - } - if err := config.initField(sheet); err != nil { - return nil, err - } - return config, nil -} - -type Config struct { - Exist map[string]bool - Prefix string - DisplayName string - Name string - Describe string - ExportParam string - IndexCount int - Fields []*Field - - matrix *matrix.Matrix[*xlsx.Cell] - excludeFields map[int]bool // 排除的字段 - ignore string - horizontal bool - dataStart int - - dataServer map[any]any - dataClient map[any]any -} - -func (slf *Config) initField(sheet *xlsx.Sheet) error { - slf.matrix = xlsxtool.GetSheetMatrix(sheet) - var displayName *Position - name, indexCount := NewPosition(1, 0), NewPosition(1, 1) - if displayName == nil { - slf.DisplayName = sheet.Name - } else { - if value := slf.matrix.Get(displayName.X, displayName.Y); value == nil { - return ErrReadConfigFailedWithDisplayName - } else { - slf.DisplayName = strings.TrimSpace(value.String()) - } - } - - if name == nil { - slf.Name = sheet.Name - } else { - if value := slf.matrix.Get(name.X, name.Y); value == nil { - return ErrReadConfigFailedWithName - } else { - slf.Name = str.FirstUpper(strings.TrimSpace(value.String())) - } - } - if strings.HasPrefix(sheet.Name, slf.ignore) { - return ErrReadConfigFailedIgnore - } - if hash.Exist(slf.Exist, slf.Name) { - return ErrReadConfigFailedSame - } - - if indexCount == nil { - slf.IndexCount, _ = strconv.Atoi(sheet.Name) - } else { - if value := slf.matrix.Get(indexCount.X, indexCount.Y); value == nil { - return ErrReadConfigFailedWithIndexCount - } else { - indexCount, err := value.Int() - if err != nil { - return err - } - if indexCount < 0 { - return ErrReadConfigFailedWithIndexCountLessThanZero - } - slf.IndexCount = indexCount - } - } - - var ( - describeStart int - horizontal bool - fields = make(map[string]bool) - dx, dy, nx, ny, tx, ty, ex, ey int - ) - horizontal = slf.IndexCount > 0 - slf.horizontal = horizontal - - if horizontal { - describeStart = 3 - dy = describeStart - ny = dy + 1 - ty = ny + 1 - ey = ty + 1 - slf.dataStart = ey + 1 - } else { - delete(slf.excludeFields, 0) - describeStart = 4 - dy = describeStart - ny = dy - ty = dy - ey = dy - nx = dx + 1 - tx = nx + 1 - ex = tx + 1 - slf.dataStart = ey + 1 - } - var index = slf.IndexCount - for { - var ( - describe, fieldName, fieldType, exportParam string - ) - var skip bool - if value, exist := slf.matrix.GetExist(dx, dy); !exist { - skip = true - } else { - describe = value.String() - } - if value, exist := slf.matrix.GetExist(nx, ny); !exist { - skip = true - } else { - fieldName = str.FirstUpper(strings.TrimSpace(value.String())) - } - if value, exist := slf.matrix.GetExist(tx, ty); !exist { - skip = true - } else { - fieldType = strings.TrimSpace(value.String()) - } - if value, exist := slf.matrix.GetExist(ex, ey); !exist { - skip = true - } else { - exportParam = strings.ToLower(strings.TrimSpace(value.String())) - } - if len(strings.TrimSpace(fieldName))+len(strings.TrimSpace(fieldType))+len(strings.TrimSpace(exportParam)) < 3 { - skip = true - } - - var field = NewField(slf.Name, fieldName, fieldType) - field.Describe = strings.ReplaceAll(describe, "\n", ", ") - if strings.HasSuffix(field.Describe, ", ") { - field.Describe = field.Describe[:len(field.Describe)-2] - } - field.ExportParam = exportParam - switch field.ExportParam { - case "s", "sc", "cs": - field.Server = true - } - - if horizontal { - dx++ - nx++ - tx++ - ex++ - } else { - dy++ - ny++ - ty++ - ey++ - } - - if !skip { - - field.Ignore = slf.excludeFields[len(slf.Fields)] - if !field.Ignore { - if strings.HasPrefix(field.Describe, slf.ignore) { - field.Ignore = true - } else if strings.HasPrefix(field.Name, slf.ignore) { - field.Ignore = true - } else if strings.HasPrefix(field.Type, slf.ignore) { - field.Ignore = true - } else if strings.HasPrefix(field.ExportParam, slf.ignore) { - field.Ignore = true - } - } - if !field.Ignore { - switch exportParam { - case "s", "c", "sc", "cs": - default: - continue - } - } - - if fields[field.Name] && !field.Ignore { - return ErrReadConfigFailedWithNameDuplicate - } - if index > 0 && !field.Ignore { - if _, exist := basicTypeName[field.Type]; !exist { - return ErrReadConfigFailedWithIndexTypeException - } - index-- - } - - fields[field.Name] = true - slf.Fields = append(slf.Fields, field) - } - - if horizontal { - if dx >= slf.matrix.GetWidth() { - break - } - } else { - if dy >= slf.matrix.GetHeight() { - break - } - } - } - - return slf.initData() -} - -func (slf *Config) initData() error { - var x, y int - if slf.horizontal { - y = slf.dataStart - } else { - x = 4 - y = 4 - } - var dataSourceServer = make(map[any]any) - var dataSourceClient = make(map[any]any) - for { - var dataServer = dataSourceServer - var dataClient = dataSourceClient - var currentIndex = 0 - - var lineServer = map[any]any{} - var lineClient = map[any]any{} - var skip bool - var offset int - var stop bool - for i := 0; i < len(slf.Fields); i++ { - if slf.excludeFields[i] { - if c := slf.matrix.Get(x+i, y); c != nil && strings.HasPrefix(c.String(), "#") { - skip = true - break - } - continue - } - - field := slf.Fields[i] - if field.Ignore { - continue - } - var value any - var zero bool - if slf.horizontal { - c := slf.matrix.Get(x+i, y) - if c == nil { - if currentIndex < slf.IndexCount { - stop = true - break - } - value = getValueZero(field.SourceType) - zero = true - } else if currentIndex < slf.IndexCount && len(strings.TrimSpace(c.String())) == 0 { - stop = true - break - } - if !zero { - value = getValueWithType(field.SourceType, c.String()) - } - } else { - c := slf.matrix.Get(x, y+i+offset) - for c == nil { - offset++ - c = slf.matrix.Get(x, y+i+offset) - if y+i+offset >= slf.matrix.GetHeight() { - break - } - } - value = getValueWithType(field.SourceType, c.String()) - } - switch field.ExportParam { - case "s": - lineServer[field.Name] = value - case "c": - lineClient[field.Name] = value - case "sc", "cs": - lineServer[field.Name] = value - lineClient[field.Name] = value - default: - skip = true - break - } - - if currentIndex < slf.IndexCount { - currentIndex++ - m, exist := dataServer[value] - if !exist { - if currentIndex == slf.IndexCount { - dataServer[value] = lineServer - } else { - m = map[any]any{} - dataServer[value] = m - } - } - if currentIndex < slf.IndexCount { - dataServer = m.(map[any]any) - } - - m, exist = dataClient[value] - if !exist { - if currentIndex == slf.IndexCount { - dataClient[value] = lineClient - } else { - m = map[any]any{} - dataClient[value] = m - } - } - if currentIndex < slf.IndexCount { - dataClient = m.(map[any]any) - } - } - } - if stop { - break - } else if slf.horizontal { - y++ - if y >= slf.matrix.GetHeight() { - break - } - } else { - if !skip { - slf.dataServer = lineServer - slf.dataClient = lineClient - } - break - } - } - if slf.horizontal { - slf.dataServer = dataSourceServer - slf.dataClient = dataSourceClient - } - return nil -} - -func (slf *Config) String() string { - tmpl, err := template.New("struct").Parse(generateConfigTemplate) - if err != nil { - return "" - } - - var buf bytes.Buffer - if err = tmpl.Execute(&buf, slf); err != nil { - return "" - } - var result string - _ = str.RangeLine(buf.String(), func(index int, line string) error { - if len(strings.TrimSpace(line)) == 0 { - return nil - } - result += fmt.Sprintf("%s\n", strings.ReplaceAll(line, "\t\t", "\t")) - if len(strings.TrimSpace(line)) == 1 { - result += "\n" - } - return nil - }) - return result -} - -func (slf *Config) JsonServer() []byte { - buffer := &bytes.Buffer{} - encoder := jsonIter.NewEncoder(buffer) - encoder.SetEscapeHTML(false) - encoder.SetIndent("", " ") - _ = encoder.Encode(slf.dataServer) - return buffer.Bytes() -} - -func (slf *Config) JsonClient() []byte { - buffer := &bytes.Buffer{} - encoder := jsonIter.NewEncoder(buffer) - encoder.SetEscapeHTML(false) - encoder.SetIndent("", " ") - _ = encoder.Encode(slf.dataClient) - return buffer.Bytes() -} - -func (slf *Config) GetVariable() string { - var result string - var count int - if slf.IndexCount > 0 { - for _, field := range slf.Fields { - if field.Ignore { - continue - } - result += fmt.Sprintf("map[%s]", field.Type) - count++ - if count >= slf.IndexCount { - break - } - } - } - return fmt.Sprintf("%s*%sDefine", result, slf.Name) -} - -func (slf *Config) GetVariableGen() string { - if slf.IndexCount == 0 { - return fmt.Sprintf("new(%s)", strings.TrimPrefix(slf.GetVariable(), "*")) - } - return fmt.Sprintf("make(%s)", slf.GetVariable()) -} diff --git a/planner/configexport/internal/errors.go b/planner/configexport/internal/errors.go deleted file mode 100644 index 2e8fbf3..0000000 --- a/planner/configexport/internal/errors.go +++ /dev/null @@ -1,14 +0,0 @@ -package internal - -import "errors" - -var ( - ErrReadConfigFailedIgnore = errors.New("read config skip ignore") - ErrReadConfigFailedSame = errors.New("read config skip, same name") - ErrReadConfigFailedWithDisplayName = errors.New("read config display name failed, can not found position") - ErrReadConfigFailedWithName = errors.New("read config name failed, can not found position") - ErrReadConfigFailedWithIndexCount = errors.New("read config index count failed, can not found position") - ErrReadConfigFailedWithIndexCountLessThanZero = errors.New("read config index count failed, value less than zero") - ErrReadConfigFailedWithNameDuplicate = errors.New("read config index count failed, duplicate field names") - ErrReadConfigFailedWithIndexTypeException = errors.New("read config index count failed, the index type is only allowed to be the basic type") -) diff --git a/planner/configexport/internal/field.go b/planner/configexport/internal/field.go deleted file mode 100644 index b0f5762..0000000 --- a/planner/configexport/internal/field.go +++ /dev/null @@ -1,146 +0,0 @@ -package internal - -import ( - "bytes" - "fmt" - "github.com/kercylan98/minotaur/utils/str" - "html/template" - "strings" -) - -func NewField(configName, fieldName, fieldType string) *Field { - sourceType := fieldType - var handleStruct = func(configName, fieldType string) []*Field { - var fs []*Field - var s = strings.TrimSuffix(strings.TrimPrefix(fieldType, "{"), "}") - var fields []string - var field string - var leftBrackets []int - for i, c := range s { - switch c { - case ',': - if len(leftBrackets) == 0 { - fields = append(fields, field) - field = "" - } else { - field += string(c) - } - case '{': - leftBrackets = append(leftBrackets, i) - field += string(c) - case '}': - leftBrackets = leftBrackets[:len(leftBrackets)-1] - field += string(c) - if len(leftBrackets) == 0 { - fields = append(fields, field) - field = "" - } - default: - field += string(c) - } - } - if len(field) > 0 { - fields = append(fields, field) - } - - for _, fieldInfo := range fields { - fieldName, fieldType := str.KV(strings.TrimSpace(fieldInfo), ":") - fs = append(fs, NewField(configName, str.FirstUpper(fieldName), fieldType)) - - } - return fs - } - - var fs []*Field - var sliceField *Field - if t, exist := basicTypeName[fieldType]; exist { - fieldType = t - goto end - } - if strings.HasPrefix(fieldType, "[]") { - fieldType = strings.TrimPrefix(fieldType, "[]") - if t, exist := basicTypeName[fieldType]; exist { - fieldType = fmt.Sprintf("map[int]%s", t) - } else { - sliceField = NewField(configName, fieldName, fieldType) - fieldType = fmt.Sprintf("map[int]*%s", configName+fieldName) - } - goto end - } - - fs = handleStruct(configName+fieldName, fieldType) - fieldType = fmt.Sprintf("*%s", configName+fieldName) - -end: - { - return &Field{ - Name: fieldName, - Type: fieldType, - SourceType: sourceType, - TypeNotStar: strings.TrimPrefix(fieldType, "*"), - Fields: fs, - SliceField: sliceField, - } - } -} - -type Field struct { - Name string - Type string - SourceType string - TypeNotStar string - Fields []*Field - SliceField *Field - ExportParam string - Server bool - Describe string - Ignore bool -} - -func (slf *Field) Struct() string { - if len(slf.Fields) == 0 && slf.SliceField == nil { - return "" - } - tmpl, err := template.New("struct").Parse(generateGoStructTemplate) - if err != nil { - return "" - } - var buf bytes.Buffer - if len(slf.Fields) > 0 { - if err = tmpl.Execute(&buf, slf); err != nil { - return "" - } - } else if slf.SliceField != nil { - if err = tmpl.Execute(&buf, slf.SliceField); err != nil { - return "" - } - } - s := buf.String() - return s -} - -func (slf *Field) String() string { - if len(slf.Fields) == 0 && slf.SliceField == nil { - return "" - } - tmpl, err := template.New("struct").Parse(generateGoStructTemplate) - if err != nil { - return "" - } - - var buf bytes.Buffer - if len(slf.Fields) > 0 { - if err = tmpl.Execute(&buf, slf); err != nil { - return "" - } - } else if slf.SliceField != nil { - if err = tmpl.Execute(&buf, slf.SliceField); err != nil { - return "" - } - } - s := buf.String() - for _, field := range slf.Fields { - s += fmt.Sprintf("%s", field.String()) - } - return s -} diff --git a/planner/configexport/internal/field_types.go b/planner/configexport/internal/field_types.go deleted file mode 100644 index d44ddd3..0000000 --- a/planner/configexport/internal/field_types.go +++ /dev/null @@ -1,304 +0,0 @@ -package internal - -import ( - "github.com/kercylan98/minotaur/utils/str" - "github.com/tidwall/gjson" - "math" - "strconv" - "strings" -) - -var basicTypeName = map[string]string{ - "string": "string", - "int": "int", - "int8": "int8", - "int16": "int16", - "int32": "int32", - "int64": "int64", - "uint": "uint", - "uint8": "uint8", - "uint16": "uint16", - "uint32": "uint32", - "uint64": "uint64", - "float32": "float32", - "float64": "float64", - "float": "float64", - "double": "float64", - "number": "float64", - "byte": "byte", - "rune": "rune", - "bool": "bool", - "boolean": "bool", -} - -var basicType = map[string]func(fieldValue string) any{ - "string": withStringType, - "int": withIntType, - "int8": withInt8Type, - "int16": withInt16Type, - "int32": withInt32Type, - "int64": withInt64Type, - "uint": withUintType, - "uint8": withUint8Type, - "uint16": withUint16Type, - "uint32": withUint32Type, - "uint64": withUint64Type, - "float32": withFloat32Type, - "float64": withFloat64Type, - "float": withFloat64Type, - "double": withFloat64Type, - "number": withFloat64Type, - "byte": withByteType, - "rune": withRuneType, - "bool": withBoolType, - "boolean": withBoolType, -} - -func getValueZero(fileType string) any { - switch basicTypeName[fileType] { - case "string": - return getValueWithType(fileType, "") - case "int": - return getValueWithType(fileType, "0") - case "int8": - return getValueWithType(fileType, "0") - case "int16": - return getValueWithType(fileType, "0") - case "int32": - return getValueWithType(fileType, "0") - case "int64": - return getValueWithType(fileType, "0") - case "uint": - return getValueWithType(fileType, "0") - case "uint8": - return getValueWithType(fileType, "0") - case "uint16": - return getValueWithType(fileType, "0") - case "uint32": - return getValueWithType(fileType, "0") - case "uint64": - return getValueWithType(fileType, "0") - case "float32": - return getValueWithType(fileType, "0") - case "float64": - return getValueWithType(fileType, "0") - case "byte": - return getValueWithType(fileType, "0") - case "rune": - return getValueWithType(fileType, "0") - case "bool": - return getValueWithType(fileType, "false") - } - return nil -} - -func getValueWithType(fieldType string, fieldValue string) any { - fieldType = strings.ToLower(strings.TrimSpace(fieldType)) - handle, exist := basicType[fieldType] - if exist { - return handle(fieldValue) - } else { - return withStructType(fieldType, fieldValue) - } -} - -func withStructType(fieldType string, fieldValue string) any { - // {id:int,name:string,info:{lv:int,exp:int}} - if strings.HasPrefix(fieldType, "[]") { - return withSliceType(fieldType, fieldValue) - } else if !strings.HasPrefix(fieldType, "{") || !strings.HasSuffix(fieldType, "}") { - return nil - } - var s = strings.TrimSuffix(strings.TrimPrefix(fieldType, "{"), "}") - var data = map[any]any{} - var fields []string - var field string - var leftBrackets []int - for i, c := range s { - switch c { - case ',': - if len(leftBrackets) == 0 { - fields = append(fields, field) - field = "" - } else { - field += string(c) - } - case '{': - leftBrackets = append(leftBrackets, i) - field += string(c) - case '}': - leftBrackets = leftBrackets[:len(leftBrackets)-1] - field += string(c) - if len(leftBrackets) == 0 { - fields = append(fields, field) - field = "" - } - default: - field += string(c) - } - } - if len(field) > 0 { - fields = append(fields, field) - } - - for _, fieldInfo := range fields { - fieldName, fieldType := str.KV(strings.TrimSpace(fieldInfo), ":") - handle, exist := basicType[fieldType] - if exist { - data[fieldName] = handle(gjson.Get(fieldValue, fieldName).String()) - } else { - data[fieldName] = withStructType(fieldType, gjson.Get(fieldValue, fieldName).String()) - } - } - - return data -} - -func withSliceType(fieldType string, fieldValue string) any { - if !strings.HasPrefix(fieldType, "[]") { - return nil - } - t := strings.TrimPrefix(fieldType, "[]") - var data = map[any]any{} - gjson.ForEachLine(fieldValue, func(line gjson.Result) bool { - line.ForEach(func(key, value gjson.Result) bool { - handle, exist := basicType[t] - if exist { - data[len(data)] = handle(value.String()) - } else { - data[len(data)] = withStructType(t, value.String()) - } - return true - }) - return true - }) - return data -} - -func withStringType(fieldValue string) any { - return fieldValue -} - -func withIntType(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - return value -} - -func withInt8Type(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - if value < 0 { - return int8(0) - } else if value > math.MaxInt8 { - return int8(math.MaxInt8) - } - return int8(value) -} - -func withInt16Type(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - if value < 0 { - return int16(0) - } else if value > math.MaxInt16 { - return int16(math.MaxInt16) - } - return int16(value) -} - -func withInt32Type(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - if value < 0 { - return int32(0) - } else if value > math.MaxInt32 { - return int32(math.MaxInt32) - } - return int32(value) -} - -func withInt64Type(fieldValue string) any { - value, _ := strconv.ParseInt(fieldValue, 10, 64) - return value -} - -func withUintType(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - if value < 0 { - return uint(0) - } - return uint(value) -} - -func withUint8Type(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - if value < 0 { - return uint8(0) - } else if value > math.MaxUint8 { - return uint8(math.MaxUint8) - } - return uint8(value) -} - -func withUint16Type(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - if value < 0 { - return uint16(0) - } else if value > math.MaxUint16 { - return uint16(math.MaxUint16) - } - return uint16(value) -} - -func withUint32Type(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - if value < 0 { - return uint32(0) - } else if value > math.MaxUint32 { - return uint32(math.MaxUint32) - } - return uint32(value) -} - -func withUint64Type(fieldValue string) any { - value, _ := strconv.ParseInt(fieldValue, 10, 64) - return uint64(value) -} - -func withFloat32Type(fieldValue string) any { - value, _ := strconv.ParseFloat(fieldValue, 32) - return value -} - -func withFloat64Type(fieldValue string) any { - value, _ := strconv.ParseFloat(fieldValue, 64) - return value -} - -func withByteType(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - if value < 0 { - return byte(0) - } else if value > math.MaxUint8 { - return byte(math.MaxInt8) - } - return byte(value) -} - -func withRuneType(fieldValue string) any { - value, _ := strconv.Atoi(fieldValue) - if value < math.MinInt32 { - return rune(0) - } else if value > math.MaxInt32 { - return rune(math.MaxInt32) - } - return rune(value) -} - -func withBoolType(fieldValue string) any { - switch fieldValue { - case "0", "false", "!": - return false - case "1", "true", "&": - return true - default: - return false - } -} diff --git a/planner/configexport/internal/postion.go b/planner/configexport/internal/postion.go deleted file mode 100644 index 5a7fcd9..0000000 --- a/planner/configexport/internal/postion.go +++ /dev/null @@ -1,13 +0,0 @@ -package internal - -func NewPosition(x, y int) *Position { - return &Position{ - X: x, - Y: y, - } -} - -type Position struct { - X int - Y int -} diff --git a/planner/configexport/internal/template.go b/planner/configexport/internal/template.go deleted file mode 100644 index f4a98e9..0000000 --- a/planner/configexport/internal/template.go +++ /dev/null @@ -1,108 +0,0 @@ -package internal - -const ( - generateConfigTemplate = ` - -// {{.Name}}Define {{.DisplayName}} -type {{.Name}}Define struct { - {{range $index, $value := .Fields}}{{if eq $value.Server true}}{{if eq $value.Ignore false}}{{$value.Name}} {{$value.Type}} // {{$value.Describe}}{{end}}{{end}} - {{end}} -} - -func (slf *{{.Name}}Define) String() string { - if data, err := json.Marshal(slf); err == nil { - return string(data) - } - return "{}" -} - -{{range $index, $value := .Fields}}{{$value}}{{end}} -` - - generateGoStructTemplate = ` -{{if eq .Ignore false}} -type {{.TypeNotStar}} struct { - {{range $index, $value := .Fields}} - {{$value.Name}} {{$value.Type}} - {{end}} -} -{{end}} -` - - GenerateGoConfigTemplate = `// Code generated by minotaur-config-export. DO NOT EDIT. - -package {{.Package}} - -import ( - jsonIter "github.com/json-iterator/go" - "github.com/kercylan98/minotaur/utils/log" - "go.uber.org/zap" - "os" -) - -var json = jsonIter.ConfigCompatibleWithStandardLibrary -var full map[string]any - -var ( -{{range $index, $config := .Configs}} - // {{$config.Name}}Sign {{$config.DisplayName}}签名 - {{$config.Name}}Sign = "{{$config.Name}}" - // {{$config.Name}} {{$config.DisplayName}} - {{$config.Name}} {{$config.GetVariable}} - _{{$config.Name}} {{$config.GetVariable}} -{{end}} -) - -func LoadConfig(handle func(filename string, config any) error) { - var err error -{{range $index, $config := .Configs}} - _{{$config.Name}} = {{$config.GetVariableGen}} -{{if eq $config.IndexCount 0}} - if err = handle("{{$config.Prefix}}{{$config.Name}}.json", _{{$config.Name}}); err != nil { - log.Err("Config", log.String("Name", "{{$config.Name}}"), log.Bool("Invalid", true), log.Err(err)) - } -{{else}} - if err = handle("{{$config.Prefix}}{{$config.Name}}.json", &_{{$config.Name}}); err != nil { - log.Err("Config", log.String("Name", "{{$config.Name}}"), log.Bool("Invalid", true), log.Err(err)) - } -{{end}} -{{end}} -} - -// Refresh 将加载后的配置刷新到线上 -func Refresh() { - full = make(map[string]any) -{{range $index, $config := .Configs}} - {{$config.Name}} = _{{$config.Name}} - full["{{$config.Name}}"] = {{$config.Name}} -{{end}} -} - -// DefaultLoad 默认提供的配置加载函数 -func DefaultLoad(filepath string) { - LoadConfig(func(filename string, config any) error { - bytes, err := os.ReadFile(filepath) - if err != nil { - return err - } - return json.Unmarshal(bytes, &config) - }) -} - -// GetFull 获取所有配置的 map 集合 -// - 通常用于前端配置通过后端接口获取的情况 -func GetFull() map[string]any { - return full -} -` - - GenerateGoDefineTemplate = `// Code generated by minotaur-config-export. DO NOT EDIT. - -package {{.Package}} - -{{range $index, $config := .Configs}} - {{$config.String}} -{{end}} - -` -) diff --git a/planner/pce/config.go b/planner/pce/config.go new file mode 100644 index 0000000..95ac5f2 --- /dev/null +++ b/planner/pce/config.go @@ -0,0 +1,16 @@ +package pce + +type Config interface { + // GetConfigName 配置名称 + GetConfigName() string + // GetDisplayName 配置显示名称 + GetDisplayName() string + // GetDescription 配置描述 + GetDescription() string + // GetIndexCount 索引数量 + GetIndexCount() int + // GetFields 获取字段 + GetFields() []dataField + // GetData 获取数据 + GetData() [][]dataInfo +} diff --git a/planner/pce/config_xlsx.go b/planner/pce/config_xlsx.go new file mode 100644 index 0000000..e3745ef --- /dev/null +++ b/planner/pce/config_xlsx.go @@ -0,0 +1,133 @@ +package pce + +import ( + "github.com/kercylan98/minotaur/utils/str" + "github.com/tealeg/xlsx" + "strings" +) + +func NewIndexXlsxConfig(sheet *xlsx.Sheet) *XlsxIndexConfig { + config := &XlsxIndexConfig{ + sheet: sheet, + } + return config +} + +// XlsxIndexConfig 内置的 Xlsx 配置 +type XlsxIndexConfig struct { + sheet *xlsx.Sheet +} + +func (slf *XlsxIndexConfig) GetConfigName() string { + return str.FirstUpper(strings.TrimSpace(slf.sheet.Rows[0].Cells[1].String())) +} + +func (slf *XlsxIndexConfig) GetDisplayName() string { + return slf.sheet.Name +} + +func (slf *XlsxIndexConfig) GetDescription() string { + return "暂无描述" +} + +func (slf *XlsxIndexConfig) GetIndexCount() int { + index, err := slf.sheet.Rows[1].Cells[1].Int() + if err != nil { + panic(err) + } + return index +} + +func (slf *XlsxIndexConfig) GetFields() []dataField { + var fields []dataField + for x := 1; x < slf.getWidth(); x++ { + var ( + desc = slf.get(x, 3) + name = slf.get(x, 4) + fieldType = slf.get(x, 5) + exportType = slf.get(x, 6) + ) + if desc == nil || name == nil || fieldType == nil || exportType == nil { + continue + } + if len(desc.String()) == 0 || len(name.String()) == 0 || len(fieldType.String()) == 0 || len(exportType.String()) == 0 { + continue + } + fields = append(fields, dataField{ + Name: name.String(), + Type: fieldType.String(), + ExportType: exportType.String(), + Desc: desc.String(), + }) + } + return fields +} + +func (slf *XlsxIndexConfig) GetData() [][]dataInfo { + var data [][]dataInfo + var fields = slf.GetFields() + for y := 7; y < slf.getHeight(); y++ { + var line []dataInfo + var stop bool + for x := 0; x < slf.getWidth(); x++ { + if prefixCell := slf.get(x, y); prefixCell != nil { + prefix := prefixCell.String() + if strings.HasPrefix(prefix, "#") { + break + } + } + if x == 0 { + continue + } + var isIndex = x-1 < slf.GetIndexCount() + + var value string + if valueCell := slf.get(x, y); valueCell != nil { + value = valueCell.String() + } else if isIndex { + stop = true + break + } + valueCell := slf.get(x, y) + if valueCell == nil { + break + } + if len(fields) > x-1 { + line = append(line, dataInfo{ + dataField: fields[x-1], + Value: value, + }) + } + } + if len(line) > 0 { + data = append(data, line) + } + if stop { + break + } + } + + return data +} + +// getWidth 获取宽度 +func (slf *XlsxIndexConfig) getWidth() int { + return slf.sheet.MaxCol +} + +// getHeight 获取高度 +func (slf *XlsxIndexConfig) getHeight() int { + return slf.sheet.MaxRow +} + +// get 获取单元格 +func (slf *XlsxIndexConfig) get(x, y int) *xlsx.Cell { + if x < 0 || y < 0 || y >= len(slf.sheet.Rows) { + return nil + } + row := slf.sheet.Rows[y] + if x >= len(row.Cells) { + return nil + } + return row.Cells[x] +} diff --git a/planner/pce/config_xlsx_test.go b/planner/pce/config_xlsx_test.go new file mode 100644 index 0000000..4056426 --- /dev/null +++ b/planner/pce/config_xlsx_test.go @@ -0,0 +1,25 @@ +package pce_test + +import ( + "github.com/kercylan98/minotaur/planner/pce" + "github.com/tealeg/xlsx" + "testing" +) + +func TestNewXlsxIndexConfig(t *testing.T) { + f, err := xlsx.OpenFile(`D:\sources\minotaur\planner\ce\template.xlsx`) + if err != nil { + panic(err) + } + xlsxConfig := pce.NewIndexXlsxConfig(f.Sheets[1]) + + loader := pce.NewLoader() + loader.BindField( + new(pce.Int), + new(pce.String), + ) + + loader.LoadStruct(xlsxConfig) + loader.LoadData(xlsxConfig) + +} diff --git a/planner/pce/data_tmpl.go b/planner/pce/data_tmpl.go new file mode 100644 index 0000000..09a36e2 --- /dev/null +++ b/planner/pce/data_tmpl.go @@ -0,0 +1,7 @@ +package pce + +// DataTmpl 数据导出模板 +type DataTmpl interface { + // Render 渲染模板 + Render(data map[any]any) (string, error) +} diff --git a/planner/pce/exporter.go b/planner/pce/exporter.go new file mode 100644 index 0000000..bf5c6a9 --- /dev/null +++ b/planner/pce/exporter.go @@ -0,0 +1,53 @@ +package pce + +import ( + "github.com/kercylan98/minotaur/utils/file" + "os/exec" + "path/filepath" +) + +// NewExporter 创建导出器 +func NewExporter(filePath string) *Exporter { + return &Exporter{ + filePath: filePath, + } +} + +// Exporter 导出器 +type Exporter struct { + filePath string +} + +// ExportStruct 导出结构 +func (slf *Exporter) ExportStruct(tmpl Tmpl, tmplStruct ...*TmplStruct) error { + filePath, err := filepath.Abs(slf.filePath) + if err != nil { + return err + } + raw, err := tmpl.Render(tmplStruct) + if err != nil { + return err + } + if err = file.WriterFile(filePath, []byte(raw)); err != nil { + return err + } + + cmd := exec.Command("gofmt", "-w", filePath) + return cmd.Run() +} + +// ExportData 导出数据 +func (slf *Exporter) ExportData(tmpl DataTmpl, data map[any]any) error { + filePath, err := filepath.Abs(slf.filePath) + if err != nil { + return err + } + raw, err := tmpl.Render(data) + if err != nil { + return err + } + if err = file.WriterFile(filePath, []byte(raw)); err != nil { + return err + } + return nil +} diff --git a/planner/pce/field.go b/planner/pce/field.go new file mode 100644 index 0000000..e135b9d --- /dev/null +++ b/planner/pce/field.go @@ -0,0 +1,25 @@ +package pce + +import ( + "github.com/kercylan98/minotaur/utils/super" + "reflect" + "strings" +) + +// Field 基本字段类型接口 +type Field interface { + // TypeName 字段类型名称 + TypeName() string + // Zero 获取零值 + Zero() any + // Parse 解析 + Parse(value string) any +} + +// GetFieldGolangType 获取字段的 Golang 类型 +func GetFieldGolangType(field Field) string { + typeOf := reflect.TypeOf(field).Elem() + kind := strings.ToLower(typeOf.Kind().String()) + name := strings.ToLower(typeOf.Name()) + return super.If(kind == name, kind, name) +} diff --git a/planner/pce/field_test.go b/planner/pce/field_test.go new file mode 100644 index 0000000..b8e0626 --- /dev/null +++ b/planner/pce/field_test.go @@ -0,0 +1,11 @@ +package pce_test + +import ( + "fmt" + "github.com/kercylan98/minotaur/planner/pce" + "testing" +) + +func TestGetFieldGolangType(t *testing.T) { + fmt.Println(pce.GetFieldGolangType(new(pce.String))) +} diff --git a/planner/pce/fields.go b/planner/pce/fields.go new file mode 100644 index 0000000..83feec4 --- /dev/null +++ b/planner/pce/fields.go @@ -0,0 +1,456 @@ +package pce + +import ( + "github.com/kercylan98/minotaur/utils/super" + "math" + "strconv" +) + +type Int int + +func (slf Int) TypeName() string { + return "int" +} + +func (slf Int) Zero() any { + return int(0) +} + +func (slf Int) Parse(value string) any { + return super.StringToInt(value) +} + +type Int8 int8 + +func (slf Int8) TypeName() string { + return "int8" +} + +func (slf Int8) Zero() any { + return int8(0) +} + +func (slf Int8) Parse(value string) any { + v := super.StringToInt(value) + if v < 0 { + return int8(0) + } else if v > math.MaxInt8 { + return int8(math.MaxInt8) + } + return int8(v) +} + +type Int16 int16 + +func (slf Int16) TypeName() string { + return "int16" +} + +func (slf Int16) Zero() any { + return int16(0) +} + +func (slf Int16) Parse(value string) any { + v := super.StringToInt(value) + if v < 0 { + return int16(0) + } else if v > math.MaxInt16 { + return int16(math.MaxInt16) + } + return int16(v) +} + +type Int32 int32 + +func (slf Int32) TypeName() string { + return "int32" +} + +func (slf Int32) Zero() any { + return int32(0) +} + +func (slf Int32) Parse(value string) any { + v := super.StringToInt(value) + if v < 0 { + return int32(0) + } else if v > math.MaxInt32 { + return int32(math.MaxInt32) + } + return int32(v) +} + +type Int64 int64 + +func (slf Int64) TypeName() string { + return "int64" +} + +func (slf Int64) Zero() any { + return int64(0) +} + +func (slf Int64) Parse(value string) any { + v, _ := strconv.ParseInt(value, 10, 64) + return v +} + +type Uint uint + +func (slf Uint) TypeName() string { + return "uint" +} + +func (slf Uint) Zero() any { + return uint(0) +} + +func (slf Uint) Parse(value string) any { + v, _ := strconv.Atoi(value) + if v < 0 { + return uint(0) + } + return uint(v) +} + +type Uint8 uint8 + +func (slf Uint8) TypeName() string { + return "uint8" +} + +func (slf Uint8) Zero() any { + return uint8(0) +} + +func (slf Uint8) Parse(value string) any { + v, _ := strconv.Atoi(value) + if v < 0 { + return uint8(0) + } else if v > math.MaxUint8 { + return uint8(math.MaxUint8) + } + return uint8(v) +} + +type Uint16 uint16 + +func (slf Uint16) TypeName() string { + return "uint16" +} + +func (slf Uint16) Zero() any { + return uint16(0) +} + +func (slf Uint16) Parse(value string) any { + v, _ := strconv.Atoi(value) + if v < 0 { + return uint16(0) + } else if v > math.MaxUint16 { + return uint16(math.MaxUint16) + } + return uint16(v) +} + +type Uint32 uint32 + +func (slf Uint32) TypeName() string { + return "uint32" +} + +func (slf Uint32) Zero() any { + return uint32(0) +} + +func (slf Uint32) Parse(value string) any { + v, _ := strconv.Atoi(value) + if v < 0 { + return uint32(0) + } else if v > math.MaxUint32 { + return uint32(math.MaxUint32) + } + return uint32(v) +} + +type Uint64 uint64 + +func (slf Uint64) TypeName() string { + return "uint64" +} + +func (slf Uint64) Zero() any { + return uint64(0) +} + +func (slf Uint64) Parse(value string) any { + v, _ := strconv.ParseUint(value, 10, 64) + if v < 0 { + return uint64(0) + } + return v +} + +type Float32 float32 + +func (slf Float32) TypeName() string { + return "float32" +} + +func (slf Float32) Zero() any { + return float32(0) +} + +func (slf Float32) Parse(value string) any { + v, _ := strconv.ParseFloat(value, 32) + return v +} + +type Float64 float64 + +func (slf Float64) TypeName() string { + return "float64" +} + +func (slf Float64) Zero() any { + return float64(0) +} + +func (slf Float64) Parse(value string) any { + v, _ := strconv.ParseFloat(value, 64) + return v +} + +type String string + +func (slf String) TypeName() string { + return "string" +} + +func (slf String) Zero() any { + return "" +} + +func (slf String) Parse(value string) any { + return value +} + +type Bool bool + +func (slf Bool) TypeName() string { + return "bool" +} + +func (slf Bool) Zero() any { + return false +} + +func (slf Bool) Parse(value string) any { + v, _ := strconv.ParseBool(value) + return v +} + +type Byte byte + +func (slf Byte) TypeName() string { + return "byte" +} + +func (slf Byte) Zero() any { + return byte(0) +} + +func (slf Byte) Parse(value string) any { + v, _ := strconv.Atoi(value) + if v < 0 { + return byte(0) + } else if v > math.MaxUint8 { + return byte(math.MaxUint8) + } + return byte(v) +} + +type Rune rune + +func (slf Rune) TypeName() string { + return "rune" +} + +func (slf Rune) Zero() any { + return rune(0) +} + +func (slf Rune) Parse(value string) any { + v, _ := strconv.Atoi(value) + if v < 0 { + return rune(0) + } else if v > math.MaxInt32 { + return rune(math.MaxInt32) + } + return rune(v) +} + +type Complex64 complex64 + +func (slf Complex64) TypeName() string { + return "complex64" +} + +func (slf Complex64) Zero() any { + return complex64(0) +} + +func (slf Complex64) Parse(value string) any { + v, _ := strconv.ParseComplex(value, 64) + return v +} + +type Complex128 complex128 + +func (slf Complex128) TypeName() string { + return "complex128" +} + +func (slf Complex128) Zero() any { + return complex128(0) +} + +func (slf Complex128) Parse(value string) any { + v, _ := strconv.ParseComplex(value, 128) + return v +} + +type Uintptr uintptr + +func (slf Uintptr) TypeName() string { + return "uintptr" +} + +func (slf Uintptr) Zero() any { + return uintptr(0) +} + +func (slf Uintptr) Parse(value string) any { + v, _ := strconv.ParseUint(value, 10, 64) + return uintptr(v) +} + +type Double float64 + +func (slf Double) TypeName() string { + return "double" +} + +func (slf Double) Zero() any { + return float64(0) +} + +func (slf Double) Parse(value string) any { + v, _ := strconv.ParseFloat(value, 64) + return v +} + +type Float float32 + +func (slf Float) TypeName() string { + return "float" +} + +func (slf Float) Zero() any { + return float32(0) +} + +func (slf Float) Parse(value string) any { + v, _ := strconv.ParseFloat(value, 32) + return v +} + +type Long int64 + +func (slf Long) TypeName() string { + return "long" +} + +func (slf Long) Zero() any { + return int64(0) +} + +func (slf Long) Parse(value string) any { + v, _ := strconv.ParseInt(value, 10, 64) + return v +} + +type Short int16 + +func (slf Short) TypeName() string { + return "short" +} + +func (slf Short) Zero() any { + return int16(0) +} + +func (slf Short) Parse(value string) any { + v, _ := strconv.ParseInt(value, 10, 16) + return v +} + +type Char int8 + +func (slf Char) TypeName() string { + return "char" +} + +func (slf Char) Zero() any { + return int8(0) +} + +func (slf Char) Parse(value string) any { + v, _ := strconv.ParseInt(value, 10, 8) + return v +} + +type Number float64 + +func (slf Number) TypeName() string { + return "number" +} + +func (slf Number) Zero() any { + return float64(0) +} + +func (slf Number) Parse(value string) any { + v, _ := strconv.ParseFloat(value, 64) + return v +} + +type Integer int64 + +func (slf Integer) TypeName() string { + return "integer" +} + +func (slf Integer) Zero() any { + return int64(0) +} + +func (slf Integer) Parse(value string) any { + v, _ := strconv.ParseInt(value, 10, 64) + return v +} + +type Boolean bool + +func (slf Boolean) TypeName() string { + return "boolean" +} + +func (slf Boolean) Zero() any { + return false +} + +func (slf Boolean) Parse(value string) any { + v, _ := strconv.ParseBool(value) + return v +} diff --git a/planner/pce/loader.go b/planner/pce/loader.go new file mode 100644 index 0000000..4c57328 --- /dev/null +++ b/planner/pce/loader.go @@ -0,0 +1,175 @@ +package pce + +import ( + "github.com/kercylan98/minotaur/utils/str" + "github.com/tidwall/gjson" + "strings" +) + +// NewLoader 创建加载器 +// - 加载器被用于加载配置表的数据和结构信息 +func NewLoader() *Loader { + return &Loader{ + fields: make(map[string]Field), + } +} + +// Loader 配置加载器 +type Loader struct { + fields map[string]Field +} + +// BindField 绑定字段 +func (slf *Loader) BindField(fields ...Field) { + for _, field := range fields { + slf.fields[field.TypeName()] = field + } +} + +// LoadStruct 加载结构 +func (slf *Loader) LoadStruct(config Config) *TmplStruct { + var tmpl = &TmplStruct{ + Name: str.FirstUpper(config.GetConfigName()), + Desc: config.GetDescription(), + } + indexCount := config.GetIndexCount() + for i, field := range config.GetFields() { + f := tmpl.addField(tmpl.Name, str.FirstUpper(field.Name), field.Desc, field.Type, slf.fields) + if i < indexCount { + f.isIndex = true + } + } + return tmpl +} + +// LoadData 加载配置并得到配置数据 +func (slf *Loader) LoadData(config Config) map[any]any { + var source = make(map[any]any) + var action = source + var indexCount = config.GetIndexCount() - 1 + for _, row := range config.GetData() { + var item = make(map[any]any) + for index, field := range row { + bind, exist := slf.fields[field.Type] + var value any + if exist { + if len(field.Value) == 0 { + value = bind.Zero() + } else { + value = bind.Parse(field.Value) + } + } else { + value = slf.structInterpreter(field.Type, field.Value) + } + + if value != nil { + item[field.Name] = value + } + + if index < indexCount { + m, exist := action[value] + if !exist { + m = map[any]any{} + action[value] = m + action = m.(map[any]any) + } else { + action = m.(map[any]any) + } + } else if index == indexCount { + action[value] = item + } + } + action = source + } + + return source +} + +// sliceInterpreter 切片解释器 +func (slf *Loader) sliceInterpreter(fieldType, fieldValue string) any { + if !strings.HasPrefix(fieldType, "[]") { + return nil + } + t := strings.TrimPrefix(fieldType, "[]") + var data = map[any]any{} + gjson.ForEachLine(fieldValue, func(line gjson.Result) bool { + line.ForEach(func(key, value gjson.Result) bool { + field, exist := slf.fields[t] + if exist { + data[len(data)] = field.Parse(value.String()) + } else { + data[len(data)] = slf.structInterpreter(t, value.String()) + } + return true + }) + return true + }) + return data +} + +// structInterpreter 结构体解释器 +// - {id:int,name:string,info:{lv:int,exp:int}} +func (slf *Loader) structInterpreter(fieldType, fieldValue string) any { + if strings.HasPrefix(fieldType, "[]") { + return slf.sliceInterpreter(fieldType, fieldValue) + } else if !strings.HasPrefix(fieldType, "{") || !strings.HasSuffix(fieldType, "}") { + return nil + } + var s = strings.TrimSuffix(strings.TrimPrefix(fieldType, "{"), "}") + var data = map[any]any{} + var fields []string + var field string + var leftBrackets []int + for i, c := range s { + switch c { + case ',': + if len(leftBrackets) == 0 { + fields = append(fields, field) + field = "" + } else { + field += string(c) + } + case '{': + leftBrackets = append(leftBrackets, i) + field += string(c) + case '}': + leftBrackets = leftBrackets[:len(leftBrackets)-1] + field += string(c) + if len(leftBrackets) == 0 { + fields = append(fields, field) + field = "" + } + default: + field += string(c) + } + } + if len(field) > 0 { + fields = append(fields, field) + } + + for _, fieldInfo := range fields { + fieldName, fieldType := str.KV(strings.TrimSpace(fieldInfo), ":") + field, exist := slf.fields[fieldType] + if exist { + data[fieldName] = field.Parse(gjson.Get(fieldValue, fieldName).String()) + } else { + data[fieldName] = slf.structInterpreter(fieldType, gjson.Get(fieldValue, fieldName).String()) + } + } + + return data +} + +// dataInfo 配置数据 +type dataInfo struct { + dataField // 字段 + Value string // 字段值 +} + +// dataField 配置数据字段 +type dataField struct { + Name string // 字段名称 + Desc string // 字段描述 + Type string // 字段类型 + ExportType string // 导出类型 +} diff --git a/planner/configexport/template.xlsx b/planner/pce/template.xlsx similarity index 69% rename from planner/configexport/template.xlsx rename to planner/pce/template.xlsx index aa39090b1d05ed21eb50607ee92d2589cf1c6919..7ebc65ea2eb7e93285b54963444ac502df6ba001 100644 GIT binary patch delta 3135 zcmZ9Oc{CJ!7sqF;g&AX+?E6|sGqQ|b%09AWU&b2Q#%>71*b5DV?4eK^>kyv7l9;hXSqg7G&wJkYyzl+vckccD?)RK~&OPVz`|d;@N47KqnM6nlY=l;z61KK1 z^~nHd^pY$NIz+~o2M@`DOxxEf>g#`KT5rL7(3RSsrBO6ro_Jhq)MGYYVXVCDp2jf+nqHwpWiilFLpaZZpDGx0# z7UC>bvSUmdD&3BG!dwo44{!@(c_v`-fb=-Y8m_bZsjtQA1OPa1e|=o|nGx%33K^W; zj&bm)o4Mkq>5n<#r!+ZS9eC*32qsgL#s?AwuYY*g z9B!M^_2t>k3q2?|z2*IwB6i(b>yRV_BpG{0lx{g@9(U70$+`qD4Kh_eGrV(4`l9(+ z2{b~tWBA7>rh@xVDTA^6e$eik?d*J7Hin@fWp7GPnF6pfXJjIXsR@!~7};6a0uSB0 zR~P{R7?`lhC4hyU#{>uEIJlwjYw#wZZk#ZF{gGN6St`pWfGit}eBgGY{oNfuHcK2^ zaYx0A;~(8Kva+*AYvxHyOE=>w3)go(H8$0-^Rz7^%~pdfCEqOf$d`GW9Ut60`I3Cu z#uu4q*W-CM)-ON)?eX#Zx+SVzCBH3~qrZ=trCGzanRO4^~BrU&!0xz{dH*-55a9E!wC+I_ zz3-zre4=eTc(iES9)45wYy9o(o}>%!g{9S4GcSR~U;Y|k%pfV>aomJ@UOrjAXsxQH zQ8bxrOMtTo#_h<$3=v@` z(xRmnR90UoNHPChIDlP>BwD&!}7C*q0ek7_X*W}hndX3g-_}e zZROl4OuzHV5zfA{yAq^cW#DA08TUp4NGmps3?CGT3)ro+*t)qHQ=2XV?L;w@4_VQ@ z3qv>M5>d)?X5g?o$uroEgyOUhJ&M0eSE$NisZ;ZH>cb2lfloi@78KbBQm=ouiM{Cd6lwGE`$vOV1NpFc$b52fP3P;1nRklFF{{HK%{ghY0|%nRR4C205b(u}{MU4}UZopV`eBk&=p`~GaYSulRyBA}CbdLmNoC1f z2;E0H(;XobMR*CXY*V+3FRTX~9TQGS^r)jk z;a$vx4fo4k8+`tlwCWg)@%TC7ajEY6^+odouxd#4o60HBkV#y6{5(~JB55A@?uAs@ zgZ5CFjy=11@}6_WmBaISwNA`UsPoh6CawlyQ%;qw>eeAwv6&YN>x18$x~LM`X^wLj zM_sy8>E}WBucQhXz0WC57V98?5QeWx-ixc39RcWI)<;S*o=S*geIEpe9BXmt>E)F_ z$QIUD7+n;^)a|A*Vu7y;Z%xw?S#{?Yk}k`r0n4#EN19-AL6PjN z3^+b*t^I&)J&e-d@5gI9p$=-s7R(MK(YCL!Z;}fcN$;-}HwU8W1MPKl`%fEzI3=L- zeA2f+DwNeWpt2X};?=48oY27;2`>GDh(}sWT=ncdEaCVB@lN5jG@k)p!mMsc8um{t4r+?8&RVhIzBM$ zv_u{=^$UKM0d{!TQ9MHDnW%WfnfpU`q%0e)4xF83WVDIavc%7%Wi1LUi#%WNc#ys(b$UCb6Z6q3 zVa_u|eXh3p(O|lDWV__SqT=oHM@Yo-n^w)Zdkx+<{9*a{JL{_##NK!gWWVmmb|84+ z{#v{%ecUN4A)yU6@rF6p83$cOqPw0jdwhe@YWS4FQiI4&fXetIa0P#)5ZjKw9EKyN zq5tl%C?x8%?w3@Ha};jxt=e|_8S*yk+ZB6nEb|O|VeEcOc6Y3{y*qSy??&3yWp&qkZEa!U;i*+$ zn4-zf^NfR7BL&Yi#@!Nl*WNDLuPc#zKexiNs@K@e>4f3qqV^__=iTu~p;y-GX{au? zrwp}GEPTi?3WwE|K>MZa?Z7mPqD;lDH83BQj{P4T=@aBMA*63yLqga!ljG+BKmfp! z0RZ6qg)2;uatt~=&4?wEfb^+EUeGcU1*|teLd3AD6hrbDKP*eqSfLGCr%ukP+47pA+ z#KngFfi=l$wZINr$e#xGvKVG8ZcJ8L#p&7wSVF{+`nG{PeM`miY1t)3;|5gIn#f_r zqPUe}SH{~&HV>6WOw-K;pKNnyp2I^ujzVc|oHtYnj(?Kw51FV*Abg#B5sD855;VCy zV-qLgyS>~6r>@gXCzJ+(bdN`Dvug2XyOMg&p~>~V*xYq%xu2&IZyXD5$O*HN=yzq# zc4gaz4SAQbyxxh^xjfygvOs!Gb=0BUPVvqAWZvarODl-1Hy{qyG4z4nb>TkCwh{?9hFW5ue-6XkdVA z1Sy08gD{++1eYP)MnF#g$FLF}AasQP`&|J5{J*uo;vcy#h~NnlB=BjTW0>Xol|l)Q MnoyQMFaGZM7l7Nuh5!Hn delta 3160 zcmZ8jc{J3G_x{X`wK8KFlNdW?%RU%8p{x;-$XH^sWZxRg$6CnRc#-T|gcM<{(a7>5 zgr=-z=T&AZ+4M4h8i25ENAM*)?=t{oXr6rTIbCT{@R)gJrQ)rc>H911paw zrK|pI@5~)}En_BAV$ea3W9_8&eo{rd9Q8IgORu#f?CP~F|NPSYfLv#us;<{G?p*Dty@=t@8Kv~>j01M(dZi(Vd4y@#%@*ceuV*m4xC73 zI|s^1hu-x{vAN~5pn{CRxu0BG+7VOX1D6T&35mgs z*&dq)UEcwO$91Y|V{yFg^Y@ctBdttm{UmD+8o^sDdJ**~%!$)->-?;zwiQcc>vQl) zP;DNkDgRs3XsUeq#<~<|U5FmrtJxg*A#y#~QogdpJ3?qp@G_3JkF^sZIf#&iXwH;|5s=>br!9O-;^_wV@)&EMC$6_<|eNN4Hi1$|8 zGOQF^c)%2wM|r2b>9*K&91^Tnvz)Gc%54c0OwL-XCI7=HMkrp#1tmftrr?W50IunW zDIxkhN@Mxu)0xNWjboNko6se@s7=^XSd{v_ka*eB_ZUKMLHEw(_t0EZ$cw8=Nn(0KRbDNP5Z?ul(XY}k3zSn7Z5hd;O}nU5B=O%X$W6v z+}~{}LDQ$CiOXaU6)te$os<2-r&-j$MXn(HlmG19Lwg4*ZR+A)GU1IxJAbLzZ%BR2 z{xj(*bo-Rg=y-0F<(=-jnCw|GVkLojpOKhc~qf`v&Ocj~D;beigupv{iF z>2TO3g6KsPYpKoyU!`9M_0$X4UYhmh7^Ps_Ln3u0U5Xe}$Pnl)g$u8GJ!wDEJlF>c&0{e&g5N zToknd)G+GF{R_*kWyBL7wl{r@FgJ$LApv#(U;-YPEofW1pxo{006-t{=PVF?SQx=E z|57Dn#FoiP^wYqfDlEtsqQg zXU(W+l9F9deV(I)tr9{e_x6*m4dC~Jl19^B2jjk_Q(nAMEu*jUjdSpe?R*X%xlXe0 z&*aIu@yS}5#=T3PG@kdVSCAfe(*r&1b(XH&c`Q#Vzwo+B+zcU9C3QFus=hO*SeJhL z#`_W9^hLQ5U)_4+M9K4pV$#|ugSve=l zf~~hOFv1yy*)4Z~J`=WXJ_%^Izr-UtCvZ`u`wIo%h46JHGY+h7xliv-TiAihr8OH? zGh9fi@FAt_`x)|vwn-l((eKW3hT&BtCBD%l(u?sLU^^c&Nhljzmkv$H< z5q0XcpstJA{nL4VI~_=AoAz#fw&GzghKL_&j>{*}?``s$Pr{D#*N8q7YM)&Q;verL z!BxiK)KQI%zGIQE!tbu)8B#!1-uQmuv)7k6k9l!^5N5WUR7Te_;QH?N-)I6Mrd>XQ zjdER{fjAZpU1tfqSX2&4XAWy+JO#7be`Wl@GaDXbRS}*S&T1vaM@K1UoPDDc6-920 zm2o?{L}~v6;FH!g+bPF7ON1)d*kr!qtH}hCo>_LL#=0_%=hC`CMon(PkI=5~3<3X;&ma=Ru56;ip^Tf{^xM#a@rWl+!MW zCiYy_15MJ&7(cbMy}2zKj+q~;P|jS?>RBfyehkaY6@@G&GGZFe*poZb17WURnQE2I z%FRFR(n#TxSbn2Gc1G+0C|poih=+?c3J!;JRm@di-mFy>~vQ3l(YZ*2RT1 zE>Sd~G^Q2I9Np+GBe&y>5rk&03s-D}_x(q7$hXvx7`IGgYqQGEl(*C(4)q6&+vL>` zeCdI7{3?Qp(AWX*k%9rh{lbvPPn%1XJb^r1TY+I=TuHe@hw(Gbnz(vrhK0`xTc4t~ z`sFF+m>0~0rVlT)tb8!1?_(aW(UfWq4^^?@<6LsyanCQH@{4OMTQ73%G8rziZ3bHv zz(3#%_fSNjKU&#Z=7y0KbR*(bH%yl2IF}&mw1tBW)x|A5)yjE-|&%bkq1nZURiR40Dv|W01yBGgnG$@`1pG| z`}lbNYfds=n~`N%dqYI#y5$vy3oDqORs6*&&{_mHcO%+!SEurRk``BksRO!K&LqU2 zbzBNMrOvRb7cYQ1fAH<_=x4-g_Z?d%f95G)Q5WvOa3k&W63hOm@rLozueXenUFAVn zUBiTRPA*k$Z|^e_<*R3nhMA#diSFKaKkcX!m&|3yEkv*6-8MQq5XZcjSOS_@ z9o7!i9J)zmEX8#vWOLhI4i)o(62P4&fuUP!N*OD|!V8y|cAOFss*$>SBf2v?hP^vk z!=xo%vEr7LHN92}pD4lNn+&OI-2tQ^s+14m*s&X=SC;U<_SV}TS=m=SQ(dhZcHuT~ zN~o*|ITM~`XYcv(VR+w 0 { + fs = append(fs, field) + } + + for _, fieldInfo := range fs { + fieldName, fieldType := str.KV(strings.TrimSpace(fieldInfo), ":") + slf.Struct.addField(slf.Struct.Name, str.FirstUpper(fieldName), fieldName, fieldType, fields) + } + + slf.Type = slf.Struct.Name +} + +// handleSlice 处理切片类型 +func (slf *TmplField) handleSlice(fieldName, fieldType string, fields map[string]Field) { + if !strings.HasPrefix(fieldType, "[]") { + return + } + slf.slice = true + t := strings.TrimPrefix(fieldType, "[]") + if hash.Exist(fields, t) { + slf.Struct = nil + slf.Type = t + } else { + slf.handleStruct(fieldName, t, fields) + } +} diff --git a/planner/pce/tmpl_struct.go b/planner/pce/tmpl_struct.go new file mode 100644 index 0000000..99983fe --- /dev/null +++ b/planner/pce/tmpl_struct.go @@ -0,0 +1,38 @@ +package pce + +import ( + "github.com/kercylan98/minotaur/utils/hash" +) + +// TmplStruct 模板结构 +type TmplStruct struct { + Name string // 结构名称 + Desc string // 结构描述 + Fields []*TmplField // 字段列表 +} + +// addField 添加字段 +func (slf *TmplStruct) addField(parent, name, desc, fieldType string, fields map[string]Field) *TmplField { + field := &TmplField{ + Name: name, + Desc: desc, + Type: fieldType, + } + if !hash.Exist(fields, fieldType) { + field.setStruct(parent, name, desc, fieldType, fields) + } + slf.Fields = append(slf.Fields, field) + return field +} + +// AllChildren 获取所有子结构 +func (slf *TmplStruct) AllChildren() []*TmplStruct { + var children []*TmplStruct + for _, field := range slf.Fields { + if field.IsStruct() { + children = append(children, field.Struct) + children = append(children, field.Struct.AllChildren()...) + } + } + return children +} diff --git a/planner/pce/tmpls/golang.go b/planner/pce/tmpls/golang.go new file mode 100644 index 0000000..f32d66a --- /dev/null +++ b/planner/pce/tmpls/golang.go @@ -0,0 +1,174 @@ +package tmpls + +import ( + "fmt" + "github.com/kercylan98/minotaur/planner/pce" + "strings" +) + +// NewGolang 创建一个 Golang 配置导出模板 +func NewGolang(packageName string) *Golang { + return &Golang{ + Package: packageName, + } +} + +// Golang 配置导出模板 +type Golang struct { + Package string + Templates []*pce.TmplStruct +} + +func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { + slf.Templates = templates + return render(`// Code generated by minotaur. DO NOT EDIT. + package {{.Package}} + + import ( + jsonIter "github.com/json-iterator/go" + "github.com/kercylan98/minotaur/utils/log" + "sync" + ) + + type Sign string + + const ( + {{- range .Templates}} + {{.Name}}Sign Sign = "{{.Name}}" + {{- end}} + ) + + var ( + json = jsonIter.ConfigCompatibleWithStandardLibrary + configs map[Sign]any = map[Sign]any{ + {{- range .Templates}} + {{.Name}}Sign: {{.Name}}, + {{- end}} + } + signs = []Sign{ + {{- range .Templates}} + {{.Name}}Sign, + {{- end}} + } + mutex sync.Mutex + ) + + var ( + {{- range .Templates}} + {{.Name}} {{$.GetVariable .}} + {{- end}} + ) + + var ( + {{- range .Templates}} + _{{.Name}} {{$.GetVariable .}} + {{- end}} + ) + + {{- range .Templates}} + type {{$.GetConfigName .}} struct { + {{- range .Fields}} + {{- if .IsSlice}} + {{- if .IsStruct}} + {{.Name}} []*{{.Struct.Name}} // {{.Desc}} + {{- else}} + {{.Name}} []{{.Type}} // {{.Desc}} + {{- end}} + {{- else}} + {{- if .IsStruct}} + {{.Name}} *{{.Struct.Name}} // {{.Desc}} + {{- else}} + {{.Name}} {{.Type}} // {{.Desc}} + {{- end}} + {{- end}} + {{- end}} + } + + func (slf *{{$.GetConfigName .}}) String() string { + if data, err := json.Marshal(slf); err == nil { + return string(data) + } + return "{}" + } + {{- end}} + + {{- range .Templates}} + {{- range .AllChildren}} + type {{.Name}} struct { + {{- range .Fields}} + {{- if .IsSlice}} + {{- if .IsStruct}} + {{.Name}} []*{{.Struct.Name}} // {{.Desc}} + {{- else}} + {{.Name}} []{{.Type}} // {{.Desc}} + {{- end}} + {{- else}} + {{- if .IsStruct}} + {{.Name}} *{{.Struct.Name}} // {{.Desc}} + {{- else}} + {{.Name}} {{.Type}} // {{.Desc}} + {{- end}} + {{- end}} + {{- end}} + } + + {{- end}} + {{- end}} + + // Load 通过自定义的方式加载配置 + // - 通常建议使用该方法加载配置,因为仅执行一次加解锁 + func LoadWithHandle(handle func(sign Sign, config any, json jsonIter.API) error) { + mutex.Lock() + defer mutex.Unlock() + for _, sign := range signs { + {{- range .Templates}} + temp := make({{$.GetVariable .}}) + if err := handle(sign, &temp, json);err != nil { + log.Error("Config", log.String("Name", "{{.Name}}"), log.Bool("Invalid", true), log.Err(err)) + }else { + _{{.Name}} = temp + } + {{- end}} + } + } + + // LoadIndexConfig 通过 JSON 加载配置 + func LoadWithJSON(sign Sign, data []byte) { + switch sign { + {{- range .Templates}} + case {{.Name}}Sign: + temp := make({{$.GetVariable .}}) + if err := json.Unmarshal(data, &{{.Name}}); err != nil { + log.Error("Config", log.String("Name", "{{.Name}}"), log.Bool("Invalid", true), log.Err(err)) + return + } + _{{.Name}} = temp + {{- end}} + } + } + + // Refresh 将加载后的配置刷新到线上 + func Refresh() { + mutex.Lock() + defer mutex.Unlock() + {{- range .Templates}} + {{.Name}} = _{{.Name}} + _{{.Name}} = nil + {{- end}} + } + `, slf) +} + +func (slf *Golang) GetVariable(config *pce.TmplStruct) string { + var prefix string + for _, field := range config.Fields { + if field.IsIndex() { + prefix += fmt.Sprintf("map[%s]", field.Type) + } + } + return fmt.Sprintf("%s*%s", prefix, slf.GetConfigName(config)) +} + +func (slf *Golang) GetConfigName(config *pce.TmplStruct) string { + return strings.ReplaceAll(config.Name, "Config", "Configuration") +} diff --git a/planner/pce/tmpls/json.go b/planner/pce/tmpls/json.go new file mode 100644 index 0000000..50fffa8 --- /dev/null +++ b/planner/pce/tmpls/json.go @@ -0,0 +1,29 @@ +package tmpls + +import ( + "bytes" + jsonIter "github.com/json-iterator/go" + "github.com/kercylan98/minotaur/utils/str" +) + +func NewJSON() *JSON { + return &JSON{ + API: jsonIter.ConfigCompatibleWithStandardLibrary, + } +} + +type JSON struct { + jsonIter.API +} + +func (slf *JSON) Render(data map[any]any) (string, error) { + buffer := &bytes.Buffer{} + encoder := jsonIter.NewEncoder(buffer) + encoder.SetEscapeHTML(false) + encoder.SetIndent("", " ") + err := encoder.Encode(data) + if err != nil { + return str.None, err + } + return buffer.String(), nil +} diff --git a/planner/pce/tmpls/tmpls.go b/planner/pce/tmpls/tmpls.go new file mode 100644 index 0000000..ee184b1 --- /dev/null +++ b/planner/pce/tmpls/tmpls.go @@ -0,0 +1,19 @@ +package tmpls + +import ( + "bytes" + "github.com/kercylan98/minotaur/utils/str" + "text/template" +) + +func render(temp string, o any) (string, error) { + tmpl, err := template.New(temp).Parse(temp) + if err != nil { + return str.None, err + } + var buf bytes.Buffer + if err = tmpl.Execute(&buf, o); err != nil { + return str.None, err + } + return buf.String(), nil +} diff --git a/utils/super/parse.go b/utils/super/parse.go new file mode 100644 index 0000000..bcb742e --- /dev/null +++ b/utils/super/parse.go @@ -0,0 +1,9 @@ +package super + +import "strconv" + +// StringToInt 字符串转换为整数 +func StringToInt(value string) int { + i, _ := strconv.Atoi(value) + return i +} From 91b2b52fc8229959c18d048c0c33d49da8b7b4ae Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Mon, 17 Jul 2023 14:36:29 +0800 Subject: [PATCH 07/10] =?UTF-8?q?other:=20pce.ce=20=E5=8C=85=E6=8F=90?= =?UTF-8?q?=E4=BE=9B=E5=86=85=E7=BD=AE=E7=9A=84=20xlsx=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- planner/pce/config.go | 7 +- planner/pce/config_xlsx.go | 133 ------------- planner/pce/config_xlsx_test.go | 25 --- planner/pce/cs/xlsx.go | 183 ++++++++++++++++++ .../{template.xlsx => cs/xlsx_template.xlsx} | Bin planner/pce/cs/xlsx_test.go | 63 ++++++ planner/pce/exporter.go | 45 +---- planner/pce/fields.go | 35 ++++ planner/pce/loader.go | 27 ++- 9 files changed, 309 insertions(+), 209 deletions(-) delete mode 100644 planner/pce/config_xlsx.go delete mode 100644 planner/pce/config_xlsx_test.go create mode 100644 planner/pce/cs/xlsx.go rename planner/pce/{template.xlsx => cs/xlsx_template.xlsx} (100%) create mode 100644 planner/pce/cs/xlsx_test.go diff --git a/planner/pce/config.go b/planner/pce/config.go index 95ac5f2..683ddaa 100644 --- a/planner/pce/config.go +++ b/planner/pce/config.go @@ -1,5 +1,8 @@ package pce +// Config 配置解析接口 +// - 用于将配置文件解析为可供分析的数据结构 +// - 可以在 cs 包中找到内置提供的实现及其模板,例如 cs.XlsxIndexConfig type Config interface { // GetConfigName 配置名称 GetConfigName() string @@ -10,7 +13,7 @@ type Config interface { // GetIndexCount 索引数量 GetIndexCount() int // GetFields 获取字段 - GetFields() []dataField + GetFields() []DataField // GetData 获取数据 - GetData() [][]dataInfo + GetData() [][]DataInfo } diff --git a/planner/pce/config_xlsx.go b/planner/pce/config_xlsx.go deleted file mode 100644 index e3745ef..0000000 --- a/planner/pce/config_xlsx.go +++ /dev/null @@ -1,133 +0,0 @@ -package pce - -import ( - "github.com/kercylan98/minotaur/utils/str" - "github.com/tealeg/xlsx" - "strings" -) - -func NewIndexXlsxConfig(sheet *xlsx.Sheet) *XlsxIndexConfig { - config := &XlsxIndexConfig{ - sheet: sheet, - } - return config -} - -// XlsxIndexConfig 内置的 Xlsx 配置 -type XlsxIndexConfig struct { - sheet *xlsx.Sheet -} - -func (slf *XlsxIndexConfig) GetConfigName() string { - return str.FirstUpper(strings.TrimSpace(slf.sheet.Rows[0].Cells[1].String())) -} - -func (slf *XlsxIndexConfig) GetDisplayName() string { - return slf.sheet.Name -} - -func (slf *XlsxIndexConfig) GetDescription() string { - return "暂无描述" -} - -func (slf *XlsxIndexConfig) GetIndexCount() int { - index, err := slf.sheet.Rows[1].Cells[1].Int() - if err != nil { - panic(err) - } - return index -} - -func (slf *XlsxIndexConfig) GetFields() []dataField { - var fields []dataField - for x := 1; x < slf.getWidth(); x++ { - var ( - desc = slf.get(x, 3) - name = slf.get(x, 4) - fieldType = slf.get(x, 5) - exportType = slf.get(x, 6) - ) - if desc == nil || name == nil || fieldType == nil || exportType == nil { - continue - } - if len(desc.String()) == 0 || len(name.String()) == 0 || len(fieldType.String()) == 0 || len(exportType.String()) == 0 { - continue - } - fields = append(fields, dataField{ - Name: name.String(), - Type: fieldType.String(), - ExportType: exportType.String(), - Desc: desc.String(), - }) - } - return fields -} - -func (slf *XlsxIndexConfig) GetData() [][]dataInfo { - var data [][]dataInfo - var fields = slf.GetFields() - for y := 7; y < slf.getHeight(); y++ { - var line []dataInfo - var stop bool - for x := 0; x < slf.getWidth(); x++ { - if prefixCell := slf.get(x, y); prefixCell != nil { - prefix := prefixCell.String() - if strings.HasPrefix(prefix, "#") { - break - } - } - if x == 0 { - continue - } - var isIndex = x-1 < slf.GetIndexCount() - - var value string - if valueCell := slf.get(x, y); valueCell != nil { - value = valueCell.String() - } else if isIndex { - stop = true - break - } - valueCell := slf.get(x, y) - if valueCell == nil { - break - } - if len(fields) > x-1 { - line = append(line, dataInfo{ - dataField: fields[x-1], - Value: value, - }) - } - } - if len(line) > 0 { - data = append(data, line) - } - if stop { - break - } - } - - return data -} - -// getWidth 获取宽度 -func (slf *XlsxIndexConfig) getWidth() int { - return slf.sheet.MaxCol -} - -// getHeight 获取高度 -func (slf *XlsxIndexConfig) getHeight() int { - return slf.sheet.MaxRow -} - -// get 获取单元格 -func (slf *XlsxIndexConfig) get(x, y int) *xlsx.Cell { - if x < 0 || y < 0 || y >= len(slf.sheet.Rows) { - return nil - } - row := slf.sheet.Rows[y] - if x >= len(row.Cells) { - return nil - } - return row.Cells[x] -} diff --git a/planner/pce/config_xlsx_test.go b/planner/pce/config_xlsx_test.go deleted file mode 100644 index 4056426..0000000 --- a/planner/pce/config_xlsx_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package pce_test - -import ( - "github.com/kercylan98/minotaur/planner/pce" - "github.com/tealeg/xlsx" - "testing" -) - -func TestNewXlsxIndexConfig(t *testing.T) { - f, err := xlsx.OpenFile(`D:\sources\minotaur\planner\ce\template.xlsx`) - if err != nil { - panic(err) - } - xlsxConfig := pce.NewIndexXlsxConfig(f.Sheets[1]) - - loader := pce.NewLoader() - loader.BindField( - new(pce.Int), - new(pce.String), - ) - - loader.LoadStruct(xlsxConfig) - loader.LoadData(xlsxConfig) - -} diff --git a/planner/pce/cs/xlsx.go b/planner/pce/cs/xlsx.go new file mode 100644 index 0000000..40b1931 --- /dev/null +++ b/planner/pce/cs/xlsx.go @@ -0,0 +1,183 @@ +package cs + +import ( + "github.com/kercylan98/minotaur/planner/pce" + "github.com/kercylan98/minotaur/utils/str" + "github.com/tealeg/xlsx" + "regexp" + "strings" +) + +func NewXlsx(sheet *xlsx.Sheet) *Xlsx { + config := &Xlsx{ + sheet: sheet, + } + return config +} + +// Xlsx 内置的 Xlsx 配置 +type Xlsx struct { + sheet *xlsx.Sheet +} + +func (slf *Xlsx) GetConfigName() string { + return str.FirstUpper(strings.TrimSpace(slf.sheet.Rows[0].Cells[1].String())) +} + +func (slf *Xlsx) GetDisplayName() string { + return slf.sheet.Name +} + +func (slf *Xlsx) GetDescription() string { + return "暂无描述" +} + +func (slf *Xlsx) GetIndexCount() int { + index, err := slf.sheet.Rows[1].Cells[1].Int() + if err != nil { + panic(err) + } + return index +} + +func (slf *Xlsx) GetFields() []pce.DataField { + var handle = func(desc, name, fieldType, exportType *xlsx.Cell) (pce.DataField, bool) { + var field pce.DataField + if desc == nil || name == nil || fieldType == nil || exportType == nil { + return field, false + } + field = pce.DataField{ + Name: strings.ReplaceAll(strings.ReplaceAll(str.FirstUpper(name.String()), "\r", ""), "\n", ""), + Type: fieldType.String(), + ExportType: exportType.String(), + Desc: strings.ReplaceAll(strings.ReplaceAll(desc.String(), "\r", ""), "\n", ""), + } + if len(field.Name) == 0 || len(field.Type) == 0 || len(field.ExportType) == 0 { + return field, false + } + + if slf.checkFieldInvalid(field) { + return field, false + } + + return field, true + } + var fields []pce.DataField + if slf.GetIndexCount() > 0 { + for x := 1; x < slf.getWidth(); x++ { + if field, match := handle(slf.get(x, 3), slf.get(x, 4), slf.get(x, 5), slf.get(x, 6)); match { + fields = append(fields, field) + } + } + } else { + for y := 4; y < slf.getHeight(); y++ { + if field, match := handle(slf.get(0, y), slf.get(1, y), slf.get(2, y), slf.get(3, y)); match { + fields = append(fields, field) + } + } + } + return fields +} + +func (slf *Xlsx) GetData() [][]pce.DataInfo { + var data [][]pce.DataInfo + var fields = slf.GetFields() + if slf.GetIndexCount() > 0 { + for y := 7; y < slf.getHeight(); y++ { + var line []pce.DataInfo + var stop bool + for x := 0; x < slf.getWidth(); x++ { + if prefixCell := slf.get(x, y); prefixCell != nil { + prefix := prefixCell.String() + if strings.HasPrefix(prefix, "#") { + break + } + } + if x == 0 { + continue + } + var isIndex = x-1 < slf.GetIndexCount() + + var value string + if valueCell := slf.get(x, y); valueCell != nil { + value = valueCell.String() + } else if isIndex { + stop = true + break + } + valueCell := slf.get(x, y) + if valueCell == nil { + break + } + if len(fields) > x-1 { + line = append(line, pce.DataInfo{ + DataField: fields[x-1], + Value: value, + }) + } + } + if len(line) > 0 { + data = append(data, line) + } + if stop { + break + } + } + } else { + var line []pce.DataInfo + for i, field := range slf.GetFields() { + var value string + if valueCell := slf.get(4, 4+i); valueCell != nil { + value = valueCell.String() + } + line = append(line, pce.DataInfo{ + DataField: field, + Value: value, + }) + } + data = append(data, line) + } + return data +} + +// getWidth 获取宽度 +func (slf *Xlsx) getWidth() int { + return slf.sheet.MaxCol +} + +// getHeight 获取高度 +func (slf *Xlsx) getHeight() int { + return slf.sheet.MaxRow +} + +// get 获取单元格 +func (slf *Xlsx) get(x, y int) *xlsx.Cell { + if x < 0 || y < 0 || y >= len(slf.sheet.Rows) { + return nil + } + row := slf.sheet.Rows[y] + if x >= len(row.Cells) { + return nil + } + return row.Cells[x] +} + +func (slf *Xlsx) checkFieldInvalid(field pce.DataField) bool { + switch strings.ToLower(field.ExportType) { + case "s", "c", "sc", "cs": + default: + return true + } + + pattern := "^[a-zA-Z][a-zA-Z0-9]*$" + reg := regexp.MustCompile(pattern) + if !reg.MatchString(field.Name) { + return true + } + + if strings.HasPrefix(field.Name, "#") || strings.HasPrefix(field.Type, "#") { + return true + } + + return false +} diff --git a/planner/pce/template.xlsx b/planner/pce/cs/xlsx_template.xlsx similarity index 100% rename from planner/pce/template.xlsx rename to planner/pce/cs/xlsx_template.xlsx diff --git a/planner/pce/cs/xlsx_test.go b/planner/pce/cs/xlsx_test.go new file mode 100644 index 0000000..5ae90f3 --- /dev/null +++ b/planner/pce/cs/xlsx_test.go @@ -0,0 +1,63 @@ +package cs_test + +import ( + "github.com/kercylan98/minotaur/planner/pce/cs" + . "github.com/smartystreets/goconvey/convey" + "github.com/tealeg/xlsx" + "testing" +) + +func TestNewIndexXlsxConfig(t *testing.T) { + Convey("TestNewIndexXlsxConfig", t, func() { + f, err := xlsx.OpenFile("./xlsx_template.xlsx") + if err != nil { + panic(err) + } + config := cs.NewXlsx(f.Sheets[1]) + So(config, ShouldNotBeNil) + }) +} + +func TestXlsxIndexConfig_GetConfigName(t *testing.T) { + Convey("TestXlsxIndexConfig_GetConfigName", t, func() { + f, err := xlsx.OpenFile("./xlsx_template.xlsx") + if err != nil { + panic(err) + } + config := cs.NewXlsx(f.Sheets[1]) + So(config.GetConfigName(), ShouldEqual, "IndexConfig") + }) +} + +func TestXlsxIndexConfig_GetDisplayName(t *testing.T) { + Convey("TestXlsxIndexConfig_GetDisplayName", t, func() { + f, err := xlsx.OpenFile("./xlsx_template.xlsx") + if err != nil { + panic(err) + } + config := cs.NewXlsx(f.Sheets[1]) + So(config.GetDisplayName(), ShouldEqual, "有索引") + }) +} + +func TestXlsxIndexConfig_GetDescription(t *testing.T) { + Convey("TestXlsxIndexConfig_GetDescription", t, func() { + f, err := xlsx.OpenFile("./xlsx_template.xlsx") + if err != nil { + panic(err) + } + config := cs.NewXlsx(f.Sheets[1]) + So(config.GetDescription(), ShouldEqual, "暂无描述") + }) +} + +func TestXlsxIndexConfig_GetIndexCount(t *testing.T) { + Convey("TestXlsxIndexConfig_GetIndexCount", t, func() { + f, err := xlsx.OpenFile("./xlsx_template.xlsx") + if err != nil { + panic(err) + } + config := cs.NewXlsx(f.Sheets[1]) + So(config.GetIndexCount(), ShouldEqual, 2) + }) +} diff --git a/planner/pce/exporter.go b/planner/pce/exporter.go index bf5c6a9..25b6581 100644 --- a/planner/pce/exporter.go +++ b/planner/pce/exporter.go @@ -1,53 +1,28 @@ package pce -import ( - "github.com/kercylan98/minotaur/utils/file" - "os/exec" - "path/filepath" -) - // NewExporter 创建导出器 -func NewExporter(filePath string) *Exporter { - return &Exporter{ - filePath: filePath, - } +func NewExporter() *Exporter { + return &Exporter{} } // Exporter 导出器 -type Exporter struct { - filePath string -} +type Exporter struct{} // ExportStruct 导出结构 -func (slf *Exporter) ExportStruct(tmpl Tmpl, tmplStruct ...*TmplStruct) error { - filePath, err := filepath.Abs(slf.filePath) - if err != nil { - return err - } +func (slf *Exporter) ExportStruct(tmpl Tmpl, tmplStruct ...*TmplStruct) ([]byte, error) { raw, err := tmpl.Render(tmplStruct) if err != nil { - return err + return nil, err } - if err = file.WriterFile(filePath, []byte(raw)); err != nil { - return err - } - - cmd := exec.Command("gofmt", "-w", filePath) - return cmd.Run() + return []byte(raw), nil } // ExportData 导出数据 -func (slf *Exporter) ExportData(tmpl DataTmpl, data map[any]any) error { - filePath, err := filepath.Abs(slf.filePath) - if err != nil { - return err - } +func (slf *Exporter) ExportData(tmpl DataTmpl, data map[any]any) ([]byte, error) { raw, err := tmpl.Render(data) if err != nil { - return err + return nil, err } - if err = file.WriterFile(filePath, []byte(raw)); err != nil { - return err - } - return nil + + return []byte(raw), nil } diff --git a/planner/pce/fields.go b/planner/pce/fields.go index 83feec4..cb168c6 100644 --- a/planner/pce/fields.go +++ b/planner/pce/fields.go @@ -6,6 +6,41 @@ import ( "strconv" ) +var fields = []Field{ + new(Int), + new(Int8), + new(Int16), + new(Int32), + new(Int64), + new(Uint), + new(Uint8), + new(Uint16), + new(Uint32), + new(Uint64), + new(Float32), + new(Float64), + new(String), + new(Bool), + new(Byte), + new(Rune), + new(Complex64), + new(Complex128), + new(Uintptr), + new(Double), + new(Float), + new(Long), + new(Short), + new(Char), + new(Number), + new(Integer), + new(Boolean), +} + +// GetFields 获取所有内置支持的字段 +func GetFields() []Field { + return fields +} + type Int int func (slf Int) TypeName() string { diff --git a/planner/pce/loader.go b/planner/pce/loader.go index 4c57328..035c1cf 100644 --- a/planner/pce/loader.go +++ b/planner/pce/loader.go @@ -8,10 +8,14 @@ import ( // NewLoader 创建加载器 // - 加载器被用于加载配置表的数据和结构信息 -func NewLoader() *Loader { - return &Loader{ +func NewLoader(fields []Field) *Loader { + loader := &Loader{ fields: make(map[string]Field), } + for _, f := range fields { + loader.fields[f.TypeName()] = f + } + return loader } // Loader 配置加载器 @@ -19,13 +23,6 @@ type Loader struct { fields map[string]Field } -// BindField 绑定字段 -func (slf *Loader) BindField(fields ...Field) { - for _, field := range fields { - slf.fields[field.TypeName()] = field - } -} - // LoadStruct 加载结构 func (slf *Loader) LoadStruct(config Config) *TmplStruct { var tmpl = &TmplStruct{ @@ -77,6 +74,8 @@ func (slf *Loader) LoadData(config Config) map[any]any { } } else if index == indexCount { action[value] = item + } else if indexCount == -1 { + source = item } } action = source @@ -160,14 +159,14 @@ func (slf *Loader) structInterpreter(fieldType, fieldValue string) any { return data } -// dataInfo 配置数据 -type dataInfo struct { - dataField // 字段 +// DataInfo 配置数据 +type DataInfo struct { + DataField // 字段 Value string // 字段值 } -// dataField 配置数据字段 -type dataField struct { +// DataField 配置数据字段 +type DataField struct { Name string // 字段名称 Desc string // 字段描述 Type string // 字段类型 From 130869af4eb0cec045730d7bc85cf11c0137a236 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Mon, 17 Jul 2023 16:06:36 +0800 Subject: [PATCH 08/10] =?UTF-8?q?other:=20=E9=85=8D=E7=BD=AE=E5=AF=BC?= =?UTF-8?q?=E8=A1=A8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- planner/pce/cs/xlsx.go | 57 ++++++++++++++++---------- planner/pce/exporter.go | 2 +- planner/pce/field.go | 4 +- planner/pce/loader.go | 9 +++-- planner/pce/tmpl.go | 2 +- planner/pce/tmpl_struct.go | 9 +++-- planner/pce/tmpls/golang.go | 79 +++++++++++++++++++++++++++++-------- 7 files changed, 113 insertions(+), 49 deletions(-) diff --git a/planner/pce/cs/xlsx.go b/planner/pce/cs/xlsx.go index 40b1931..a62ec0b 100644 --- a/planner/pce/cs/xlsx.go +++ b/planner/pce/cs/xlsx.go @@ -8,16 +8,25 @@ import ( "strings" ) -func NewXlsx(sheet *xlsx.Sheet) *Xlsx { +type XlsxExportType int + +const ( + XlsxExportTypeServer XlsxExportType = iota + XlsxExportTypeClient +) + +func NewXlsx(sheet *xlsx.Sheet, exportType XlsxExportType) *Xlsx { config := &Xlsx{ - sheet: sheet, + sheet: sheet, + exportType: exportType, } return config } // Xlsx 内置的 Xlsx 配置 type Xlsx struct { - sheet *xlsx.Sheet + sheet *xlsx.Sheet + exportType XlsxExportType } func (slf *Xlsx) GetConfigName() string { @@ -41,12 +50,13 @@ func (slf *Xlsx) GetIndexCount() int { } func (slf *Xlsx) GetFields() []pce.DataField { - var handle = func(desc, name, fieldType, exportType *xlsx.Cell) (pce.DataField, bool) { + var handle = func(index int, desc, name, fieldType, exportType *xlsx.Cell) (pce.DataField, bool) { var field pce.DataField if desc == nil || name == nil || fieldType == nil || exportType == nil { return field, false } field = pce.DataField{ + Index: index, Name: strings.ReplaceAll(strings.ReplaceAll(str.FirstUpper(name.String()), "\r", ""), "\n", ""), Type: fieldType.String(), ExportType: exportType.String(), @@ -65,13 +75,13 @@ func (slf *Xlsx) GetFields() []pce.DataField { var fields []pce.DataField if slf.GetIndexCount() > 0 { for x := 1; x < slf.getWidth(); x++ { - if field, match := handle(slf.get(x, 3), slf.get(x, 4), slf.get(x, 5), slf.get(x, 6)); match { + if field, match := handle(x, slf.get(x, 3), slf.get(x, 4), slf.get(x, 5), slf.get(x, 6)); match { fields = append(fields, field) } } } else { for y := 4; y < slf.getHeight(); y++ { - if field, match := handle(slf.get(0, y), slf.get(1, y), slf.get(2, y), slf.get(3, y)); match { + if field, match := handle(y, slf.get(0, y), slf.get(1, y), slf.get(2, y), slf.get(3, y)); match { fields = append(fields, field) } } @@ -86,32 +96,31 @@ func (slf *Xlsx) GetData() [][]pce.DataInfo { for y := 7; y < slf.getHeight(); y++ { var line []pce.DataInfo var stop bool - for x := 0; x < slf.getWidth(); x++ { - if prefixCell := slf.get(x, y); prefixCell != nil { - prefix := prefixCell.String() - if strings.HasPrefix(prefix, "#") { - break - } - } - if x == 0 { + + if prefixCell := slf.get(0, y); prefixCell != nil { + prefix := prefixCell.String() + if strings.HasPrefix(prefix, "#") { continue } - var isIndex = x-1 < slf.GetIndexCount() + } + + for i, field := range slf.GetFields() { + var isIndex = i-1 < slf.GetIndexCount() var value string - if valueCell := slf.get(x, y); valueCell != nil { + if valueCell := slf.get(field.Index, y); valueCell != nil { value = valueCell.String() } else if isIndex { stop = true break } - valueCell := slf.get(x, y) + valueCell := slf.get(field.Index, y) if valueCell == nil { break } - if len(fields) > x-1 { + if len(fields) > i-1 { line = append(line, pce.DataInfo{ - DataField: fields[x-1], + DataField: field, Value: value, }) } @@ -164,7 +173,15 @@ func (slf *Xlsx) get(x, y int) *xlsx.Cell { func (slf *Xlsx) checkFieldInvalid(field pce.DataField) bool { switch strings.ToLower(field.ExportType) { - case "s", "c", "sc", "cs": + case "s": + if slf.exportType != XlsxExportTypeServer { + return true + } + case "c": + if slf.exportType != XlsxExportTypeClient { + return true + } + case "sc", "cs": default: return true } diff --git a/planner/pce/exporter.go b/planner/pce/exporter.go index 25b6581..6df3a4f 100644 --- a/planner/pce/exporter.go +++ b/planner/pce/exporter.go @@ -10,7 +10,7 @@ type Exporter struct{} // ExportStruct 导出结构 func (slf *Exporter) ExportStruct(tmpl Tmpl, tmplStruct ...*TmplStruct) ([]byte, error) { - raw, err := tmpl.Render(tmplStruct) + raw, err := tmpl.Render(tmplStruct...) if err != nil { return nil, err } diff --git a/planner/pce/field.go b/planner/pce/field.go index e135b9d..e2672dd 100644 --- a/planner/pce/field.go +++ b/planner/pce/field.go @@ -1,7 +1,6 @@ package pce import ( - "github.com/kercylan98/minotaur/utils/super" "reflect" "strings" ) @@ -20,6 +19,5 @@ type Field interface { func GetFieldGolangType(field Field) string { typeOf := reflect.TypeOf(field).Elem() kind := strings.ToLower(typeOf.Kind().String()) - name := strings.ToLower(typeOf.Name()) - return super.If(kind == name, kind, name) + return kind } diff --git a/planner/pce/loader.go b/planner/pce/loader.go index 035c1cf..b6bd373 100644 --- a/planner/pce/loader.go +++ b/planner/pce/loader.go @@ -26,13 +26,13 @@ type Loader struct { // LoadStruct 加载结构 func (slf *Loader) LoadStruct(config Config) *TmplStruct { var tmpl = &TmplStruct{ - Name: str.FirstUpper(config.GetConfigName()), - Desc: config.GetDescription(), + Name: str.FirstUpper(config.GetConfigName()), + Desc: config.GetDescription(), + IndexCount: config.GetIndexCount(), } - indexCount := config.GetIndexCount() for i, field := range config.GetFields() { f := tmpl.addField(tmpl.Name, str.FirstUpper(field.Name), field.Desc, field.Type, slf.fields) - if i < indexCount { + if i < tmpl.IndexCount { f.isIndex = true } } @@ -167,6 +167,7 @@ type DataInfo struct { // DataField 配置数据字段 type DataField struct { + Index int // 字段索引 Name string // 字段名称 Desc string // 字段描述 Type string // 字段类型 diff --git a/planner/pce/tmpl.go b/planner/pce/tmpl.go index fb7497a..3bf9319 100644 --- a/planner/pce/tmpl.go +++ b/planner/pce/tmpl.go @@ -3,5 +3,5 @@ package pce // Tmpl 配置结构模板接口 type Tmpl interface { // Render 渲染模板 - Render(templates []*TmplStruct) (string, error) + Render(templates ...*TmplStruct) (string, error) } diff --git a/planner/pce/tmpl_struct.go b/planner/pce/tmpl_struct.go index 99983fe..11d727b 100644 --- a/planner/pce/tmpl_struct.go +++ b/planner/pce/tmpl_struct.go @@ -6,9 +6,10 @@ import ( // TmplStruct 模板结构 type TmplStruct struct { - Name string // 结构名称 - Desc string // 结构描述 - Fields []*TmplField // 字段列表 + Name string // 结构名称 + Desc string // 结构描述 + Fields []*TmplField // 字段列表 + IndexCount int // 索引数量 } // addField 添加字段 @@ -20,6 +21,8 @@ func (slf *TmplStruct) addField(parent, name, desc, fieldType string, fields map } if !hash.Exist(fields, fieldType) { field.setStruct(parent, name, desc, fieldType, fields) + } else { + field.Type = GetFieldGolangType(fields[fieldType]) } slf.Fields = append(slf.Fields, field) return field diff --git a/planner/pce/tmpls/golang.go b/planner/pce/tmpls/golang.go index f32d66a..be01d50 100644 --- a/planner/pce/tmpls/golang.go +++ b/planner/pce/tmpls/golang.go @@ -40,11 +40,7 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { var ( json = jsonIter.ConfigCompatibleWithStandardLibrary - configs map[Sign]any = map[Sign]any{ - {{- range .Templates}} - {{.Name}}Sign: {{.Name}}, - {{- end}} - } + configs map[Sign]any signs = []Sign{ {{- range .Templates}} {{.Name}}Sign, @@ -55,13 +51,33 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { var ( {{- range .Templates}} - {{.Name}} {{$.GetVariable .}} + {{- if $.HasIndex .}} + {{.Name}} {{$.GetVariable .}} + {{- end}} + {{- end}} + ) + + var ( + {{- range .Templates}} + {{- if $.HasIndex .}}{{- else}} + {{.Name}} *{{$.GetConfigName .}} + {{- end}} {{- end}} ) var ( {{- range .Templates}} - _{{.Name}} {{$.GetVariable .}} + {{- if $.HasIndex .}} + _{{.Name}} {{$.GetVariable .}} + {{- end}} + {{- end}} + ) + + var ( + {{- range .Templates}} + {{- if $.HasIndex .}}{{- else}} + _{{.Name}} *{{$.GetConfigName .}} + {{- end}} {{- end}} ) @@ -121,14 +137,21 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { mutex.Lock() defer mutex.Unlock() for _, sign := range signs { - {{- range .Templates}} - temp := make({{$.GetVariable .}}) - if err := handle(sign, &temp, json);err != nil { - log.Error("Config", log.String("Name", "{{.Name}}"), log.Bool("Invalid", true), log.Err(err)) - }else { - _{{.Name}} = temp - } - {{- end}} + switch sign { + {{- range .Templates}} + case {{.Name}}Sign: + {{- if $.HasIndex .}} + temp := make({{$.GetVariable .}}) + {{- else}} + temp := new({{$.GetConfigName .}}) + {{- end}} + if err := handle(sign, &temp, json);err != nil { + log.Error("Config", log.String("Name", "{{.Name}}"), log.Bool("Invalid", true), log.Err(err)) + }else { + _{{.Name}} = temp + } + {{- end}} + } } } @@ -137,7 +160,11 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { switch sign { {{- range .Templates}} case {{.Name}}Sign: - temp := make({{$.GetVariable .}}) + {{- if $.HasIndex .}} + temp := make({{$.GetVariable .}}) + {{- else}} + temp := new({{$.GetConfigName .}}) + {{- end}} if err := json.Unmarshal(data, &{{.Name}}); err != nil { log.Error("Config", log.String("Name", "{{.Name}}"), log.Bool("Invalid", true), log.Err(err)) return @@ -151,10 +178,24 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { func Refresh() { mutex.Lock() defer mutex.Unlock() + cs := make(map[Sign]any) + {{- range .Templates}} {{.Name}} = _{{.Name}} - _{{.Name}} = nil + cs[{{.Name}}Sign] = {{.Name}} {{- end}} + + configs = cs + } + + // GetConfigs 获取所有配置 + func GetConfigs() map[Sign]any { + return configs + } + + // GetConfigSigns 获取所有配置的标识 + func GetConfigSigns() []Sign { + return signs } `, slf) } @@ -172,3 +213,7 @@ func (slf *Golang) GetVariable(config *pce.TmplStruct) string { func (slf *Golang) GetConfigName(config *pce.TmplStruct) string { return strings.ReplaceAll(config.Name, "Config", "Configuration") } + +func (slf *Golang) HasIndex(config *pce.TmplStruct) bool { + return config.IndexCount > 0 +} From 9349e3cdbedfdc7d9a4e3a68294afce8ca63da1d Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Mon, 17 Jul 2023 16:11:29 +0800 Subject: [PATCH 09/10] =?UTF-8?q?other:=20=E9=85=8D=E7=BD=AE=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=20Golang=20=E7=BB=93=E6=9E=84=E4=BD=93=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- planner/pce/cs/xlsx.go | 6 +++--- planner/pce/tmpls/golang.go | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/planner/pce/cs/xlsx.go b/planner/pce/cs/xlsx.go index a62ec0b..b81c6a5 100644 --- a/planner/pce/cs/xlsx.go +++ b/planner/pce/cs/xlsx.go @@ -38,7 +38,7 @@ func (slf *Xlsx) GetDisplayName() string { } func (slf *Xlsx) GetDescription() string { - return "暂无描述" + return slf.GetDisplayName() } func (slf *Xlsx) GetIndexCount() int { @@ -57,10 +57,10 @@ func (slf *Xlsx) GetFields() []pce.DataField { } field = pce.DataField{ Index: index, - Name: strings.ReplaceAll(strings.ReplaceAll(str.FirstUpper(name.String()), "\r", ""), "\n", ""), + Name: strings.ReplaceAll(strings.ReplaceAll(str.FirstUpper(name.String()), "\r", " "), "\n", " "), Type: fieldType.String(), ExportType: exportType.String(), - Desc: strings.ReplaceAll(strings.ReplaceAll(desc.String(), "\r", ""), "\n", ""), + Desc: strings.ReplaceAll(strings.ReplaceAll(desc.String(), "\r", " "), "\n", " "), } if len(field.Name) == 0 || len(field.Type) == 0 || len(field.ExportType) == 0 { return field, false diff --git a/planner/pce/tmpls/golang.go b/planner/pce/tmpls/golang.go index be01d50..f7afb2b 100644 --- a/planner/pce/tmpls/golang.go +++ b/planner/pce/tmpls/golang.go @@ -34,7 +34,7 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { const ( {{- range .Templates}} - {{.Name}}Sign Sign = "{{.Name}}" + {{.Name}}Sign Sign = "{{.Name}}" // {{.Desc}} {{- end}} ) @@ -52,7 +52,7 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { var ( {{- range .Templates}} {{- if $.HasIndex .}} - {{.Name}} {{$.GetVariable .}} + {{.Name}} {{$.GetVariable .}} // {{.Desc}} {{- end}} {{- end}} ) @@ -60,7 +60,7 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { var ( {{- range .Templates}} {{- if $.HasIndex .}}{{- else}} - {{.Name}} *{{$.GetConfigName .}} + {{.Name}} *{{$.GetConfigName .}} // {{.Desc}} {{- end}} {{- end}} ) @@ -68,7 +68,7 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { var ( {{- range .Templates}} {{- if $.HasIndex .}} - _{{.Name}} {{$.GetVariable .}} + _{{.Name}} {{$.GetVariable .}} // {{.Desc}} {{- end}} {{- end}} ) @@ -76,12 +76,13 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { var ( {{- range .Templates}} {{- if $.HasIndex .}}{{- else}} - _{{.Name}} *{{$.GetConfigName .}} + _{{.Name}} *{{$.GetConfigName .}} // {{.Desc}} {{- end}} {{- end}} ) {{- range .Templates}} + // {{$.GetConfigName .}} {{.Desc}} type {{$.GetConfigName .}} struct { {{- range .Fields}} {{- if .IsSlice}} @@ -110,6 +111,7 @@ func (slf *Golang) Render(templates ...*pce.TmplStruct) (string, error) { {{- range .Templates}} {{- range .AllChildren}} + // {{.Name}} {{.Desc}} type {{.Name}} struct { {{- range .Fields}} {{- if .IsSlice}} From 3ee638f4df459f36a05190b3874502f68e815fd2 Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Mon, 17 Jul 2023 17:05:21 +0800 Subject: [PATCH 10/10] =?UTF-8?q?feat:=20super=20=E5=8C=85=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=BD=BF=E7=94=A8=20super.GoFormat=20=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E6=A0=BC=E5=BC=8F=E5=8C=96=20go=20=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/super/gofmt.go | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 utils/super/gofmt.go diff --git a/utils/super/gofmt.go b/utils/super/gofmt.go new file mode 100644 index 0000000..a4f2d24 --- /dev/null +++ b/utils/super/gofmt.go @@ -0,0 +1,9 @@ +package super + +import "os/exec" + +// GoFormat go 代码格式化 +func GoFormat(filePath string) { + cmd := exec.Command("gofmt", "-w", filePath) + _ = cmd.Run() +}