diff --git a/external_tools/tiger/codetemplate.go b/external_tools/tiger/codetemplate.go new file mode 100644 index 0000000..b348535 --- /dev/null +++ b/external_tools/tiger/codetemplate.go @@ -0,0 +1,154 @@ +package main + +const ( + DemoCode = `package main + +import ( + "github.com/karldoenitz/Tigo/web" +) + +// HelloHandler it's a demo handler +type HelloHandler struct { + web.BaseHandler +} + +// Get http get method +func (h *HelloHandler) Get() { + // write your code here + h.ResponseAsHtml("Hello Tiger Go!") +} + +// urls url mapping +var urls = []web.Pattern{ + {"/hello-world", HelloHandler{}, nil}, +} + +func main() { + application := web.Application{ + IPAddress: "0.0.0.0", + Port: 8888, + UrlPatterns: urls, + } + application.Run() +} +` + mainCode = `package main + +import ( + "github.com/karldoenitz/Tigo/web" + "{{ .ProjectName }}/handler" +) + +// Write you url mapping here +var urls = []web.Pattern{ + {"/ping", handler.PingHandler{}, nil}, +} + +func main() { + application := web.Application{ + IPAddress: "0.0.0.0", + Port: 8080, + UrlPatterns: urls, + } + application.Run() +} + +` + handlerCode = `// you can write your code here. +// You can add 'Post', 'Put', 'Delete' and other methods to handler. +package handler + +import ( + "github.com/karldoenitz/Tigo/web" +) + +type {{ .HandlerName }} struct { + web.BaseHandler +} + +func (p *{{ .HandlerName }}) Get() { + // write your code here + p.ResponseAsText("Pong") +} + +func (p *{{ .HandlerName }}) Post() { + // write your code here + p.ResponseAsText("Pong") +} + +` + logCode = `// you can write your code here. +// You can modify the log level and add more logs. +package logger + +import ( + "os" + "github.com/sirupsen/logrus" +) + +var Logger = logrus.New() + +func init() { + Logger.SetOutput(os.Stdout) + Logger.SetLevel(logrus.InfoLevel) +} + +` + configCodeJson = `{ + "cookie": "{{ .CookieKey }}", + "ip": "0.0.0.0", + "port": 8080, + "log": { + "trace": "stdout", + "info": "{{ .WorkDir }}/log/tigo-framework-info.log", + "warning": "{{ .WorkDir }}/log/tigo-framework-warning.log", + "error": "{{ .WorkDir }}/log/tigo-framework-info-error.log" + } +} +` + configCodeYaml = `cookie: {{ .CookieKey }} +ip: 0.0.0.0 +port: 8080 +log: + trace: stdout + info: "{{ .WorkDir }}/log/tigo-framework-info.log" + warning: "{{ .WorkDir }}/log/tigo-framework-warning.log" + error: "{{ .WorkDir }}/log/tigo-framework-info-error.log" +` + cmdVerbose = ` +use command tiger to create a Tigo projection. + +Usage: + + tiger [args] + +The commands are: + + addHandler to add a handler for Tigo projection + create to create a Tigo projection + conf to add a configuration for Tigo projection + logger to add a logger for Tigo projection + mod to run go mod + version to show Tigo version + +Use "tiger help " for more information about a command. + +` + cmdCreateVerbose = ` +use this command to create a Tigo project. +"tiger create " can create a project with name "project_name", +"tiger create demo" can create a demo project. + +` + cmdConfVerbose = ` +use this command to add a configuration. +if it's an empty folder, this command will throw an error. +the new configuration will replace the old configuration. + +` + cmdAddHandlerVerbose = ` +use this command to add a handler with defined name. +"tiger addHandler " will add a handler named "handler_name". + +` +) diff --git a/external_tools/tiger/egg.go b/external_tools/tiger/egg.go new file mode 100644 index 0000000..11777d3 --- /dev/null +++ b/external_tools/tiger/egg.go @@ -0,0 +1,221 @@ +package main + +import ( + "fmt" + "math/rand" +) + +// MapItem 定义迷宫元素枚举 +type MapItem int + +const ( + MapWall MapItem = iota + MapGround + MapEntrance + MapExit + MapOutside + MapStep +) + +// Point 定义点结构体 +type Point struct { + X, Y int +} + +// Size 定义大小结构体 +type Size struct { + Width, Height int +} + +// Rect 定义矩形结构体 +type Rect struct { + X, Y, Width, Height int +} + +// Maze 迷宫结构 +type Maze struct { + Map [][]MapItem // 迷宫地图 + MapSize Size // 迷宫尺寸 + PlayerPos Point // 游戏者位置 +} + +// MakeMaze 生成迷宫(注:宽高必须是奇数) +func (m *Maze) MakeMaze(width, height int) { + if width%2 != 1 { + width += 1 + } + + if height%2 != 1 { + height += 1 + } + + // 记录迷宫尺寸 + m.MapSize = Size{Width: width, Height: height} + + // 分配迷宫内存 + m.Map = make([][]MapItem, width+2) + for x := 0; x < width+2; x++ { + m.Map[x] = make([]MapItem, height+2) + // 初始化为墙 + for y := 0; y < height+2; y++ { + m.Map[x][y] = MapWall + } + } + + // 定义边界 + for x := 0; x <= width+1; x++ { + m.Map[x][0] = MapGround + m.Map[x][height+1] = MapGround + } + + for y := 1; y <= height; y++ { + m.Map[0][y] = MapGround + m.Map[width+1][y] = MapGround + } + + // 定义入口和出口 + m.Map[1][2] = MapEntrance + m.Map[width][height-1] = MapExit + + // 设置玩家初始位置 + m.PlayerPos = Point{X: 1, Y: 2} + + // 从任意点开始遍历生成迷宫 + x := ((rand.Intn(width-1) & 0xfffe) + 2) + y := ((rand.Intn(height-1) & 0xfffe) + 2) + m.TravelMaze(x, y) + + // 将边界标记为迷宫外 + for x := 0; x <= width+1; x++ { + m.Map[x][0] = MapOutside + m.Map[x][height+1] = MapOutside + } + + for y := 1; y <= height; y++ { + m.Map[0][y] = MapOutside + m.Map[width+1][y] = MapOutside + } +} + +// TravelMaze 生成迷宫:遍历 (x, y) 四周 +func (m *Maze) TravelMaze(x, y int) { + // 定义遍历方向 + directions := [4][2]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}} + + // 将遍历方向乱序 + for i := 0; i < 4; i++ { + n := rand.Intn(4) + directions[i], directions[n] = directions[n], directions[i] + } + + // 尝试周围四个方向 + m.Map[x][y] = MapGround + for i := 0; i < 4; i++ { + dx, dy := directions[i][0], directions[i][1] + if m.Map[x+2*dx][y+2*dy] == MapWall { + m.Map[x+dx][y+dy] = MapGround + m.TravelMaze(x+dx*2, y+dy*2) // 递归 + } + } +} + +// MapRoute 实现迷宫求解,使用深度优先搜索算法 +func (m *Maze) MapRoute() { + // 定义方向:上、右、下、左 + directions := [4][2]int{{-1, 0}, {0, 1}, {1, 0}, {0, -1}} + + // 找到入口位置 + var start Point + found := false + for i := 0; i < m.MapSize.Width+2 && !found; i++ { + for j := 0; j < m.MapSize.Height+2; j++ { + if m.Map[i][j] == MapEntrance { + start = Point{X: i, Y: j} + found = true + break + } + } + } + + if !found { + fmt.Println("未找到迷宫入口") + return + } + + // 创建访问标记数组 + visited := make([][]bool, m.MapSize.Width+2) + for i := range visited { + visited[i] = make([]bool, m.MapSize.Height+2) + } + + // 记录路径的栈 + path := []Point{start} + visited[start.X][start.Y] = true + + // 深度优先搜索函数 + var dfs func(x, y int) bool + dfs = func(x, y int) bool { + // 如果到达出口,返回成功 + if m.Map[x][y] == MapExit { + return true + } + + // 尝试四个方向 + for _, dir := range directions { + nx, ny := x+dir[0], y+dir[1] + + // 检查是否可以移动到(nx, ny) + if nx >= 0 && nx < m.MapSize.Width+2 && + ny >= 0 && ny < m.MapSize.Height+2 && + (m.Map[nx][ny] == MapGround || m.Map[nx][ny] == MapExit) && + !visited[nx][ny] { + + visited[nx][ny] = true + path = append(path, Point{X: nx, Y: ny}) + + // 递归搜索 + if dfs(nx, ny) { + return true + } + + // 回溯 + path = path[:len(path)-1] + } + } + + return false + } + + // 开始搜索 + if dfs(start.X, start.Y) { + // 标记路径 + for i := 1; i < len(path)-1; i++ { // 跳过入口和出口 + point := path[i] + m.Map[point.X][point.Y] = MapStep + } + fmt.Println("迷宫路径已找到并标记") + } else { + fmt.Println("未找到可行的迷宫路径") + } +} + +func (m *Maze) PrintMaze() { + for j := 0; j < m.MapSize.Height+2; j++ { + for i := 0; i < m.MapSize.Width+2; i++ { + if m.Map[i][j] == MapWall { + fmt.Print("\x1b[43m \x1b[0m") + } else if m.Map[i][j] == MapGround { + fmt.Print(" ") + } else if m.Map[i][j] == MapOutside { + fmt.Print("\x1b[44m \x1b[0m") + } else if m.Map[i][j] == MapEntrance { + fmt.Print("\x1b[42m \x1b[0m") + } else if m.Map[i][j] == MapExit { + fmt.Print("\x1b[41m \x1b[0m") + } else if m.Map[i][j] == MapStep { + fmt.Print("\x1b[45m \x1b[0m") + } + } + fmt.Println() + } +} diff --git a/external_tools/tiger/main.go b/external_tools/tiger/main.go index f5da862..d18565f 100644 --- a/external_tools/tiger/main.go +++ b/external_tools/tiger/main.go @@ -6,163 +6,27 @@ import ( "os" "os/exec" "strings" + "text/template" "time" "github.com/karldoenitz/Tigo/web" ) -const ( - DemoCode = `package main - -import ( - "github.com/karldoenitz/Tigo/web" -) - -// HelloHandler it's a demo handler -type HelloHandler struct { - web.BaseHandler -} - -// Get http get method -func (h *HelloHandler) Get() { - // write your code here - h.ResponseAsHtml("Hello Tiger Go!") -} - -// urls url mapping -var urls = []web.Pattern{ - {"/hello-world", HelloHandler{}, nil}, -} - -func main() { - application := web.Application{ - IPAddress: "0.0.0.0", - Port: 8888, - UrlPatterns: urls, - } - application.Run() -} -` - mainCode = `package main - -import ( - "github.com/karldoenitz/Tigo/web" - "%s/handler" -) - -// Write you url mapping here -var urls = []web.Pattern{ - {"/ping", handler.PingHandler{}, nil}, +type TemplateData struct { + ProjectName string + PackageName string + HandlerName string + ConfigWorkDir string } -func main() { - application := web.Application{ - IPAddress: "0.0.0.0", - Port: 8080, - UrlPatterns: urls, - } - application.Run() -} - -` - handlerCode = `// you can write your code here. -// You can add 'Post', 'Put', 'Delete' and other methods to handler. -package handler - -import ( - "github.com/karldoenitz/Tigo/web" -) - -type %s struct { - web.BaseHandler -} - -func (p *%s) Get() { - // write your code here - p.ResponseAsText("Pong") -} - -func (p *%s) Post() { - // write your code here - p.ResponseAsText("Pong") -} - -` - logCode = `// you can write your code here. -// You can modify the log level and add more logs. -package logger - -import ( - "os" - "github.com/sirupsen/logrus" -) - -var Logger = logrus.New() - -func init() { - Logger.SetOutput(os.Stdout) - Logger.SetLevel(logrus.InfoLevel) +type HandlerTemplateData struct { + HandlerName string } -` - configCodeJson = `{ - "cookie": "%s", - "ip": "0.0.0.0", - "port": 8080, - "log": { - "trace": "stdout", - "info": "%s/log/tigo-framework-info.log", - "warning": "%s/log/tigo-framework-warning.log", - "error": "%s/log/tigo-framework-info-error.log" - } +type ConfigTemplateData struct { + CookieKey string + WorkDir string } -` - configCodeYaml = `cookie: %s -ip: 0.0.0.0 -port: 8080 -log: - trace: stdout - info: "%s/log/tigo-framework-info.log" - warning: "%s/log/tigo-framework-warning.log" - error: "%s/log/tigo-framework-info-error.log" -` - cmdVerbose = ` -use command tiger to create a Tigo projection. - -Usage: - - tiger [args] - -The commands are: - - addHandler to add a handler for Tigo projection - create to create a Tigo projection - conf to add a configuration for Tigo projection - logger to add a logger for Tigo projection - mod to run go mod - version to show Tigo version - -Use "tiger help " for more information about a command. - -` - cmdCreateVerbose = ` -use this command to create a Tigo project. -"tiger create " can create a project with name "project_name", -"tiger create demo" can create a demo project. - -` - cmdConfVerbose = ` -use this command to add a configuration. -if it's an empty folder, this command will throw an error. -the new configuration will replace the old configuration. - -` - cmdAddHandlerVerbose = ` -use this command to add a handler with defined name. -"tiger addHandler " will add a handler named "handler_name". - -` -) // getWorkingDirPath 获取当前工作路径 func getWorkingDirPath() string { @@ -251,10 +115,19 @@ func execCreate(arg string) { defer func() { _ = f.Close() }() - if _, err := f.WriteString(fmt.Sprintf(mainCode, arg)); err != nil { - panic(err) + + // 解析main模板 + mainTmpl, err := template.New("main").Parse(mainCode) + if err != nil { + panic(fmt.Sprintf("main模板解析失败: %v", err)) + } + + // 执行main模板渲染 + mainData := TemplateData{ProjectName: arg} + if err := mainTmpl.Execute(f, mainData); err != nil { + panic(fmt.Sprintf("main模板渲染失败: %v", err)) } - // 创建handler文件 + if err := os.Mkdir(projectPath+"/handler", os.ModePerm); err != nil { fmt.Println(err.Error()) } @@ -263,11 +136,24 @@ func execCreate(arg string) { fmt.Println(err.Error()) return } - _, _ = fHandler.WriteString(fmt.Sprintf(handlerCode, "PingHandler", "PingHandler", "PingHandler")) + + // 解析handler模板 + handlerTmpl, err := template.New("handler").Parse(handlerCode) + if err != nil { + panic(fmt.Sprintf("handler模板解析失败: %v", err)) + } + + // 执行handler模板渲染 + handlerData := HandlerTemplateData{HandlerName: "PingHandler"} + if err := handlerTmpl.Execute(fHandler, handlerData); err != nil { + panic(fmt.Sprintf("handler模板渲染失败: %v", err)) + } + _ = f.Close() _ = fHandler.Close() fmt.Printf("project `%s` created successfully\n", arg) + fmt.Printf("execute command `cd %s` to enter the project directory\n", projectPath) fmt.Println("Execute go mod") } @@ -307,7 +193,18 @@ func execAddHandler(handlerName string) { fmt.Println(err.Error()) return } - _, _ = fHandler.WriteString(fmt.Sprintf(handlerCode, handlerName, handlerName, handlerName)) + + // 解析handler模板 + handlerTmpl, err := template.New("handler").Parse(handlerCode) + if err != nil { + panic(fmt.Sprintf("handler模板解析失败: %v", err)) + } + + // 执行handler模板渲染 + handlerData := HandlerTemplateData{HandlerName: handlerName} + if err := handlerTmpl.Execute(fHandler, handlerData); err != nil { + panic(fmt.Sprintf("handler模板渲染失败: %v", err)) + } _ = fHandler.Close() // 判断是否有 main 文件 _, err = os.Stat(fmt.Sprintf("%s/main.go", workDir)) @@ -377,10 +274,31 @@ func execConf(arg string) { return } currentTime := time.Now().String() + arg + // 准备配置模板数据 + cookieKey := web.MD5m16(currentTime) + configData := ConfigTemplateData{ + CookieKey: cookieKey, + WorkDir: workDir, + } + if strings.HasSuffix(arg, ".json") { - _, _ = f.WriteString(fmt.Sprintf(configCodeJson, web.MD5m16(currentTime), workDir, workDir, workDir)) + // 解析JSON配置模板 + jsonTmpl, err := template.New("configJson").Parse(configCodeJson) + if err != nil { + panic(fmt.Sprintf("JSON配置模板解析失败: %v", err)) + } + if err := jsonTmpl.Execute(f, configData); err != nil { + panic(fmt.Sprintf("JSON配置模板渲染失败: %v", err)) + } } else { - _, _ = f.WriteString(fmt.Sprintf(configCodeYaml, web.MD5m16(currentTime), workDir, workDir, workDir)) + // 解析YAML配置模板 + yamlTmpl, err := template.New("configYaml").Parse(configCodeYaml) + if err != nil { + panic(fmt.Sprintf("YAML配置模板解析失败: %v", err)) + } + if err := yamlTmpl.Execute(f, configData); err != nil { + panic(fmt.Sprintf("YAML配置模板渲染失败: %v", err)) + } } _ = f.Close() content, err := os.ReadFile(fmt.Sprintf("%s/main.go", workDir)) diff --git a/web/enums.go b/web/enums.go index f9217a2..9a7762b 100644 --- a/web/enums.go +++ b/web/enums.go @@ -1,6 +1,6 @@ package web -const Version = "2.0.0" +const Version = "2.0.2" const ( httpLowerGet = "get"