1. 創作背景
使用deepin-terminal的時候,我發現一些小的問題。
在論壇的帖子(https://bbs.deepin.org/zh/post/224502)也總結反饋了這些問題
- 終端標籤變色
- 遠端管理標籤標題跟右鍵選項顯示異常
- 截圖傳送到微信之後,再切換到終端時,雙擊複製無法將內容置入剪下板
經過我虛擬機器全新安裝deepin20.2.3後,幾輪測試下來發現
終端標籤變色的問題,應該只是個特性,發生在如果標籤1有工作正在進行,或者有更新,比如sudo apt update
或者ssh 連線超時被close時,而此時你正在標籤2工作,那麼這個變色會提醒你,標籤1的工作結束了,或者有更新
截圖傳送到微信,然後切換到終端,雙擊複製,概率性無法複製的問題,應該是個穩定的bug。這個bug我也反饋給官方了,不清楚是否後續會解決。
今天來說的是遠端管理
2. 遠端管理的bug描述
deepin-terminal提供的遠端管理,一般會要求我們輸入名稱,地址 ,帳號,密碼這些。正常情況下,如果這些都是正常的,遠端連線不會存在問題。連線上以後,標籤標題會變成遠端主機的使用者@主機名,而終端右鍵也出現“上傳檔案”和“下載檔案“的選項。
正常的情況我們就不說了,說說不正常的情況
2.1 點選遠端連線時,突然不想連線了,或者密碼錯誤了,ctrl+c終止連線失敗
這種情況發生在,比如管理員重新設定了遠端連線的密碼,而你的遠端連線並未更新,那麼你使用這個連線遠端主機時,必然會提示你輸入密碼,3此輸入不正確,那麼就無法登陸。如果你輸入1次,發現不正確,直接ctrl+c了,那麼此時標籤的標題已經被設定為遠端主機的主機名@主機地址了,而右鍵選項也多出了“上傳檔案”和“下載檔案”的選項。
在未成功登陸遠端主機的情況下,這種顯示的變化,顯然是個BUG。如何解決,且等下文分析
2.2 輸錯了伺服器的IP,因為網路路由不正確,連線失敗
如果你不小心直接輸錯了遠端主機的IP地址,而且點選登陸時發現根本沒法登陸,報一些比如No route to host的資訊,告訴你沒有到遠端主機的路由。而此時標籤的標題已經被設定為遠端主機的主機名@主機地址了,而右鍵選項也多出了“上傳檔案”和“下載檔案”的選項。
在未成功登陸遠端主機的情況下,這種顯示的變化,顯然是個BUG。如何解決,且等下文分析
2.3 修改了ssh配置檔案,比如修改了LogLevel導致退出遠端主機後顯示異常
如果你是一個不喜歡被繁雜的資訊打擾的人,修改了/etc/ssh/ssh_config裡面,把LogLevel設定為quit,那麼當你使用deepi-terminal的遠端管理登陸遠端主機時,標籤標題和右鍵選項均可以正常顯示,但是你工作結束,通過exit命令,logout命令或者直接ctrl+d登出時,你會發現你的標籤和右鍵選項還在。
在成功退出遠端主機後,終端標籤標題跟右鍵選項沒有變化,這顯然是個BUG。如何解決,且等下文分析
3. 如何解決
具體的解決,肯定是要修改程式碼的啦
3.1 先分析一下為何如此
分析deepin-terminal的原始碼得知,當你使用遠端管理登陸遠端節點時,deepi-terminal實際上載入和執行了一段標準的expect指令碼,該指令碼是一個免互動的指令碼。deepin-terminal會把遠端管理皮膚裡面的資訊同步到這段expect裡面,替換到設定的“巨集”,然後執行它們。
同時deepin-terminal啟動了一個定時器觸發,0.1s的時間,判斷這個遠端管理是否存在expect的程式資訊,如果有就把當前標籤的連線,設定為遠端標籤的格式,還有其他資訊,比如編碼,和右鍵選項。
試想,如果expect執行的ssh超時還沒有到,標籤已經變化,而ssh連線失敗後,變化的標籤會變回去嗎?
答案是不一定的。這就是上面的2.1和2.2描述的bug原因。
至於2.3的描述,就要看deepin-terminal退出遠端時,是如何把標籤重新設定為本地的。它是通過截獲收發資料的字串,判斷其是否包含"Connected to "和"closed."或者"Permission denied"來判斷終端斷開了遠端連線。
inline void TermWidget::onTermWidgetReceivedData(QString value)
{
/******** Modify by ut000610 daizhengwen 2020-05-25: quit download****************/
if (value.contains("Transfer incomplete")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_C, Qt::ControlModifier);
QApplication::sendEvent(focusWidget(), &keyPress);
}
if (value.endsWith("\b \b #")) { // 結束的時候有亂碼的話,將它清除
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_U, Qt::ControlModifier);
QApplication::sendEvent(focusWidget(), &keyPress);
}
/********************* Modify by ut000610 daizhengwen End ************************/
// 退出遠端後,設定成false
if ((value.contains("Connection to") && value.contains(" closed.")) || value.contains("Permission denied"))
QTimer::singleShot(100, this, &TermWidget::onExitRemoteServer);
}
而我修改了LogLevel為quit,這個配置在我登出遠端節點時,只顯示Logout或者中文“登出”,”登出“等字樣,並不存在”Connection to"的字樣,因此終端就認定這個操作不是退出遠端,自然它的標籤標題跟右鍵選單是不會變化的了。
3.2 再看看如何處理
直接看修改結果吧,對於2.1和2.2的bug描述,直接修改原始碼檔案:deepin-terminal/src/assets/other/ssh_login.sh
修改為:
# Spawn and expect
if { $authentication == "no" } {
eval spawn $ssh_cmd $ssh_opt -t $remote_command exec \\\$SHELL -l
} else {
eval spawn $ssh_cmd $ssh_opt -i $private_key -t $remote_command exec \\\$SHELL -l
}
#fix bug:修復在登陸過程中直接ctlr+c終止登陸時,終端標籤和右鍵選項變成遠端的現象.
trap {
send_user "Connection to closed.\n"
exit
} SIGINT
if { [string length $password] } {
expect {
timeout {send_user "ssh connection time out, please operate manually\n"}
-nocase "yes/no" {send "yes\r"; exp_continue}
-nocase -re "password:|enter passphrase for key" { send "$encoded_password\r" }
"No route to host" { send "Connection to closed.\n";exp_continue} #修改遠端地址錯誤導致的終端標籤和右鍵選項變成遠端
"Connection to closed." { exit }
}
}
interact
大概意思就是通過expect捕獲2.1和2.2描述的bug或者crtl+c訊號,向終端丟擲"Connection to closed."字樣,讓終端捕獲這個字樣後,把當前標籤設定為本地標籤即可,就不會顯示為遠端的樣式了
而對於2.3的bug描述,還是修改/etc/ssh/ssh_config的LogLevel引數吧,修改為LogLevel=ERROR即可,另外一種動作比較大就是修改原始碼,把"登出",“登出”,"logout"等字樣包含在對終端退出遠端的判斷,不過這個成本比較大了,意義也不是很大。暫且不做了。
4. 總結
花了2天時間摸索和測試吧,總的來說,達到了驗證,修改和修復這些bug的目的。估計沒有多少人會觸發這樣的bug,但是至少可以學習deepin-terminal的工作原理不是,賺到了。