232 lines
5.5 KiB
Go
232 lines
5.5 KiB
Go
package support
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/eyebluecn/tank/code/core"
|
|
"github.com/eyebluecn/tank/code/rest"
|
|
"github.com/eyebluecn/tank/code/tool/result"
|
|
"github.com/eyebluecn/tank/code/tool/util"
|
|
"github.com/json-iterator/go"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type TankRouter struct {
|
|
installController *rest.InstallController
|
|
footprintService *rest.FootprintService
|
|
userService *rest.UserService
|
|
routeMap map[string]func(writer http.ResponseWriter, request *http.Request)
|
|
installRouteMap map[string]func(writer http.ResponseWriter, request *http.Request)
|
|
}
|
|
|
|
func NewRouter() *TankRouter {
|
|
router := &TankRouter{
|
|
routeMap: make(map[string]func(writer http.ResponseWriter, request *http.Request)),
|
|
installRouteMap: make(map[string]func(writer http.ResponseWriter, request *http.Request)),
|
|
}
|
|
|
|
//installController.
|
|
b := core.CONTEXT.GetBean(router.installController)
|
|
if b, ok := b.(*rest.InstallController); ok {
|
|
router.installController = b
|
|
}
|
|
|
|
//load userService
|
|
b = core.CONTEXT.GetBean(router.userService)
|
|
if b, ok := b.(*rest.UserService); ok {
|
|
router.userService = b
|
|
}
|
|
|
|
//load footprintService
|
|
b = core.CONTEXT.GetBean(router.footprintService)
|
|
if b, ok := b.(*rest.FootprintService); ok {
|
|
router.footprintService = b
|
|
}
|
|
|
|
//load Controllers except InstallController
|
|
for _, controller := range core.CONTEXT.GetControllerMap() {
|
|
|
|
if controller == router.installController {
|
|
routes := controller.RegisterRoutes()
|
|
for k, v := range routes {
|
|
router.installRouteMap[k] = v
|
|
}
|
|
} else {
|
|
routes := controller.RegisterRoutes()
|
|
for k, v := range routes {
|
|
router.routeMap[k] = v
|
|
}
|
|
}
|
|
|
|
}
|
|
return router
|
|
|
|
}
|
|
|
|
//catch global panic.
|
|
func (this *TankRouter) GlobalPanicHandler(writer http.ResponseWriter, request *http.Request, startTime time.Time) {
|
|
if err := recover(); err != nil {
|
|
|
|
//get panic file and line number.
|
|
_, file, line, ok := runtime.Caller(2)
|
|
if !ok {
|
|
file = "???"
|
|
line = 0
|
|
}
|
|
|
|
//unkown panic
|
|
if strings.HasSuffix(file, "runtime/panic.go") {
|
|
_, file, line, ok = runtime.Caller(4)
|
|
if !ok {
|
|
file = "???"
|
|
line = 0
|
|
}
|
|
}
|
|
//async panic
|
|
if strings.HasSuffix(file, "core/handler.go") {
|
|
_, file, line, ok = runtime.Caller(4)
|
|
if !ok {
|
|
file = "???"
|
|
line = 0
|
|
}
|
|
}
|
|
|
|
core.LOGGER.Error("panic on %s:%d %v", util.GetFilenameOfPath(file), line, err)
|
|
|
|
var webResult *result.WebResult = nil
|
|
if value, ok := err.(string); ok {
|
|
//string, default as BadRequest.
|
|
webResult = result.CustomWebResult(result.BAD_REQUEST, value)
|
|
} else if value, ok := err.(*result.WebResult); ok {
|
|
//*result.WebResult
|
|
webResult = value
|
|
} else if value, ok := err.(*result.CodeWrapper); ok {
|
|
//*result.CodeWrapper
|
|
webResult = result.ConstWebResult(value)
|
|
} else if value, ok := err.(error); ok {
|
|
//normal error
|
|
webResult = result.CustomWebResult(result.UNKNOWN, value.Error())
|
|
} else {
|
|
//other error
|
|
webResult = result.ConstWebResult(result.UNKNOWN)
|
|
}
|
|
|
|
//change the http status.
|
|
writer.WriteHeader(result.FetchHttpStatus(webResult.Code))
|
|
|
|
//if json, set the Content-Type to json.
|
|
writer.Header().Set("Content-Type", "application/json;charset=UTF-8")
|
|
|
|
//write the response.
|
|
b, _ := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(webResult)
|
|
|
|
//write to writer.
|
|
_, err := fmt.Fprintf(writer, string(b))
|
|
if err != nil {
|
|
fmt.Printf("occur error while write response %s\r\n", err.Error())
|
|
}
|
|
|
|
//log error.
|
|
go core.RunWithRecovery(func() {
|
|
this.footprintService.Trace(request, time.Now().Sub(startTime), false)
|
|
})
|
|
}
|
|
}
|
|
|
|
func (this *TankRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
|
|
|
startTime := time.Now()
|
|
|
|
//global panic handler
|
|
defer this.GlobalPanicHandler(writer, request, startTime)
|
|
|
|
path := request.URL.Path
|
|
if strings.HasPrefix(path, "/api") {
|
|
|
|
//IE browser will cache automatically. disable the cache.
|
|
util.DisableCache(writer)
|
|
|
|
if core.CONFIG.Installed() {
|
|
|
|
//if installed.
|
|
|
|
//handler user's auth info.
|
|
this.userService.PreHandle(writer, request)
|
|
|
|
if handler, ok := this.routeMap[path]; ok {
|
|
handler(writer, request)
|
|
} else {
|
|
|
|
//dispatch the request to controller's handler.
|
|
canHandle := false
|
|
for _, controller := range core.CONTEXT.GetControllerMap() {
|
|
if handler, exist := controller.HandleRoutes(writer, request); exist {
|
|
canHandle = true
|
|
handler(writer, request)
|
|
break
|
|
}
|
|
}
|
|
|
|
if !canHandle {
|
|
panic(result.CustomWebResult(result.NOT_FOUND, fmt.Sprintf("cannot handle %s", path)))
|
|
}
|
|
}
|
|
|
|
//log the request
|
|
go core.RunWithRecovery(func() {
|
|
this.footprintService.Trace(request, time.Now().Sub(startTime), true)
|
|
})
|
|
|
|
} else {
|
|
//if not installed. try to install.
|
|
if handler, ok := this.installRouteMap[path]; ok {
|
|
handler(writer, request)
|
|
} else {
|
|
panic(result.ConstWebResult(result.NOT_INSTALLED))
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//static file.
|
|
dir := util.GetHtmlPath()
|
|
|
|
if path == "" || path == "/" {
|
|
path = "index.html"
|
|
}
|
|
|
|
filePath := dir + path
|
|
exists := util.PathExists(filePath)
|
|
if !exists {
|
|
filePath = dir + "/index.html"
|
|
exists = util.PathExists(filePath)
|
|
if !exists {
|
|
panic(fmt.Sprintf("404 not found:%s", filePath))
|
|
}
|
|
}
|
|
|
|
writer.Header().Set("Content-Type", util.GetMimeType(util.GetExtension(filePath)))
|
|
|
|
diskFile, err := os.Open(filePath)
|
|
if err != nil {
|
|
panic("cannot get file.")
|
|
}
|
|
defer func() {
|
|
err := diskFile.Close()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}()
|
|
_, err = io.Copy(writer, diskFile)
|
|
if err != nil {
|
|
panic("cannot get file.")
|
|
}
|
|
|
|
}
|
|
|
|
}
|