Skip to content

Commit 51cf397

Browse files
committed
fix: use Unirest instead of Apache HttpClient
1 parent 209b5c8 commit 51cf397

2 files changed

Lines changed: 63 additions & 163 deletions

File tree

pom.xml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,14 @@
3333
<dependencies>
3434
<!-- HTTP client -->
3535
<dependency>
36-
<groupId>org.apache.httpcomponents</groupId>
37-
<artifactId>httpclient</artifactId>
38-
<version>4.5.14</version>
36+
<groupId>com.konghq</groupId>
37+
<artifactId>unirest-java-core</artifactId>
38+
<version>${unirest.version}</version>
39+
</dependency>
40+
<dependency>
41+
<groupId>com.konghq</groupId>
42+
<artifactId>unirest-modules-jackson</artifactId>
43+
<version>${unirest.version}</version>
3944
</dependency>
4045
<!-- JSON -->
4146
<dependency>

src/main/java/io/github/hiwepy/opencode/http/OpenCodeHttpClient.java

Lines changed: 55 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,11 @@
66
import io.github.hiwepy.opencode.OpenCodeClientConfig;
77
import io.github.hiwepy.opencode.exception.OpenCodeHttpException;
88
import io.github.hiwepy.opencode.model.*;
9-
import org.apache.http.client.config.RequestConfig;
10-
import org.apache.http.client.methods.*;
11-
import org.apache.http.conn.ssl.NoopHostnameVerifier;
12-
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
13-
import org.apache.http.entity.ContentType;
14-
import org.apache.http.entity.StringEntity;
15-
import org.apache.http.impl.client.CloseableHttpClient;
16-
import org.apache.http.impl.client.HttpClients;
17-
import org.apache.http.ssl.SSLContextBuilder;
18-
import org.apache.http.util.EntityUtils;
9+
import kong.unirest.core.*;
10+
import kong.unirest.modules.jackson.JacksonObjectMapper;
1911
import org.slf4j.Logger;
2012
import org.slf4j.LoggerFactory;
2113

22-
import javax.net.ssl.SSLContext;
23-
import java.nio.charset.StandardCharsets;
24-
import java.util.Base64;
2514
import java.util.List;
2615
import java.util.Map;
2716
import java.util.Objects;
@@ -34,15 +23,24 @@
3423
public class OpenCodeHttpClient implements AutoCloseable {
3524

3625
private static final Logger log = LoggerFactory.getLogger(OpenCodeHttpClient.class);
37-
private static final ObjectMapper MAPPER = new ObjectMapper()
38-
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
3926

4027
private final OpenCodeClientConfig config;
41-
private final CloseableHttpClient http;
28+
private final UnirestInstance unirest;
4229

4330
public OpenCodeHttpClient(OpenCodeClientConfig config) {
4431
this.config = Objects.requireNonNull(config, "config");
45-
this.http = buildHttpClient(config);
32+
ObjectMapper mapper = new ObjectMapper()
33+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
34+
this.unirest = new UnirestInstance(new Config()
35+
.connectTimeout(config.getConnectTimeoutMillis())
36+
.requestTimeout(config.getReadTimeoutMillis())
37+
.verifySsl(config.isVerifySsl())
38+
.setObjectMapper(new JacksonObjectMapper(mapper)));
39+
40+
String password = config.resolvePassword();
41+
if (!password.isEmpty()) {
42+
this.unirest.config().setDefaultBasicAuth(config.getUsername(), password);
43+
}
4644
}
4745

4846
// ============================================================
@@ -67,12 +65,12 @@ public Session getSession(String sessionId) {
6765
}
6866

6967
public List<Session> listSessions() {
70-
String json = getRaw("/session");
71-
return parseList(json, new TypeReference<List<Session>>() {});
68+
return getList("/session", new GenericType<List<Session>>() {});
7269
}
7370

7471
public boolean deleteSession(String sessionId) {
75-
return delete("/session/" + sessionId);
72+
HttpResponse<String> resp = unirest.delete(url("/session/" + sessionId)).asString();
73+
return resp.isSuccess();
7674
}
7775

7876
// ============================================================
@@ -90,176 +88,73 @@ public PromptResult prompt(String sessionId, PromptRequest request) {
9088
* 异步发送消息,不等待响应(POST /session/:id/prompt_async)。
9189
*/
9290
public boolean promptAsync(String sessionId, PromptRequest request) {
93-
return postNoContent("/session/" + sessionId + "/prompt_async", request);
91+
HttpResponse<String> resp = unirest.post(url("/session/" + sessionId + "/prompt_async"))
92+
.header("Content-Type", "application/json")
93+
.body(request)
94+
.asString();
95+
return resp.isSuccess();
9496
}
9597

9698
public List<PromptResult> getMessages(String sessionId) {
97-
String json = getRaw("/session/" + sessionId + "/message");
98-
return parseList(json, new TypeReference<List<PromptResult>>() {});
99+
return getList("/session/" + sessionId + "/message", new GenericType<List<PromptResult>>() {});
99100
}
100101

102+
/**
103+
* 中止正在运行的会话。
104+
*/
101105
public boolean abortSession(String sessionId) {
102-
return postNoContent("/session/" + sessionId + "/abort", null);
106+
HttpResponse<String> resp = unirest.post(url("/session/" + sessionId + "/abort")).asString();
107+
return resp.isSuccess();
103108
}
104109

105110
// ============================================================
106111
// Agent
107112
// ============================================================
108113

109114
public List<Agent> listAgents() {
110-
String json = getRaw("/agent");
111-
return parseList(json, new TypeReference<List<Agent>>() {});
115+
return getList("/agent", new GenericType<List<Agent>>() {});
112116
}
113117

114118
// ============================================================
115-
// Internal HTTP helpers
119+
// Internal helpers
116120
// ============================================================
117121

118-
private <T> T get(String path, Class<T> type) {
119-
String json = getRaw(path);
120-
try {
121-
return MAPPER.readValue(json, type);
122-
} catch (Exception e) {
123-
throw new OpenCodeHttpException(200, "JSON parse error: " + e.getMessage());
124-
}
125-
}
126-
127-
private String getRaw(String path) {
128-
String url = config.getServerUrl() + path;
129-
HttpGet request = new HttpGet(url);
130-
addAuthHeader(request);
131-
try (CloseableHttpResponse response = http.execute(request)) {
132-
int status = response.getStatusLine().getStatusCode();
133-
String body = response.getEntity() != null
134-
? EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8) : "";
135-
if (status < 200 || status >= 300) {
136-
throw new OpenCodeHttpException(status, body);
137-
}
138-
return body;
139-
} catch (OpenCodeHttpException e) {
140-
throw e;
141-
} catch (Exception e) {
142-
throw new OpenCodeHttpException(0, "Request failed: " + e.getMessage());
143-
}
144-
}
145-
146-
private <T> T post(String path, Object body, Class<T> type) {
147-
String json = postRaw(path, body);
148-
try {
149-
return MAPPER.readValue(json, type);
150-
} catch (Exception e) {
151-
throw new OpenCodeHttpException(200, "JSON parse error: " + e.getMessage());
152-
}
153-
}
154-
155-
private boolean postNoContent(String path, Object body) {
156-
String url = config.getServerUrl() + path;
157-
HttpPost request = new HttpPost(url);
158-
addAuthHeader(request);
159-
if (body != null) {
160-
try {
161-
String json = MAPPER.writeValueAsString(body);
162-
request.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));
163-
} catch (Exception e) {
164-
throw new OpenCodeHttpException(0, "JSON serialize error: " + e.getMessage());
165-
}
166-
}
167-
try (CloseableHttpResponse response = http.execute(request)) {
168-
int status = response.getStatusLine().getStatusCode();
169-
return status >= 200 && status < 300;
170-
} catch (Exception e) {
171-
return false;
172-
}
173-
}
174-
175-
private String postRaw(String path, Object body) {
176-
String url = config.getServerUrl() + path;
177-
HttpPost request = new HttpPost(url);
178-
addAuthHeader(request);
179-
if (body != null) {
180-
try {
181-
String json = MAPPER.writeValueAsString(body);
182-
request.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));
183-
} catch (Exception e) {
184-
throw new OpenCodeHttpException(0, "JSON serialize error: " + e.getMessage());
185-
}
186-
}
187-
try (CloseableHttpResponse response = http.execute(request)) {
188-
int status = response.getStatusLine().getStatusCode();
189-
String responseBody = response.getEntity() != null
190-
? EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8) : "";
191-
if (status < 200 || status >= 300) {
192-
throw new OpenCodeHttpException(status, responseBody);
193-
}
194-
return responseBody;
195-
} catch (OpenCodeHttpException e) {
196-
throw e;
197-
} catch (Exception e) {
198-
throw new OpenCodeHttpException(0, "Request failed: " + e.getMessage());
199-
}
200-
}
201-
202-
private boolean delete(String path) {
203-
String url = config.getServerUrl() + path;
204-
HttpDelete request = new HttpDelete(url);
205-
addAuthHeader(request);
206-
try (CloseableHttpResponse response = http.execute(request)) {
207-
int status = response.getStatusLine().getStatusCode();
208-
return status >= 200 && status < 300;
209-
} catch (Exception e) {
210-
return false;
211-
}
122+
private String url(String path) {
123+
return config.getServerUrl() + path;
212124
}
213125

214-
private void addAuthHeader(HttpRequestBase request) {
215-
String password = config.resolvePassword();
216-
if (!password.isEmpty()) {
217-
String credentials = Base64.getEncoder()
218-
.encodeToString((config.getUsername() + ":" + password).getBytes());
219-
request.setHeader("Authorization", "Basic " + credentials);
126+
private <T> T get(String path, Class<T> type) {
127+
HttpResponse<T> resp = unirest.get(url(path)).asObject(type);
128+
if (!resp.isSuccess()) {
129+
throw new OpenCodeHttpException(resp.getStatus(),
130+
resp.getBody() != null ? resp.getBody().toString() : "");
220131
}
132+
return resp.getBody();
221133
}
222134

223-
private <T> List<T> parseList(String json, TypeReference<List<T>> typeRef) {
224-
try {
225-
return MAPPER.readValue(json, typeRef);
226-
} catch (Exception e) {
227-
throw new OpenCodeHttpException(200, "JSON parse error: " + e.getMessage());
135+
private <T> T getList(String path, GenericType<T> genericType) {
136+
HttpResponse<T> resp = unirest.get(url(path)).asObject(genericType);
137+
if (!resp.isSuccess()) {
138+
throw new OpenCodeHttpException(resp.getStatus(),
139+
resp.getBody() != null ? resp.getBody().toString() : "");
228140
}
141+
return resp.getBody();
229142
}
230143

231-
private CloseableHttpClient buildHttpClient(OpenCodeClientConfig config) {
232-
try {
233-
RequestConfig requestConfig = RequestConfig.custom()
234-
.setConnectTimeout(config.getConnectTimeoutMillis())
235-
.setSocketTimeout(config.getReadTimeoutMillis())
236-
.setConnectionRequestTimeout(config.getConnectTimeoutMillis())
237-
.build();
238-
239-
if (!config.isVerifySsl()) {
240-
SSLContext sslContext = new SSLContextBuilder()
241-
.loadTrustMaterial(null, (chain, authType) -> true)
242-
.build();
243-
SSLConnectionSocketFactory sslFactory = new SSLConnectionSocketFactory(
244-
sslContext, NoopHostnameVerifier.INSTANCE);
245-
return HttpClients.custom()
246-
.setDefaultRequestConfig(requestConfig)
247-
.setSSLSocketFactory(sslFactory)
248-
.build();
249-
}
250-
return HttpClients.custom()
251-
.setDefaultRequestConfig(requestConfig)
252-
.build();
253-
} catch (Exception e) {
254-
throw new RuntimeException("Failed to build HTTP client", e);
144+
private <T> T post(String path, Object body, Class<T> type) {
145+
HttpResponse<T> resp = unirest.post(url(path))
146+
.header("Content-Type", "application/json")
147+
.body(body)
148+
.asObject(type);
149+
if (!resp.isSuccess()) {
150+
throw new OpenCodeHttpException(resp.getStatus(),
151+
resp.getBody() != null ? resp.getBody().toString() : "");
255152
}
153+
return resp.getBody();
256154
}
257155

258156
@Override
259157
public void close() {
260-
try {
261-
http.close();
262-
} catch (Exception ignored) {
263-
}
158+
unirest.close();
264159
}
265160
}

0 commit comments

Comments
 (0)