給Node.js加個遠程調試系統

遠程調試系統

這個項目適用於所有的node.js程序.本文不涉及任何Puppeteer的內容.

起因

因爲最近很長一段時間的工作內容都是用Puppeteer框架分析數據.
有一種經常性的需求是: 在程序工作的中間環境 試驗新的代碼.eg:
某個頁面希望執行 自動點擊鍵入命令,但是這個過程非常依賴前面的流程,耗時不短.
每每被打斷思路,效率低下.
所以希望實現:

在Puppeteer工作時 隨時插入 測試 即時 執行代碼.

使用控制檯來控制程序也嘗試過,有兩個原因讓我放棄這個方案:

  • VSCode的調試器不支持IO輸入窗口
    沒辦法鍵入命令(也許是我沒找到)
  • 單獨的CMD命令行輸入窗口
    命令太單一.且和日誌輸出等混在一起了.

其實原因在於命令行窗口作爲Log輸出,一個平面無法區分更多數據.

所以對 輸出數據,輸入數據,命令 採取多通道的需求 就誕生了.
網頁作爲數據顯示平面是我首先想到的。

但是這個功能說大不大,說小又沒底.所以一直擱淺,直到最近客戶提出 無法區分兩個項目Puppeteer實例.
又恰逢兩個項目的間隙,開始動手.

主要設計點

功能點:

  • node.js的日誌顯示到網頁上
  • 網頁調試
  • 執行功能
    暫停,恢復
    屏幕顯示
    執行遠程代碼

數據結構

因爲有: KD-RPC,P2PManager,Canvas遠程控制系統 的設計經驗,所以核心直奔數據結構設計:

因爲要打日誌,所以初步設計成這樣:
Rep =XX=> 網頁端
Rep <=cmd=網頁端

interface IF_DB{
  serviceNumber:number,//這是往總控上設計,獨立的服務其實不必要這個
  data:{
   name: 日誌
   type:{
    main:圖片文本,
    附屬:屏幕等
   }
   time:Rep運行到現在的時間
   data:any
  }
  
}
interface cmd{
 name: 即時執行函數
 data: any //字符串代碼
	
}

通過什麼方式區分不同的返回數據呢?
當然是 通道,可以爲每種特別的數據通道:
服務端發送 客戶端監聽的通道有三個:

  • 普通的Rep主動發送給用戶的數據
    eg:日誌
  • 命令的返回值,執行結果
  • 命令的錯誤信息

客戶端發送 服務端監聽的通道有:

  • 命令通道
    結構是cmd

WebSocket

之前分析某款通訊軟件的Web版時,其使用的WebSocket給我留下了很深的印象.
從網上找了一些現成的代碼,作爲基礎,使用Socket.IO庫.
這裏記錄一下node.js是如何斷開websocket的:

服務端發送一個CloseConnect事件,這個鏈接在執行完這一需求後,會自動斷開.
客戶端則是直接 socket.close()//不太記清,具體是不是這個函數自行打印對象驗證.

  • Auth
    因爲需要 本地向服務端通信,而又不希望可能的暴露信息,所以需要認證,即:
    服務器連接後,監聽認證通道,認證密碼通過才設置標註允許進一步通訊.
    注意: 每次連接建立都要清除認證標註.

eval 即時執行遠程異步代碼

當我們將一段代碼 從網頁端輸入 傳輸回 node.js 後,怎麼執行呢?

console.log('Hello')

直接let ret = await eval(cmdString)即可.
爲什麼有異步? 因爲我們要執行異步代碼:

例如遠程輸入:
cmdString =

async sleep(ms){
 return new Promise((reslove)=>{
  setTimeout(()=>{reslove()},ms)
 })
}
function async run(){
 console.log('1')
 await sleep(5000)
 console.log('2')
}

有了await,eval會等待整個代碼(包括異步)執行完畢.

暫停/恢復

玩法也很簡單,但難點其實是時機:
什麼時候調用Trap?需要用戶自己埋點嗎?
答案是No! 直接將 將我們整個系統埋入 log中即可.這樣每次log都會有一個時機.
暫停命令其實就是輪循,額額或許是因爲我這邊不太掌握更多node.js的事件.

執行遠程代碼?需要暫停嗎?

不需要,因爲node.js是單線程.又需要,因爲我們的遠程代碼可能也有異步代碼.
不暫停,可能會造成 遠程命令和本地代碼交替執行.

效果

好了,網頁拿到數據拿到後怎麼顯示就是 前端的設計了.

效果很6.讓停就停,讓走就走.想執行就執行,寫錯代碼也沒關係.

收穫

之前曾經嘗試讓後臺引入 websocket 實現控制,通過這次項目,遇到類似需求,可以用node.js在服務器上做代理.

下一步方向

既然網頁端搞成了 代碼輸入端,不加個高亮,語法分析說不過去.
Monaco Editor

Monaco Editor 遇到的障礙

直接使用了其Github範例做基礎.
結果我在其它地方 appendChild 方式添加的 socket.io 不能工作了。
monaco 異常提示:
Can only have one anonymous define call per script file.
解決方案: 用一個script標籤佔位,直接修改其src來實現 socket.io的加載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章