创建仓库
This commit is contained in:
96
Module/DeviceInfo.py
Normal file
96
Module/DeviceInfo.py
Normal file
@@ -0,0 +1,96 @@
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
import wda
|
||||
from tidevice import Usbmux
|
||||
from Entity.DeviceModel import DeviceModel
|
||||
from Entity.Variables import tikTokApp, WdaAppBundleId
|
||||
from Module.FlaskSubprocessManager import FlaskSubprocessManager
|
||||
|
||||
threadLock = threading.Lock()
|
||||
|
||||
class Deviceinfo(object):
|
||||
def __init__(self):
|
||||
self.deviceIndex = 0
|
||||
# 投屏端口
|
||||
self.screenProxy = 9110
|
||||
# 存放pid的数组
|
||||
self.pidList = []
|
||||
# 设备列表
|
||||
self.deviceArray = []
|
||||
# 获取到县城管理类
|
||||
self.manager = FlaskSubprocessManager.get_instance()
|
||||
# 给前端的设备模型数组
|
||||
self.deviceModelList = []
|
||||
|
||||
# 监听设备连接
|
||||
def startDeviceListener(self):
|
||||
while True:
|
||||
lists = Usbmux().device_list()
|
||||
# 添加设备逻辑
|
||||
for device in lists:
|
||||
if device not in self.deviceArray:
|
||||
self.screenProxy += 1
|
||||
self.connectDevice(device.udid)
|
||||
self.deviceArray.append(device)
|
||||
# 创建模型
|
||||
model = DeviceModel(device.udid,self.screenProxy,type=1)
|
||||
self.deviceModelList.append(model)
|
||||
# 发送数据
|
||||
self.manager.send(model.toDict())
|
||||
|
||||
# 处理拔出设备的逻辑
|
||||
def removeDevice():
|
||||
set1 = set(self.deviceArray)
|
||||
set2 = set(lists)
|
||||
difference = set1 - set2
|
||||
differenceList = list(difference)
|
||||
for i in differenceList:
|
||||
for j in self.deviceArray:
|
||||
# 判断是否为差异设备
|
||||
if i.udid == j.udid:
|
||||
# 从设备模型中删除数据
|
||||
for a in self.deviceModelList:
|
||||
if i.udid == a.deviceId:
|
||||
a.type = 2
|
||||
# 发送数据
|
||||
self.manager.send(a.toDict())
|
||||
self.deviceModelList.remove(a)
|
||||
|
||||
for k in self.pidList:
|
||||
# 干掉端口短发进程
|
||||
if j.udid == k["id"]:
|
||||
target = k["target"]
|
||||
target.kill()
|
||||
self.pidList.remove(k)
|
||||
# 删除已经拔出的设备
|
||||
self.deviceArray.remove(j)
|
||||
|
||||
removeDevice()
|
||||
time.sleep(1)
|
||||
|
||||
# 连接设备
|
||||
def connectDevice(self, identifier):
|
||||
d = wda.USBClient(identifier, 8100)
|
||||
d.app_start(WdaAppBundleId)
|
||||
time.sleep(2)
|
||||
d.app_start(tikTokApp)
|
||||
target = self.relayDeviceScreenPort()
|
||||
self.pidList.append({
|
||||
"target": target,
|
||||
"id": identifier
|
||||
})
|
||||
|
||||
# 转发设备端口
|
||||
def relayDeviceScreenPort(self):
|
||||
try:
|
||||
command = f"iproxy.exe {self.screenProxy} 9100"
|
||||
# 创建一个没有窗口的进程
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = 0
|
||||
r = subprocess.Popen(command, shell=True, startupinfo=startupinfo)
|
||||
return r
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 0
|
||||
101
Module/FlaskSubprocessManager.py
Normal file
101
Module/FlaskSubprocessManager.py
Normal file
@@ -0,0 +1,101 @@
|
||||
import subprocess
|
||||
import threading
|
||||
import atexit
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import time
|
||||
from typing import Optional, Union, Dict, List
|
||||
|
||||
class FlaskSubprocessManager:
|
||||
_instance: Optional['FlaskSubprocessManager'] = None
|
||||
_lock: threading.Lock = threading.Lock()
|
||||
|
||||
def __new__(cls):
|
||||
with cls._lock:
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
cls._instance._init_manager()
|
||||
return cls._instance
|
||||
|
||||
def _init_manager(self):
|
||||
self.process: Optional[subprocess.Popen] = None
|
||||
self.comm_port = self._find_available_port()
|
||||
self._stop_event = threading.Event()
|
||||
atexit.register(self.stop)
|
||||
|
||||
def _find_available_port(self):
|
||||
"""动态获取可用端口"""
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.bind(('0.0.0.0', 0))
|
||||
return s.getsockname()[1]
|
||||
|
||||
def start(self):
|
||||
"""启动子进程(Windows兼容方案)"""
|
||||
with self._lock:
|
||||
if self.process is not None:
|
||||
raise RuntimeError("子进程已在运行中!")
|
||||
# 通过环境变量传递通信端口
|
||||
env = os.environ.copy()
|
||||
env['FLASK_COMM_PORT'] = str(self.comm_port)
|
||||
|
||||
self.process = subprocess.Popen(
|
||||
['python', 'Flask/FlaskService.py'], # 启动一个子进程 FlaskService.py
|
||||
stdin=subprocess.PIPE, # 标准输入流,用于向子进程发送数据
|
||||
stdout=subprocess.PIPE, # 标准输出流,用于接收子进程的输出
|
||||
stderr=subprocess.PIPE, # 标准错误流,用于接收子进程的错误信息
|
||||
text=True, # 以文本模式打开流,否则以二进制模式打开
|
||||
bufsize=1, # 缓冲区大小设置为 1,表示行缓冲
|
||||
encoding='utf-8', # 指定编码为 UTF-8,确保控制台输出不会报错
|
||||
env=env # 指定子进程的环境变量
|
||||
)
|
||||
print(f"Flask子进程启动 (PID: {self.process.pid}, 通信端口: {self.comm_port})")
|
||||
|
||||
# 将日志通过主进程输出
|
||||
def print_output():
|
||||
while True:
|
||||
output = self.process.stdout.readline()
|
||||
if not output:
|
||||
break
|
||||
print(output.strip())
|
||||
|
||||
while True:
|
||||
error = self.process.stderr.readline()
|
||||
if not error:
|
||||
break
|
||||
print(f"Error: {error.strip()}")
|
||||
|
||||
threading.Thread(target=print_output, daemon=True).start()
|
||||
|
||||
def send(self, data: Union[str, Dict, List]) -> bool:
|
||||
"""通过Socket发送数据"""
|
||||
try:
|
||||
if not isinstance(data, str):
|
||||
data = json.dumps(data)
|
||||
# 等待子进程启动并准备好
|
||||
time.sleep(1) # 延时1秒,根据实际情况调整
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.connect(('127.0.0.1', self.comm_port))
|
||||
s.sendall((data + "\n").encode('utf-8'))
|
||||
return True
|
||||
except ConnectionRefusedError:
|
||||
print(f"连接被拒绝,确保子进程在端口 {self.comm_port} 上监听")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"发送失败: {e}")
|
||||
return False
|
||||
|
||||
def stop(self):
|
||||
with self._lock:
|
||||
if self.process and self.process.poll() is None:
|
||||
print(f"[INFO] Stopping Flask child process (PID: {self.process.pid})...")
|
||||
self.process.terminate()
|
||||
self.process.wait()
|
||||
print("[INFO] Flask child process stopped.")
|
||||
self._stop_event.set()
|
||||
else:
|
||||
print("[INFO] No Flask child process to stop.")
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls) -> 'FlaskSubprocessManager':
|
||||
return cls()
|
||||
11
Module/Main.py
Normal file
11
Module/Main.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from Module.DeviceInfo import Deviceinfo
|
||||
from Module.FlaskSubprocessManager import FlaskSubprocessManager
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("启动flask")
|
||||
manager = FlaskSubprocessManager.get_instance()
|
||||
manager.start()
|
||||
|
||||
print("启动主线程")
|
||||
info = Deviceinfo()
|
||||
info.startDeviceListener()
|
||||
BIN
Module/iproxy.exe
Normal file
BIN
Module/iproxy.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user