portal/api/router/router.go

116 lines
2.4 KiB
Go
Raw Permalink Normal View History

2024-01-12 00:11:53 +00:00
package router
import (
"net/http"
2024-03-21 20:53:48 +00:00
"sync"
2024-01-12 00:11:53 +00:00
"git.lumeweb.com/LumeWeb/portal/config"
"go.uber.org/zap"
"github.com/julienschmidt/httprouter"
)
type RoutableAPI interface {
Name() string
Domain() string
AuthTokenName() string
Can(w http.ResponseWriter, r *http.Request) bool
Handle(w http.ResponseWriter, r *http.Request)
Routes() (*httprouter.Router, error)
}
type APIRouter struct {
apis map[string]RoutableAPI
apiDomain map[string]string
apiHandlers map[string]http.Handler
logger *zap.Logger
config *config.Manager
2024-03-21 20:53:48 +00:00
mutex *sync.RWMutex
}
2024-01-12 00:11:53 +00:00
// Implement the ServeHTTP method on our new type
func (hs APIRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if handler := hs.getHandlerByDomain(r.Host); handler != nil {
2024-01-12 00:11:53 +00:00
handler.ServeHTTP(w, r)
return
}
for _, api := range hs.apis {
if api.Can(w, r) {
api.Handle(w, r)
return
}
2024-01-12 00:11:53 +00:00
}
http.NotFound(w, r)
}
func (hs *APIRouter) RegisterAPI(impl RoutableAPI) {
name := impl.Name()
hs.apis[name] = impl
hs.apiDomain[name+"."+hs.config.Config().Core.Domain] = name
}
func (hs *APIRouter) getHandlerByDomain(domain string) http.Handler {
if apiName := hs.apiDomain[domain]; apiName != "" {
return hs.getHandler(apiName)
}
return nil
}
func (hs *APIRouter) getHandler(protocol string) http.Handler {
2024-03-21 20:53:48 +00:00
hs.mutex.RLock()
2024-03-21 20:56:29 +00:00
handler, ok := hs.apiHandlers[protocol]
hs.mutex.RUnlock()
if ok {
return handler
}
2024-03-21 20:56:29 +00:00
hs.mutex.Lock()
defer hs.mutex.Unlock()
2024-03-21 20:56:29 +00:00
// Double-check if the handler was created while acquiring the write lock
if handler, ok := hs.apiHandlers[protocol]; ok {
return handler
}
proto, ok := hs.apis[protocol]
if !ok {
hs.logger.Fatal("Protocol not found", zap.String("protocol", protocol))
return nil
}
2024-03-21 20:56:29 +00:00
routes, err := proto.Routes()
if err != nil {
hs.logger.Fatal("Error getting routes", zap.Error(err))
return nil
}
2024-03-21 20:56:29 +00:00
hs.apiHandlers[protocol] = routes
return routes
}
func NewAPIRouter() *APIRouter {
return &APIRouter{
apis: make(map[string]RoutableAPI),
apiHandlers: make(map[string]http.Handler),
2024-02-25 14:54:34 +00:00
apiDomain: make(map[string]string),
2024-03-21 20:53:48 +00:00
mutex: &sync.RWMutex{},
}
}
func (hs *APIRouter) SetLogger(logger *zap.Logger) {
hs.logger = logger
}
func (hs *APIRouter) SetConfig(config *config.Manager) {
hs.config = config
2024-01-12 00:11:53 +00:00
}
2024-03-17 13:01:28 +00:00
func BuildSubdomain(api RoutableAPI, cfg *config.Manager) string {
return api.Name() + "." + cfg.Config().Core.Domain
}