mirror of
https://github.com/eolinker/apinto
synced 2025-10-19 15:14:32 +08:00
171 lines
4.4 KiB
Go
171 lines
4.4 KiB
Go
package manager
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"errors"
|
|
"net"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/eolinker/apinto/certs"
|
|
"github.com/eolinker/eosc/traffic/mixl"
|
|
|
|
http_complete "github.com/eolinker/apinto/drivers/router/http-router/http-complete"
|
|
http_context "github.com/eolinker/apinto/node/http-context"
|
|
http_router "github.com/eolinker/apinto/router/http-router"
|
|
"github.com/eolinker/eosc/config"
|
|
eoscContext "github.com/eolinker/eosc/eocontext"
|
|
http_service "github.com/eolinker/eosc/eocontext/http-context"
|
|
"github.com/eolinker/eosc/log"
|
|
"github.com/eolinker/eosc/traffic"
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
var _ IManger = (*Manager)(nil)
|
|
var notFound = new(HttpNotFoundHandler)
|
|
var completeCaller = http_complete.NewHttpCompleteCaller()
|
|
|
|
type IManger interface {
|
|
Set(id string, port int, hosts []string, method []string, path string, append []AppendRule, router http_router.IRouterHandler) error
|
|
Delete(id string)
|
|
}
|
|
|
|
type Manager struct {
|
|
lock sync.RWMutex
|
|
matcher http_router.IMatcher
|
|
|
|
routersData IRouterData
|
|
globalFilters eoscContext.IChainPro
|
|
}
|
|
|
|
func (m *Manager) Set(id string, port int, hosts []string, method []string, path string, append []AppendRule, router http_router.IRouterHandler) error {
|
|
m.lock.Lock()
|
|
defer m.lock.Unlock()
|
|
routersData := m.routersData.Set(id, port, hosts, method, path, append, router)
|
|
matchers, err := routersData.Parse()
|
|
if err != nil {
|
|
log.Error("parse router data error: ", err)
|
|
return err
|
|
}
|
|
m.matcher = matchers
|
|
m.routersData = routersData
|
|
return nil
|
|
}
|
|
|
|
func (m *Manager) Delete(id string) {
|
|
m.lock.Lock()
|
|
defer m.lock.Unlock()
|
|
routersData := m.routersData.Delete(id)
|
|
matchers, err := routersData.Parse()
|
|
if err != nil {
|
|
log.Errorf("delete router:%s %s", id, err.Error())
|
|
return
|
|
}
|
|
m.matcher = matchers
|
|
m.routersData = routersData
|
|
return
|
|
}
|
|
|
|
var errNoCertificates = errors.New("tls: no certificates configured")
|
|
|
|
// NewManager 创建路由管理器
|
|
func NewManager(tf traffic.ITraffic, listenCfg *config.ListenUrl, globalFilters eoscContext.IChainPro) *Manager {
|
|
log.Debug("new router manager")
|
|
m := &Manager{
|
|
globalFilters: globalFilters,
|
|
routersData: new(RouterData),
|
|
}
|
|
|
|
if tf.IsStop() {
|
|
return m
|
|
}
|
|
|
|
wg := sync.WaitGroup{}
|
|
tcp, ssl := tf.Listen(listenCfg.ListenUrls...)
|
|
|
|
listenerByPort := make(map[int][]net.Listener)
|
|
for _, l := range tcp {
|
|
port := readPort(l.Addr())
|
|
listenerByPort[port] = append(listenerByPort[port], l)
|
|
}
|
|
if len(ssl) > 0 {
|
|
tlsConfig := &tls.Config{GetCertificate: certs.GetCertificateFunc()}
|
|
|
|
for _, l := range ssl {
|
|
port := readPort(l.Addr())
|
|
listenerByPort[port] = append(listenerByPort[port], tls.NewListener(l, tlsConfig))
|
|
}
|
|
}
|
|
for port, lns := range listenerByPort {
|
|
|
|
var ln net.Listener = mixl.NewMixListener(port, lns...)
|
|
|
|
wg.Add(1)
|
|
go func(ln net.Listener, port int) {
|
|
log.Debug("fast server:", port, ln.Addr())
|
|
wg.Done()
|
|
server := fasthttp.Server{
|
|
StreamRequestBody: true,
|
|
DisablePreParseMultipartForm: true,
|
|
MaxRequestBodySize: 100 * 1024 * 1024,
|
|
Handler: func(ctx *fasthttp.RequestCtx) {
|
|
m.FastHandler(port, ctx)
|
|
}}
|
|
server.Serve(ln)
|
|
}(ln, port)
|
|
}
|
|
wg.Wait()
|
|
return m
|
|
}
|
|
func readPort(addr net.Addr) int {
|
|
ipPort := addr.String()
|
|
i := strings.LastIndex(ipPort, ":")
|
|
port := ipPort[i+1:]
|
|
pv, _ := strconv.Atoi(port)
|
|
return pv
|
|
}
|
|
func (m *Manager) FastHandler(port int, ctx *fasthttp.RequestCtx) {
|
|
httpContext := http_context.NewContext(ctx, port)
|
|
log.Debug("port is ", port, " request: ", httpContext.Request())
|
|
r, has := m.matcher.Match(port, httpContext.Request())
|
|
if !has {
|
|
httpContext.SetFinish(notFound)
|
|
httpContext.SetCompleteHandler(notFound)
|
|
m.globalFilters.Chain(httpContext, completeCaller)
|
|
} else {
|
|
log.Debug("match has:", port)
|
|
r.ServeHTTP(httpContext)
|
|
}
|
|
finishHandler := httpContext.GetFinish()
|
|
if finishHandler != nil {
|
|
finishHandler.Finish(httpContext)
|
|
}
|
|
}
|
|
|
|
type NotFoundHandler struct {
|
|
}
|
|
|
|
type HttpNotFoundHandler struct {
|
|
}
|
|
|
|
func (m *HttpNotFoundHandler) Complete(ctx eoscContext.EoContext) error {
|
|
|
|
httpContext, err := http_service.Assert(ctx)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
httpContext.Response().SetStatus(404, "404")
|
|
httpContext.Response().SetBody([]byte("404 Not Found"))
|
|
return nil
|
|
}
|
|
|
|
func (m *HttpNotFoundHandler) Finish(ctx eoscContext.EoContext) error {
|
|
httpContext, err := http_service.Assert(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
httpContext.FastFinish()
|
|
return nil
|
|
}
|