mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-17 23:14:21 +01:00
147 lines
3.3 KiB
Go
147 lines
3.3 KiB
Go
package entrypoint
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
|
|
"github.com/yusing/godoxy/internal/common"
|
|
"github.com/yusing/godoxy/internal/types"
|
|
)
|
|
|
|
func (ep *Entrypoint) IterRoutes(yield func(r types.Route) bool) {
|
|
for _, r := range ep.HTTPRoutes().Iter {
|
|
if !yield(r) {
|
|
return
|
|
}
|
|
}
|
|
for _, r := range ep.streamRoutes.Iter {
|
|
if !yield(r) {
|
|
return
|
|
}
|
|
}
|
|
for _, r := range ep.excludedRoutes.Iter {
|
|
if !yield(r) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (ep *Entrypoint) NumRoutes() int {
|
|
return ep.HTTPRoutes().Size() + ep.streamRoutes.Size() + ep.excludedRoutes.Size()
|
|
}
|
|
|
|
func (ep *Entrypoint) GetRoute(alias string) (types.Route, bool) {
|
|
if r, ok := ep.HTTPRoutes().Get(alias); ok {
|
|
return r, true
|
|
}
|
|
if r, ok := ep.streamRoutes.Get(alias); ok {
|
|
return r, true
|
|
}
|
|
if r, ok := ep.excludedRoutes.Get(alias); ok {
|
|
return r, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (ep *Entrypoint) StartAddRoute(r types.Route) error {
|
|
if r.ShouldExclude() {
|
|
ep.excludedRoutes.Add(r)
|
|
r.Task().OnCancel("remove_route", func() {
|
|
ep.excludedRoutes.Del(r)
|
|
})
|
|
return nil
|
|
}
|
|
switch r := r.(type) {
|
|
case types.HTTPRoute:
|
|
if err := ep.AddHTTPRoute(r); err != nil {
|
|
return err
|
|
}
|
|
ep.shortLinkMatcher.AddRoute(r.Key())
|
|
r.Task().OnCancel("remove_route", func() {
|
|
ep.delHTTPRoute(r)
|
|
ep.shortLinkMatcher.DelRoute(r.Key())
|
|
})
|
|
case types.StreamRoute:
|
|
err := r.ListenAndServe(r.Task().Context(), nil, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ep.streamRoutes.Add(r)
|
|
|
|
r.Task().OnCancel("remove_route", func() {
|
|
r.Stream().Close()
|
|
ep.streamRoutes.Del(r)
|
|
})
|
|
default:
|
|
return fmt.Errorf("unknown route type: %T", r)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getAddr(route types.HTTPRoute) (httpAddr, httpsAddr string) {
|
|
if port := route.ListenURL().Port(); port == "" || port == "0" {
|
|
host := route.ListenURL().Hostname()
|
|
if host == "" {
|
|
httpAddr = common.ProxyHTTPAddr
|
|
httpsAddr = common.ProxyHTTPSAddr
|
|
} else {
|
|
httpAddr = net.JoinHostPort(host, strconv.Itoa(common.ProxyHTTPPort))
|
|
httpsAddr = net.JoinHostPort(host, strconv.Itoa(common.ProxyHTTPSPort))
|
|
}
|
|
return httpAddr, httpsAddr
|
|
}
|
|
|
|
httpsAddr = route.ListenURL().Host
|
|
return
|
|
}
|
|
|
|
// AddHTTPRoute adds a HTTP route to the entrypoint's server.
|
|
//
|
|
// If the server does not exist, it will be created, started and return any error.
|
|
func (ep *Entrypoint) AddHTTPRoute(route types.HTTPRoute) error {
|
|
httpAddr, httpsAddr := getAddr(route)
|
|
var httpErr, httpsErr error
|
|
if httpAddr != "" {
|
|
httpErr = ep.addHTTPRoute(route, httpAddr, HTTPProtoHTTP)
|
|
}
|
|
if httpsAddr != "" {
|
|
httpsErr = ep.addHTTPRoute(route, httpsAddr, HTTPProtoHTTPS)
|
|
}
|
|
return errors.Join(httpErr, httpsErr)
|
|
}
|
|
|
|
func (ep *Entrypoint) addHTTPRoute(route types.HTTPRoute, addr string, proto HTTPProto) error {
|
|
var err error
|
|
srv, _ := ep.servers.LoadOrCompute(addr, func() (newSrv *httpServer, cancel bool) {
|
|
newSrv = newHTTPServer(ep)
|
|
err = newSrv.Listen(addr, proto)
|
|
cancel = err != nil
|
|
return
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
srv.AddRoute(route)
|
|
return nil
|
|
}
|
|
|
|
func (ep *Entrypoint) delHTTPRoute(route types.HTTPRoute) {
|
|
httpAddr, httpsAddr := getAddr(route)
|
|
if httpAddr != "" {
|
|
srv, _ := ep.servers.Load(httpAddr)
|
|
if srv != nil {
|
|
srv.DelRoute(route)
|
|
}
|
|
}
|
|
if httpsAddr != "" {
|
|
srv, _ := ep.servers.Load(httpsAddr)
|
|
if srv != nil {
|
|
srv.DelRoute(route)
|
|
}
|
|
}
|
|
// TODO: close server if no routes are left
|
|
}
|