Skip to main content
Glama

Storyden

by Southclaws
Mozilla Public License 2.0
229
frontend.go2.7 kB
package frontend import ( "errors" "log/slog" "net/http" "net/http/httputil" "strings" "time" "go.uber.org/fx" "github.com/Southclaws/storyden/app/transports/http/middleware/session_cookie" "github.com/Southclaws/storyden/internal/config" frontendService "github.com/Southclaws/storyden/internal/infrastructure/frontend" ) type Provider struct { handler func(http.ResponseWriter, *http.Request) frontend frontendService.Frontend logger *slog.Logger } func New( cfg config.Config, logger *slog.Logger, mux *http.ServeMux, cj *session_cookie.Jar, fe frontendService.Frontend, ) *Provider { if cfg.FrontendProxy.String() == "" { return &Provider{} } handler := func(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { defer func() { if err, ok := recover().(error); ok && err != nil { if errors.Is(err, http.ErrAbortHandler) { return } logger.Error("frontend proxy panic", slog.String("url", r.URL.String()), slog.String("method", r.Method), slog.String("remote_addr", r.RemoteAddr), slog.Any("error", err), ) return } }() p.ServeHTTP(w, r) } } proxy := httputil.NewSingleHostReverseProxy(&cfg.FrontendProxy) proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) { logger.Error("frontend proxy error", slog.String("url", r.URL.String()), slog.String("method", r.Method), slog.String("remote_addr", r.RemoteAddr), slog.String("error", err.Error()), ) w.WriteHeader(http.StatusBadGateway) } return &Provider{ handler: handler(proxy), frontend: fe, logger: logger, } } func (p *Provider) WithFrontendProxy() func(next http.Handler) http.Handler { if p.handler == nil { return func(next http.Handler) http.Handler { return next } } return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/api") { next.ServeHTTP(w, r) } else { if p.frontend == nil { p.handler(w, r) return } // Wait for frontend to be ready before proxying select { case <-p.frontend.Ready(): p.handler(w, r) case <-time.After(30 * time.Second): p.logger.Error("timeout waiting for frontend to be ready", slog.String("url", r.URL.String()), slog.String("method", r.Method), slog.String("remote_addr", r.RemoteAddr), ) w.WriteHeader(http.StatusServiceUnavailable) w.Write([]byte("Frontend service is unavailable")) } } }) } } func Build() fx.Option { return fx.Options( fx.Provide(New), ) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Southclaws/storyden'

If you have feedback or need assistance with the MCP directory API, please join our Discord server