mirror of
https://github.com/duanhf2012/origin.git
synced 2026-02-04 06:54:45 +08:00
优化文件结构
This commit is contained in:
545
sysservice/httpservice/httpservice.go
Normal file
545
sysservice/httpservice/httpservice.go
Normal file
@@ -0,0 +1,545 @@
|
||||
package httpservice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duanhf2012/origin/event"
|
||||
"github.com/duanhf2012/origin/network"
|
||||
"github.com/duanhf2012/origin/service"
|
||||
"github.com/duanhf2012/origin/util/uuid"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
var Default_ReadTimeout time.Duration = time.Second*10
|
||||
var Default_WriteTimeout time.Duration = time.Second*10
|
||||
var Default_ProcessTimeout time.Duration = time.Second*10
|
||||
|
||||
var Default_HttpRouter *HttpRouter= &HttpRouter{}
|
||||
|
||||
//http redirect
|
||||
type HttpRedirectData struct {
|
||||
Url string
|
||||
CookieList []*http.Cookie
|
||||
}
|
||||
|
||||
type HTTP_METHOD int
|
||||
|
||||
const (
|
||||
METHOD_NONE HTTP_METHOD = iota
|
||||
METHOD_GET
|
||||
METHOD_POST
|
||||
|
||||
METHOD_INVALID
|
||||
)
|
||||
|
||||
type HttpHandle func(session *HttpSession)
|
||||
|
||||
type routerMatchData struct {
|
||||
matchURL string
|
||||
httpHandle HttpHandle
|
||||
}
|
||||
|
||||
|
||||
type routerServeFileData struct {
|
||||
matchUrl string
|
||||
localPath string
|
||||
method HTTP_METHOD
|
||||
}
|
||||
|
||||
type IHttpRouter interface {
|
||||
//RegRouter(method HTTP_METHOD, url string, handle HttpHandle) bool
|
||||
GET(url string, handle HttpHandle) bool
|
||||
POST(url string, handle HttpHandle) bool
|
||||
Router(session *HttpSession)
|
||||
|
||||
SetServeFile(method HTTP_METHOD, urlpath string, dirname string) error
|
||||
SetFormFileKey(formFileKey string)
|
||||
GetFormFileKey()string
|
||||
AddHttpFiltrate(FiltrateFun HttpFiltrate) bool
|
||||
}
|
||||
|
||||
|
||||
type HttpRouter struct {
|
||||
pathRouter map[HTTP_METHOD] map[string] routerMatchData //url地址,对应本service地址
|
||||
serveFileData map[string] *routerServeFileData
|
||||
//eventReciver event.IEventHandler
|
||||
httpFiltrateList [] HttpFiltrate
|
||||
|
||||
formFileKey string
|
||||
}
|
||||
|
||||
type HttpSession struct {
|
||||
httpRouter IHttpRouter
|
||||
r *http.Request
|
||||
w http.ResponseWriter
|
||||
|
||||
//parse result
|
||||
mapParam map[string]string
|
||||
body []byte
|
||||
|
||||
//processor result
|
||||
statusCode int
|
||||
msg []byte
|
||||
fileData *routerServeFileData
|
||||
redirectData *HttpRedirectData
|
||||
sessionDone chan *HttpSession
|
||||
}
|
||||
|
||||
|
||||
type HttpService struct {
|
||||
service.Service
|
||||
|
||||
httpServer network.HttpServer
|
||||
postAliasUrl map[HTTP_METHOD] map[string]routerMatchData //url地址,对应本service地址
|
||||
httpRouter IHttpRouter
|
||||
listenAddr string
|
||||
corsHeader *CORSHeader
|
||||
processTimeout time.Duration
|
||||
}
|
||||
|
||||
func (slf *HttpService) AddFiltrate(FiltrateFun HttpFiltrate) bool {
|
||||
return slf.httpRouter.AddHttpFiltrate(FiltrateFun)
|
||||
}
|
||||
|
||||
func NewHttpHttpRouter() IHttpRouter {
|
||||
httpRouter := &HttpRouter{}
|
||||
//httpRouter.eventReciver = eventHandler
|
||||
httpRouter.pathRouter =map[HTTP_METHOD] map[string] routerMatchData{}
|
||||
httpRouter.serveFileData = map[string] *routerServeFileData{}
|
||||
httpRouter.formFileKey = "file"
|
||||
for i:=METHOD_NONE+1;i<METHOD_INVALID;i++{
|
||||
httpRouter.pathRouter[i] = map[string] routerMatchData{}
|
||||
}
|
||||
|
||||
|
||||
return httpRouter
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (slf *HttpSession) Query(key string) (string, bool) {
|
||||
|
||||
if slf.mapParam == nil {
|
||||
slf.mapParam = make(map[string]string)
|
||||
|
||||
paramStr := strings.Trim(slf.r.URL.RawQuery, "/")
|
||||
paramStrList := strings.Split(paramStr, "&")
|
||||
for _, val := range paramStrList {
|
||||
index := strings.Index(val, "=")
|
||||
if index >= 0 {
|
||||
slf.mapParam[val[0:index]] = val[index+1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret, ok := slf.mapParam[key]
|
||||
return ret, ok
|
||||
}
|
||||
|
||||
func (slf *HttpSession) GetBody() []byte{
|
||||
return slf.body
|
||||
}
|
||||
|
||||
func (slf *HttpSession) GetMethod() HTTP_METHOD {
|
||||
return slf.getMethod(slf.r.Method)
|
||||
}
|
||||
|
||||
func (slf *HttpSession) GetPath() string{
|
||||
return strings.Trim(slf.r.URL.Path,"/")
|
||||
}
|
||||
|
||||
func (slf *HttpSession) SetHeader(key, value string) {
|
||||
slf.w.Header().Set(key,value)
|
||||
}
|
||||
|
||||
func (slf *HttpSession) AddHeader(key, value string) {
|
||||
slf.w.Header().Add(key,value)
|
||||
}
|
||||
|
||||
func (slf *HttpSession) GetHeader(key string) string{
|
||||
return slf.r.Header.Get(key)
|
||||
}
|
||||
|
||||
func (slf *HttpSession) DelHeader(key string) {
|
||||
slf.r.Header.Del(key)
|
||||
}
|
||||
|
||||
func (slf *HttpSession) WriteStatusCode(statusCode int){
|
||||
slf.statusCode = statusCode
|
||||
}
|
||||
|
||||
func (slf *HttpSession) Write(msg []byte) {
|
||||
slf.msg = msg
|
||||
}
|
||||
|
||||
func (slf *HttpSession) WriteJsonDone(statusCode int,msgJson interface{}) error {
|
||||
msg, err := json.Marshal(msgJson)
|
||||
if err == nil {
|
||||
slf.Write(msg)
|
||||
}
|
||||
|
||||
slf.Done()
|
||||
return err
|
||||
}
|
||||
|
||||
func (slf *HttpSession) flush() {
|
||||
slf.w.WriteHeader(slf.statusCode)
|
||||
if slf.msg!=nil {
|
||||
slf.w.Write(slf.msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (slf *HttpSession) Done(){
|
||||
slf.sessionDone <- slf
|
||||
}
|
||||
|
||||
func (slf *HttpSession) getMethod(method string) HTTP_METHOD {
|
||||
switch method {
|
||||
case "POST":
|
||||
return METHOD_POST
|
||||
case "GET":
|
||||
return METHOD_GET
|
||||
}
|
||||
|
||||
return METHOD_INVALID
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (slf *HttpRouter) analysisRouterUrl(url string) (string, error) {
|
||||
|
||||
//替换所有空格
|
||||
url = strings.ReplaceAll(url, " ", "")
|
||||
if len(url) <= 1 || url[0] != '/' {
|
||||
return "", fmt.Errorf("url %s format is error!", url)
|
||||
}
|
||||
|
||||
//去掉尾部的/
|
||||
return strings.Trim(url, "/"), nil
|
||||
}
|
||||
|
||||
func (slf *HttpSession) Handle(){
|
||||
slf.httpRouter.Router(slf)
|
||||
}
|
||||
|
||||
func (slf *HttpRouter) SetFormFileKey(formFileKey string){
|
||||
slf.formFileKey = formFileKey
|
||||
}
|
||||
|
||||
func (slf *HttpRouter) GetFormFileKey()string{
|
||||
return slf.formFileKey
|
||||
}
|
||||
|
||||
|
||||
func (slf *HttpRouter) GET(url string, handle HttpHandle) bool {
|
||||
return slf.regRouter(METHOD_GET, url, handle)
|
||||
}
|
||||
|
||||
func (slf *HttpRouter) POST(url string, handle HttpHandle) bool {
|
||||
return slf.regRouter(METHOD_POST, url, handle)
|
||||
}
|
||||
|
||||
func (slf *HttpRouter) regRouter(method HTTP_METHOD, url string, handle HttpHandle) bool{
|
||||
mapRouter,ok := slf.pathRouter[method]
|
||||
if ok == false{
|
||||
return false
|
||||
}
|
||||
|
||||
mapRouter[strings.Trim(url,"/")] = routerMatchData{httpHandle:handle}
|
||||
return true
|
||||
}
|
||||
|
||||
func (slf *HttpRouter) Router(session *HttpSession){
|
||||
if slf.httpFiltrateList!=nil {
|
||||
for _,fun := range slf.httpFiltrateList{
|
||||
if fun(session) == false {
|
||||
//session.done()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
urlPath := session.GetPath()
|
||||
for {
|
||||
mapRouter, ok := slf.pathRouter[session.GetMethod()]
|
||||
if ok == false {
|
||||
break
|
||||
}
|
||||
|
||||
v, ok := mapRouter[urlPath]
|
||||
if ok == false {
|
||||
break
|
||||
}
|
||||
|
||||
v.httpHandle(session)
|
||||
//session.done()
|
||||
return
|
||||
}
|
||||
|
||||
for k, v := range slf.serveFileData {
|
||||
idx := strings.Index(urlPath, k)
|
||||
if idx != -1 {
|
||||
session.fileData = v
|
||||
session.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
session.WriteStatusCode(http.StatusNotFound)
|
||||
session.Done()
|
||||
}
|
||||
|
||||
|
||||
func (slf *HttpService) HttpEventHandler(ev *event.Event) {
|
||||
ev.Data.(*HttpSession).Handle()
|
||||
}
|
||||
|
||||
func (slf *HttpService) SetHttpRouter(httpRouter IHttpRouter,eventHandler event.IEventHandler) {
|
||||
slf.httpRouter = httpRouter
|
||||
slf.RegEventReciverFunc(event.Sys_Event_Http_Event,eventHandler,slf.HttpEventHandler)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
func (slf *HttpRouter) SetServeFile(method HTTP_METHOD, urlpath string, dirname string) error {
|
||||
_, err := os.Stat(dirname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
matchURL, aErr := slf.analysisRouterUrl(urlpath)
|
||||
if aErr != nil {
|
||||
return aErr
|
||||
}
|
||||
|
||||
var routerData routerServeFileData
|
||||
routerData.method = method
|
||||
routerData.localPath = dirname
|
||||
routerData.matchUrl = matchURL
|
||||
slf.serveFileData[matchURL] = &routerData
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
type HttpFiltrate func(session *HttpSession) bool //true is pass
|
||||
|
||||
func (slf *HttpRouter) AddHttpFiltrate(FiltrateFun HttpFiltrate) bool {
|
||||
slf.httpFiltrateList = append(slf.httpFiltrateList, FiltrateFun)
|
||||
return false
|
||||
}
|
||||
|
||||
func (slf *HttpSession) Redirect(url string, cookieList []*http.Cookie) {
|
||||
redirectData := &HttpRedirectData{}
|
||||
redirectData.Url = url
|
||||
redirectData.CookieList = cookieList
|
||||
|
||||
slf.redirectData = redirectData
|
||||
}
|
||||
|
||||
func (slf *HttpSession) redirects() {
|
||||
if slf.redirectData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if slf.redirectData.CookieList != nil {
|
||||
for _, v := range slf.redirectData.CookieList {
|
||||
http.SetCookie(slf.w, v)
|
||||
}
|
||||
}
|
||||
|
||||
http.Redirect(slf.w, slf.r, slf.redirectData.Url,
|
||||
http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (slf *HttpService) OnInit() error {
|
||||
iConfig := slf.GetServiceCfg()
|
||||
if iConfig == nil {
|
||||
return fmt.Errorf("%s service config is error!",slf.GetName())
|
||||
}
|
||||
tcpCfg := iConfig.(map[string]interface{})
|
||||
addr,ok := tcpCfg["ListenAddr"]
|
||||
if ok == false {
|
||||
return fmt.Errorf("%s service config is error!",slf.GetName())
|
||||
}
|
||||
var readTimeout time.Duration = Default_ReadTimeout
|
||||
var writeTimeout time.Duration = Default_WriteTimeout
|
||||
|
||||
if cfgRead,ok := tcpCfg["ReadTimeout"];ok == true {
|
||||
readTimeout = time.Duration(cfgRead.(float64))*time.Millisecond
|
||||
}
|
||||
|
||||
if cfgWrite,ok := tcpCfg["WriteTimeout"];ok == true {
|
||||
writeTimeout = time.Duration(cfgWrite.(float64))*time.Millisecond
|
||||
}
|
||||
|
||||
slf.processTimeout = Default_ProcessTimeout
|
||||
if cfgProcessTimeout,ok := tcpCfg["ProcessTimeout"];ok == true {
|
||||
slf.processTimeout = time.Duration(cfgProcessTimeout.(float64))*time.Millisecond
|
||||
}
|
||||
|
||||
slf.httpServer.Init(addr.(string), slf, readTimeout, writeTimeout)
|
||||
//Set CAFile
|
||||
caFileList,ok := tcpCfg["CAFile"]
|
||||
if ok == false {
|
||||
return nil
|
||||
}
|
||||
iCaList := caFileList.([]interface{})
|
||||
var caFile [] network.CAFile
|
||||
for _,i := range iCaList {
|
||||
mapCAFile := i.(map[string]interface{})
|
||||
c,ok := mapCAFile["Certfile"]
|
||||
if ok == false{
|
||||
continue
|
||||
}
|
||||
k,ok := mapCAFile["Certfile"]
|
||||
if ok == false{
|
||||
continue
|
||||
}
|
||||
|
||||
if c.(string)!="" && k.(string)!="" {
|
||||
caFile = append(caFile,network.CAFile{
|
||||
Certfile: c.(string),
|
||||
Keyfile: k.(string),
|
||||
})
|
||||
}
|
||||
}
|
||||
slf.httpServer.SetCAFile(caFile)
|
||||
slf.httpServer.Start()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (slf *HttpService) SetAllowCORS(corsHeader *CORSHeader) {
|
||||
slf.corsHeader = corsHeader
|
||||
}
|
||||
|
||||
func (slf *HttpService) ProcessFile(session *HttpSession){
|
||||
upath := session.r.URL.Path
|
||||
idx := strings.Index(upath, session.fileData.matchUrl)
|
||||
subPath := strings.Trim(upath[idx+len(session.fileData.matchUrl):], "/")
|
||||
|
||||
destLocalPath := session.fileData.localPath + "/"+subPath
|
||||
|
||||
switch session.GetMethod() {
|
||||
case METHOD_GET:
|
||||
//判断文件夹是否存在
|
||||
_, err := os.Stat(destLocalPath)
|
||||
if err == nil {
|
||||
http.ServeFile(session.w, session.r, destLocalPath)
|
||||
} else {
|
||||
session.WriteStatusCode(http.StatusNotFound)
|
||||
session.flush()
|
||||
return
|
||||
}
|
||||
//上传资源
|
||||
case METHOD_POST:
|
||||
// 在这儿处理例外路由接口
|
||||
session.r.ParseMultipartForm(32 << 20) // max memory is set to 32MB
|
||||
resourceFile, resourceFileHeader, err := session.r.FormFile(session.httpRouter.GetFormFileKey())
|
||||
if err != nil {
|
||||
session.WriteStatusCode(http.StatusNotFound)
|
||||
session.flush()
|
||||
return
|
||||
}
|
||||
defer resourceFile.Close()
|
||||
//重新拼接文件名
|
||||
imgFormat := strings.Split(resourceFileHeader.Filename, ".")
|
||||
if len(imgFormat) < 2 {
|
||||
session.WriteStatusCode(http.StatusNotFound)
|
||||
session.flush()
|
||||
return
|
||||
}
|
||||
filePrefixName := uuid.Rand().HexEx()
|
||||
fileName := filePrefixName + "." + imgFormat[len(imgFormat)-1]
|
||||
//创建文件
|
||||
localpath := fmt.Sprintf("%s%s", destLocalPath, fileName)
|
||||
localfd, err := os.OpenFile(localpath, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
session.WriteStatusCode(http.StatusNotFound)
|
||||
session.flush()
|
||||
return
|
||||
}
|
||||
defer localfd.Close()
|
||||
io.Copy(localfd, resourceFile)
|
||||
session.WriteStatusCode(http.StatusOK)
|
||||
session.Write([]byte(upath+"/"+fileName))
|
||||
session.flush()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type CORSHeader struct {
|
||||
AllowCORSHeader map[string][]string
|
||||
}
|
||||
|
||||
func NewAllowCORSHeader() *CORSHeader{
|
||||
header := &CORSHeader{}
|
||||
header.AllowCORSHeader = map[string][]string{}
|
||||
header.AllowCORSHeader["Access-Control-Allow-Origin"] = []string{"*"}
|
||||
header.AllowCORSHeader["Access-Control-Allow-Methods"] =[]string{ "POST, GET, OPTIONS, PUT, DELETE"}
|
||||
header.AllowCORSHeader["Access-Control-Allow-Headers"] = []string{"Content-Type"}
|
||||
|
||||
return header
|
||||
}
|
||||
|
||||
func (slf *CORSHeader) AddAllowHeader(key string,val string){
|
||||
slf.AllowCORSHeader["Access-Control-Allow-Headers"] = append(slf.AllowCORSHeader["Access-Control-Allow-Headers"],fmt.Sprintf("%s,%s",key,val))
|
||||
}
|
||||
|
||||
func (slf *CORSHeader) copyTo(header http.Header){
|
||||
for k,v := range slf.AllowCORSHeader{
|
||||
for _,val := range v{
|
||||
header.Add(k,val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (slf *HttpService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if slf.corsHeader != nil {
|
||||
if origin := r.Header.Get("Origin"); origin != "" {
|
||||
slf.corsHeader.copyTo(w.Header())
|
||||
}
|
||||
}
|
||||
if r.Method == "OPTIONS" {
|
||||
return
|
||||
}
|
||||
|
||||
session := &HttpSession{sessionDone:make(chan *HttpSession,1),httpRouter:slf.httpRouter,statusCode:http.StatusOK}
|
||||
session.r = r
|
||||
session.w = w
|
||||
|
||||
defer r.Body.Close()
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
session.WriteStatusCode(http.StatusGatewayTimeout)
|
||||
session.flush()
|
||||
return
|
||||
}
|
||||
session.body = body
|
||||
|
||||
slf.GetEventHandler().NotifyEvent(&event.Event{Type:event.Sys_Event_Http_Event,Data:session})
|
||||
ticker := time.NewTicker(slf.processTimeout)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
session.WriteStatusCode(http.StatusGatewayTimeout)
|
||||
session.flush()
|
||||
break
|
||||
case <- session.sessionDone:
|
||||
if session.fileData!=nil {
|
||||
slf.ProcessFile(session)
|
||||
}else if session.redirectData!=nil {
|
||||
session.redirects()
|
||||
}else{
|
||||
session.flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user