-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.go
More file actions
121 lines (106 loc) · 4.2 KB
/
Copy pathserver.go
File metadata and controls
121 lines (106 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2026 ScitiX
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package e2bcompat provides an E2B-compatible HTTP API server for AgentBox.
// It runs on an independent port and maps E2B SDK calls to AgentBox operations.
package e2bcompat
import (
"context"
"errors"
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
apimiddleware "github.com/scitix/agent-sandbox/pkg/apiserver/router/middleware"
"github.com/scitix/agent-sandbox/pkg/apiserver/service"
"github.com/scitix/agent-sandbox/pkg/e2bcompat/router"
"github.com/scitix/agent-sandbox/pkg/e2bcompat/router/middleware"
"github.com/scitix/agent-sandbox/pkg/metrics"
"github.com/scitix/agent-sandbox/pkg/utils/apikey"
"github.com/scitix/agent-sandbox/pkg/utils/httplog"
)
const shutdownTimeout = 5 * time.Second
// Config holds the configuration for the E2B-compatible API server.
type Config struct {
// BindAddress is the TCP address the HTTP server listens on (e.g. ":8090").
BindAddress string
// Domain is the gateway domain name returned to SDK clients for building
// connection URLs. Can be a hostname (e.g. "my.gateway.com") or host:port.
// When empty, the domain field in API responses will be null.
Domain string
// ServerVersion is stamped on every response via X-AgentBox-Server-Version.
ServerVersion string
}
// Server is the E2B-compatible HTTP API server.
type Server struct {
httpServer *http.Server
}
// New creates and configures the E2B-compatible HTTP server.
// keyStore, adminKeyMgr, and iamSvc are shared with the native API server so
// that both servers validate keys against the same store without duplicating
// the Secret-backed cache.
// sandboxSvc is the shared SandboxService instance; passing the same instance
// avoids duplicate per-pool scheduler goroutines and ensures a single Shutdown path.
func New(cfg Config, k8sClient client.Client,
keyStore apikey.KeyStore, adminKeyMgr *apikey.AdminKeyManager, iamSvc service.IAMService,
sandboxSvc service.SandboxService, forwarder *service.CrossClusterForwarder) *Server {
gin.SetMode(gin.ReleaseMode)
binding.EnableDecoderDisallowUnknownFields = false // E2B SDK may send extra fields
r := gin.New()
r.Use(gin.Recovery())
r.Use(httplog.RequestID())
r.Use(gin.LoggerWithConfig(gin.LoggerConfig{
Formatter: httplog.GinLogFormatter("[E2B]"),
SkipPaths: []string{"/health"},
}))
r.Use(metrics.GinPrometheusMiddleware("e2b"))
r.Use(apimiddleware.NewServerVersionMiddleware(cfg.ServerVersion))
svcs := router.Services{
Sandbox: sandboxSvc,
APIKey: service.NewAPIKeyService(keyStore),
Forwarder: forwarder,
}
authMw := middleware.NewE2BAuthMiddleware(adminKeyMgr, keyStore, iamSvc)
router.Setup(r, svcs, k8sClient, authMw, cfg.Domain)
return &Server{
httpServer: &http.Server{
Addr: cfg.BindAddress,
Handler: r,
ReadHeaderTimeout: 5 * time.Second,
},
}
}
// Start runs the server until ctx is cancelled, then gracefully shuts down.
func (s *Server) Start(ctx context.Context) error {
log := ctrl.Log.WithName("e2b-api-server")
shutdownDone := make(chan struct{})
go func() {
defer close(shutdownDone)
<-ctx.Done()
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if err := s.httpServer.Shutdown(shutdownCtx); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Error(err, "Failed to shut down E2B API server")
}
}()
log.Info("Starting E2B-compatible API server", "address", s.httpServer.Addr)
err := s.httpServer.ListenAndServe()
if errors.Is(err, http.ErrServerClosed) {
<-shutdownDone
return nil
}
return fmt.Errorf("e2b-api-server: %w", err)
}