frp/pkg/util/vhost/router.go
百里(barry) c0b091f139
add proxy manager and monitor (#7)
* GitButler Integration Commit

This is an integration commit for the virtual branches that GitButler is tracking.

Due to GitButler managing multiple virtual branches, you cannot switch back and
forth between git branches and virtual branches easily. 

If you switch to another branch, GitButler will need to be reinitialized.
If you commit on this branch, GitButler will throw it away.

Here are the branches that are currently applied:
 - feat/frpcc (refs/gitbutler/feat/frpcc)
   branch head: e52195a01a6e3432cccc3ba952a8c940ad4d3fc6
   - test/main.go
   - go.sum
   - go.mod
   - server/service.go
For more information about what we're doing here, check out our docs:
https://docs.gitbutler.com/features/virtual-branches/integration-branch

* fix: barry 2024-07-03 15:36:17

* fix: barry 2024-07-03 15:44:12

* fix: barry 2024-07-03 15:46:25

* fix: barry 2024-07-03 16:52:13

* fix: barry 2024-07-03 17:30:53

* fix: barry 2024-07-03 17:42:01

* fix: barry 2024-07-03 18:43:39

* fix: barry 2024-07-03 19:36:06

* fix: barry 2024-07-03 19:43:47

* fix: barry 2024-07-04 10:51:06

* fix: barry 2024-07-04 12:29:01

* fix log and body

* fix rate calc

* fix: barry 2024-07-09 18:20:06

---------

Co-authored-by: GitButler <gitbutler@gitbutler.com>
2024-07-09 19:20:28 +08:00

156 lines
2.8 KiB
Go

package vhost
import (
"cmp"
"errors"
"slices"
"strings"
"sync"
)
var ErrRouterConfigConflict = errors.New("router config conflict")
type routerByHTTPUser map[string][]*Router
type Routers struct {
indexByDomain map[string]routerByHTTPUser
mutex sync.RWMutex
}
type Router struct {
domain string
location string
httpUser string
// store any object here
payload interface{}
}
func NewRouters() *Routers {
return &Routers{
indexByDomain: make(map[string]routerByHTTPUser),
}
}
func (r *Routers) Add(domain, location, httpUser string, payload interface{}) error {
domain = strings.ToLower(domain)
r.mutex.Lock()
defer r.mutex.Unlock()
if _, exist := r.exist(domain, location, httpUser); exist {
return ErrRouterConfigConflict
}
routersByHTTPUser, found := r.indexByDomain[domain]
if !found {
routersByHTTPUser = make(map[string][]*Router)
}
vrs, found := routersByHTTPUser[httpUser]
if !found {
vrs = make([]*Router, 0, 1)
}
vr := &Router{
domain: domain,
location: location,
httpUser: httpUser,
payload: payload,
}
vrs = append(vrs, vr)
slices.SortFunc(vrs, func(a, b *Router) int {
return -cmp.Compare(a.location, b.location)
})
routersByHTTPUser[httpUser] = vrs
r.indexByDomain[domain] = routersByHTTPUser
return nil
}
func (r *Routers) Del(domain, location, httpUser string) {
domain = strings.ToLower(domain)
r.mutex.Lock()
defer r.mutex.Unlock()
routersByHTTPUser, found := r.indexByDomain[domain]
if !found {
return
}
vrs, found := routersByHTTPUser[httpUser]
if !found {
return
}
newVrs := make([]*Router, 0)
for _, vr := range vrs {
if vr.location != location {
newVrs = append(newVrs, vr)
}
}
routersByHTTPUser[httpUser] = newVrs
}
func (r *Routers) GetAll() (rr []map[string]any) {
r.mutex.RLock()
defer r.mutex.RUnlock()
for _, v := range r.indexByDomain {
for _, v1 := range v {
for _, v2 := range v1 {
rr = append(rr, map[string]any{
"domain": v2.domain,
"location": v2.location,
"httpUser": v2.httpUser,
"payload": v2.payload,
})
}
}
}
return rr
}
func (r *Routers) Get(host, path, httpUser string) (vr *Router, exist bool) {
host = strings.ToLower(host)
r.mutex.RLock()
defer r.mutex.RUnlock()
routersByHTTPUser, found := r.indexByDomain[host]
if !found {
return
}
vrs, found := routersByHTTPUser[httpUser]
if !found {
return
}
for _, vr = range vrs {
if strings.HasPrefix(path, vr.location) {
return vr, true
}
}
return
}
func (r *Routers) exist(host, path, httpUser string) (route *Router, exist bool) {
routersByHTTPUser, found := r.indexByDomain[host]
if !found {
return
}
routers, found := routersByHTTPUser[httpUser]
if !found {
return
}
for _, route = range routers {
if path == route.location {
return route, true
}
}
return
}