package f5 import ( "net/http" "sync" "sync/atomic" "fmt" "q5" ) type HttpServer struct { totalRequestTimes int64 okTimes int64 pageNotFoundTimes int64 maxHandleTime int64 startTimes int64 handlersMutex sync.RWMutex handlers map[string]HandlerFunc restHandlersMutex sync.RWMutex restHandlers map[string]*q5.ListHead groupHandlersMutex sync.RWMutex groupHandlers map[string]*q5.ListHead globalMiddlewareMutex sync.RWMutex globalMiddlewareList q5.ListHead currGroups []string } func (this *HttpServer) Init(serviceName string, logOutputTime int32) *HttpServer { this.handlers = make(map[string]HandlerFunc) this.restHandlers = make(map[string]*q5.ListHead) this.groupHandlers = make(map[string]*q5.ListHead) this.globalMiddlewareList.Init(nil) this.RegisterRestHandle("/webapp/index.php", this.dispatchRequest) this.RegisterHandle("Ops", "selfChecking", func (c *Context) { c.Response(`{"errcode":0, "errmsg":"", "healthy":1, "max_rundelay":10}`) }) SysLog().Info("HttpServer.Init") if logOutputTime > 0 { Timer().SetInterval( logOutputTime, func (ev int32, params *q5.Args) { if ev == q5.TIMER_EXEC_EVENT { /* SysLog().Info("%s maxHandleTime:%d totalRequestTimes:%d okTimes:%d pageNotFoundTimes:%d", params.Sender.GetString(), this.maxHandleTime, this.totalRequestTimes, this.okTimes, this.pageNotFoundTimes) this.maxHandleTime = 0 this.okTimes = 0 this.pageNotFoundTimes = 0 */ } }) } return this } func (this *HttpServer) UnInit() { SysLog().Info("HttpServer.UnInit") } func (this *HttpServer) Start(listen_port int32) { atomic.AddInt64(&this.totalRequestTimes, 1) this.installGlobalMiddleware() SysLog().Info("HttpServer.Start listen_port:%d", listen_port) go http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", listen_port), nil) } func (this *HttpServer) dispatchRequest(c *Context) { /* atomic.AddInt64(&this.totalRequestTimes, 1) handleName := c.Request("c").GetString() + "$" + c.Request("a").GetString() handle := this.getHandle(handleName) if handle != nil { beginTick := q5.GetTickCount() defer func() { endTick := q5.GetTickCount() if oldVal := atomic.LoadInt64(&this.maxHandleTime); beginTick - endTick > oldVal { atomic.CompareAndSwapInt64(&this.maxHandleTime, oldVal, endTick - beginTick) } atomic.AddInt64(&this.okTimes, 1) if err := recover(); err != nil { SysLog().Error("handle name:%s error:%s", handleName, err) c.Response(`{"errcode":500, "errmsg":"server internal error"}`) } }() handle(c) } else { c.Response(`{"errcode":404, "errmsg":"interface not found"}`) atomic.AddInt64(&this.pageNotFoundTimes, 1) }*/ } func (this *HttpServer) getHandle(handleName string) HandlerFunc { this.handlersMutex.Lock() defer this.handlersMutex.Unlock() if handle, ok := this.handlers[handleName]; ok { return handle } else { return nil } } func (this *HttpServer) RegisterHandle(c string, a string, handle HandlerFunc) { this.handlersMutex.Lock() defer this.handlersMutex.Unlock() handleName := c + "$" + a this.handlers[handleName] = handle } func (this *HttpServer) RegisterRestHandle(pattern string, handle HandlerFunc) { if this.totalRequestTimes > 0 { panic("") } this.restHandlersMutex.Lock() defer this.restHandlersMutex.Unlock() p := new(middleware) p.entry.Init(p) p.handlerFunc = handle if l, ok := this.restHandlers[pattern]; ok { l.AddTail(&p.entry) this.applyCurrGroup(l) } else { l := q5.MakeListHead() l.AddTail(&p.entry) this.applyCurrGroup(l) this.restHandlers[pattern] = l http.HandleFunc(pattern, func (w http.ResponseWriter, r *http.Request) { c := new(Context) c.s = this c.w = &w c.r = r c.l = l c.do() }) } } func (this *HttpServer) Use(handle HandlerFunc) { if this.totalRequestTimes > 0 { panic("") } this.globalMiddlewareMutex.Lock() defer this.globalMiddlewareMutex.Unlock() p := new(middleware) p.entry.Init(nil) p.handlerFunc = handle this.globalMiddlewareList.AddTail(&p.entry) } func (this *HttpServer) installGlobalMiddleware() { this.restHandlersMutex.Lock() this.globalMiddlewareMutex.Lock() defer this.restHandlersMutex.Unlock() defer this.globalMiddlewareMutex.Unlock() for _, l := range this.restHandlers { this.globalMiddlewareList.ForEach_r( func (data interface{}) bool { m := data.(*middleware) p := new(middleware) p.entry.Init(p) p.handlerFunc = m.handlerFunc l.AddHead(&p.entry) return true }) } } func (this *HttpServer) UseGroupBegin(groupNames ...string) { if this.currGroups != nil { panic("") } this.currGroups = groupNames } func (this *HttpServer) UseGroupEnd() { if this.currGroups == nil { panic("") } this.currGroups = nil } func (this *HttpServer) applyCurrGroup(l *q5.ListHead) { if this.currGroups != nil { for _, groupName := range this.currGroups { this.groupHandlersMutex.Lock() defer this.groupHandlersMutex.Unlock() gl, ok := this.groupHandlers[groupName]; if ok { gl.ForEach_r( func (data interface{}) bool { m := data.(*middleware) p := new(middleware) p.entry.Init(p) p.handlerFunc = m.handlerFunc l.AddHead(&p.entry) return true }) } else { panic("") } } } } func (this *HttpServer) DefineGroup(groupName string, handlers ...HandlerFunc) { this.groupHandlersMutex.Lock() defer this.groupHandlersMutex.Unlock() l, ok := this.groupHandlers[groupName]; if !ok { l = q5.MakeListHead() this.groupHandlers[groupName] = l } for i := 0; i < len(handlers); i++ { p := new(middleware) p.entry.Init(p) p.handlerFunc = handlers[i] l.AddTail(&p.entry) } }