YYPOST群发软件 发表于 2026-8-13 06:53:11

WebSocket调试okhttp版


WebSocket调试okhttp版


/**
* WebSocket 屏幕截图传输 - 本地调试版(okhttp3 版)
*
* 配套 WebSocket测试服务器.py 使用
*
* 使用方法:
*   
*    确认下面 serverUrl 里的 IP 是 PC 的局域网 IP
*手机和 PC 在同一 WiFi 局域网
*AIWROK 里运行本脚本
*
* 本次使用 okhttp3 的 WebSocketListener(非 AIWROK 原生 websocket 对象)
* 已在 AIWROK v3.7.81 实际跑通
*/

// ========== 导入 okhttp3(AIWROK 自带这些 Java 类) ==========
importClass(Packages.okhttp3.OkHttpClient);
importClass(Packages.okhttp3.Request);
importClass(Packages.okhttp3.WebSocketListener);
importClass(Packages.java.util.concurrent.TimeUnit);



print.log("===== WebSocket 屏幕截图传输(okhttp3 版)开始 =====");

// ========== 配置 ==========
var config = {
    serverUrl: "192.168.10.107:8886",   // ← 改成 PC 局域网 IP:端口
    screenshotInterval: 5000,            // 截图间隔(毫秒)
    reconnectInterval: 2500,            // 断线重试间隔(毫秒)
    maxReconnectAttempts: 12,             // 最多重试次数
    connectTimeoutSec: 15,                // 握手超时(秒)
    readTimeoutSec: 30,                   // 读超时(秒)
    runDuration: 30000                  // 脚本总运行时长(毫秒)
};

// ========== 全局状态 ==========
var okHttpClient = null;   // OkHttpClient
var webSocket = null;      // 当前 WebSocket 对象
var timer = null;            // 定时器
var state = {
    connected: false,      // 是否已连接
    err: null,            // 最近错误
    closeReason: null,      // 关闭原因
    reconnectCount: 0,       // 已重连次数
    saveDir: "",            // 由服务器 WELCOME 带出
    saveUrlPrefix: "",      // file:/// 前缀
    totalSent: 0,         // 已尝试发送的图片数
    totalConfirmed: 0       // 服务器确认收到的图片数
};

// ========== 工具:解析服务器结构化消息 ==========
function parseServerMessage(rawStr) {
    if (typeof rawStr !== "string") { try { rawStr = String(rawStr); } catch (e) { rawStr = "" + rawStr; } }
    var result = { type: "UNKNOWN", raw: rawStr };
    if (rawStr.indexOf("WELCOME|") === 0) {
      result.type = "WELCOME";
      var parts = rawStr.split("|");
      result.id = parts || "";
      for (var i = 2; i < parts.length; i++) {
            var idx = parts.indexOf("=");
            if (idx > 0) result.substring(0, idx)] = parts.substring(idx + 1);
      }
    } else if (rawStr.indexOf("IMG_SAVED|") === 0) {
      result.type = "IMG_SAVED";
      var p = rawStr.split("|");
      result.seq = p || "";
      result.sizeTxt = p || "";
      result.absPath = p || "";
      result.fileUrl = p || "";
    } else if (rawStr.indexOf("IMG_FAIL|") === 0) {
      result.type = "IMG_FAIL";
    } else if (rawStr.indexOf("ECHO|") === 0) {
      result.type = "ECHO";
      result.text = rawStr.substring("ECHO|".length);
    }
    return result;
}

// ========== 释放资源(每次重连前清理旧 client) ==========
function shutdownClient() {
    if (webSocket) {
      try { webSocket.close(1000, "shutdown"); } catch (e) {}
      webSocket = null;
    }
    if (okHttpClient) {
      try { okHttpClient.dispatcher().executorService().shutdownNow(); } catch (e) {}
      okHttpClient = null;
    }
}

// ========== 建立连接(okhttp3 方案) ==========
function connect() {
    // 先清旧资源
    shutdownClient();

    state.connected = false;
    state.err = null;

    // 构造新 OkHttpClient
    okHttpClient = new OkHttpClient.Builder()
      .pingInterval(10, TimeUnit.SECONDS)
      .connectTimeout(config.connectTimeoutSec, TimeUnit.SECONDS)
      .readTimeout(config.readTimeoutSec, TimeUnit.SECONDS)
      .build();

    // 构造 listener
    var listener = new WebSocketListener({
      onOpen: function (wsObj, response) {
            state.connected = true;
            state.err = null;
            state.reconnectCount = 0;
            print.log("WS: onOpen");
            printl("✅ 连接成功(onOpen)");
            startScreenshotLoop();
      },
      onMessage: function (wsObj, message) {
            var raw;
            try { raw = String(message); } catch (e) { raw = ""; }
            print.log("WS: onMessage len=" + raw.length);

            var parsed = parseServerMessage(raw);

            if (parsed.type === "WELCOME") {
                state.saveDir = parsed.save_dir || "";
                state.saveUrlPrefix = parsed.save_file_url || "";
                printl("&#128233; WELCOME 客户端" + parsed.id);
                if (state.saveDir) {
                  printl("&#128193; 保存目录: " + state.saveDir);
                  printl("&#128279; 目录URL: " + state.saveUrlPrefix);
                }
            } else if (parsed.type === "IMG_SAVED") {
                state.totalConfirmed++;
                printl("&#128190; 服务器已保存图片 " + parsed.seq);
                printl("    大小: " + parsed.sizeTxt);
                printl("    路径: " + parsed.absPath);
                printl("    &#128279; " + parsed.fileUrl);
            } else if (parsed.type === "IMG_FAIL") {
                printl("&#128308; 服务器保存图片失败: " + parsed.raw);
            } else if (parsed.type === "ECHO") {
                printl("&#128233; 回显: " + parsed.text.substring(0, 150));
            } else {
                // 未知格式(旧版服务器返回)
                printl("&#128233; 收到: " + raw.substring(0, 200) + (raw.length > 200 ? "..." : ""));
            }
      },
      onClosed: function (wsObj, code, reason) {
            state.connected = false;
            state.closeReason = reason || "closed";
            print.log("WS: onClosed code=" + code + " reason=" + reason);
            printl("&#128268; 连接关闭(onClosed code=" + code + ")");
            stopScreenshotLoop();
            scheduleReconnect();
      },
      onFailure: function (wsObj, throwable, response) {
            state.connected = false;
            state.err = (throwable ? String(throwable.getMessage()) : "unknown_failure");
            print.log("WS: onFailure " + state.err);
            printl("❌ 连接错误(onFailure): " + state.err);
            stopScreenshotLoop();
            scheduleReconnect();
      }
    });

    // 发起连接
    var url = "ws://" + config.serverUrl;
    printl("正在连接: " + url + "(" + config.connectTimeoutSec + " 秒超时)");

    try {
      var request = new Request.Builder().url(url).build();
      webSocket = okHttpClient.newWebSocket(request, listener);
    } catch (e) {
      state.err = String(e.message);
      printl("❌ newWebSocket 抛异常: " + state.err);
      scheduleReconnect();
    }

    // 同步等最多 connectTimeoutSec + 5 秒看事件
    var waited = 0;
    while (!state.connected && !state.err && waited < (config.connectTimeoutSec + 5) * 1000) {
      sleep.millisecond(100);
      waited += 100;
    }
    if (!state.connected && !state.err) {
      state.err = "连接超时(" + (config.connectTimeoutSec + 5) + " 秒内无 onOpen/onFailure)";
      printl("❌ " + state.err);
      scheduleReconnect();
    }
}

// ========== 重连调度 ==========
function scheduleReconnect() {
    if (state.reconnectCount >= config.maxReconnectAttempts) {
      printl("&#128721; 已达到最大重连次数 " + config.maxReconnectAttempts + ",停止");
      return;
    }
    state.reconnectCount++;
    printl("⏱️重连 " + state.reconnectCount + "/" + config.maxReconnectAttempts + "," + (config.reconnectInterval / 1000).toFixed(1) + " 秒后...");

    shutdownClient();

    setTimeout(function () {
      connect();
    }, config.reconnectInterval);
}

// ========== 截一张图并发送 ==========
function sendOne() {
    if (!state.connected || !webSocket) {
      print.log("跳过截图:未连接");
      return;
    }
    try {
      print.log("截取屏幕...");
      printl("&#128248; 截图中...");

      var bitmap = screen.screenShotFull();
      if (!bitmap) { printl("❌ 截图失败(返回 null)"); return; }

      print.log("转 Base64...");
      var base64 = "" + bitmap.toBase64();   // Java ByteString → JS 字符串,必须用 ""+

      if (!base64) { printl("❌ Base64 为空"); return; }

      var chars = base64.length;
      var estKB = Math.round(chars * 0.75 / 1024);
      printl("&#128230; 图片大小: " + chars + " 字符(约 " + estKB + " KB)");

      try { bitmap.recycle(); } catch (e) {}

      state.totalSent++;
      printl("&#128228; 发送图片 #" + state.totalSent + " ...");
      webSocket.send(base64);

      printl("✅ 图片 #" + state.totalSent + " 已投递(" + estKB + " KB)");

    } catch (e) {
      printl("❌ sendOne 异常: " + e.message);
      print.log("sendOne: " + e.message);
    }
}

// ========== 定时截图循环 ==========
function startScreenshotLoop() {
    if (timer) { try { clearInterval(timer); } catch (e) {} timer = null; }

    print.log("定时截图循环启动, 间隔 " + config.screenshotInterval + "ms");
    printl("⏰ 定时截图已启动(间隔 " + (config.screenshotInterval / 1000) + " 秒)");

    // 首张立即来
    setTimeout(function () { sendOne(); }, 300);

    timer = setInterval(function () {
      if (state.connected && webSocket) sendOne();
    }, config.screenshotInterval);
}

function stopScreenshotLoop() {
    if (timer) {
      try { clearInterval(timer); } catch (e) {}
      timer = null;
      print.log("停止定时截图循环");
    }
}

// ========== 关闭清理 ==========
function cleanup() {
    stopScreenshotLoop();
    shutdownClient();
    state.connected = false;
    printl("&#128268; 资源已清理");
}

// ========== 主程序 ==========
function main() {
    try {
      printl("========================================");
      printl("WebSocket 屏幕截图传输 - okhttp3 版");
      printl("服务器: " + config.serverUrl);
      printl("截图间隔: " + (config.screenshotInterval / 1000) + " 秒");
      printl("总运行: " + (config.runDuration / 1000) + " 秒");
      printl("最大重连: " + config.maxReconnectAttempts + " 次");
      printl("========================================");
      printl("ℹ️ 请确认 PC 已运行: python WebSocket测试服务器.py");

      connect();

      print.log("倒计时 " + (config.runDuration / 1000) + " 秒...");
      printl("⏳ 运行 " + (config.runDuration / 1000) + " 秒后自动结束");
      sleep.millisecond(config.runDuration);

      cleanup();

      printl("");
      printl("===== 执行结束 =====");
      printl("尝试发送: " + state.totalSent + " 张");
      printl("服务器确认: " + state.totalConfirmed + " 张");
      if (state.saveDir) printl("PC 保存目录: " + state.saveDir);
      print.log("===== 屏幕截图传输结束, 发送 " + state.totalSent + " 张 =====");

    } catch (e) {
      print.log("主程序异常: " + e.message);
      printl("❌ 程序错误: " + e.message);
      try { cleanup(); } catch (e2) {}
    }
}

main();


页: [1]
查看完整版本: WebSocket调试okhttp版