前言
來啦老鐵氛改!
前段時間寫了一篇文章:快看,這有一款遠程訪問工具比伏!
當時手搓了一個看起來很 cheap 的前端胜卤,實在上不了臺面!
于是抽空對其做了一次升級赁项,同時也在后端做了一點提升葛躏,先睹為快:
簡單做一下說明:
- 前端改用 vue3+element-plus+axios澈段;
- 前端頁面做了重構(gòu),分成主頁(圖1)跟設(shè)備實時瀏覽頁面(圖4)舰攒,這樣就能一邊執(zhí)行代碼败富,一邊實時查看被測對象的表現(xiàn)了;
- 首頁增加 Ping摩窃、Boot Up 入口兽叮,Ping 能對所有遠程服務(wù)進行 ping 操作,獲得遠程服務(wù)的狀態(tài)猾愿,Boot Up 入口能對掉線的遠程服務(wù)進行重啟操作(也可開放重啟遠程服務(wù)等操作)鹦聪;
- 首頁右側(cè)的電腦畫面更新頻率改為0.8秒一次(原 1秒一次),讓畫面更為實時蒂秘,同時具備隱藏畫面等功能入口泽本;
- 左側(cè)側(cè)邊欄,每個服務(wù) item 中有一個小小的手機 icon材彪,點擊打開另一個“被測對象實時查看器”頁面 tab,默認選擇所有設(shè)備進行展示琴儿,讓用戶能一次性知道所有發(fā)生的情況段化,能對每個設(shè)備進行一些基本的操作;
- 考慮到存在多個用戶打開同一服務(wù)的“被測對象實時查看器”造成,對后端服務(wù)帶來過分的壓力显熏,從而容易導(dǎo)致后端服務(wù)掛掉,因此在后端采用:減小圖片尺寸+降低圖片質(zhì)量+多線程+緩存策略(3 秒以內(nèi)晒屎,同一臺設(shè)備的截圖都一樣喘蟆,3 秒后會刷新截圖),目前就簡單緩存在后端服務(wù)的內(nèi)存中(多線程+緩存能解決 ADB I/O 阻塞問題鼓鲁,代價是沒那么“實時”)蕴轨。后端代碼如:
cache_duration = 3
@app.get("/bridge/adb_screenshot")
async def do_adb_screenshot(device_id: str):
"""
do adb screenshot
:param device_id: android device's serial number
:return: screenshot of current android device
"""
try:
if device_id in device_screenshots:
cached_img_stream, screenshot_time = device_screenshots[device_id]
if (time.time() - screenshot_time) > cache_duration:
thread = threading.Thread(target=ScreenshotUtil.get_adb_screenshot, args=(device_id,))
thread.start()
return StreamingResponse(BytesIO(cached_img_stream), media_type='image/jpeg')
thread = threading.Thread(target=ScreenshotUtil.get_adb_screenshot, args=(device_id,))
thread.start()
return JSONResponse(status_code=200, content={"message": "Please wait..."})
except Exception as e:
return JSONResponse(status_code=500, content={"error": str(e)})
其中,使用 screenshots.py 文件進行圖片數(shù)據(jù)緩存骇吭,screenshots.py 內(nèi)的代碼就一行:
device_screenshots = {}
ScreenshotUtil 內(nèi)的 get_adb_screenshot 方法如下:
@staticmethod
def get_adb_screenshot(device_id):
try:
print("Take screenshot...")
result = subprocess.run(
["adb", "-s", device_id, "exec-out", "screencap", "-p"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=5
)
if result.returncode != 0:
return {"error": "Failed to capture screenshot by adb", "details": result.stderr.decode()}
img = Image.open(BytesIO(result.stdout))
new_width = int(img.width * 0.4)
new_height = int(img.height * 0.4)
img = img.resize((new_width, new_height))
# set image's quality to 40% of original one
output_stream = BytesIO()
img.convert("RGB").save(output_stream, format='JPEG', quality=40)
output_stream.seek(0)
device_screenshots[device_id] = (output_stream.getvalue(), time.time())
return {"message": "success", "device_id": device_id}
except subprocess.TimeoutExpired:
return {"error": "Timeout expired while trying to capture screenshot."}
except Exception as e:
return {"error": "An error occurred.", "details": str(e)}
- 前端代碼倉庫:由于內(nèi)含 ip橙弱,較為敏感,暫時不公開燥狰,有需要可以私信我棘脐;
- 后端代碼倉庫:https://github.com/dylanz666/debug-bridge-server.git
展望:
- 考慮加入截圖生成視頻的功能;
- 研究更為實時的“被測對象實時查看器”龙致;
(原本想考慮使用 websocket 或者 SSE(Server-Sent Events)來更為實時同步設(shè)備畫面蛀缝,但是會卡在畫面無法渲染方面,后續(xù)可以考慮再調(diào)研調(diào)研目代。)
好了屈梁,今天就記錄到這里啦嗤练,下期再見嘍~
如果本文對您有幫助,麻煩動動手指點點贊俘闯?
謝謝潭苞!