app作为eudore框架的主体存在,拥有context.Context、Config、Logger、Server、Router、ContextPool六点基础组件,分别对应生命周期、配置、日志、服务、路由、请求上下文六块功能。
生命周期负责整体停止运行,在Context结束后一层层对象全部停止;配置负责保存全局配置对象;日志负责日志输出;服务负责启动监听处理连接;路由负责请求匹配和处理注册;请求上下文提供基本的请求处理方法。
额外的Validater、GetWarp、HandlerFuncs三项属性对应数据校验、Config值类型转换、全局中间件,除此之外没有其他额外的配置属性,App定义及其简单,具体参考源码。
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
}
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
}