runningwater před 4 roky
rodič
revize
1ca0843d02
7 změnil soubory, kde provedl 301 přidání a 10 odebrání
  1. 6 0
      .idea/vcs.xml
  2. 49 0
      controller.go
  3. 207 0
      framework/context.go
  4. 3 0
      framework/controller.go
  5. 22 4
      framework/core.go
  6. 5 6
      main.go
  7. 9 0
      route.go

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 49 - 0
controller.go

@@ -0,0 +1,49 @@
+package main
+
+import (
+    "context"
+    "coredemo/framework"
+    "fmt"
+    "time"
+)
+
+func FooControllerHandler(ctx *framework.Context) error {
+    // 这个 channal 负责通知结束
+    finish := make(chan struct{}, 1)
+    // 这个 channel 负责通知 panic 异常
+    panicChan := make(chan interface{}, 1)
+
+    durationCtx, cancel := context.WithTimeout(ctx.BaseContext(), time.Duration(5*time.Second))
+
+    defer cancel()
+    {
+        // 增加异常处理
+        if p := recover(); p != nil {
+            panicChan <- p
+        }
+    }
+
+    go func() {
+        // 这里做具体的业务
+        time.Sleep(10 * time.Second)
+        ctx.Json(200, "ok")
+
+        // 结束的时候通过一个 finish 通道告知父 goroutine
+        finish <- struct{}{}
+    }()
+
+    select {
+        // 监听 panic
+    case <-panicChan:
+        ctx.Json(500, "panic")
+        // 监听结束
+    case <-finish:
+        fmt.Println("finish")
+        // 监听超时
+    case <-durationCtx.Done():
+        ctx.Json(500, "time out")
+    }
+    return ctx.Json(200, map[string]interface{}{
+        "code": 0,
+    })
+}

+ 207 - 0
framework/context.go

@@ -0,0 +1,207 @@
+package framework
+
+import (
+    "bytes"
+    "context"
+    "encoding/json"
+    "errors"
+    "io/ioutil"
+    "net/http"
+    "strconv"
+    "sync"
+)
+
+// 自定义 Context
+type Context struct {
+    request        *http.Request
+    responseWriter http.ResponseWriter
+    // 是否超时标记位
+    hasTimeout bool
+    // 写保护机制
+    writeMux *sync.Mutex
+}
+
+func NewContext(r *http.Request, w http.ResponseWriter) *Context {
+    return &Context{
+        request:        r,
+        responseWriter: w,
+        writeMux:       &sync.Mutex{},
+    }
+}
+
+// #region base function  base 封装基本的函数功能
+func (ctx *Context) WriterMux() *sync.Mutex {
+    return ctx.writeMux
+}
+
+func (ctx *Context) GetRequest() *http.Request {
+    return ctx.request
+}
+
+func (ctx *Context) GetResponse() http.ResponseWriter {
+    return ctx.responseWriter
+}
+
+func (ctx *Context) SetHasTimeout() {
+    ctx.hasTimeout = true
+}
+
+func (ctx *Context) HasTimeout() bool {
+    return ctx.hasTimeout
+}
+
+// #endregion
+
+func (ctx *Context) BaseContext() context.Context {
+    return ctx.request.Context()
+}
+
+// #region implement context.Context
+//  context 实现标准 Context 接口
+func (ctx *Context) Done() <-chan struct{} {
+    return ctx.BaseContext().Done()
+}
+
+func (ctx *Context) Err() error {
+    return ctx.BaseContext().Err()
+}
+
+func (ctx *Context) Value(key interface{}) interface{} {
+    return ctx.BaseContext().Value(key)
+}
+
+// #endregion
+
+// #region query url
+// request 封装了 http.Request 的对外接口
+func (ctx *Context) QueryInt(key string, def int) int {
+    params := ctx.QueryAll()
+    if vals, ok := params[key]; ok {
+        len := len(vals)
+        if len > 0 {
+            intVal, err := strconv.Atoi(vals[len-1])
+            if err != nil {
+                return def
+            }
+            return intVal
+        }
+    }
+    return def
+}
+
+func (ctx *Context) QueryString(key string, def string) string {
+    params := ctx.QueryAll()
+    if vals, ok := params[key]; ok {
+        len := len(vals)
+        if len > 0 {
+            return vals[len-1]
+        }
+    }
+    return def
+}
+
+func (ctx *Context) QueryArray(key string, def []string) []string {
+    params := ctx.QueryAll()
+    if vals, ok := params[key]; ok {
+        return vals
+    }
+    return def
+}
+
+func (ctx *Context) QueryAll() map[string][]string {
+    if ctx.request != nil {
+        return map[string][]string( ctx.request.URL.Query())
+    }
+    return map[string][]string{}
+}
+
+// #endregion
+
+// #region form post
+func (ctx *Context) FormInt(key string, def int) int {
+    params := ctx.FormAll()
+    if vals, ok := params[key]; ok {
+        len := len(vals)
+        if len > 0 {
+            intVal, err := strconv.Atoi(vals[len-1])
+            if err != nil {
+                return def
+            }
+            return intVal
+        }
+    }
+    return def
+}
+
+func (ctx *Context) FormString(key string, def string) string {
+    params := ctx.FormAll()
+    if vals, ok := params[key]; ok {
+        len := len(vals)
+        if len > 0 {
+            return vals[len-1]
+        }
+    }
+    return def
+}
+
+func (ctx *Context) FormArray(key string, def []string) []string {
+    params := ctx.FormAll()
+    if vals, ok := params[key]; ok {
+        return vals
+    }
+    return def
+}
+
+func (ctx *Context) FormAll() map[string][]string {
+    if ctx.request != nil {
+        return map[string][]string(ctx.request.PostForm)
+    }
+    return map[string][]string{}
+}
+
+// #endregion
+
+// #region application/json post
+//response 封装了 http.ResponseWriter 对外接口
+func (ctx *Context) BindJson(obj interface{}) error {
+    if ctx.request != nil {
+        body, err := ioutil.ReadAll(ctx.request.Body)
+        if err != nil {
+            return err
+        }
+        ctx.request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
+
+        err = json.Unmarshal(body, obj)
+        if err != nil {
+            return err
+        }
+    } else {
+        return errors.New("ctx.request empty")
+    }
+    return nil
+}
+
+func (ctx *Context) Json(status int, obj interface{}) error {
+    if ctx.HasTimeout() {
+        return nil
+    }
+    ctx.responseWriter.Header().Set("Content-Type", "application/json")
+    ctx.responseWriter.WriteHeader(status)
+    byt, err := json.Marshal(obj)
+    if err != nil {
+        ctx.responseWriter.WriteHeader(500)
+        return err
+    }
+    ctx.responseWriter.Write(byt)
+    return nil
+}
+
+func (ctx *Context) HTML(status int, obj interface{}, template string) error {
+    return nil
+}
+
+func (ctx *Context) Text(status int , obj string ) error {
+    return nil
+}
+
+// #endregion

+ 3 - 0
framework/controller.go

@@ -0,0 +1,3 @@
+package framework
+
+type ControllerHandler func(c *Context) error

+ 22 - 4
framework/core.go

@@ -1,17 +1,35 @@
 package framework
 
-import "net/http"
+import (
+    "log"
+    "net/http"
+)
 
 // 核心框架
 type Core struct {
+    router map[string]ControllerHandler
 }
 
 // 初始化框架核心结构
 func NewCore() *Core {
-    return &Core{}
+    return &Core{router: map[string]ControllerHandler{}}
+}
+
+func (c *Core) Get(url string, handler ControllerHandler) {
+    c.router[url] = handler
 }
 
 // 框架核心结构实现 handler 接口
-func (c *Core) ServeHttp(response http.ResponseWriter, request *http.Request) {
-    //: TODO
+func (c *Core) ServeHTTP(response http.ResponseWriter, request *http.Request) {
+    log.Println("core.ServeHTTP")
+    ctx := NewContext(request,response)
+
+    // 一个简单的路由选择器,这里直接写死为测试路由 foo
+    router:= c.router["foo"]
+    if router == nil {
+        return
+    }
+    log.Println("core.router")
+
+    router(ctx)
 }

+ 5 - 6
main.go

@@ -1,17 +1,16 @@
 package main
 
 import (
-    "context"
     "coredemo/framework"
     "net/http"
-    "time"
 )
 
 func main() {
+    core := framework.NewCore()
+    registerRouter(core)
     server := &http.Server{
-        Addr: ":8080",
-        // 自定义的请求核心处理函数
-        Handler: framework.NewCore(),
+        Handler: core,
+        Addr:    ":8888",
     }
-
+    server.ListenAndServe()
 }

+ 9 - 0
route.go

@@ -0,0 +1,9 @@
+package main
+
+import (
+    "coredemo/framework"
+)
+
+func registerRouter(core *framework.Core)  {
+    core.Get("foo", FooControllerHandler)
+}