router 驱动

This commit is contained in:
黄孟柱
2021-07-23 19:57:32 +08:00
parent fd21628fa6
commit f8a7e0abe6
15 changed files with 259 additions and 92 deletions

3
go.sum
View File

@@ -6,9 +6,6 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eolinker/eosc v0.0.0-20210719112509-35868a3fa3ed h1:ohyziPArYFDUmaMkjfmy7h7v1vZKxmhERBwb1Vup39U=
github.com/eolinker/eosc v0.0.1 h1:xRDaWSomXpn9E6wVZXE1fQYBpGOeQ2liCwpV4+l+QSc=
github.com/eolinker/eosc v0.0.1/go.mod h1:h9RyDaBnWKeg6fxQu8faG8TQq/sdG+ipaePTTVTEqqA=
github.com/eolinker/eosc v0.0.2 h1:PKSutO9OemDcGyJifNX8EsfOyS73E2ORZmaSJqv4f0M= github.com/eolinker/eosc v0.0.2 h1:PKSutO9OemDcGyJifNX8EsfOyS73E2ORZmaSJqv4f0M=
github.com/eolinker/eosc v0.0.2/go.mod h1:h9RyDaBnWKeg6fxQu8faG8TQq/sdG+ipaePTTVTEqqA= github.com/eolinker/eosc v0.0.2/go.mod h1:h9RyDaBnWKeg6fxQu8faG8TQq/sdG+ipaePTTVTEqqA=
github.com/eolinker/goku-standard-plugin v0.1.5 h1:0ydlgjaWsbeQi0le1I7cDrEWTramh5hMdTM7ifG78HM= github.com/eolinker/goku-standard-plugin v0.1.5 h1:0ydlgjaWsbeQi0le1I7cDrEWTramh5hMdTM7ifG78HM=

View File

@@ -1,5 +1,6 @@
package checker package checker
var globalCheckerAll = &checkerAll{}
type checkerAll struct { type checkerAll struct {
} }
@@ -12,10 +13,6 @@ func (t *checkerAll) Value() string {
return "*" return "*"
} }
func newCheckerAll() *checkerAll {
return &checkerAll{}
}
func (t *checkerAll) Check(v string, has bool) bool { func (t *checkerAll) Check(v string, has bool) bool {
return true return true
} }
@@ -24,3 +21,6 @@ func (t *checkerAll) CheckType() CheckType {
return CheckTypeAll return CheckTypeAll
} }
func newCheckerAll() *checkerAll {
return globalCheckerAll
}

View File

@@ -1,5 +1,9 @@
package checker package checker
var (
globalCheckerExist = &checkerExist{}
globalCheckerNotExist = &checkerNotExits{}
)
type checkerExist struct { type checkerExist struct {
} }
@@ -14,7 +18,7 @@ func (t *checkerExist) Value() string {
func newCheckerExist() *checkerExist { func newCheckerExist() *checkerExist {
return &checkerExist{} return globalCheckerExist
} }
func (t *checkerExist) Check(v string, has bool) bool { func (t *checkerExist) Check(v string, has bool) bool {
@@ -46,5 +50,5 @@ func (c *checkerNotExits) CheckType() CheckType {
} }
func newCheckerNotExits() *checkerNotExits { func newCheckerNotExits() *checkerNotExits {
return &checkerNotExits{} return globalCheckerNotExist
} }

View File

@@ -2,6 +2,9 @@ package checker
import "strings" import "strings"
var (
globalCheckerNone = &checkerNone{}
)
type checkerNone struct { type checkerNone struct {
} }
@@ -15,7 +18,7 @@ func (t *checkerNone) Value() string {
} }
func newCheckerNone() *checkerNone { func newCheckerNone() *checkerNone {
return &checkerNone{} return globalCheckerNone
} }
func (t *checkerNone) Check(v string, has bool) bool { func (t *checkerNone) Check(v string, has bool) bool {
@@ -26,6 +29,6 @@ func (t *checkerNone) Check(v string, has bool) bool {
} }
func (t *checkerNone) CheckType() CheckType { func (t *checkerNone) CheckType() CheckType {
return CheckTypeNull return CheckTypeNone
} }

View File

@@ -7,7 +7,7 @@ const (
CheckTypePrefix CheckTypePrefix
CheckTypeSuffix CheckTypeSuffix
CheckTypeNotEqual CheckTypeNotEqual
CheckTypeNull CheckTypeNone
CheckTypeExist CheckTypeExist
CheckTypeNotExist CheckTypeNotExist
CheckTypeRegular CheckTypeRegular

View File

@@ -1,30 +1,35 @@
package http_router package http_router
import "net/http" import (
"github.com/eolinker/eosc"
router_http "github.com/eolinker/goku-eosc/router/router-http"
"github.com/eolinker/goku-eosc/service"
)
type DriverConfig struct {
ID string `json:"id"`
Name string `json:"name" yaml:"name"`
Driver string `json:"driver" yaml:"driver"`
Listen int `json:"listen" yaml:"listen"`
Host []string `json:"host" yaml:"host"`
Rules []DriverRule `json:"rules" yaml:"rules"`
Target eosc.RequireId `json:"target" target:"target" skill:"github.com/eolinker/goku-eosc/service.service.IService"`
}
type DriverRule struct {
Location string `json:"location" yaml:"location"`
Header map[string]string `json:"header" yaml:"header"`
Query map[string]string `json:"query" yaml:"query"`
}
type Config struct { type Config struct {
name string name string
port int port int
Rules []RouterRule rules []router_http.Rule
host []string host []string
service http.Handler target service.IService
} }
type RouterRule struct {
location string
header map[string]string
query map[string]string
}
type RouterWork struct {
Service http.Handler
Config Config
}
//func (r *RouterWork) Start() error {
// routerManager.Add(r.Config, r.Service)
//}
//
//func (r *RouterWork) Stop() error {
// routerManager.Del(r.Config, r.Service)
//}

View File

@@ -1,6 +1,8 @@
package http_router package http_router
import ( import (
"fmt"
"github.com/eolinker/goku-eosc/service"
"reflect" "reflect"
"github.com/eolinker/eosc" "github.com/eolinker/eosc"
@@ -11,12 +13,34 @@ type HttpRouterDriver struct {
configType reflect.Type configType reflect.Type
} }
func (h *HttpRouterDriver) Create(id, name string, v interface{}, workers map[string]interface{}) (eosc.IWorker, error) { func (h *HttpRouterDriver) Create(id, name string, v interface{}, workers map[eosc.RequireId]interface{}) (eosc.IWorker, error) {
panic("implement me") conf, iService, err := h.check(v, workers)
if err!= nil{
return nil,err
}
return NewRouter(id,name,conf,iService),nil
} }
func (h*HttpRouterDriver)check(v interface{},workers map[eosc.RequireId]interface{})( *DriverConfig,service.IService,error) {
conf,ok:=v.(*DriverConfig)
if !ok{
return nil, nil,fmt.Errorf("get %s but %s %w",eosc.TypeNameOf(v),eosc.TypeNameOf(new(DriverConfig)),eosc.ErrorRequire)
}
ser,has:=workers[conf.Target]
if !has{
return nil,nil,fmt.Errorf("target %w",eosc.ErrorRequire)
}
target,ok:=ser.(service.IService)
if !ok{
return nil,nil,fmt.Errorf("target %w",eosc.ErrorNotGetSillForRequire)
}
return conf,target,nil
}
func NewHttpRouter(profession, name, label, desc string, params map[string]string) *HttpRouterDriver { func NewHttpRouter(profession, name, label, desc string, params map[string]string) *HttpRouterDriver {
return &HttpRouterDriver{ return &HttpRouterDriver{
configType:reflect.TypeOf(new(DriverConfig)),
info: eosc.DriverInfo{ info: eosc.DriverInfo{
Name: name, Name: name,
Label: label, Label: label,

View File

@@ -2,8 +2,17 @@ package http_router
import "github.com/eolinker/eosc" import "github.com/eolinker/eosc"
var (
driverInfo =eosc.ExtendInfo{
ID: "eolinker:goku:http_router",
Group: "eolinker",
Project: "goku",
Name: "http_router",
}
)
func Register() { func Register() {
eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver("eolinker:goku:http_router",NewRouterDriverFactory()) eosc.DefaultProfessionDriverRegister.RegisterProfessionDriver(driverInfo.ID,NewRouterDriverFactory())
} }
type RouterDriverFactory struct { type RouterDriverFactory struct {
@@ -11,11 +20,11 @@ type RouterDriverFactory struct {
} }
func (r *RouterDriverFactory) ExtendInfo() eosc.ExtendInfo { func (r *RouterDriverFactory) ExtendInfo() eosc.ExtendInfo {
panic("implement me") return driverInfo
} }
func (r *RouterDriverFactory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) { func (r *RouterDriverFactory) Create(profession string, name string, label string, desc string, params map[string]string) (eosc.IProfessionDriver, error) {
panic("implement me") return NewHttpRouter(profession,name,label,desc,params),nil
} }
func NewRouterDriverFactory() *RouterDriverFactory { func NewRouterDriverFactory() *RouterDriverFactory {

View File

@@ -2,33 +2,97 @@ package http_router
import ( import (
"github.com/eolinker/eosc" "github.com/eolinker/eosc"
router_http "github.com/eolinker/goku-eosc/router/router-http"
"github.com/eolinker/goku-eosc/service"
) )
type Router struct { type Router struct {
id string
name string
port int
conf *router_http.Config
driver * HttpRouterDriver
} }
func (r *Router) Marshal() ([]byte, error) { func (r *Router) Reset(conf interface{}, workers map[eosc.RequireId]interface{}) error {
panic("implement me") cf, target, err := r.driver.check(conf, workers)
} if err!= nil{
return err
}
func (r *Router) Worker() (eosc.IWorker, error) {
panic("implement me") newConf := getConfig(target,cf)
err =router_http.Add(cf.Listen,r.id,newConf)
if err!= nil{
return err
}
if cf.Listen != r.port{
router_http.Del(r.port,r.id)
}
r.port = cf.Listen
r.conf = newConf
return nil
} }
func (r *Router) CheckSkill(skill string) bool { func (r *Router) CheckSkill(skill string) bool {
panic("implement me") return false
} }
func (r *Router) Info() eosc.WorkerInfo { func (r *Router) Id() string {
return eosc.WorkerInfo{ return r.id
Id: "", }
Name: "",
Driver: "", func (r *Router) Start() error {
Create: "", return router_http.Add(r.port,r.id,r.conf)
Update: "", }
func (r *Router) Stop() error {
return router_http.Del(r.port,r.id)
}
func getConfig(target service.IService,cf *DriverConfig) *router_http.Config {
rules:=make([]router_http.Rule,0,len(cf.Rules))
for _,r:=range cf.Rules{
rr:=router_http.Rule{
Location: r.Location,
Header: make([]router_http.HeaderItem,0,len(r.Header)),
Query: make([]router_http.QueryItem,0,len(r.Query)),
}
for k,v:=range r.Header{
rr.Header = append(rr.Header, router_http.HeaderItem{
Name: k,
Pattern: v,
})
}
for k,v:=range r.Query{
rr.Query = append(rr.Query, router_http.QueryItem{
Name: k,
Pattern: v,
})
}
rules = append(rules, rr)
}
return &router_http.Config{
Id: cf.ID,
Name: cf.Name,
Hosts: cf.Host,
Target: target,
Rules: rules,
}
}
func NewRouter(id,name string,c *DriverConfig,target service.IService) *Router {
return &Router{
id:id,
name:name,
port:c.Listen,
conf:getConfig(target,c),
} }
} }
func NewRouter(c *Config) *Router {
return &Router{}
}

View File

@@ -15,34 +15,42 @@ import (
) )
const ( const (
cmdLocation="LOCATION" cmdLocation = "LOCATION"
cmdHeader = "HEADER" cmdHeader = "HEADER"
cmdQuery = "QUERY" cmdQuery = "QUERY"
cmdHost = "HOST"
) )
func toLocation()string{
func toLocation() string {
return cmdLocation return cmdLocation
} }
func toHeader(key string) string { func toHeader(key string) string {
return fmt.Sprint(cmdHeader ,":",textproto.CanonicalMIMEHeaderKey(key)) return fmt.Sprint(cmdHeader, ":", textproto.CanonicalMIMEHeaderKey(key))
} }
func toQuery(key string) string { func toQuery(key string) string {
return fmt.Sprint(cmdQuery ,":",key) return fmt.Sprint(cmdQuery, ":", key)
} }
func toHost()string {
func headerName(cmd string) (string,bool) { return cmdHost
if b:= strings.HasPrefix(cmd,"HEADER:");b{ }
return strings.TrimPrefix(cmd,"HEADER:"),true func headerName(cmd string) (string, bool) {
if b := strings.HasPrefix(cmd, "HEADER:"); b {
return strings.TrimPrefix(cmd, "HEADER:"), true
} }
return "",false return "", false
} }
func queryName(cmd string)(string,bool) { func queryName(cmd string) (string, bool) {
if b:= strings.HasPrefix(cmd,"QUERY:");b{ if b := strings.HasPrefix(cmd, "QUERY:"); b {
return strings.TrimPrefix(cmd,"QUERY:"),true return strings.TrimPrefix(cmd, "QUERY:"), true
} }
return "",false return "", false
} }
func isLocation(cmd string)bool { func isLocation(cmd string) bool {
return strings.EqualFold(cmd,cmdLocation) return cmd == cmdLocation
} }
func isHost(cmd string) bool {
return cmd == cmdHost
}

View File

@@ -1,11 +1,11 @@
package router_http package router_http
import ( import (
"fmt"
"github.com/eolinker/goku-eosc/router" "github.com/eolinker/goku-eosc/router"
"github.com/eolinker/goku-eosc/router/checker" "github.com/eolinker/goku-eosc/router/checker"
"github.com/eolinker/goku-eosc/service" "github.com/eolinker/goku-eosc/service"
"net/textproto"
) )
type HeaderItem struct { type HeaderItem struct {
@@ -24,6 +24,7 @@ type Rule struct {
type Config struct { type Config struct {
Id string Id string
Name string
Hosts []string Hosts []string
Target service.IService Target service.IService
Rules []Rule Rules []Rule
@@ -31,16 +32,19 @@ type Config struct {
func (r *Rule) toPath()([]router.RulePath ,error) { func (r *Rule) toPath()([]router.RulePath ,error) {
locationChecker,err:= checker.Parse(r.Location)
if err!= nil{
return nil,err
}
path:=make([]router.RulePath,0,len(r.Header)+len(r.Query)+1) path:=make([]router.RulePath,0,len(r.Header)+len(r.Query)+1)
path = append(path, router.RulePath{ if len(r.Location) >0{
CMD: toLocation(), locationChecker,err:= checker.Parse(r.Location)
Checker:locationChecker, if err!= nil{
} ) return nil,err
}
path = append(path, router.RulePath{
CMD: toLocation(),
Checker:locationChecker,
} )
}
for _,h:=range r.Header{ for _,h:=range r.Header{
ck,err:= checker.Parse(h.Pattern) ck,err:= checker.Parse(h.Pattern)

View File

@@ -18,7 +18,7 @@ var (
func init() { func init() {
n := time.Now().UnixNano() n := time.Now().UnixNano()
data := make([]byte, 8) data := make([]byte, 9)
binary.PutVarint(data, n) binary.PutVarint(data, n)
sign = hex.EncodeToString(data) sign = hex.EncodeToString(data)
} }

View File

@@ -38,5 +38,29 @@ func newHttpSources(req *http.Request) *HttpSources {
} }
func (h *HttpSources) Get(cmd string) (string, bool) { func (h *HttpSources) Get(cmd string) (string, bool) {
if isHost(cmd){
return h.req.Host,true
}
if isLocation(cmd){
return h.req.RequestURI,true
}
if hn,yes:=headerName(cmd);yes{
if vs,has:=h.req.Header[hn];has {
if len(vs) == 0{
return "",true
}
return vs[0],true
}
}
if qn,yes:=queryName(cmd);yes{
if vs,has:=h.req.URL.Query()[qn];has{
if len(vs) == 0{
return "",true
}
return vs[0],true
}
}
return "",false
} }

View File

@@ -2,6 +2,7 @@ package router_http
import ( import (
"github.com/eolinker/goku-eosc/router" "github.com/eolinker/goku-eosc/router"
"github.com/eolinker/goku-eosc/router/checker"
"github.com/eolinker/goku-eosc/service" "github.com/eolinker/goku-eosc/service"
) )
@@ -9,16 +10,30 @@ func parse(cs []*Config) (IMatcher, error) {
count:=0 count:=0
for i:=range cs{ for i:=range cs{
hsize := len(cs[i].Hosts)
count += len(cs[i].Rules) if hsize <1{
hsize = 1
}
count += len(cs[i].Rules)*len(cs[i].Hosts)
} }
rules :=make([]router.Rule,0,count) rules :=make([]router.Rule,0,count)
targets :=make(map[string]service.IService) targets :=make(map[string]service.IService)
for _,c:=range cs{ for _,c:=range cs{
hosts:=make([]router.RulePath,0,len(c.Hosts))
for _,h:=range c.Hosts{
hck,e:= checker.Parse(h)
if e!= nil{
return nil,e
}
hosts = append(hosts, router.RulePath{
CMD: toHost(),
Checker: hck,
})
}
targets[c.Id]=c.Target targets[c.Id]=c.Target
for _,r:=range c.Rules{ for _,r:=range c.Rules{
@@ -26,10 +41,21 @@ func parse(cs []*Config) (IMatcher, error) {
if err!= nil{ if err!= nil{
return nil,err return nil,err
} }
rules = append(rules, router.Rule{ if len(hosts) >0{
Path:path, for _,hp:=range hosts{
Target:c.Id, pathWidthHost := append(make([]router.RulePath,0,len(path)+1),hp)
} ) pathWidthHost = append(pathWidthHost,path...)
rules = append(rules,router.Rule{
Path:path,
Target:c.Id,
} )
}
}else{
rules = append(rules, router.Rule{
Path:path,
Target:c.Id,
} )
}
} }
} }
r,err:=router.ParseRouter(rules,NewHttpRouterHelper()) r,err:=router.ParseRouter(rules,NewHttpRouterHelper())

View File

@@ -37,8 +37,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
http.NotFound(w, req) http.NotFound(w, req)
return return
} }
h.Handle(w,req,nee) h.Handle(w,req,NewEndPoint(e))
} }
func (r *Router) SetRouter(id string, config *Config) error { func (r *Router) SetRouter(id string, config *Config) error {