工作階段檔案存取
files 能力讓你的 App 以目前登入的使用者身分使用 File Station。App 可以列出共用資料夾與資料夾、建立資料夾、上傳與下載檔案,並提供 NAS 檔案選擇器。每位使用者能看到與修改什麼,由 DSM 依該使用者自己的權限決定。套件帳號的權限絕不會取代呼叫者的權限。此能力不需要管理員設定,也不會讓 App 取得離線存取:使用者關閉瀏覽器後,存取就結束。若需要離線作業,請見背景工作與 Delegate。
新專案:
synopkgland init -t native-go --with files my-files既有專案(具有 backend/ 資料夾的 Go 後端):
synopkgland add files兩者都會在 dsm-package.yaml 設定:
capabilities: files: sessionsession 是唯一可用的值。files 可用於 Go 後端,支援 x86_64、aarch64 與 armv7。binary 後端不能使用。產生的 Vue UI 含有檔案頁,內有瀏覽器與選擇器。plain UI 沒有檔案頁,但後端 route 仍存在,你可以從自己的程式碼呼叫。
在 UI 中瀏覽與選取
Section titled “在 UI 中瀏覽與選取”Vue 專案使用 @synopackageland/sdk 的下列匯出:
| 匯出 | 用途 |
|---|---|
FileBrowser(@synopackageland/sdk/vue) | 共用資料夾、資料夾樹(TreeView)、檔案表格(DataGrid)、上傳與下載。屬性:provider、locale、mode('file' 或 'folder')、transfers |
NasPicker(@synopackageland/sdk/vue) | 對話框形式的瀏覽器。選取後以 selected 送出所選路徑 |
createNasProvider(@synopackageland/sdk) | createNasProvider(ctx) 把下列呼叫包成兩個元件共用的 provider |
選取路徑不會授予任何權限。後端在使用該路徑時,會再次檢查工作階段與權限。選擇器的屬性請見 UI 元件。路徑採用 File Station 的寫法,例如 /home/report.txt 與 /photos。
以 ctx.call(method, params) 呼叫這些方法。全部都需要已登入的使用者。每次呼叫也會檢查該 DSM 工作階段屬於登入你的 App 的同一位使用者。
| 方法 | 參數 | 結果 |
|---|---|---|
nas.session.status | {} | { mode: "filestation-session" } |
nas.files.shares | { offset } | 一頁共用資料夾 |
nas.files.list | { path, offset, limit, sortBy, sortDirection } | 一頁項目 |
nas.files.info | { path } | 單一項目 |
nas.files.create_folder | { parent, name } | { created: true } |
limit為 1 到 100(預設 100)。sortBy為name(預設)、size、type或mtime。sortDirection為ASC(預設)或DESC。- 一頁的格式為
{ files, total, offset }。共用資料夾的清單則是shares。項目為{ path, name, isdir, additional: { size } }。 - 路徑必須是絕對路徑、已經過正規化(沒有
.或..片段)、最長 4096 個字元,且不含反斜線、逗號、雙引號或控制字元。
const page = await ctx.call<{ files: { name: string; isdir: boolean }[]; total: number }>( 'nas.files.list', { path: '/home', offset: 0, limit: 50, sortBy: 'mtime', sortDirection: 'DESC' },)檔案以串流傳輸,而不是 JSON。createNasProvider 與 FileBrowser 已經處理好這些。若你自己撰寫程式,請搭配 ctx.files.endpoint 與 ctx.files.token() 送出下列請求:
上傳 nas.files.upload | 下載 nas.files.download | |
|---|---|---|
| 請求 | POST ?method=nas.files.upload&parent=<folder>&name=<file> | GET 或 POST ?method=nas.files.download&path=<file> |
| 本文 | 檔案位元組,Content-Type: application/octet-stream,並附 Content-Length | 無。POST 以表單欄位 SynoToken 帶上 token |
| 驗證 | X-SYNO-TOKEN 標頭與 DSM id cookie | 同一個工作階段 cookie |
| 成功 | {"success":true,"data":{"uploaded":true}} | 檔案,以 application/octet-stream 附件回傳 |
| 不支援 | 覆寫既有檔案、建立上層資料夾 |
請求必須與 App 來自同一來源。下載開始後若失敗,檔案會停在被截斷的狀態,之後不會有 JSON 錯誤。上傳的回應若遺失,結果是 commit-uncertain:再次上傳之前,請先檢查資料夾。
在 handler 中讀取檔案
Section titled “在 handler 中讀取檔案”Go handler 可以用呼叫者的工作階段讀取小型檔案。請以 api.HandleRequest 註冊、在 permissions.json 列為 authenticated,並在 routes.go 的 import 加入 net/http。
func (cfg Config) readNote(ctx context.Context, caller api.Caller, r *http.Request, params json.RawMessage) (any, error) { var in struct { Folder string `json:"folder"` Relative string `json:"relative"` } if err := decodeParams(params, &in); err != nil { return nil, err } data, err := cfg.SessionFiles.ReadFile(ctx, caller, r, in.Folder, in.Relative) if err != nil { return nil, err } return map[string]any{"bytes": len(data)}, nil}ReadFile 讀取 Folder 底下的單一一般檔案,最多回傳 512 KiB(超過則為 limit-exceeded)。cfg.SessionFiles.Upload 與 Download 就是串流呼叫所用的同樣操作。
| 項目 | 限制 |
|---|---|
| 上傳大小 | 16 GiB,且必須有 Content-Length(upload_size_required) |
| 單一請求的時間(含傳輸) | 產生的後端為 20 秒。超過的傳輸會被中斷 |
| 產生的 UI 等待呼叫的時間 | 22 秒 |
| 每頁項目數 | 100 |
offset | 最大 1,000,000 |
| 路徑長度 | 4096 個字元 |
handler 讀取的檔案(ReadFile) | 512 KiB |
| DSM 7.1 上的下載 | DSM 7.1 傳送檔案時沒有 Content-Disposition。檔案不超過 4 KiB 且整個內容就是一個 DSM 回應(含 success 欄位的 JSON 物件)時,會被當成該回應而拒絕 |
| JSON 請求本文 | 1 MiB |
| 覆寫、建立不存在的上層資料夾 | 不支援 |
| 錯誤碼 | 原因 | 解法 |
|---|---|---|
session_required | 沒有有效的 DSM 工作階段,或該 DSM 工作階段屬於另一位使用者 | 在同一個瀏覽器重新登入 DSM |
dsm_session_required | App 使用獨立登入,而此呼叫需要 DSM id cookie,但瀏覽器沒有送出 | 在與 App 相同的主機名稱登入 DSM,然後重試 |
denied | File Station 拒絕(DSM 錯誤 105、403、407、408) | 該使用者沒有該路徑或 File Station 的權限 |
conflict | 目標已存在或正在使用(DSM 錯誤 414、1805) | 選擇其他名稱 |
invalid-request | 路徑、名稱、排序值或 limit 無效 | 修正參數 |
not_found | 路徑不存在 | 重新整理清單 |
unavailable | File Station 失敗,或回應不符預期 | 稍後重試 |
upload_size_required | 上傳沒有 Content-Length,或超過 16 GiB | 傳送單一檔案,最大 16 GiB |
commit-uncertain | 上傳或建立資料夾可能已完成,也可能未完成 | 重試之前先檢查目的地 |
limit-exceeded | handler 讀取的檔案超過 512 KiB | 讀取較少內容,或改用串流 |
read_failed | 檔案串流提早結束,或長度不符 | 重試 |
unknown_method | App 建置時沒有 files 能力 | 執行 synopkgland add files 並重新建置 |
admin_required、app_privilege_denied | App 的 permissions.json 或 entry 設定拒絕了呼叫者 | 請見原生 App |
錯誤碼的說明請見錯誤碼。