dsh-subpages:在 DSH 同一端口掛載獨立看板與統一門戶

前言

在 DSH 上跑 Harness 時,常會額外做幾個小網頁:待辦彙總、用量統計、內部工具面板。常見做法是再起一個端口、單獨配域名,或再寫一套登錄。DSH 客戶端本身也沒有可收藏、可深鏈的前端路由,刷新後狀態容易丟。

dsh-subpages(維護者 SJTUMalPan)是 DSH 的客戶端插件:複用 DSH webServer 上的前綴路由(默認 /subpages),提供網關與統一門戶,把獨立倉庫裏開發的下級頁面掛進來。請求先過 DSH 既有鑑權,不必爲新頁面單獨開端口、單獨暴露面。

這是什麼

一句話:DSH 看板宿主——把獨立開發的小網頁應用變成 DSH 裏的「看板」,共用 DSH 端口與登錄態,用一個門戶統一進入。

核心能力

網關與門戶

瀏覽器訪問 DSH 端口(例如 :3080)下的 /subpages/ 進入門戶殼:導航欄、iframe、hash 路由。公共前端在 /subpages/_assets/*(含 subpage.css);已掛載清單由 /subpages/_api/pages 提供。每個 /subpages/<id>/* 請求經 DSH 鑑權(connection.requestRejection)後再轉發到看板後端或靜態目錄。

瀏覽器 ──> DSH :3080 /subpages/            門戶殼(導航欄 + iframe + hash 路由)
                   /subpages/_assets/*      公共前端庫(subpage.css)
                   /subpages/_api/pages     已掛載清單(殼用)
                   /subpages/<id>/*   ──►   看板自己的 http 服務(127.0.0.1:<port>)

門戶 URL 如 /subpages/notify-hub/todos 可收藏、可深鏈、刷新不丟——這是相對 DSH 客戶端自身路由的補足。

兩種看板形態

  1. 代理形態:subpage.json 裏 target 爲 http://…,宿主反向代理到本機服務;可選 health 探活(默認 /healthz)。
  2. 靜態形態:target 爲目錄路徑,宿主直接投遞文件,並對 ../、符號鏈接做 realpath 邊界校驗。

樣式策略:style 爲 inherit(默認,宿主在導航類 HTML 裏注入公共樣式)或 standalone(不注入)。靜態頁可自引:

<link rel="stylesheet" href="/subpages/_assets/subpage.css">

公共樣式基於 Pico 2 classless + 深色 token + sp-* 組件類(.sp-page、.sp-card 等)。

掛載方式

目錄掃描:在插件包內 pages/<id>/ 下放 subpage.json;也可通過 submodule 指向獨立看板倉庫(git submodule add <看板倉庫> pages/<id>,清單放在看板倉庫根目錄,詳見倉庫內 pages/README.md)。重啓 dsh web 即可,不必改宿主代碼。

運行時註冊(供其它 DSH 插件):

await ctx.subPages.register({ id: 'x', title: 'X', target: 'http://127.0.0.1:9000' })
ctx.subPages.list()
ctx.subPages.unregister('x')
ctx.subPages.mountPath     // '/subpages'

下游鑑權(令牌不下發)

可選 auth:從 tokenEnv 或 tokenFile + tokenPath 讀令牌,以 header/scheme 或 queryParam 注入轉發;瀏覽器側的 ?token= 會在轉發前剝掉。宿主還可代持下游會話 cookie,瀏覽器既看不到令牌,也拿不到下游 cookie。令牌不會出現在清單 JSON、HTML 或可見 URL 中(倉庫含對應測試)。

自帶示例看板

pages/ 下兩個 submodule 分別演示代理 + standalone 與靜態 + 獨立樣式:

看板 倉庫 形態
待辦 notify-hub 代理
用量 dsh-usage-stats 靜態單文件 HTML

可選:啓動通告

配置 startupNotice 後,DSH 每次啓動可把帶 token 的訪問鏈接投遞到 notify-hub(再轉發飛書等)。須顯式 enabled: true 並配置 publicHost;token 從啓動日誌新增橫幅讀取,未配 publicHost 則不投遞。

安裝與啓用

安裝命令以 README 爲準:

# 本機開發(符號鏈接,改完即生效)
dsh plugin --profile web add "$PWD"     # 在倉庫根目錄執行

# 從 GitHub 裝(插件市場也可直接裝)
dsh plugin --profile web add github:SJTUMalPan/dsh-subpages

# 鎖 commit(可復現)
dsh plugin --profile web add "git+https://github.com/SJTUMalPan/dsh-subpages#<sha>"

裝完重啓 dsh web。側邊欄底部會出現「看板」按鈕。

卸載:

dsh plugin --profile web remove dsh-subpages

典型用法:掛載一個代理看板

在 pages/ 下建目錄並放置 subpage.json(字段以 README 表格爲準):

{
  "id": "notify-hub",
  "title": "待辦",
  "icon": "inbox",
  "order": 10,
  "target": "http://127.0.0.1:8000",
  "health": "/healthz",
  "style": "standalone",
  "auth": {
    "tokenFile": "~/notify-hub-run/config.yaml",
    "tokenPath": "server.auth_token",
    "queryParam": "token"
  }
}

target 必填;id 缺省用目錄名,須 kebab-case。下游服務需在本機監聽對應端口並已啓動,否則門戶會顯示「看板離線」。

profile 中可改插件 config(或 cordis.patch.yml):

- id: subpages
  config:
    mountPath: /subpages
    pagesDirs: [/abs/extra]
    requestTimeoutMs: 15000
    probeTimeoutMs: 2000

適用場景與注意

適合:已有或計劃用獨立倉庫維護小面板,希望與 DSH Web 同端口、同登錄;需要真 URL 深鏈;希望靜態頁與門戶風格統一且零額外設計系統。

信任模型(掛載前必讀):掛一個看板等於讓它的前端在 DSH 同源下運行。門戶 iframe 使用 allow-same-origin allow-scripts,看板腳本可訪問 DSH 的 Cookie、存儲與 HTTP 接口,並可操作父窗口 DOM。只掛自己信任、自己審計過的看板;第三方代碼應部署在獨立源再以跨源方式接入,本插件不做跨源隔離。

進程與權限:插件以當前 DSH 進程權限運行;安裝前請閱讀源碼與 MIT 許可證,並理解 auth、轉發頭白名單(瀏覽器 cookie/authorization 不會透傳給下游)及「同一看板共用進程級下游會話」的語義。

排障速查:無「看板」按鈕 → 確認 profile 已裝插件且重啓過 dsh web;「還沒有掛載任何看板」→ 檢查 pages/ 與 subpage.json;鏈接跳出網關 404 → 下游勿用絕對 URL 重定向;401 → 刷新 DSH 頁面重新登錄。

結尾

dsh-subpages 把「獨立小應用」收成 DSH 內的看板:不新開監聽端口、清單與 submodule 解耦宿主代碼、網關補上前端深鏈,並可選把啓動鏈接推到 notify-hub。DeepSeek Harness 生態強調「一切皆插件」;社區目錄 SkillHub 與 GitHub 倉庫並列,便於檢索與安裝,與 DeepSeek / 幻方無官方從屬關係。

  • 目錄頁:https://www.skillhub.cn/plugins/SJTUMalPan/dsh-subpages
  • GitHub:https://github.com/SJTUMalPan/dsh-subpages
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜