feat: phone ServerClient (OkHttp WebSocket) + MainActivity wiring
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
|
||||
@@ -8,15 +8,56 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private TextView status;
|
||||
private ServerClient client;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
TextView status = findViewById(R.id.status_text);
|
||||
status.setText(getString(R.string.status_disconnected));
|
||||
status = findViewById(R.id.status_text);
|
||||
|
||||
client = new ServerClient(new ServerClient.Listener() {
|
||||
@Override
|
||||
public void onConnectionChanged(boolean connected) {
|
||||
runOnUiThread(() -> status.setText(connected ? "已连接(空壳)" : "连接断开"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHello(JSONObject hello) {
|
||||
// 连接建立后拉一次状态
|
||||
client.sendRequest("harness.status", new JSONObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatus(JSONObject s) {
|
||||
runOnUiThread(() -> {
|
||||
if (s != null) {
|
||||
status.setText("状态: " + s.optString("model") + " / " + s.optString("cwd"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(JSONObject event) {
|
||||
// 空壳:后续写入事件流
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(String requestId, boolean ok, JSONObject result, JSONObject error) {
|
||||
runOnUiThread(() -> status.setText(ok ? "响应 OK" : "错误: " + (error != null ? error.optString("message") : "")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message) {
|
||||
runOnUiThread(() -> status.setText("错误: " + message));
|
||||
}
|
||||
});
|
||||
|
||||
Button settings = findViewById(R.id.btn_settings);
|
||||
settings.setOnClickListener(new View.OnClickListener() {
|
||||
@@ -30,9 +71,16 @@ public class MainActivity extends AppCompatActivity {
|
||||
refresh.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// 空壳:后续调用 ServerClient 拉取 Harness 状态
|
||||
status.setText(R.string.status_disconnected);
|
||||
status.setText("连接中...");
|
||||
// 空壳:默认连本机模拟器 server;真实地址/用户/Token 从设置读取
|
||||
client.connect("ws://10.0.2.2:8787/ws", "dshwatch", "change-me");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (client != null) client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,119 @@
|
||||
package com.dshwatch.app;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.WebSocket;
|
||||
import okhttp3.WebSocketListener;
|
||||
|
||||
/**
|
||||
* Harness 服务器客户端(空壳)。
|
||||
* 后续接入 WebSocket(OkHttp ws),通过 DSHWatch_Server 或直连 dsh-watch 插件,
|
||||
* 实现 harness.status / session.prompt / session.list 等 RPC。
|
||||
* Harness 服务器客户端(WebSocket)。
|
||||
* 对接 DSHWatch_Server 中继服务器,或直连 dsh-watch 插件(direct 模式)。
|
||||
* 请求/响应/事件均走 JSON 帧,见 DSHWatch_Server/docs/PROTOCOL.md。
|
||||
*/
|
||||
public class ServerClient {
|
||||
private String serverUrl;
|
||||
private String userId;
|
||||
private String token;
|
||||
|
||||
public ServerClient(String serverUrl, String userId, String token) {
|
||||
this.serverUrl = serverUrl;
|
||||
this.userId = userId;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
// 空壳:TODO 实现 WebSocket 握手 + 请求/响应 + 事件回调
|
||||
}
|
||||
|
||||
public void sendRequest(String method, String paramsJson, Callback cb) {
|
||||
// 空壳:TODO
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onResult(String json);
|
||||
public interface Listener {
|
||||
void onConnectionChanged(boolean connected);
|
||||
void onHello(JSONObject hello);
|
||||
void onStatus(JSONObject status);
|
||||
void onEvent(JSONObject event);
|
||||
void onResponse(String requestId, boolean ok, JSONObject result, JSONObject error);
|
||||
void onError(String message);
|
||||
}
|
||||
|
||||
private final OkHttpClient client;
|
||||
private final Listener listener;
|
||||
private WebSocket webSocket;
|
||||
|
||||
public ServerClient(Listener listener) {
|
||||
this.listener = listener;
|
||||
this.client = new OkHttpClient.Builder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void connect(String serverUrl, String userId, String token) {
|
||||
Request request = new Request.Builder()
|
||||
.url(serverUrl)
|
||||
.build();
|
||||
webSocket = client.newWebSocket(request, new WebSocketListener() {
|
||||
@Override
|
||||
public void onOpen(WebSocket ws, Response response) {
|
||||
listener.onConnectionChanged(true);
|
||||
JSONObject hello = new JSONObject();
|
||||
try {
|
||||
hello.put("type", "hello");
|
||||
hello.put("role", "client");
|
||||
hello.put("userId", userId);
|
||||
hello.put("token", token);
|
||||
ws.send(hello.toString());
|
||||
} catch (Exception e) {
|
||||
listener.onError("hello error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket ws, String text) {
|
||||
try {
|
||||
JSONObject msg = new JSONObject(text);
|
||||
String type = msg.optString("type", "");
|
||||
if ("hello".equals(type)) {
|
||||
listener.onHello(msg);
|
||||
} else if ("status".equals(type)) {
|
||||
listener.onStatus(msg.optJSONObject("status"));
|
||||
} else if ("event".equals(type)) {
|
||||
listener.onEvent(msg.optJSONObject("event"));
|
||||
} else if ("response".equals(type)) {
|
||||
String requestId = msg.optString("requestId");
|
||||
boolean ok = msg.optBoolean("ok", false);
|
||||
JSONObject result = msg.optJSONObject("result");
|
||||
JSONObject error = msg.optJSONObject("error");
|
||||
listener.onResponse(requestId, ok, result, error);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
listener.onError("bad message: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(WebSocket ws, int code, String reason) {
|
||||
listener.onConnectionChanged(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(WebSocket ws, Throwable t, Response response) {
|
||||
listener.onConnectionChanged(false);
|
||||
listener.onError(t != null ? t.getMessage() : "websocket failure");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void sendRequest(String method, JSONObject params) {
|
||||
if (webSocket == null) return;
|
||||
JSONObject msg = new JSONObject();
|
||||
try {
|
||||
msg.put("type", "request");
|
||||
msg.put("requestId", UUID.randomUUID().toString());
|
||||
msg.put("method", method);
|
||||
msg.put("params", params != null ? params : new JSONObject());
|
||||
webSocket.send(msg.toString());
|
||||
} catch (Exception e) {
|
||||
listener.onError("sendRequest error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (webSocket != null) {
|
||||
webSocket.close(1000, "bye");
|
||||
webSocket = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user