本书未发布

5.2. Eudore App

未匹配的标注

Application

app作为eudore框架的主体存在,拥有context.Context、Config、Logger、Server、Router、ContextPool六点基础组件,分别对应生命周期、配置、日志、服务、路由、请求上下文六块功能。

生命周期负责整体停止运行,在Context结束后一层层对象全部停止;配置负责保存全局配置对象;日志负责日志输出;服务负责启动监听处理连接;路由负责请求匹配和处理注册;请求上下文提供基本的请求处理方法。

额外的Validater、GetWarp、HandlerFuncs三项属性对应数据校验、Config值类型转换、全局中间件,除此之外没有其他额外的配置属性,App定义及其简单,具体参考源码

App对象定义:

// App combines the main functional interfaces to implement a simple basic method.
//
// App 组合主要功能接口,实现简单的基本方法。
type App struct {
    context.Context    `alias:"context"`
    context.CancelFunc `alias:"cancelfunc"`
    Config             `alias:"config"`
    Logger             `alias:"logger"`
    Server             `alias:"server"`
    Router             `alias:"router"`
    Binder             `alias:"binder"`
    Renderer           `alias:"renderer"`
    Validater          `alias:"validater"`
    GetWarp            `alias:"getwarp"`
    HandlerFuncs       `alias:"handlerfuncs"`
    ContextPool        sync.Pool `alias:"contextpool"`
    CancelError        error     `alias:"cancelerror"`
    cancelMutex        sync.Mutex
}

App api列表:

type App
    func NewApp(options ...interface{}) *App
    func (app *App) AddMiddleware(hs ...interface{}) error
    func (app *App) Listen(addr string) error
    func (app *App) ListenTLS(addr, key, cert string) error
    func (app *App) Options(options ...interface{})
    func (app *App) Run() error
    func (app *App) Serve(ln net.Listener)
    func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP 方法实现http.Handler接口,处理http请求。

func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    ctx := app.ContextPool.Get().(Context)
    ctx.Reset(r.Context(), w, r)
    ctx.SetHandler(-1, app.HandlerFuncs)
    ctx.Next()
    ctx.End()
    app.ContextPool.Put(ctx)
}

Options 方法加载app组件,option类型为context.Context、Logger、Config、Server、Router、Binder、Renderer、Validater时会设置app属性, 并设置组件的print属性,如果类型为error将作为app结束错误返回给Run方法。

func (app *App) Options(options ...interface{}) {
    for _, i := range options {
        if i == nil {
            continue
        }
        switch val := i.(type) {
        case context.Context:
            app.Context = val
            app.Context, app.CancelFunc = context.WithCancel(app.Context)
        // ....
        case error:
            app.Error("eudore app cannel context on handler error: " + val.Error())
            app.CancelFunc()
            app.cancelMutex.Lock()
            defer app.cancelMutex.Unlock()
            // 记录第一个错误
            if app.CancelError == nil {
                app.CancelError = val
            }
        default:
            app.Logger.Warningf("eudore app invalid option: %v", i)
        }
    }
}

ListenTLS、ListenTLS、Serve 方法非注册启动一个监听,最后返回err给使用Options方法处理。

func (app *App) Listen(addr string) error {
    conf := ServerListenConfig{
        Addr: addr,
    }
    ln, err := conf.Listen()
    if err != nil {
        app.Error(err)
        return err
    }
    app.Logger.Infof("listen http in %s %s", ln.Addr().Network(), ln.Addr().String())
    app.Serve(ln)
    return nil
}

// Serve 方法非阻塞启动一个Server监听,并处理结束返回err。
func (app *App) Serve(ln net.Listener) {
    go func() {
        app.Options(app.Server.Serve(ln))
    }()
}

AddMiddleware 方法如果第一个参数为字符串"global",则使用DefaultHandlerExtend创建请求处理函数,并作为全局请求中间件添加给App。

func (app *App) AddMiddleware(hs ...interface{}) error {
    if len(hs) > 1 {
        name, ok := hs[0].(string)
        if ok && name == "global" {
            handler := DefaultHandlerExtend.NewHandlerFuncs("", hs[1:])
            app.Info("Register app global middleware:", handler)
            app.HandlerFuncs = HandlerFuncsCombine(app.HandlerFuncs[0:len(app.HandlerFuncs)-1], handler)
            app.HandlerFuncs = HandlerFuncsCombine(app.HandlerFuncs, HandlerFuncs{app.serveContext})
            return nil
        }
    }
    return app.Router.AddMiddleware(hs...)
}

Run 方法启动App阻塞等待App结束,并周期调用app.Logger.Sync()将日志输出。

func (app *App) Run() error {
    ticker := time.NewTicker(time.Millisecond * 80)
    defer ticker.Stop()
    go func() {
        for range ticker.C {
            app.Logger.Sync()
        }
    }()

    <-app.Done()
    time.Sleep(time.Millisecond * 100)
    app.Shutdown(context.Background())
    time.Sleep(time.Millisecond * 100)
    app.cancelMutex.Lock()
    defer app.cancelMutex.Unlock()
    return app.CancelError
}

反馈和交流请加群组:QQ群373278915

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~