дȫÏîĿÉó²éÎÊÌⲢ·¢²¼ v1.1.9
¸ÄÓñ¾»ú¶ÀÁ¢ CA£¬»ָ´ CLI TLS УÑ飬±£»¤ƾ¾ÝÓëÅäÖò¢·¢±£´档 д Cursor Êý¾ݡ¢»Ự·¾¶¡¢´úÀíÉúÃüÖÜÆڡ¢ģÐÍÇëÇóÓë Skills Îļþ²Ù×÷¡£ Ϊ¶ÀÁ¢ Tab ·þÎñÔö¼ӿͻ§¶˼øȨ£¬Éý¼¶ÒÀÀµÓ빤¾ßÁ´£¬ÍêÉƷ¢²¼ԪÐÅϢͬ²½¡£ Ñé֤£ºÁ½¸ö Go ģ¿éµIJâÊÔ/vet¡¢¹ؼüģ¿é race¡¢ǰ¶˲âÊÔ/Éú²ú¹¹½¨/Éó¼ơ¢ Go ¿ɴï©¶´ɨÃèÓë macOS/Linux ¿ÉÐÐģ¿齻²æ±àÒë¾ùͨ¹ý¡£ Windows ¸ôÀëÆô¶¯ͨ¹ý£»δÍê³ɵĵã»÷ðÑ̺ÍԭÉúƽ̨Ñé֤¼ûÉó²鱨¸档
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
serverconfig "cursor/internal/backend/server/config"
|
||||
"cursor/internal/backend/server/upstream"
|
||||
"cursor/internal/certs"
|
||||
"cursor/internal/localaccess"
|
||||
"cursor/internal/logger"
|
||||
"cursor/internal/netproxy"
|
||||
legacyruntime "cursor/internal/runtime"
|
||||
@@ -27,21 +28,22 @@ import (
|
||||
const healthPath = "/healthz"
|
||||
|
||||
type Host struct {
|
||||
store *serverconfig.Store
|
||||
listenAddr string
|
||||
lifecycleMu sync.Mutex
|
||||
store *serverconfig.Store
|
||||
listenAddr string
|
||||
cliHTTPSListenAddr string
|
||||
tabServerBaseURL string
|
||||
configs *serverconfig.Manager
|
||||
healthHTTP *http.Client
|
||||
certManager *certs.Manager
|
||||
tabServerBaseURL string
|
||||
configs *serverconfig.Manager
|
||||
healthHTTP *http.Client
|
||||
certManager *certs.Manager
|
||||
|
||||
runMu sync.RWMutex
|
||||
httpServer *http.Server
|
||||
httpsServer *http.Server
|
||||
runMu sync.RWMutex
|
||||
httpServer *http.Server
|
||||
httpsServer *http.Server
|
||||
|
||||
lastRunErr error
|
||||
lastRunErr error
|
||||
|
||||
mux http.Handler
|
||||
mux http.Handler
|
||||
}
|
||||
|
||||
func NewHost(store *serverconfig.Store, certManager *certs.Manager) (*Host, error) {
|
||||
@@ -54,13 +56,13 @@ func NewHost(store *serverconfig.Store, certManager *certs.Manager) (*Host, erro
|
||||
}
|
||||
cfg := configs.Current()
|
||||
host := &Host{
|
||||
store: store,
|
||||
listenAddr: cfg.BackendListenAddr,
|
||||
store: store,
|
||||
listenAddr: cfg.BackendListenAddr,
|
||||
cliHTTPSListenAddr: cfg.CLIHTTPSListenAddr,
|
||||
tabServerBaseURL: cfg.TabServerBaseURL,
|
||||
configs: configs,
|
||||
healthHTTP: newLoopbackHTTPClient(),
|
||||
certManager: certManager,
|
||||
tabServerBaseURL: cfg.TabServerBaseURL,
|
||||
configs: configs,
|
||||
healthHTTP: newLoopbackHTTPClient(),
|
||||
certManager: certManager,
|
||||
}
|
||||
if err := host.rebuild(cfg); err != nil {
|
||||
return nil, err
|
||||
@@ -86,6 +88,8 @@ func (host *Host) SaveConfig(ctx context.Context, cfg serverconfig.Config) (serv
|
||||
if host == nil || host.configs == nil {
|
||||
return serverconfig.Config{}, fmt.Errorf("backend config manager is not initialized")
|
||||
}
|
||||
host.lifecycleMu.Lock()
|
||||
defer host.lifecycleMu.Unlock()
|
||||
normalized, err := host.configs.Save(ctx, cfg)
|
||||
if err != nil {
|
||||
return serverconfig.Config{}, err
|
||||
@@ -157,6 +161,8 @@ func (host *Host) Start() error {
|
||||
if host == nil {
|
||||
return fmt.Errorf("backend host is nil")
|
||||
}
|
||||
host.lifecycleMu.Lock()
|
||||
defer host.lifecycleMu.Unlock()
|
||||
cfg := host.configs.Current()
|
||||
|
||||
host.runMu.Lock()
|
||||
@@ -170,7 +176,7 @@ func (host *Host) Start() error {
|
||||
|
||||
httpServer := &http.Server{
|
||||
Addr: host.listenAddr,
|
||||
Handler: host.mux,
|
||||
Handler: localaccess.Wrap(host.mux),
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
listener, err := net.Listen("tcp", host.listenAddr)
|
||||
@@ -199,8 +205,10 @@ func (host *Host) Start() error {
|
||||
|
||||
// 启动 CLI HTTPS+HTTP/2 监听器
|
||||
if err := host.startHTTPSLocked(cfg); err != nil {
|
||||
// HTTPS 失败不阻断 HTTP,仅记录
|
||||
logger.Errorf("启动 CLI HTTPS 监听器失败: %v", err)
|
||||
host.httpServer = nil
|
||||
_ = httpServer.Close()
|
||||
host.lastRunErr = fmt.Errorf("启动 CLI HTTPS 监听器失败: %w", err)
|
||||
return host.lastRunErr
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -230,7 +238,7 @@ func (host *Host) startHTTPSLocked(cfg serverconfig.Config) error {
|
||||
|
||||
httpsServer := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: host.mux,
|
||||
Handler: localaccess.Wrap(host.mux),
|
||||
TLSConfig: tlsConfig,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
@@ -262,28 +270,29 @@ func (host *Host) Stop(ctx context.Context) error {
|
||||
if host == nil {
|
||||
return nil
|
||||
}
|
||||
host.runMu.Lock()
|
||||
httpServer := host.httpServer
|
||||
httpsServer := host.httpsServer
|
||||
host.httpServer = nil
|
||||
host.httpsServer = nil
|
||||
host.runMu.Unlock()
|
||||
host.lifecycleMu.Lock()
|
||||
defer host.lifecycleMu.Unlock()
|
||||
host.runMu.RLock()
|
||||
httpServer, httpsServer := host.httpServer, host.httpsServer
|
||||
host.runMu.RUnlock()
|
||||
var errs []error
|
||||
if httpsServer != nil {
|
||||
if err := httpsServer.Shutdown(ctx); err != nil {
|
||||
errs = append(errs, fmt.Errorf("stop CLI HTTPS: %w", err))
|
||||
for _, srv := range []*http.Server{httpsServer, httpServer} {
|
||||
if srv != nil {
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
_ = srv.Close()
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if serverInstance := httpServer; serverInstance != nil {
|
||||
err := serverInstance.Shutdown(ctx)
|
||||
if err != nil && !errors.Is(err, context.Canceled) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
host.runMu.Lock()
|
||||
if host.httpServer == httpServer {
|
||||
host.httpServer = nil
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
if host.httpsServer == httpsServer {
|
||||
host.httpsServer = nil
|
||||
}
|
||||
return nil
|
||||
host.runMu.Unlock()
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (host *Host) HealthCheck(ctx context.Context) error {
|
||||
@@ -928,19 +937,27 @@ func uploadServiceProcedure(pattern string, name string, protocol server.RouteOp
|
||||
func tabServerUpstreamProcedure(pattern string, name string, protocol server.RouteOption, deps upstream.Dependencies, host *Host) server.Option {
|
||||
direct := upstream.DirectAction(deps, upstream.CompatRouteConfig{Name: name})
|
||||
action := func(ctx *server.Context) error {
|
||||
if host == nil || host.tabServerBaseURL == "" {
|
||||
if host == nil || ctx == nil || ctx.Request == nil {
|
||||
return fmt.Errorf("invalid tab request")
|
||||
}
|
||||
cfg := host.configs.Current()
|
||||
if cfg.TabServerBaseURL == "" {
|
||||
http.NotFound(ctx.Writer, ctx.Request)
|
||||
return nil
|
||||
}
|
||||
if ctx != nil && ctx.Request != nil && ctx.Request.URL != nil {
|
||||
baseURL, err := url.Parse(host.tabServerBaseURL)
|
||||
baseURL, err := url.Parse(cfg.TabServerBaseURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("解析 tab server 地址失败: %w", err)
|
||||
}
|
||||
targetURL := *ctx.Request.URL
|
||||
targetURL.Scheme = baseURL.Scheme
|
||||
targetURL.Host = baseURL.Host
|
||||
targetURL.Path = strings.TrimRight(baseURL.Path, "/") + ctx.Request.URL.Path
|
||||
targetURL.RawPath = ""
|
||||
ctx.UpstreamURL = &targetURL
|
||||
ctx.Request = ctx.Request.Clone(ctx.Request.Context())
|
||||
ctx.Request.Header.Set("Authorization", "Bearer "+cfg.TabServerToken)
|
||||
}
|
||||
return direct(ctx)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user