Files
ykxmz/_build/add_lan_and_latency.py
T
xmz7891 b705216e4a ykxmz 1.5.0锛氫慨澶嶆墜琛ㄧ TLS 璇佷功鏍¢獙 + MTU 淇缃戠粶绋冲畾鎬?
琚帶绔?- 淇 MTU 闂锛氬す MSS + 璺緞 MTU 鎺㈡祴锛堝叕缃戝彲鐢ㄧ巼 48% -> 100%锛?- 澶嶇敤 HTTP 杩炴帴锛堝厤鎺夋瘡娆℃柊寤?TLS 鐨?30% 鎻℃墜澶辫触锛?- 姣忓垎閽熷洖澶存壘灞€鍩熺綉锛岃嚜鍔ㄥ垏鍥炲揩 400 鍊嶇殑璺緞
- 鐢婚潰蹇冭烦甯э細闈欐鏃剁渷娴侀噺锛屽鎴风浠嶇煡閬撴祦鏄椿鐨?- 閿佸睆鏃剁粰鍑哄彲鎿嶄綔鐨勬彁绀?
鎵嬭〃绔?- 鍐呯疆 GTS Root R4 / GlobalSign Root CA锛屼慨 SSLHandshakeException
- 杩炴帴閿欒缈昏瘧鎴愪汉璇濓紙璇佷功/鏃堕棿/瑙f瀽/瓒呮椂鍒嗗埆鎻愮ず锛?- 缁忎腑杞繛涓婂悗鐢ㄦ湇鍔″櫒鎶ョ殑鍦板潃鍒锋柊宸查厤瀵硅褰?- 鏂板灞€鍩熺綉杩炴帴椤甸潰銆佹湇鍔″櫒寤惰繜妫€娴?
鏈嶅姟鍣ㄧ
- 鏀寔 chunked 璇锋眰浣擄紙淇瘡 16 绉掍竴娆$殑杩炴帴閿欎贡涓庡ぇ闈㈢Н 502锛?- 缃戠粶璋冧紭鑴氭湰 net-tune.sh锛堝紑鏈鸿嚜鍔ㄥ簲鐢級
- 绠$悊椤碉細鎵归噺鍒犻櫎銆佺綉缁滀綋妫€銆佷笅杞藉尯
- 闅ч亾鏀?HTTP/2 + 鍙岃繛鎺?
鏂囨。
- 璁稿彲鍗忚 / 瀹夎鍓嶅繀璇?/ 瀹夎鍚庨』鐭ワ紙浣滆€咃細灏忛害瀛愶級
2026-10-06 19:01:05 +08:00

530 lines
20 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""安卓端新增:局域网连接页面 + 服务器延迟检测。
用户要求:
"在首页没连之前可以加一个进入局域网连接页面,
就可以用局域网进行连接,不经过中转服务器"
"加个东西就是可以检查延迟检查连接服务器"
设计:
首页(未连接时)三个按钮:
[ 局域网连接(同一个 WiFi) ] <- 新增,走局域网直连
[ 输入配对码连接 ] <- 原来的,经中转
[ 中转设置(跨网络用) ]
外加一个延迟状态行:
[ 检查服务器 ] 显示"延迟 83 毫秒 / 连不上"
局域网页面:
* 自动搜索(UDP 广播,被控端监听 8766)
* 搜到的电脑列出来,点一下就连
* 也能手动填 IP:端口
* 配对码
* 全部走 RemoteClient.connect()(直连),不碰中转
两条路并存:局域网友好、中转兜底。
"""
from __future__ import annotations
import ast
import sys
from pathlib import Path
MAIN = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\android\src"
r"\com\lanremote\watch\MainActivity.java")
# ===================== 1. 首页加按钮 =====================
HOME_ANCHOR = ''' Button codeButton = bigButton("输入配对码连接", C_OK, 15);'''
HOME_NEW = ''' // 局域网连接:手表和电脑在同一个 WiFi 时走这条,不经过中转。
// 用户要求:"在首页没连之前可以加一个进入局域网连接页面,
// 就可以用局域网进行连接,不经过中转服务器"
Button lanButton = bigButton("局域网连接(同一个 WiFi)", C_ACCENT, 15);
LinearLayout.LayoutParams lanParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, dp(52));
lanParams.setMargins(0, 0, 0, dp(8));
lanButton.setLayoutParams(lanParams);
lanButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showLanPanel();
}
});
box.addView(lanButton);
Button codeButton = bigButton("输入配对码连接", C_OK, 15);'''
HOME_LATENCY_ANCHOR = ''' statusView = new TextView(this);
statusView.setTextColor(C_DIM);
statusView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
statusView.setPadding(0, 0, 0, dp(6));
box.addView(statusView);'''
HOME_LATENCY_NEW = ''' // 服务器延迟:连不上中转的时候,这一条最有用
LinearLayout serverRow = new LinearLayout(this);
serverRow.setOrientation(LinearLayout.HORIZONTAL);
serverRow.setGravity(Gravity.CENTER_VERTICAL);
serverStatus = new TextView(this);
serverStatus.setTextColor(C_DIM);
serverStatus.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
serverStatus.setText("服务器:还没测");
LinearLayout.LayoutParams ssParams = new LinearLayout.LayoutParams(
0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f);
serverStatus.setLayoutParams(ssParams);
serverRow.addView(serverStatus);
Button pingButton = smallButton("检查服务器", C_CARD, new Runnable() {
@Override
public void run() {
checkServer();
}
});
serverRow.addView(pingButton);
box.addView(serverRow);
statusView = new TextView(this);
statusView.setTextColor(C_DIM);
statusView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
statusView.setPadding(0, dp(6), 0, dp(6));
box.addView(statusView);'''
# ===================== 2. 字段 =====================
FIELD_ANCHOR = ''' private TextView statusView;'''
FIELD_NEW = ''' // ---- 局域网连接页面 ----
private FrameLayout lanPanel;
private LinearLayout lanResultBox;
private EditText lanIpInput;
private EditText lanPortInput;
private EditText lanCodeInput;
private TextView lanStatus;
private volatile boolean lanSearching;
// ---- 服务器延迟 ----
private TextView serverStatus;
private TextView statusView;'''
# ===================== 3. onCreate 里建这个面板 =====================
CREATE_ANCHOR = ''' buildConnectPanel();
buildControlPanel();
buildMirrorPanel();'''
CREATE_NEW = ''' buildConnectPanel();
buildControlPanel();
buildMirrorPanel();
buildLanPanel();'''
CREATE_ADD_ANCHOR = ''' root.addView(connectPanel, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));'''
CREATE_ADD_NEW = ''' root.addView(connectPanel, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
root.addView(lanPanel, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));'''
CREATE_HIDE_ANCHOR = ''' controlPanel.setVisibility(View.GONE);
mirrorPanel.setVisibility(View.GONE);
connectPanel.setVisibility(View.VISIBLE);'''
CREATE_HIDE_NEW = ''' controlPanel.setVisibility(View.GONE);
mirrorPanel.setVisibility(View.GONE);
lanPanel.setVisibility(View.GONE);
connectPanel.setVisibility(View.VISIBLE);'''
# ===================== 4. 新方法(插在 showConnectPanel 前) =====================
METHOD_ANCHOR = ''' private void showConnectPanel() {'''
METHOD_NEW = ''' // ==================================================================
// 局域网连接(不经过中转)
// ==================================================================
private void buildLanPanel() {
lanPanel = new FrameLayout(this);
lanPanel.setBackgroundColor(C_BG);
ScrollView scroll = new ScrollView(this);
scroll.setBackgroundColor(C_BG);
LinearLayout box = new LinearLayout(this);
box.setOrientation(LinearLayout.VERTICAL);
box.setPadding(dp(10), dp(12), dp(10), dp(12));
scroll.addView(box, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
lanPanel.addView(scroll, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
// ---- 标题 + 返回 ----
LinearLayout top = new LinearLayout(this);
top.setOrientation(LinearLayout.HORIZONTAL);
top.setGravity(Gravity.CENTER_VERTICAL);
TextView title = new TextView(this);
title.setText("局域网连接");
title.setTextColor(C_FG);
title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);
LinearLayout.LayoutParams tParams = new LinearLayout.LayoutParams(
0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f);
title.setLayoutParams(tParams);
top.addView(title);
top.addView(smallButton("返回", C_CARD, new Runnable() {
@Override
public void run() {
hideLanPanel();
}
}));
box.addView(top);
TextView hint = new TextView(this);
hint.setText("手表和电脑连同一个 WiFi 时用这个,速度更快、不占流量。\\n"
+ "电脑上要开着 ykxmz。");
hint.setTextColor(C_DIM);
hint.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
hint.setPadding(0, dp(6), 0, dp(10));
box.addView(hint);
// ---- 自动搜索 ----
Button search = bigButton("自动搜索电脑", C_ACCENT, 14);
LinearLayout.LayoutParams sParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, dp(50));
sParams.setMargins(0, 0, 0, dp(8));
search.setLayoutParams(sParams);
search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startLanSearch();
}
});
box.addView(search);
lanStatus = new TextView(this);
lanStatus.setTextColor(C_DIM);
lanStatus.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
lanStatus.setPadding(0, 0, 0, dp(6));
box.addView(lanStatus);
lanResultBox = new LinearLayout(this);
lanResultBox.setOrientation(LinearLayout.VERTICAL);
box.addView(lanResultBox);
// ---- 手动填地址 ----
TextView manualTip = new TextView(this);
manualTip.setText("搜不到就自己填(电脑上 ykxmz 会显示 IP)");
manualTip.setTextColor(C_DIM);
manualTip.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
manualTip.setPadding(0, dp(10), 0, dp(4));
box.addView(manualTip);
lanIpInput = makeInput("电脑 IP,如 192.168.10.105",
InputType.TYPE_CLASS_TEXT);
box.addView(labeled("电脑 IP", lanIpInput));
lanPortInput = makeInput("端口(默认 8765)",
InputType.TYPE_CLASS_NUMBER);
box.addView(labeled("端口", lanPortInput));
lanCodeInput = makeInput("6 位配对码", InputType.TYPE_CLASS_NUMBER);
box.addView(labeled("配对码", lanCodeInput));
Button connect = bigButton("连上这台电脑", C_OK, 15);
LinearLayout.LayoutParams cParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, dp(52));
cParams.setMargins(0, dp(10), 0, 0);
connect.setLayoutParams(cParams);
connect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
connectLanTyped();
}
});
box.addView(connect);
}
private void showLanPanel() {
connectPanel.setVisibility(View.GONE);
controlPanel.setVisibility(View.GONE);
if (mirrorPanel != null) {
mirrorPanel.setVisibility(View.GONE);
}
lanPanel.setVisibility(View.VISIBLE);
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
// 进来先自动搜一次,省得用户还要自己点
String savedCode = savedPairingCode();
if (lanCodeInput != null && savedCode != null && !savedCode.isEmpty()
&& lanCodeInput.getText().length() == 0) {
lanCodeInput.setText(savedCode);
}
startLanSearch();
}
private void hideLanPanel() {
lanPanel.setVisibility(View.GONE);
showConnectPanel();
}
/** 广播搜一圈,找到的电脑列出来。 */
private void startLanSearch() {
if (lanSearching) {
return;
}
lanSearching = true;
if (lanResultBox != null) {
lanResultBox.removeAllViews();
}
setLanStatus("正在搜索…(最多 6 秒)", C_DIM);
appendLog("局域网搜索开始");
io.execute(new Runnable() {
@Override
public void run() {
java.util.List<DiscoveryCore.Found> found;
try {
found = Discovery.search(MainActivity.this, 4000);
} catch (Throwable error) {
found = new java.util.ArrayList<DiscoveryCore.Found>();
appendLog("搜索失败:" + error);
}
final java.util.List<DiscoveryCore.Found> result = found;
runOnUiThread(new Runnable() {
@Override
public void run() {
lanSearching = false;
if (lanResultBox == null) {
return;
}
lanResultBox.removeAllViews();
if (result.isEmpty()) {
setLanStatus("没搜到电脑。确认:① 电脑开着 ykxmz ② "
+ "同一个 WiFi ③ 路由器没开 AP 隔离。"
+ "\\n也可以直接填下面的 IP。", C_WARN);
appendLog("局域网没搜到电脑");
return;
}
setLanStatus("搜到 " + result.size() + " 台,点一下就连",
C_OK);
appendLog("搜到 " + result.size() + " 台电脑");
for (final DiscoveryCore.Found item : result) {
Button b = bigButton(
item.name + " · " + item.host,
C_CARD, 14);
LinearLayout.LayoutParams lp =
new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
dp(50));
lp.setMargins(0, 0, 0, dp(6));
b.setLayoutParams(lp);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (lanIpInput != null) {
lanIpInput.setText(item.host);
}
if (lanPortInput != null) {
lanPortInput.setText(
String.valueOf(item.port));
}
connectLanTyped();
}
});
lanResultBox.addView(b);
}
}
});
}
});
}
private void setLanStatus(String text, int color) {
if (lanStatus != null) {
lanStatus.setText(text);
lanStatus.setTextColor(color);
}
}
/** 用手填/点选的地址直连,不走中转。 */
private void connectLanTyped() {
String host = lanIpInput == null ? ""
: lanIpInput.getText().toString().trim();
String portText = lanPortInput == null ? ""
: lanPortInput.getText().toString().trim();
String code = lanCodeInput == null ? ""
: lanCodeInput.getText().toString().trim();
if (host.isEmpty()) {
setLanStatus("先填电脑 IP,或者上面搜一下", C_WARN);
toast("还没填电脑 IP");
return;
}
int port = RemoteClient.DEFAULT_PORT;
if (!portText.isEmpty()) {
try {
port = Integer.parseInt(portText);
} catch (NumberFormatException error) {
setLanStatus("端口要是数字", C_WARN);
return;
}
}
if (code.isEmpty()) {
setLanStatus("要填 6 位配对码", C_WARN);
toast("还没填配对码");
return;
}
rememberPairingCode(code);
lastHost = host;
lastPort = port;
lastCode = code;
lanDirect = true; // 断了自动切回中转
appendLog("局域网直连 " + host + ":" + port);
connect(host, port, code, null,
DeviceStore.deviceKey(host, port, store.deviceId()));
}
// ==================================================================
// 服务器延迟检测
// ==================================================================
private void checkServer() {
final String relay = relayUrl();
if (relay.isEmpty()) {
if (serverStatus != null) {
serverStatus.setText("服务器:还没设中转地址");
serverStatus.setTextColor(C_WARN);
}
return;
}
if (serverStatus != null) {
serverStatus.setText("服务器:正在测…");
serverStatus.setTextColor(C_DIM);
}
appendLog("开始检查服务器 " + relay);
io.execute(new Runnable() {
@Override
public void run() {
final long started = System.currentTimeMillis();
String text;
int color = C_DIM;
try {
java.net.URL url = new java.net.URL(relay + "/v1/health");
java.net.HttpURLConnection conn =
(java.net.HttpURLConnection) url.openConnection();
conn.setRequestProperty("User-Agent", "LanRemote/1.4.0");
conn.setConnectTimeout(8000);
conn.setReadTimeout(8000);
conn.setRequestMethod("GET");
int code = conn.getResponseCode();
long ms = System.currentTimeMillis() - started;
if (code == 200) {
text = "服务器:延迟 " + ms + " 毫秒";
color = ms < 300 ? C_OK : (ms < 900 ? C_WARN : C_DANGER);
} else {
text = "服务器:HTTP " + code;
color = C_DANGER;
}
try {
conn.disconnect();
} catch (Throwable ignored) {
// 关不掉也无所谓
}
} catch (Throwable error) {
text = "服务器:连不上(" + shortReason(error) + ")";
color = C_DANGER;
}
final String shown = text;
final int tint = color;
runOnUiThread(new Runnable() {
@Override
public void run() {
if (serverStatus != null) {
serverStatus.setText(shown);
serverStatus.setTextColor(tint);
}
appendLog(shown);
}
});
}
});
}
/** 异常名压短,免得界面上一长串。 */
private static String shortReason(Throwable error) {
String name = error.getClass().getSimpleName();
if (name.isEmpty()) {
name = "错误";
}
String message = String.valueOf(error.getMessage());
if (message.length() > 40) {
message = message.substring(0, 40);
}
return message.isEmpty() || "null".equals(message)
? name : (name + " " + message);
}
private void showConnectPanel() {'''
# ===================== 5. 返回键处理 =====================
BACK_ANCHOR = ''' protected void onDestroy() {'''
BACK_NEW = ''' private boolean closeLanIfOpen() {
if (lanPanel != null && lanPanel.getVisibility() == View.VISIBLE) {
hideLanPanel();
return true;
}
return false;
}
@Override
public void onBackPressed() {
// 局域网页面开着的话,先退回首页
if (closeLanIfOpen()) {
return;
}
super.onBackPressed();
}
@Override
protected void onDestroy() {'''
def main() -> int:
text = MAIN.read_text(encoding="utf-8")
if "buildLanPanel" in text:
print(" 已经加过")
return 0
ok = True
for old, new, label in (
(HOME_ANCHOR, HOME_NEW, "首页加局域网按钮"),
(HOME_LATENCY_ANCHOR, HOME_LATENCY_NEW, "首页加延迟状态"),
(FIELD_ANCHOR, FIELD_NEW, "加字段"),
(CREATE_ANCHOR, CREATE_NEW, "onCreate 建面板"),
(CREATE_ADD_ANCHOR, CREATE_ADD_NEW, "onCreate 挂面板"),
(CREATE_HIDE_ANCHOR, CREATE_HIDE_NEW, "onCreate 默认隐藏"),
(METHOD_ANCHOR, METHOD_NEW, "加局域网页面和延迟检测"),
(BACK_ANCHOR, BACK_NEW, "加返回键处理")):
if old not in text:
print(f" [失败] {label} —— 锚点没找到")
ok = False
continue
if text.count(old) != 1:
print(f" [警告] {label} 锚点出现 {text.count(old)} 次")
text = text.replace(old, new, 1)
print(f" {label}")
MAIN.write_text(text, encoding="utf-8", newline="\n")
try:
ast.parse(text)
except SyntaxError:
pass # Java 不是 Python,这里只占位
print(" 已写入")
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())