1. package mygin
    2. import (
    3. "fmt"
    4. "math"
    5. "net/http"
    6. "path"
    7. "sync"
    8. )
    9. const abortIndex int8 = math.MaxInt8 / 2
    10. type HandlerFun func(ctx *Context)
    11. type IRouter interface {
    12. Use(...HandlerFun) IRouter
    13. GET(string, ...HandlerFun) IRouter
    14. Group(string, ...HandlerFun) *RouterGroup
    15. }
    16. type RouterGroup struct {
    17. Handlers []HandlerFun
    18. engine *Engine
    19. basePath string
    20. }
    21. type Context struct {
    22. Request *http.Request
    23. ResponseWrite http.ResponseWriter
    24. engine *Engine
    25. }
    26. type Engine struct {
    27. router map[string][]HandlerFun
    28. pool sync.Pool
    29. RouterGroup
    30. }
    31. func NewEngine() *Engine {
    32. e := &Engine{}
    33. e.router = make(map[string][]HandlerFun)
    34. e.pool.New = func() interface{} {
    35. return e.allocateContext()
    36. }
    37. e.RouterGroup = RouterGroup{
    38. basePath: "/",
    39. Handlers: nil,
    40. engine: e,
    41. }
    42. return e
    43. }
    44. func (engine *Engine) allocateContext() *Context {
    45. return &Context{engine: engine}
    46. }
    47. func (engine *Engine) Run(addr string) error {
    48. fmt.Println("http start ", addr)
    49. return http.ListenAndServe(addr, engine)
    50. }
    51. func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    52. c := engine.pool.Get().(*Context)
    53. c.ResponseWrite = w
    54. c.Request = r
    55. engine.handleHTTPRequest(c)
    56. engine.pool.Put(c)
    57. }
    58. func (engine *Engine) handleHTTPRequest(c *Context) {
    59. method := c.Request.Method
    60. path := c.Request.URL.Path
    61. key := engine.handleRequestKey(method, path)
    62. if handlers, ok := engine.router[key]; ok {
    63. for _, h := range handlers {
    64. h(c)
    65. }
    66. }
    67. }
    68. func (e *Engine) handleRequestKey(httpMethod, path string) string {
    69. return fmt.Sprintf("%s-%s", httpMethod, path)
    70. }
    71. func (engine *Engine) addRouter(httpMethod, absolutePath string, handlers []HandlerFun) {
    72. key := engine.handleRequestKey(httpMethod, absolutePath)
    73. engine.router[key] = handlers
    74. }
    75. func (g *RouterGroup) Group(path string, handlers ...HandlerFun) *RouterGroup {
    76. rg := &RouterGroup{}
    77. rg.Handlers = g.CombineHandler(handlers)
    78. rg.basePath = path
    79. rg.engine = g.engine
    80. return rg
    81. }
    82. func (group *RouterGroup) Use(handlers ...HandlerFun) IRouter {
    83. group.Handlers = append(group.Handlers, handlers...)
    84. return group
    85. }
    86. func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
    87. return joinPaths(group.basePath, relativePath)
    88. }
    89. func joinPaths(absolutePath, relativePath string) string {
    90. if relativePath == "" {
    91. return absolutePath
    92. }
    93. finalPath := path.Join(absolutePath, relativePath)
    94. appendSlash := lastChar(relativePath) == '/' && lastChar(finalPath) != '/'
    95. if appendSlash {
    96. return finalPath + "/"
    97. }
    98. return finalPath
    99. }
    100. func lastChar(str string) uint8 {
    101. if str == "" {
    102. panic("The length of the string can't be 0")
    103. }
    104. return str[len(str)-1]
    105. }
    106. func (group *RouterGroup) CombineHandler(handlers []HandlerFun) []HandlerFun {
    107. finalSize := len(group.Handlers) + len(handlers)
    108. if finalSize >= int(abortIndex) {
    109. panic("too many handlers")
    110. }
    111. mergedHandlers := make([]HandlerFun, finalSize)
    112. copy(mergedHandlers, group.Handlers)
    113. copy(mergedHandlers[len(group.Handlers):], handlers)
    114. return mergedHandlers
    115. }
    116. func (group *RouterGroup) handle(httpMethod, relativePath string, handlers []HandlerFun) IRouter {
    117. absolutePath := group.calculateAbsolutePath(relativePath)
    118. handlers = group.CombineHandler(handlers)
    119. group.engine.addRouter(httpMethod, absolutePath, handlers)
    120. return group
    121. }
    122. func (g *RouterGroup) GET(path string, handles ...HandlerFun) IRouter {
    123. g.handle("GET", path, handles)
    124. return g
    125. }

    测试

    1. func main() {
    2. r := mygin.NewEngine()
    3. r.GET("/ping", func(ctx *mygin.Context) {
    4. ctx.ResponseWrite.Header().Set("content-type","text/json")
    5. ctx.ResponseWrite.WriteHeader(http.StatusOK)
    6. r := map[string]interface{}{"code":0,"message":"ok","data":"pong"}
    7. data,_:= json.Marshal(r)
    8. ctx.ResponseWrite.Write(data)
    9. })
    10. log.Fatal(r.Run(":8888"))
    11. }

    执行测试

    1. curl localhost:8888/ping
    2. {"code":0,"data":"pong","message":"ok"}