import com.lanremote.watch.Json; import com.lanremote.watch.RelayTransport; import com.lanremote.watch.RemoteClient; import java.util.List; import java.util.Map; /** * 手表端经中转服务器的联调测试。 * * 这条链路才是真正要交付的: * * Java 手表 --HTTPS 长轮询--> 中转服务器 <--HTTPS-- Python 被控端 * * 用法: java JavaRelayTest <中转地址> <配对码> */ public class JavaRelayTest { private static int passed = 0; private static int failed = 0; private static void check(String name, boolean condition) { check(name, condition, ""); } private static void check(String name, boolean condition, String detail) { if (condition) { passed++; System.out.println(" [PASS] " + name); } else { failed++; System.out.println(" [FAIL] " + name + " " + detail); } } public static void main(String[] args) throws Exception { String url = args.length > 0 ? args[0] : "http://127.0.0.1:8090"; String code = args.length > 1 ? args[1] : "135790"; System.out.println("中转地址: " + url + " 配对码: " + code); System.out.println(); // ---------------- 1. 传输层自己 ---------------- System.out.println("一、RelayTransport 构造"); RelayTransport probe = new RelayTransport(url, code, "中转测试手表"); check("地址归一化去掉了末尾斜杠", probe.getBaseUrl().equals(url.replaceAll("/+$", "")), probe.getBaseUrl()); check("初始状态是未连接", !probe.isClosed()); // ---------------- 2. 经中转握手 ---------------- System.out.println(); System.out.println("二、经中转连被控端(握手)"); RemoteClient client = new RemoteClient(); client.setDevice("watch-relay-test", "中转测试手表"); Map reply = client.connectViaRelay(url, code, null, new Silent(), 30000); check("握手返回 ok", Json.bool(reply, "ok", false), String.valueOf(reply)); check("拿到设备令牌", Json.str(reply, "token", "").length() == 32, Json.str(reply, "token", "")); check("拿到被控端名字", Json.str(reply, "serverName", "").length() > 0, Json.str(reply, "serverName", "")); check("客户端认为已连接", client.isConnected()); check("传输方式是中转", "中转".equals(client.transportName()), client.transportName()); System.out.println(" 被控端: " + Json.str(reply, "serverName", "?")); String token = Json.str(reply, "token", ""); // ---------------- 3. 命令往返 ---------------- System.out.println(); System.out.println("三、经中转发命令"); long started = System.currentTimeMillis(); Map pong = client.call(Json.obj("cmd", "info"), 30000); long cost = System.currentTimeMillis() - started; check("info 返回 ok", Json.bool(pong, "ok", false), String.valueOf(pong)); System.out.println(" 往返 " + cost + " ms"); Map features = client.call(Json.obj("cmd", "feature_list"), 30000); List items = Json.list(features, "features"); check("功能列表经中转拿到", Json.bool(features, "ok", false) && items.size() > 100, items.size() + " 个"); Map ran = client.call(Json.obj( "cmd", "feature_run", "name", "world_clock", "params", Json.obj()), 30000); check("执行功能经中转成功", Json.bool(ran, "ok", false), String.valueOf(ran)); check("功能有真实输出", Json.str(ran, "note", "").contains("北京"), Json.str(ran, "note", "")); // ---------------- 4. 鉴权仍然生效 ---------------- System.out.println(); System.out.println("四、中转只是管道,鉴权仍由被控端做"); RemoteClient bad = new RemoteClient(); bad.setDevice("watch-bad", "坏手表"); Map refused = bad.connectViaRelay( url, "000000", null, new Silent(), 30000); check("错的配对码连不上", !Json.bool(refused, "ok", false), String.valueOf(refused)); check("给出了原因", Json.str(refused, "error", "").length() > 0, Json.str(refused, "error", "")); System.out.println(" 原因: " + Json.str(refused, "error", "?")); bad.close(); // ---------------- 5. 令牌免配对重连 ---------------- System.out.println(); System.out.println("五、用已保存的令牌重连(下次打开不用再输码)"); // 先断开第一条连接 —— 这才是实际用法(手表关了再打开) client.close(); check("断开后 isConnected 为 false", !client.isConnected()); Thread.sleep(1500); RemoteClient again = new RemoteClient(); again.setDevice("watch-relay-test", "中转测试手表"); Map authed = again.connectViaRelay(url, code, token, new Silent(), 30000); check("令牌登录成功", Json.bool(authed, "ok", false), String.valueOf(authed)); check("新连接能发命令", Json.bool(again.call(Json.obj("cmd", "ping"), 30000), "ok", false)); again.close(); // ---------------- 6. 断开干净 ---------------- System.out.println(); System.out.println("六、断开处理"); client.close(); check("关闭后 isConnected 为 false", !client.isConnected()); System.out.println(); System.out.println("======================================================"); System.out.println("通过 " + passed + " 项,失败 " + failed + " 项"); System.exit(failed == 0 ? 0 : 1); } /** 事件回调:这个测试不关心事件。 */ static class Silent implements RemoteClient.Listener { @Override public void onEvent(String event, Map message) { } @Override public void onDisconnected(String reason) { System.out.println(" (断开: " + reason + ")"); } } }