Skip to content

Commit cddb434

Browse files
authored
feat: add E2B Java SDK
1 parent cef8f67 commit cddb434

230 files changed

Lines changed: 14024 additions & 2235 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
package io.openkruise.agents.client.e2b;
2+
3+
import io.openkruise.agents.client.e2b.api.SandboxesApi;
4+
import io.openkruise.agents.client.e2b.api.invoker.ApiClient;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
9+
/**
10+
* E2B control plane connection configuration with Builder pattern support.
11+
*/
12+
public class ConnectionConfig {
13+
14+
public enum Protocol {
15+
NATIVE("native"),
16+
PRIVATE("private");
17+
18+
private final String value;
19+
20+
Protocol(String value) {
21+
this.value = value;
22+
}
23+
24+
public String getValue() {
25+
return value;
26+
}
27+
}
28+
29+
private static final String DEFAULT_DOMAIN = "your.domain.com";
30+
private static final String DEFAULT_SCHEME = "https";
31+
private static final long DEFAULT_REQUEST_TIMEOUT_MS = 60_000L;
32+
static final int DEFAULT_SANDBOX_TIMEOUT = 300;
33+
static final int DEFAULT_RUNTIME_PORT = 49983;
34+
35+
private String apiKey;
36+
private String accessToken;
37+
private String domain;
38+
private String scheme;
39+
private Protocol protocol;
40+
private String apiURL;
41+
private String sandboxBaseURL;
42+
private boolean debug;
43+
private long requestTimeoutMs;
44+
private int port;
45+
private Map<String, String> headers;
46+
47+
private volatile ApiClient apiClient;
48+
private volatile SandboxesApi sandboxesApi;
49+
private final Object lock = new Object();
50+
51+
private ConnectionConfig() {
52+
this.domain = DEFAULT_DOMAIN;
53+
this.scheme = DEFAULT_SCHEME;
54+
this.protocol = Protocol.NATIVE;
55+
this.requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
56+
this.port = DEFAULT_RUNTIME_PORT;
57+
this.headers = new HashMap<>();
58+
}
59+
60+
private ConnectionConfig(ConnectionConfig config) {
61+
this.apiKey = config.apiKey;
62+
this.accessToken = config.accessToken;
63+
this.domain = config.domain;
64+
this.scheme = config.scheme;
65+
this.protocol = config.protocol;
66+
this.apiURL = config.apiURL;
67+
this.sandboxBaseURL = config.sandboxBaseURL;
68+
this.debug = config.debug;
69+
this.requestTimeoutMs = config.requestTimeoutMs;
70+
this.port = config.port;
71+
this.headers = new HashMap<>(config.headers);
72+
}
73+
74+
public static ConnectionConfig create() {
75+
return new Builder().build();
76+
}
77+
78+
/** API base URL, automatically selects NATIVE/PRIVATE format based on protocol. */
79+
public String getAPIURL() {
80+
if (apiURL != null && !apiURL.isEmpty()) {
81+
return apiURL;
82+
}
83+
String s = getSchemeOrDefault();
84+
if (protocol == Protocol.PRIVATE) {
85+
return String.format("%s://%s/kruise/api", s, domain);
86+
}
87+
return String.format("%s://api.%s", s, domain);
88+
}
89+
90+
/** Envd URL for a specific sandbox, automatically selects NATIVE/PRIVATE format based on protocol. */
91+
public String getSandboxURL(String sandboxID) {
92+
if (sandboxBaseURL != null && !sandboxBaseURL.isEmpty()) {
93+
return sandboxBaseURL;
94+
}
95+
String s = getSchemeOrDefault();
96+
if (protocol == Protocol.PRIVATE) {
97+
return String.format("%s://%s/kruise/%s/%d", s, domain, sandboxID, port);
98+
}
99+
return String.format("%s://%d-%s.%s", s, port, sandboxID, domain);
100+
}
101+
102+
/** Shared ApiClient with double-checked locking lazy initialization. */
103+
public ApiClient getOrCreateApiClient() {
104+
if (apiClient == null) {
105+
synchronized (lock) {
106+
if (apiClient == null) {
107+
ApiClient client = new ApiClient();
108+
client.setBasePath(getAPIURL());
109+
client.setConnectTimeout((int)requestTimeoutMs);
110+
client.setReadTimeout((int)requestTimeoutMs);
111+
if (apiKey != null && !apiKey.isEmpty()) {
112+
client.addDefaultHeader("X-API-Key", apiKey);
113+
}
114+
for (Map.Entry<String, String> entry : headers.entrySet()) {
115+
client.addDefaultHeader(entry.getKey(), entry.getValue());
116+
}
117+
this.apiClient = client;
118+
}
119+
}
120+
}
121+
return apiClient;
122+
}
123+
124+
SandboxesApi getOrCreateSandboxesApi() {
125+
if (sandboxesApi == null) {
126+
synchronized (lock) {
127+
if (sandboxesApi == null) {
128+
sandboxesApi = new SandboxesApi(getOrCreateApiClient());
129+
}
130+
}
131+
}
132+
return sandboxesApi;
133+
}
134+
135+
private String getSchemeOrDefault() {
136+
return (scheme != null && !scheme.isEmpty()) ? scheme : DEFAULT_SCHEME;
137+
}
138+
139+
public String getApiKey() {return apiKey;}
140+
141+
public String getAccessToken() {return accessToken;}
142+
143+
public String getDomain() {return domain;}
144+
145+
public String getScheme() {return scheme;}
146+
147+
public Protocol getProtocol() {return protocol;}
148+
149+
public String getApiURL() {return apiURL;}
150+
151+
public String getSandboxBaseURL() {return sandboxBaseURL;}
152+
153+
public boolean isDebug() {return debug;}
154+
155+
public long getRequestTimeoutMs() {return requestTimeoutMs;}
156+
157+
public int getPort() {return port;}
158+
159+
public Map<String, String> getHeaders() {return headers;}
160+
161+
public static class Builder {
162+
private final ConnectionConfig config = new ConnectionConfig();
163+
164+
public Builder() {
165+
// Environment variables as defaults
166+
String envApiKey = System.getenv("E2B_API_KEY");
167+
if (envApiKey != null && !envApiKey.isEmpty()) {
168+
config.apiKey = envApiKey;
169+
}
170+
String domain = System.getenv("E2B_DOMAIN");
171+
if (domain != null && !domain.isEmpty()) {
172+
config.domain = domain;
173+
}
174+
}
175+
176+
public Builder apiKey(String apiKey) {
177+
config.apiKey = apiKey;
178+
return this;
179+
}
180+
181+
public Builder accessToken(String accessToken) {
182+
config.accessToken = accessToken;
183+
return this;
184+
}
185+
186+
public Builder domain(String domain) {
187+
config.domain = domain;
188+
return this;
189+
}
190+
191+
public Builder scheme(String scheme) {
192+
config.scheme = scheme;
193+
return this;
194+
}
195+
196+
public Builder protocol(Protocol protocol) {
197+
config.protocol = protocol;
198+
return this;
199+
}
200+
201+
public Builder apiURL(String apiURL) {
202+
config.apiURL = apiURL;
203+
return this;
204+
}
205+
206+
public Builder sandboxBaseURL(String sandboxBaseURL) {
207+
config.sandboxBaseURL = sandboxBaseURL;
208+
return this;
209+
}
210+
211+
public Builder debug(boolean debug) {
212+
config.debug = debug;
213+
return this;
214+
}
215+
216+
public Builder requestTimeoutMs(long timeoutMs) {
217+
config.requestTimeoutMs = timeoutMs;
218+
return this;
219+
}
220+
221+
public Builder port(int port) {
222+
config.port = port;
223+
return this;
224+
}
225+
226+
public Builder headers(Map<String, String> headers) {
227+
config.headers.putAll(headers);
228+
return this;
229+
}
230+
231+
public Builder addHeader(String key, String value) {
232+
config.headers.put(key, value);
233+
return this;
234+
}
235+
236+
public ConnectionConfig build() {
237+
return new ConnectionConfig(config);
238+
}
239+
}
240+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package io.openkruise.agents.client.e2b;
2+
3+
import io.openkruise.agents.client.runtime.RuntimeConfig;
4+
5+
import java.util.Map;
6+
7+
/**
8+
* RuntimeConfig subclass that carries E2B-specific URL construction and request header logic.
9+
*/
10+
public class E2bRuntimeConfig extends RuntimeConfig {
11+
12+
private final String sandboxBaseURL;
13+
private final int e2bRuntimePort;
14+
15+
private E2bRuntimeConfig(Builder builder) {
16+
super(builder);
17+
this.sandboxBaseURL = builder.sandboxBaseURL;
18+
this.e2bRuntimePort = builder.e2bRuntimePort;
19+
}
20+
21+
/**
22+
* PRIVATE mode uses sandboxBaseURL, NATIVE mode uses {@code <scheme>://<port>-<sandboxID>.<domain>}.
23+
*/
24+
@Override
25+
public String getSandboxURL(String sandboxID) {
26+
if (sandboxBaseURL != null && !sandboxBaseURL.isEmpty()) {
27+
// PRIVATE mode: sandboxBaseURL already contains full path prefix
28+
return sandboxBaseURL;
29+
}
30+
return String.format("%s://%d-%s.%s", getScheme(), e2bRuntimePort, sandboxID, getDomain());
31+
}
32+
33+
/** Adds e2b-sandbox-port to the base request headers. */
34+
@Override
35+
public Map<String, String> getSandboxHeaders(String sandboxID) {
36+
Map<String, String> result = super.getSandboxHeaders(sandboxID);
37+
result.put("e2b-sandbox-port", String.valueOf(e2bRuntimePort));
38+
return result;
39+
}
40+
41+
public static E2bRuntimeConfig fromConnectionConfig(ConnectionConfig connectionConfig, String envdAccessToken) {
42+
Builder builder = new Builder();
43+
builder.domain(connectionConfig.getDomain());
44+
builder.scheme(connectionConfig.getScheme());
45+
builder.requestTimeoutMs(connectionConfig.getRequestTimeoutMs());
46+
47+
if (connectionConfig.getApiKey() != null) {
48+
builder.apiKey(connectionConfig.getApiKey());
49+
}
50+
if (connectionConfig.getHeaders() != null) {
51+
builder.headers(connectionConfig.getHeaders());
52+
}
53+
if (envdAccessToken != null && !envdAccessToken.isEmpty()) {
54+
builder.runtimeToken(envdAccessToken);
55+
}
56+
57+
builder.e2bRuntimePort(connectionConfig.getPort());
58+
59+
if (connectionConfig.getProtocol() == ConnectionConfig.Protocol.PRIVATE) {
60+
String scheme = connectionConfig.getScheme() != null ? connectionConfig.getScheme() : "https";
61+
builder.e2bSandboxBaseURL(String.format("%s://%s", scheme, connectionConfig.getDomain()));
62+
}
63+
64+
return builder.buildE2b();
65+
}
66+
67+
public static class Builder extends RuntimeConfig.Builder {
68+
private String sandboxBaseURL;
69+
private int e2bRuntimePort = ConnectionConfig.DEFAULT_RUNTIME_PORT;
70+
71+
public Builder() {
72+
super();
73+
}
74+
75+
/**
76+
* Sets sandboxBaseURL for PRIVATE mode.
77+
*/
78+
public Builder e2bSandboxBaseURL(String sandboxBaseURL) {
79+
this.sandboxBaseURL = sandboxBaseURL;
80+
return this;
81+
}
82+
83+
public Builder e2bRuntimePort(int port) {
84+
this.e2bRuntimePort = port;
85+
return this;
86+
}
87+
88+
public E2bRuntimeConfig buildE2b() {
89+
return new E2bRuntimeConfig(this);
90+
}
91+
92+
@Override
93+
public Builder domain(String domain) {
94+
super.domain(domain);
95+
return this;
96+
}
97+
98+
@Override
99+
public Builder scheme(String scheme) {
100+
super.scheme(scheme);
101+
return this;
102+
}
103+
104+
@Override
105+
public Builder runtimeToken(String runtimeToken) {
106+
super.runtimeToken(runtimeToken);
107+
return this;
108+
}
109+
110+
@Override
111+
public Builder authHeader(String authHeader) {
112+
super.authHeader(authHeader);
113+
return this;
114+
}
115+
116+
@Override
117+
public Builder apiKey(String apiKey) {
118+
super.apiKey(apiKey);
119+
return this;
120+
}
121+
122+
@Override
123+
public Builder headers(Map<String, String> headers) {
124+
super.headers(headers);
125+
return this;
126+
}
127+
128+
@Override
129+
public Builder addHeader(String key, String value) {
130+
super.addHeader(key, value);
131+
return this;
132+
}
133+
134+
@Override
135+
public Builder requestTimeoutMs(long requestTimeoutMs) {
136+
super.requestTimeoutMs(requestTimeoutMs);
137+
return this;
138+
}
139+
140+
@Override
141+
public Builder runtimeUrl(String runtimeUrl) {
142+
super.runtimeUrl(runtimeUrl);
143+
return this;
144+
}
145+
}
146+
}

0 commit comments

Comments
 (0)