lip 的工作原理
讀完本頁,你就知道你向 lip 提出要求時它對伺服器資料夾做了什麼、為什麼一次變更可以放心取消、lip 的背景處理程序是做什麼用的,以及為什麼有些事命令允許而介面拒絕。使用 lip 並不需要了解這些。遇到意料之外的情況時,它們會有幫助。
工作區
工作區是一個存放一個伺服器的資料夾。對命令來說,它是你目前所在的資料夾。對介面來說,它是目前工作區,也就是你在介面裡選取的那個。
工作區裡有兩類東西:
- 伺服器:遊戲、載入器、你的模組、你的世界和設定。這些都是普通檔案,放在遊戲期望的位置。
.lip/:lip 對這個資料夾的瞭解。
.lip/ 裡的 | 是什麼 |
|---|---|
state.json | 已安裝套件的清單:每個套件的版本、來源、是否由你安裝,以及它安裝的檔案。見狀態檔。 |
config.toml | 這個工作區的設定。見設定。 |
lock | lip 變更工作區期間佔用的檔案。 |
server.lock | lip 執行伺服器期間佔用的檔案。 |
journal | 正在進行的變更的記錄。只在變更期間存在,或者在變更被中斷之後存在。 |
logs/ | 失敗報告。 |
wine/ | 在 Linux 和 macOS 上,伺服器的 Wine 前綴。 |
lip 對一個伺服器的全部瞭解都在它的資料夾裡。移動或複製資料夾,伺服器就跟著走。工作區不相依任何登錄檔或中央清單;唯一的例外是介面顯示的資料夾清單,那只是為了方便。
每個檔案的說明見檔案和目錄。
遊戲、載入器、模組和相依
lip 安裝的一切都是套件:一組檔案,加上一份說明,也就是 lip.toml,其中寫明哪些檔案放到哪裡、這個套件還需要什麼。套件在工作區裡扮演四種角色:
| 角色 | 是什麼 | 數量 |
|---|---|---|
| 遊戲 | 某個版本的 Minecraft 基岩版專用伺服器,Windows 版或 Linux 版。lip 從 Minecraft 官方網站下載它。 | 最多一個 |
| 載入器 | LeviLamina,它改造遊戲,使之能載入模組。只用於 Windows 伺服器。 | 最多一個 |
| 模組 | 由 LeviLamina 載入的套件。安裝在 mods/<名字>/。 | 任意多個 |
| 相依 | 別的套件需要的套件。 | 按需 |
由此得出兩條規則。
遊戲和載入器是模組立足的地基。 每個載入器版本都寫明瞭它支援哪些遊戲版本,每個模組也寫明瞭自己需要什麼。所以 lip install 和 lip update 不動遊戲和載入器;它們尋找與之相配的模組版本。只有伺服器安裝會更換地基,並隨之把每個模組換成與新地基相配的版本。伺服器安裝指的是 lip setup,或者點名 LeviLamina 或遊戲本身的 lip install。
lip 記得你要求過什麼。 你點名的套件屬於你:在你解除安裝之前,它一直都在。相依之所以存在,只是因為有套件需要它;沒有套件需要時,lip 就會移除它。
每個套件擁有它安裝的檔案。兩個套件不能擁有同一個檔案,lip 也絕不刪除不屬於任何套件的檔案,只有一個例外:套件可以聲明自己留下的一些東西,在它被移除時一併清除。遊戲對它的某些資料夾就是這樣做的。見保留什麼刪除什麼。
操作
一次操作是對工作區的一次變更:一條 lip setup、lip install、lip update 或 lip uninstall 所做的一切,包括它新增或移除的每個相依。一次操作要麼完整地發生,要麼完全不發生。
它經過這些步驟:
- 加鎖。 lip 佔用
.lip/lock。如果另一個 lip 佔著它,操作立刻失敗。所以兩次變更絕不會混在一起。 - 恢復。 如果之前有操作被中斷,lip 先把它理順。
- 決定。 lip 讀取已安裝的內容,向網路查詢有哪些版本,選出一組彼此相配的套件,下載它們,並檢查每個檔案都能放置。到這裡工作區裡還什麼都沒變。大多數失敗發生在這一步,工作區原封不動。
- 準備系統。 如果要執行 Windows 程式,lip 會確保系統能執行它們。
- 變更。 lip 刪除和寫入檔案,並執行套件要求執行的程式。每次變更之前,它先在
.lip/journal裡記一筆。被取代或刪除的檔案,會先以一個隱藏的名字留在原處旁邊。 - 提交。 lip 寫入新的
state.json,把日誌標記為完成,然後刪除留在旁邊的舊檔案和日誌。 - 解鎖。
在介面裡,你在「套用」之前看到的計劃就是第 3 步的結果,它是在不做任何變更的情況下得出的。
復原
因為每次變更都先記錄再執行,每個舊檔案都保留到最後,lip 總是能退回去:
- 變更過程中某一步失敗:lip 按相反的順序復原變更。工作區和
state.json恢復原樣。 - 你取消了,用 Ctrl+C 或介面裡的「取消」:同上。
- lip 被殺掉,或者斷電:日誌還在。那個資料夾裡的下一次操作,或者下一次
lip run,會讀取它。如果那次操作已經走到了提交,lip 就把清除做完。否則就復原那次操作。
有一樣東西無法復原:套件的程式在執行期間做過的事。我們要求套件的作者把這類程式寫成重複執行也無害的樣子。
失敗會在終端機或對話方塊裡得到說明,並被完整地記錄下來。見故障排查。
試執行
試執行是一次在第 5 步之前停下的操作。用 --dry-run 就能得到一次試執行;介面在每次變更之前也會做一次,好把計劃展示給你。
試執行是一項保證:
- 它不變更任何檔案:工作區裡的、快取裡的、你的設定裡的,都不改。
- 它不執行任何程式,也不往系統裡安裝任何東西。
- 它不提問。操作會提問的地方,它只說明會問。
- 它不加鎖,所以既不會等待也不會阻塞另一個 lip。
- 它不修復被中斷的操作。它只告訴你有這樣一次操作。
它做的是第 3 步裡的一切,包括聯網和下載,所以它給出的計劃,就是工作區在目前狀態下的真實計劃。
用法見試執行。
常駐程式和客戶端
你執行 lip install 時,幹活的並不是你啟動的那個程式。它把請求交給一個背景處理程序,也就是常駐程式,再把常駐程式的反饋顯示給你。你啟動的那個程式是客戶端。
常駐程式的存在有兩個原因:
- 讓伺服器比終端機活得久。 屬於某個終端機的處理程序會隨終端機一起結束。常駐程式不屬於任何終端機,所以它執行的伺服器會一直執行下去。
- 共享同一個視圖。 你在任何終端機裡開啟的每個介面,都與同一個常駐程式通信。它們看到的是同樣的伺服器、同樣的工作區清單。
你不需要管理常駐程式:
- 它會自己啟動。 沒有常駐程式在執行時,第一條 lip 命令會啟動它。
- 每個使用者一個。 只有它所屬的使用者才能連線它:在 Windows 上通過命名管道,在其他系統上通過只有你能開啟的套接字檔案。
- 命令的表現和 lip 直接執行時一樣。 它在你的資料夾裡工作,使用你終端機的環境變數,讀取你的鍵盤輸入,輸出到你的終端機,並以同樣的結束代碼結束。Ctrl+C 也能傳到它那裡。
- 命令之間互不干擾。 常駐程式可以同時執行多個終端機的命令,每條命令都有自己的資料夾和設定。
- 它會自己結束:沒有客戶端連線、也沒有伺服器在執行,持續 10 分鐘之後。只要它在執行伺服器,就絕不會結束。
- 更新之後它會被取代。 較新的 lip 會請較舊的常駐程式結束,並啟動自己的。
lip daemon status 顯示它是否在執行,lip daemon stop 在它空閒時結束它。見 lip daemon。
沒有常駐程式時
如果客戶端無法啟動或連線常駐程式,或者常駐程式是個忙得走不開的舊版本,客戶端會說明情況,然後自己完成工作。命令做的事是一樣的。缺少的只是需要長期背景處理程序才能做到的東西:託管伺服器。
見 lip 自己執行了命令。
託管伺服器和伺服器鎖
伺服器有兩種執行方式。
普通:lip run | 託管:介面,或 lip run --managed | |
|---|---|---|
| 屬於 | 啟動它的終端機 | 常駐程式 |
| 終端機關閉時 | 伺服器被要求停止 | 伺服器繼續執行 |
| 它的主控台 | 那個終端機 | 每個接入它的客戶端,以及每個介面的伺服器頁面 |
| 誰能停止它 | 那個終端機 | 任何已接入的客戶端,以及任何介面 |
託管伺服器是常駐程式執行的、不專屬於任何人的伺服器。客戶端接入它來檢視輸出、向它輸入,之後再脫離,不會打擾它。常駐程式在一個工作區裡最多執行一個。
無論伺服器以哪種方式執行,執行它的處理程序都佔著伺服器鎖,也就是 .lip/server.lock。「一個工作區一個伺服器」正是靠它實現的:第二次啟動會發現鎖被佔用,於是失敗。lip 也是靠它得知有伺服器在執行,即使那不是它自己啟動的。
伺服器鎖和工作區鎖是分開的。執行伺服器不會鎖住工作區、阻止變更;變更工作區也不需要伺服器鎖。
見讓伺服器持續執行。
介面與命令
介面不是另一個有自己一套邏輯的程式。你在介面裡做的每件事,都是在目前工作區裡執行的一條命令,只是輸出顯示在對話方塊裡而不是終端機裡。命令做的事兩邊完全一樣。
介面只在一個地方更謹慎。目前工作區的伺服器執行期間,介面:
- 不在那裡安裝、更新、解除安裝任何東西,也不在那裡安裝伺服器;
- 不儲存
server.properties、allowlist.json和permissions.json。
它會請你先停止伺服器:
模組的設定它仍然會儲存,這些設定在下次啟動時生效。
不管伺服器是怎麼啟動的,都是如此:由這個介面啟動、由另一個介面啟動,還是由某個終端機裡普通的 lip run 啟動。介面是通過伺服器鎖得知的。
命令不會拒絕。 伺服器執行時 lip install 照樣工作,而且無論結果如何,變更都是安全的。如果某個檔案因為被執行中的伺服器開啟而無法取代,操作會失敗並被復原。如果成功了,伺服器會在下次啟動時用上變更。
| 伺服器執行期間 | 介面 | 命令 |
|---|---|---|
| 安裝、更新、解除安裝、安裝伺服器 | 拒絕 | 允許。可能因檔案被佔用而失敗,這時會被復原。 |
| 編輯遊戲的設定 | 顯示但不儲存 | lip 沒有相應的命令。請自己編輯檔案。 |
| 編輯模組的設定 | 允許 | 同上。 |
| 檢視已安裝的內容 | 允許 | 允許 |
還有一點不同:介面把伺服器作為託管伺服器啟動,而不帶 --managed 的 lip run 不是。
頁面與命令的完整對應關係見介面參考。
使用者目錄
在工作區之外,lip 為每個使用者保留四個目錄。
| 目錄 | 存放 | Windows | Linux 和 macOS |
|---|---|---|---|
| 設定 | 你的設定 config.toml | %APPDATA%\lip | $XDG_CONFIG_HOME/lip,預設 ~/.config/lip |
| 快取 | 從網上下載的檔案,留著以免重複下載 | %LOCALAPPDATA%\lip\Cache | $XDG_CACHE_HOME/lip,預設 ~/.cache/lip |
| 資料 | lip 為執行伺服器而安裝的東西:Linux 和 macOS 上是它的 Wine | %LOCALAPPDATA%\lip\Data | $XDG_DATA_HOME/lip,預設 ~/.local/share/lip |
| 狀態 | 介面的工作區清單 workspaces.json | %LOCALAPPDATA%\lip\State | $XDG_STATE_HOME/lip,預設 ~/.local/state/lip |
哪些可以放心刪除:
- 快取,任何時候都可以:
lip cache clean。需要的東西 lip 會重新下載。 - 資料目錄,在沒有 lip 執行時。lip 需要時會重新安裝 Wine。
- 狀態目錄,在沒有 lip 執行時。丟失的只是介面裡的資料夾清單,不是資料夾本身。
- 設定目錄裡只有你的設定。
在 Linux 和 macOS 上,常駐程式的套接字在 $XDG_RUNTIME_DIR/lip 裡;該變數未設定時在狀態目錄裡。在 Windows 上,常駐程式使用命名管道,它不是檔案。
除了這些目錄、套接字所在的目錄、工作區以及你給出的路徑,lip 還會寫一個地方:它自己的安裝目錄,在 lip self-update 取代 lip 的時候。它不使用系統的臨時目錄。