修复掉设备问题
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
@@ -27,140 +29,223 @@ CORS(app)
|
|||||||
app.config['JSON_AS_ASCII'] = False # Flask jsonify 不转义中文/emoji
|
app.config['JSON_AS_ASCII'] = False # Flask jsonify 不转义中文/emoji
|
||||||
app.config['JSONIFY_MIMETYPE'] = "application/json; charset=utf-8"
|
app.config['JSONIFY_MIMETYPE'] = "application/json; charset=utf-8"
|
||||||
|
|
||||||
|
# ============ 设备状态内存表 ============
|
||||||
listData = []
|
listData = []
|
||||||
listLock = threading.Lock()
|
listLock = threading.Lock()
|
||||||
|
|
||||||
|
# 历史遗留:不再消费队列,改为socket线程直接落地
|
||||||
dataQueue = Queue()
|
dataQueue = Queue()
|
||||||
|
|
||||||
|
# ---- 黏性快照(避免瞬时空) ----
|
||||||
|
_last_nonempty_snapshot = []
|
||||||
|
_last_snapshot_ts = 0.0
|
||||||
|
_STICKY_TTL_SEC = 10.0 # 在瞬时空时,回退到上一份非空快照10秒
|
||||||
|
_empty_logged = False
|
||||||
|
_recovered_logged = False
|
||||||
|
|
||||||
def start_socket_listener():
|
# ===== 设备集合变化跟踪 =====
|
||||||
port = int(os.getenv('FLASK_COMM_PORT', 0))
|
change_version = 0
|
||||||
LogManager.info(f"Received port from environment: {port}")
|
_device_ids_snapshot = set()
|
||||||
print(f"Received port from environment: {port}")
|
_last_device_count = 0
|
||||||
if port <= 0:
|
|
||||||
LogManager.info("未获取到通信端口,跳过Socket监听")
|
def _log_device_changes(action: str):
|
||||||
print("未获取到通信端口,跳过Socket监听")
|
"""记录设备集合增删变化"""
|
||||||
return
|
global _device_ids_snapshot, change_version
|
||||||
|
curr_ids = {d.get("deviceId") for d in listData if _is_online(d)}
|
||||||
|
added = curr_ids - _device_ids_snapshot
|
||||||
|
removed = _device_ids_snapshot - curr_ids
|
||||||
|
if added or removed:
|
||||||
|
change_version += 1
|
||||||
|
try:
|
||||||
|
LogManager.info(f"[DEVICE][CHANGED][{action}] rev={change_version} count={len(curr_ids)} added={list(added)} removed={list(removed)}")
|
||||||
|
except Exception:
|
||||||
|
print(f"[DEVICE][CHANGED][{action}] rev={change_version} count={len(curr_ids)} added={list(added)} removed={list(removed)}")
|
||||||
|
_device_ids_snapshot = curr_ids
|
||||||
|
|
||||||
|
def _normalize_type(v) -> int:
|
||||||
|
"""把各种表示在线/离线的值,规范成 1/0"""
|
||||||
|
if isinstance(v, bool):
|
||||||
|
return 1 if v else 0
|
||||||
|
if isinstance(v, (int, float)):
|
||||||
|
return 1 if int(v) == 1 else 0
|
||||||
|
if isinstance(v, str):
|
||||||
|
s = v.strip().lower()
|
||||||
|
if s.isdigit():
|
||||||
|
return 1 if int(s) == 1 else 0
|
||||||
|
if s in ("true", "online", "on", "yes"):
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
return 1 if v else 0
|
||||||
|
|
||||||
|
def _is_online(d: Dict[str, Any]) -> bool:
|
||||||
|
return _normalize_type(d.get("type", 1)) == 1
|
||||||
|
|
||||||
|
def _apply_device_event(obj: Dict[str, Any]):
|
||||||
|
"""把单条设备上线/下线事件落到 listData,并打印关键日志"""
|
||||||
try:
|
try:
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
dev_id = obj.get("deviceId")
|
||||||
# 设置端口复用,避免端口被占用时无法绑定
|
typ = _normalize_type(obj.get("type", 1))
|
||||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
obj["type"] = typ # 写回规范后的值,避免后续被误判
|
||||||
|
if dev_id is None:
|
||||||
# 尝试绑定端口
|
LogManager.warning(f"[DEVICE][WARN] missing deviceId in obj={obj}")
|
||||||
try:
|
return
|
||||||
s.bind(('127.0.0.1', port))
|
with listLock:
|
||||||
print(f"[INFO] Socket successfully bound to port {port}")
|
before = len(listData)
|
||||||
LogManager.info(f"[INFO] Socket successfully bound to port {port}")
|
# 删除同 udid 旧记录
|
||||||
except Exception as bind_error:
|
listData[:] = [d for d in listData if d.get("deviceId") != dev_id]
|
||||||
print(f"[ERROR]端口绑定失败: {bind_error}")
|
if typ == 1:
|
||||||
LogManager.info(f"[ERROR]端口绑定失败: {bind_error}")
|
listData.append(obj) # 上线
|
||||||
return
|
LogManager.info(f"[DEVICE][UPSERT] id={dev_id} type={typ} size={len(listData)} (replaced={before - (len(listData)-1)})")
|
||||||
|
_log_device_changes("UPSERT")
|
||||||
# 开始监听
|
else:
|
||||||
s.listen()
|
LogManager.warning(f"[DEVICE][REMOVE] id={dev_id} type={typ} size={len(listData)} (removed_prev={before - len(listData)})")
|
||||||
LogManager.info(f"[INFO] Socket listener started on port {port}, waiting for connections...")
|
_log_device_changes("REMOVE")
|
||||||
print(f"[INFO] Socket listener started on port {port}, waiting for connections...")
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
conn, addr = s.accept()
|
|
||||||
except Exception as e:
|
|
||||||
LogManager.error(f"[ERROR] accept 失败: {e}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 独立线程处理单条连接,避免单客户端异常拖垮监听线程
|
|
||||||
threading.Thread(target=_handle_conn, args=(conn, addr), daemon=True).start()
|
|
||||||
# while True:
|
|
||||||
# try:
|
|
||||||
# LogManager.info(f"[INFO] Waiting for a new connection on port {port}...")
|
|
||||||
# print(f"[INFO] Waiting for a new connection on port {port}...")
|
|
||||||
# conn, addr = s.accept()
|
|
||||||
# LogManager.info(f"[INFO] Connection accepted from: {addr}")
|
|
||||||
# print(f"[INFO] Connection accepted from: {addr}")
|
|
||||||
#
|
|
||||||
# raw_data = conn.recv(1024).decode('utf-8').strip()
|
|
||||||
# LogManager.info(f"[INFO] Raw data received: {raw_data}")
|
|
||||||
# print(f"[INFO] Raw data received: {raw_data}")
|
|
||||||
#
|
|
||||||
# data = json.loads(raw_data)
|
|
||||||
# LogManager.info(f"[INFO] Parsed data: {data}")
|
|
||||||
# print(f"[INFO] Parsed data: {data}")
|
|
||||||
# dataQueue.put(data)
|
|
||||||
# except Exception as conn_error:
|
|
||||||
# LogManager.error(f"[ERROR]连接处理失败: {conn_error}")
|
|
||||||
# print(f"[ERROR]连接处理失败: {conn_error}")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LogManager.error(f"[ERROR]Socket服务启动失败: {e}")
|
LogManager.error(f"[DEVICE][APPLY_EVT][ERROR] {e}")
|
||||||
print(f"[ERROR]Socket服务启动失败: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
|
# ============ 设备事件 socket 监听 ============
|
||||||
def _handle_conn(conn: socket.socket, addr):
|
def _handle_conn(conn: socket.socket, addr):
|
||||||
|
"""统一的连接处理函数(外部全局,避免内嵌函数覆盖)"""
|
||||||
try:
|
try:
|
||||||
|
LogManager.info(f"[SOCKET][ACCEPT] from={addr}")
|
||||||
with conn:
|
with conn:
|
||||||
# 1. 循环收包直到拿到完整 JSON
|
|
||||||
buffer = ""
|
buffer = ""
|
||||||
while True:
|
while True:
|
||||||
data = conn.recv(1024)
|
data = conn.recv(1024)
|
||||||
if not data: # 对端关闭
|
if not data: # 对端关闭
|
||||||
break
|
break
|
||||||
buffer += data.decode('utf-8', errors='ignore')
|
buffer += data.decode('utf-8', errors='ignore')
|
||||||
# 2. 尝试切出完整 JSON(简单按行,也可按长度头、分隔符)
|
# 按行切 JSON;发送端每条以 '\n' 结尾
|
||||||
while True:
|
while True:
|
||||||
line, sep, buffer = buffer.partition('\n')
|
line, sep, buffer = buffer.partition('\n')
|
||||||
if not sep: # 没找到完整行
|
if not sep:
|
||||||
break
|
break
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not line: # 空行跳过
|
if not line:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
obj = json.loads(line)
|
obj = json.loads(line)
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
LogManager.warning(f"[WARN] 非法 JSON 丢弃: {line[:100]} {e}")
|
LogManager.warning(f"[SOCKET][WARN] 非法 JSON 丢弃: {line[:120]} err={e}")
|
||||||
continue
|
continue
|
||||||
# 3. 收到合法数据,塞进队列
|
dev_id = obj.get("deviceId")
|
||||||
dataQueue.put(obj)
|
typ = _normalize_type(obj.get("type", 1))
|
||||||
LogManager.info(f"[INFO] 收到合法消息: {obj}")
|
obj["type"] = typ
|
||||||
|
LogManager.info(f"[SOCKET][RECV] deviceId={dev_id} type={typ} keys={list(obj.keys())}")
|
||||||
|
_apply_device_event(obj)
|
||||||
|
LogManager.info(f"[SOCKET][APPLY] deviceId={dev_id} type={typ}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LogManager.error(f"[ERROR] 连接处理异常: {e}")
|
LogManager.error(f"[SOCKET][ERROR] 连接处理异常: {e}")
|
||||||
|
|
||||||
|
def start_socket_listener():
|
||||||
|
"""启动设备事件监听(与 HTTP 端口无关,走 FLASK_COMM_PORT)"""
|
||||||
|
# 统一使用 FLASK_COMM_PORT,默认 34566
|
||||||
|
port = int(os.getenv('FLASK_COMM_PORT', 34566))
|
||||||
|
LogManager.info(f"Received port from environment: {port}")
|
||||||
|
print(f"Received port from environment: {port}")
|
||||||
|
|
||||||
# 在独立线程中启动Socket服务
|
if port <= 0:
|
||||||
|
LogManager.info("未获取到通信端口,跳过Socket监听")
|
||||||
|
print("未获取到通信端口,跳过Socket监听")
|
||||||
|
return
|
||||||
|
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
s.bind(('127.0.0.1', port))
|
||||||
|
print(f"[INFO] Socket successfully bound to port {port}")
|
||||||
|
LogManager.info(f"[INFO] Socket successfully bound to port {port}")
|
||||||
|
except Exception as bind_error:
|
||||||
|
print(f"[ERROR]端口绑定失败: {bind_error}")
|
||||||
|
LogManager.info(f"[ERROR]端口绑定失败: {bind_error}")
|
||||||
|
return
|
||||||
|
|
||||||
|
s.listen()
|
||||||
|
LogManager.info(f"[INFO] Socket listener started on port {port}, waiting for connections...")
|
||||||
|
print(f"[INFO] Socket listener started on port {port}, waiting for connections...")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
conn, addr = s.accept()
|
||||||
|
except Exception as e:
|
||||||
|
LogManager.error(f"[ERROR] accept 失败: {e}")
|
||||||
|
continue
|
||||||
|
threading.Thread(target=_handle_conn, args=(conn, addr), daemon=True).start()
|
||||||
|
|
||||||
|
# 监听存活看门狗:端口不可连就拉起
|
||||||
|
def _listener_watchdog():
|
||||||
|
import socket as _s
|
||||||
|
port = int(os.getenv('FLASK_COMM_PORT', 34566))
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
ok = False
|
||||||
|
try:
|
||||||
|
with _s.socket(_s.AF_INET, _s.SOCK_STREAM) as c:
|
||||||
|
c.settimeout(1.0)
|
||||||
|
c.connect(('127.0.0.1', port))
|
||||||
|
ok = True
|
||||||
|
except Exception:
|
||||||
|
ok = False
|
||||||
|
if not ok:
|
||||||
|
LogManager.warning(f"[SOCKET][WATCHDOG] listener not reachable on {port}, restarting...")
|
||||||
|
try:
|
||||||
|
threading.Thread(target=start_socket_listener, daemon=True).start()
|
||||||
|
except Exception as e:
|
||||||
|
LogManager.error(f"[SOCKET][WATCHDOG] restart failed: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
LogManager.error(f"[SOCKET][WATCHDOG] error: {e}")
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
# 独立线程启动 Socket 服务 + 看门狗
|
||||||
listener_thread = threading.Thread(target=start_socket_listener, daemon=True)
|
listener_thread = threading.Thread(target=start_socket_listener, daemon=True)
|
||||||
listener_thread.start()
|
listener_thread.start()
|
||||||
|
watchdog_thread = threading.Thread(target=_listener_watchdog, daemon=True)
|
||||||
|
watchdog_thread.start()
|
||||||
|
|
||||||
|
# ============ API 路由 ============
|
||||||
# 获取设备列表
|
|
||||||
@app.route('/deviceList', methods=['GET'])
|
@app.route('/deviceList', methods=['GET'])
|
||||||
def deviceList():
|
def deviceList():
|
||||||
|
global _last_device_count, change_version
|
||||||
|
global _last_nonempty_snapshot, _last_snapshot_ts, _STICKY_TTL_SEC
|
||||||
|
global _empty_logged, _recovered_logged
|
||||||
try:
|
try:
|
||||||
with listLock:
|
with listLock:
|
||||||
# 1. 消费完队列
|
# 宽容判定在线(字符串'1'/'true'/True 都算)
|
||||||
while not dataQueue.empty():
|
data = [d for d in listData if _is_online(d)]
|
||||||
obj = dataQueue.get()
|
now = time.time()
|
||||||
if obj["type"] == 1:
|
|
||||||
# 上线:先踢掉同 deviceId 的旧记录(端口可能变)
|
|
||||||
listData[:] = [d for d in listData if d.get("deviceId") != obj.get("deviceId")]
|
|
||||||
listData.append(obj)
|
|
||||||
else:
|
|
||||||
# 下线:只要同 deviceId 就删,不管端口
|
|
||||||
listData[:] = [d for d in listData if d.get("deviceId") != obj.get("deviceId")]
|
|
||||||
|
|
||||||
# 2. 兜底:只保留在线
|
# 记录最近一次非空快照
|
||||||
listData[:] = [d for d in listData if d.get('type') == 1]
|
if data:
|
||||||
|
_last_nonempty_snapshot = data.copy()
|
||||||
|
_last_snapshot_ts = now
|
||||||
|
if _recovered_logged:
|
||||||
|
LogManager.info(f"[API][deviceList][RECOVERED] count={len(data)} rev={change_version}")
|
||||||
|
_recovered_logged = False
|
||||||
|
_empty_logged = False
|
||||||
|
else:
|
||||||
|
# 瞬时空:在 TTL 内回退上一份非空快照
|
||||||
|
if _last_nonempty_snapshot and (now - _last_snapshot_ts) <= _STICKY_TTL_SEC:
|
||||||
|
LogManager.warning(f"[API][deviceList][STICKY] serving last non-empty snapshot count={len(_last_nonempty_snapshot)} age={now - _last_snapshot_ts:.1f}s rev={change_version}")
|
||||||
|
return ResultData(data=_last_nonempty_snapshot).toJson()
|
||||||
|
if not _empty_logged:
|
||||||
|
LogManager.error(f"[API][deviceList][DROP_TO_EMPTY] last_count={_last_device_count} rev={change_version}")
|
||||||
|
_empty_logged = True
|
||||||
|
_recovered_logged = True
|
||||||
|
|
||||||
return ResultData(data=listData.copy()).toJson()
|
_last_device_count = len(data)
|
||||||
|
LogManager.info(f"[API][deviceList] return_count={len(data)} rev={change_version}")
|
||||||
|
return ResultData(data=data).toJson()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LogManager.error("获取设备列表失败:", e)
|
LogManager.error(f"[API][deviceList] error={e}")
|
||||||
return ResultData(data=[]).toJson()
|
return ResultData(data=[]).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 传递token
|
|
||||||
@app.route('/passToken', methods=['POST'])
|
@app.route('/passToken', methods=['POST'])
|
||||||
def passToken():
|
def passToken():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
print(data)
|
print(data)
|
||||||
return ResultData(data="").toJson()
|
return ResultData(data="").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 获取设备应用列表
|
# 获取设备应用列表
|
||||||
@app.route('/deviceAppList', methods=['POST'])
|
@app.route('/deviceAppList', methods=['POST'])
|
||||||
def deviceAppList():
|
def deviceAppList():
|
||||||
@@ -169,7 +254,6 @@ def deviceAppList():
|
|||||||
apps = ControlUtils.getDeviceAppList(udid)
|
apps = ControlUtils.getDeviceAppList(udid)
|
||||||
return ResultData(data=apps).toJson()
|
return ResultData(data=apps).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 打开指定app
|
# 打开指定app
|
||||||
@app.route('/launchApp', methods=['POST'])
|
@app.route('/launchApp', methods=['POST'])
|
||||||
def launchApp():
|
def launchApp():
|
||||||
@@ -205,7 +289,6 @@ def tapAction():
|
|||||||
session.tap(x, y)
|
session.tap(x, y)
|
||||||
return ResultData(data="").toJson()
|
return ResultData(data="").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 拖拽事件
|
# 拖拽事件
|
||||||
@app.route('/swipeAction', methods=['POST'])
|
@app.route('/swipeAction', methods=['POST'])
|
||||||
def swipeAction():
|
def swipeAction():
|
||||||
@@ -224,7 +307,6 @@ def swipeAction():
|
|||||||
session.swipe(sx, sy, ex, ey, duration)
|
session.swipe(sx, sy, ex, ey, duration)
|
||||||
return ResultData(data="").toJson()
|
return ResultData(data="").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 长按事件
|
# 长按事件
|
||||||
@app.route('/longPressAction', methods=['POST'])
|
@app.route('/longPressAction', methods=['POST'])
|
||||||
def longPressAction():
|
def longPressAction():
|
||||||
@@ -238,7 +320,6 @@ def longPressAction():
|
|||||||
session.tap_hold(x, y, 1.0)
|
session.tap_hold(x, y, 1.0)
|
||||||
return ResultData(data="").toJson()
|
return ResultData(data="").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 养号
|
# 养号
|
||||||
@app.route('/growAccount', methods=['POST'])
|
@app.route('/growAccount', methods=['POST'])
|
||||||
def growAccount():
|
def growAccount():
|
||||||
@@ -254,7 +335,6 @@ def growAccount():
|
|||||||
code, msg = ThreadManager.add(udid, thread, event)
|
code, msg = ThreadManager.add(udid, thread, event)
|
||||||
return ResultData(data="", code=code, message=msg).toJson()
|
return ResultData(data="", code=code, message=msg).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 观看直播
|
# 观看直播
|
||||||
@app.route("/watchLiveForGrowth", methods=['POST'])
|
@app.route("/watchLiveForGrowth", methods=['POST'])
|
||||||
def watchLiveForGrowth():
|
def watchLiveForGrowth():
|
||||||
@@ -267,7 +347,6 @@ def watchLiveForGrowth():
|
|||||||
ThreadManager.add(udid, thread, event)
|
ThreadManager.add(udid, thread, event)
|
||||||
return ResultData(data="").toJson()
|
return ResultData(data="").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 停止脚本
|
# 停止脚本
|
||||||
@app.route("/stopScript", methods=['POST'])
|
@app.route("/stopScript", methods=['POST'])
|
||||||
def stopScript():
|
def stopScript():
|
||||||
@@ -277,7 +356,6 @@ def stopScript():
|
|||||||
code, msg = ThreadManager.stop(udid)
|
code, msg = ThreadManager.stop(udid)
|
||||||
return ResultData(code=code, data=[], message=msg).toJson()
|
return ResultData(code=code, data=[], message=msg).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 关注打招呼
|
# 关注打招呼
|
||||||
@app.route('/passAnchorData', methods=['POST'])
|
@app.route('/passAnchorData', methods=['POST'])
|
||||||
def passAnchorData():
|
def passAnchorData():
|
||||||
@@ -292,7 +370,6 @@ def passAnchorData():
|
|||||||
acList = data.get("anchorList", [])
|
acList = data.get("anchorList", [])
|
||||||
Variables.commentList = data.get("comment")
|
Variables.commentList = data.get("comment")
|
||||||
|
|
||||||
|
|
||||||
LogManager.info(f"[INFO] 获取数据: {idList} {acList}")
|
LogManager.info(f"[INFO] 获取数据: {idList} {acList}")
|
||||||
|
|
||||||
AiUtils.save_aclist_flat_append(acList)
|
AiUtils.save_aclist_flat_append(acList)
|
||||||
@@ -322,7 +399,6 @@ def passAnchorData():
|
|||||||
LogManager.error(e)
|
LogManager.error(e)
|
||||||
return ResultData(data="", code=1001).toJson()
|
return ResultData(data="", code=1001).toJson()
|
||||||
|
|
||||||
|
|
||||||
@app.route('/followAndGreetUnion', methods=['POST'])
|
@app.route('/followAndGreetUnion', methods=['POST'])
|
||||||
def followAndGreetUnion():
|
def followAndGreetUnion():
|
||||||
try:
|
try:
|
||||||
@@ -361,14 +437,12 @@ def followAndGreetUnion():
|
|||||||
LogManager.error(e)
|
LogManager.error(e)
|
||||||
return ResultData(data="", code=1001).toJson()
|
return ResultData(data="", code=1001).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 获取私信数据
|
# 获取私信数据
|
||||||
@app.route("/getPrologueList", methods=['GET'])
|
@app.route("/getPrologueList", methods=['GET'])
|
||||||
def getPrologueList():
|
def getPrologueList():
|
||||||
import Entity.Variables as Variables
|
import Entity.Variables as Variables
|
||||||
return ResultData(data=Variables.prologueList).toJson()
|
return ResultData(data=Variables.prologueList).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 添加临时数据
|
# 添加临时数据
|
||||||
# 批量追加主播到 JSON 文件
|
# 批量追加主播到 JSON 文件
|
||||||
@app.route("/addTempAnchorData", methods=['POST'])
|
@app.route("/addTempAnchorData", methods=['POST'])
|
||||||
@@ -385,7 +459,6 @@ def addTempAnchorData():
|
|||||||
AiUtils.save_aclist_flat_append(data, "log/acList.json")
|
AiUtils.save_aclist_flat_append(data, "log/acList.json")
|
||||||
return ResultData(data="ok").toJson()
|
return ResultData(data="ok").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 获取当前屏幕上的聊天信息
|
# 获取当前屏幕上的聊天信息
|
||||||
@app.route("/getChatTextInfo", methods=['POST'])
|
@app.route("/getChatTextInfo", methods=['POST'])
|
||||||
def getChatTextInfo():
|
def getChatTextInfo():
|
||||||
@@ -432,7 +505,6 @@ def getChatTextInfo():
|
|||||||
]
|
]
|
||||||
return ResultData(data=data, message="解析失败").toJson()
|
return ResultData(data=data, message="解析失败").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 监控消息
|
# 监控消息
|
||||||
@app.route("/replyMessages", methods=['POST'])
|
@app.route("/replyMessages", methods=['POST'])
|
||||||
def monitorMessages():
|
def monitorMessages():
|
||||||
@@ -449,7 +521,6 @@ def monitorMessages():
|
|||||||
ThreadManager.add(udid, thread, event)
|
ThreadManager.add(udid, thread, event)
|
||||||
return ResultData(data="").toJson()
|
return ResultData(data="").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 上传日志
|
# 上传日志
|
||||||
@app.route("/setLoginInfo", methods=['POST'])
|
@app.route("/setLoginInfo", methods=['POST'])
|
||||||
def upLoadLogLogs():
|
def upLoadLogLogs():
|
||||||
@@ -463,7 +534,6 @@ def upLoadLogLogs():
|
|||||||
else:
|
else:
|
||||||
return ResultData(data="", message="日志上传失败").toJson()
|
return ResultData(data="", message="日志上传失败").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 获取当前的主播列表数据
|
# 获取当前的主播列表数据
|
||||||
@app.route("/anchorList", methods=['POST'])
|
@app.route("/anchorList", methods=['POST'])
|
||||||
def queryAnchorList():
|
def queryAnchorList():
|
||||||
@@ -481,7 +551,6 @@ def queryAnchorList():
|
|||||||
data = []
|
data = []
|
||||||
return ResultData(data=data).toJson()
|
return ResultData(data=data).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 修改当前的主播列表数据
|
# 修改当前的主播列表数据
|
||||||
@app.route("/updateAnchorList", methods=['POST'])
|
@app.route("/updateAnchorList", methods=['POST'])
|
||||||
def updateAnchorList():
|
def updateAnchorList():
|
||||||
@@ -537,7 +606,6 @@ def updateAnchorList():
|
|||||||
else:
|
else:
|
||||||
return ResultData(data=0, message="未找到符合条件的记录").toJson()
|
return ResultData(data=0, message="未找到符合条件的记录").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 删除主播
|
# 删除主播
|
||||||
@app.route("/deleteAnchorWithIds", methods=['POST'])
|
@app.route("/deleteAnchorWithIds", methods=['POST'])
|
||||||
def deleteAnchorWithIds():
|
def deleteAnchorWithIds():
|
||||||
@@ -546,7 +614,6 @@ def deleteAnchorWithIds():
|
|||||||
deleted = AiUtils.delete_anchors_by_ids(ids)
|
deleted = AiUtils.delete_anchors_by_ids(ids)
|
||||||
return ResultData(data={"deleted": deleted}).toJson()
|
return ResultData(data={"deleted": deleted}).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 配置ai人设
|
# 配置ai人设
|
||||||
@app.route("/aiConfig", methods=['POST'])
|
@app.route("/aiConfig", methods=['POST'])
|
||||||
def aiConfig():
|
def aiConfig():
|
||||||
@@ -585,14 +652,12 @@ def aiConfig():
|
|||||||
IOSAIStorage.overwrite(dict, "aiConfig.json")
|
IOSAIStorage.overwrite(dict, "aiConfig.json")
|
||||||
return ResultData(data="").toJson()
|
return ResultData(data="").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 查询主播聊天发送的最后一条信息
|
# 查询主播聊天发送的最后一条信息
|
||||||
@app.route("/select_last_message", methods=['GET'])
|
@app.route("/select_last_message", methods=['GET'])
|
||||||
def select_last_message():
|
def select_last_message():
|
||||||
data = JsonUtils.query_all_json_items()
|
data = JsonUtils.query_all_json_items()
|
||||||
return ResultData(data=data).toJson()
|
return ResultData(data=data).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 修改消息(已读改成未读)
|
# 修改消息(已读改成未读)
|
||||||
@app.route("/update_last_message", methods=['POST'])
|
@app.route("/update_last_message", methods=['POST'])
|
||||||
def update_last_message():
|
def update_last_message():
|
||||||
@@ -611,7 +676,6 @@ def update_last_message():
|
|||||||
return ResultData(data=updated_count, message="修改成功").toJson()
|
return ResultData(data=updated_count, message="修改成功").toJson()
|
||||||
return ResultData(data=updated_count, message="修改失败").toJson()
|
return ResultData(data=updated_count, message="修改失败").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 删除已读消息
|
# 删除已读消息
|
||||||
@app.route("/delete_last_message", methods=['POST'])
|
@app.route("/delete_last_message", methods=['POST'])
|
||||||
def delete_last_message():
|
def delete_last_message():
|
||||||
@@ -630,7 +694,6 @@ def delete_last_message():
|
|||||||
|
|
||||||
return ResultData(data=updated_count, message="修改失败").toJson()
|
return ResultData(data=updated_count, message="修改失败").toJson()
|
||||||
|
|
||||||
|
|
||||||
# 停止所有任务
|
# 停止所有任务
|
||||||
@app.route("/stopAllTask", methods=['POST'])
|
@app.route("/stopAllTask", methods=['POST'])
|
||||||
def stopAllTask():
|
def stopAllTask():
|
||||||
@@ -638,7 +701,6 @@ def stopAllTask():
|
|||||||
code, msg = ThreadManager.batch_stop(idList)
|
code, msg = ThreadManager.batch_stop(idList)
|
||||||
return ResultData(code, [], msg).toJson()
|
return ResultData(code, [], msg).toJson()
|
||||||
|
|
||||||
|
|
||||||
# 切换账号
|
# 切换账号
|
||||||
@app.route('/changeAccount', methods=['POST'])
|
@app.route('/changeAccount', methods=['POST'])
|
||||||
def changeAccount():
|
def changeAccount():
|
||||||
@@ -657,7 +719,6 @@ def changeAccount():
|
|||||||
# thread.start()
|
# thread.start()
|
||||||
return ResultData(data="", code=code, message=msg).toJson()
|
return ResultData(data="", code=code, message=msg).toJson()
|
||||||
|
|
||||||
|
|
||||||
@app.route('/test', methods=['POST'])
|
@app.route('/test', methods=['POST'])
|
||||||
def test():
|
def test():
|
||||||
import wda
|
import wda
|
||||||
@@ -723,4 +784,5 @@ def getAiConfig():
|
|||||||
return ResultData(data=data).toJson()
|
return ResultData(data=data).toJson()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run("0.0.0.0", port=5000, debug=True, use_reloader=False)
|
# 注意:这里建议 debug=False,避免未来有人改成 use_reloader=True 导致多进程
|
||||||
|
app.run("0.0.0.0", port=5000, debug=False, use_reloader=False, threaded=True)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1111,23 +1111,18 @@ class ScriptManager():
|
|||||||
" or @value='Inbox' or @label='Inbox' or @name='Inbox']"
|
" or @value='Inbox' or @label='Inbox' or @name='Inbox']"
|
||||||
)
|
)
|
||||||
|
|
||||||
print("11111111111111")
|
|
||||||
# 查找所有收件箱节点
|
# 查找所有收件箱节点
|
||||||
inbox_nodes = session.xpath(xpath_query).find_elements()
|
inbox_nodes = session.xpath(xpath_query).find_elements()
|
||||||
print("222222222222222")
|
|
||||||
if len(inbox_nodes) < 2:
|
if len(inbox_nodes) < 2:
|
||||||
LogManager.method_error(f"当前页面不再收件箱页面,重启", "检测消息", udid)
|
LogManager.method_error(f"当前页面不再收件箱页面,重启", "检测消息", udid)
|
||||||
raise Exception("当前页面不再收件箱页面,重启")
|
raise Exception("当前页面不再收件箱页面,重启")
|
||||||
print("33333333333333")
|
|
||||||
|
|
||||||
m = re.search(r'(\d+)', el.label) # 抓到的第一个数字串
|
m = re.search(r'(\d+)', el.label) # 抓到的第一个数字串
|
||||||
count = int(m.group(1)) if m else 0
|
count = int(m.group(1)) if m else 0
|
||||||
print("444444444444444444")
|
|
||||||
|
|
||||||
if not count:
|
if not count:
|
||||||
LogManager.method_info(f"当前收件箱的总数量{count}", "检测消息", udid)
|
LogManager.method_info(f"当前收件箱的总数量{count}", "检测消息", udid)
|
||||||
break
|
break
|
||||||
# print("5555555555555555555555")
|
|
||||||
|
|
||||||
# 新粉丝
|
# 新粉丝
|
||||||
xp_new_fan_badge = (
|
xp_new_fan_badge = (
|
||||||
@@ -1170,7 +1165,6 @@ class ScriptManager():
|
|||||||
"[@value and translate(@value,'0123456789','')='']"
|
"[@value and translate(@value,'0123456789','')='']"
|
||||||
"/ancestor::XCUIElementTypeCell[1]"
|
"/ancestor::XCUIElementTypeCell[1]"
|
||||||
)
|
)
|
||||||
print("6666666666666666")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 如果 2 秒内找不到,会抛异常
|
# 如果 2 秒内找不到,会抛异常
|
||||||
@@ -1184,7 +1178,6 @@ class ScriptManager():
|
|||||||
print("当前屏幕没有找到 用户消息 未读徽标数字", udid)
|
print("当前屏幕没有找到 用户消息 未读徽标数字", udid)
|
||||||
user_text = None
|
user_text = None
|
||||||
info_count += 1
|
info_count += 1
|
||||||
print("777777777777777777777")
|
|
||||||
|
|
||||||
if user_text:
|
if user_text:
|
||||||
|
|
||||||
@@ -1218,11 +1211,11 @@ class ScriptManager():
|
|||||||
last_in = item['text']
|
last_in = item['text']
|
||||||
if last_out is None and item['dir'] == 'out':
|
if last_out is None and item['dir'] == 'out':
|
||||||
last_out = item['text']
|
last_out = item['text']
|
||||||
if last_in or last_out: # 任一条拿到就提前停
|
if last_in and last_out: # 任一条拿到就提前停
|
||||||
break
|
break
|
||||||
|
|
||||||
# 2. 只有两条都空才重试
|
# 2. 只有两条都空才重试
|
||||||
if not last_in and not last_out:
|
if not last_in or not last_out:
|
||||||
attempt += 1
|
attempt += 1
|
||||||
if attempt == 3:
|
if attempt == 3:
|
||||||
break # 三次用完,放弃
|
break # 三次用完,放弃
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user