You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

object.go 17 kB

1 year ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
1 year ago
11 months ago
11 months ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. package cdsapi
  2. import (
  3. "fmt"
  4. "io"
  5. "mime"
  6. "net/url"
  7. "strings"
  8. "time"
  9. "gitlink.org.cn/cloudream/common/consts/errorcode"
  10. "gitlink.org.cn/cloudream/common/pkgs/iterator"
  11. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  12. "gitlink.org.cn/cloudream/common/utils/http2"
  13. "gitlink.org.cn/cloudream/common/utils/serder"
  14. )
  15. type ObjectService struct {
  16. *Client
  17. }
  18. func (c *Client) Object() *ObjectService {
  19. return &ObjectService{
  20. Client: c,
  21. }
  22. }
  23. const ObjectListPathByPath = "/object/listByPath"
  24. type ObjectListByPath struct {
  25. UserID cdssdk.UserID `form:"userID" binding:"required"`
  26. PackageID cdssdk.PackageID `form:"packageID" binding:"required"`
  27. Path string `form:"path"` // 允许为空字符串
  28. IsPrefix bool `form:"isPrefix"`
  29. NoRecursive bool `form:"noRecursive"` // 仅当isPrefix为true时有效,表示仅查询直接属于Prefix下的对象,对于更深的对象,返回它们的公共前缀
  30. }
  31. type ObjectListByPathResp struct {
  32. CommonPrefixes []string `json:"commonPrefixes"` // 仅在IsPrefix为true且NoRecursive为true时有效,包含更深层对象的shared prefix
  33. Objects []cdssdk.Object `json:"objects"` // 如果IsPrefix为true且NoRecursive为false,则返回所有匹配的对象,否则只返回直接属于Prefix下的对象
  34. }
  35. func (c *ObjectService) ListByPath(req ObjectListByPath) (*ObjectListByPathResp, error) {
  36. url, err := url.JoinPath(c.baseURL, ObjectListPathByPath)
  37. if err != nil {
  38. return nil, err
  39. }
  40. resp, err := http2.GetForm(url, http2.RequestParam{
  41. Query: req,
  42. })
  43. if err != nil {
  44. return nil, err
  45. }
  46. jsonResp, err := ParseJSONResponse[response[ObjectListByPathResp]](resp)
  47. if err != nil {
  48. return nil, err
  49. }
  50. if jsonResp.Code == errorcode.OK {
  51. return &jsonResp.Data, nil
  52. }
  53. return nil, jsonResp.ToError()
  54. }
  55. const ObjectListByIDsPath = "/object/listByIDs"
  56. type ObjectListByIDs struct {
  57. UserID cdssdk.UserID `json:"userID" binding:"required"`
  58. ObjectIDs []cdssdk.ObjectID `json:"objectIDs" binding:"required"`
  59. }
  60. type ObjectListByIDsResp struct {
  61. Objects []*cdssdk.Object `json:"object"` // 与ObjectIDs一一对应,如果某个ID不存在,则对应位置为nil
  62. }
  63. func (c *ObjectService) ListByIDs(req ObjectListByIDs) (*ObjectListByIDsResp, error) {
  64. url, err := url.JoinPath(c.baseURL, ObjectListByIDsPath)
  65. if err != nil {
  66. return nil, err
  67. }
  68. resp, err := http2.PostJSON(url, http2.RequestParam{
  69. Body: req,
  70. })
  71. if err != nil {
  72. return nil, err
  73. }
  74. jsonResp, err := ParseJSONResponse[response[ObjectListByIDsResp]](resp)
  75. if err != nil {
  76. return nil, err
  77. }
  78. if jsonResp.Code == errorcode.OK {
  79. return &jsonResp.Data, nil
  80. }
  81. return nil, jsonResp.ToError()
  82. }
  83. const ObjectUploadPath = "/object/upload"
  84. type ObjectUpload struct {
  85. ObjectUploadInfo
  86. Files UploadObjectIterator `json:"-"`
  87. }
  88. type ObjectUploadInfo struct {
  89. UserID cdssdk.UserID `json:"userID" binding:"required"`
  90. PackageID cdssdk.PackageID `json:"packageID" binding:"required"`
  91. Affinity cdssdk.StorageID `json:"affinity"`
  92. LoadTo []cdssdk.StorageID `json:"loadTo"`
  93. LoadToPath []string `json:"loadToPath"`
  94. }
  95. type UploadingObject struct {
  96. Path string
  97. File io.ReadCloser
  98. }
  99. type UploadObjectIterator = iterator.Iterator[*UploadingObject]
  100. type ObjectUploadResp struct {
  101. Uploadeds []cdssdk.Object `json:"uploadeds"`
  102. }
  103. func (c *ObjectService) Upload(req ObjectUpload) (*ObjectUploadResp, error) {
  104. url, err := url.JoinPath(c.baseURL, ObjectUploadPath)
  105. if err != nil {
  106. return nil, err
  107. }
  108. infoJSON, err := serder.ObjectToJSON(req)
  109. if err != nil {
  110. return nil, fmt.Errorf("upload info to json: %w", err)
  111. }
  112. resp, err := http2.PostMultiPart(url, http2.MultiPartRequestParam{
  113. Form: map[string]string{"info": string(infoJSON)},
  114. Files: iterator.Map(req.Files, func(src *UploadingObject) (*http2.IterMultiPartFile, error) {
  115. return &http2.IterMultiPartFile{
  116. FieldName: "files",
  117. FileName: src.Path,
  118. File: src.File,
  119. }, nil
  120. }),
  121. })
  122. if err != nil {
  123. return nil, err
  124. }
  125. contType := resp.Header.Get("Content-Type")
  126. if strings.Contains(contType, http2.ContentTypeJSON) {
  127. var err error
  128. var codeResp response[ObjectUploadResp]
  129. if codeResp, err = serder.JSONToObjectStreamEx[response[ObjectUploadResp]](resp.Body); err != nil {
  130. return nil, fmt.Errorf("parsing response: %w", err)
  131. }
  132. if codeResp.Code == errorcode.OK {
  133. return &codeResp.Data, nil
  134. }
  135. return nil, codeResp.ToError()
  136. }
  137. return nil, fmt.Errorf("unknow response content type: %s", contType)
  138. }
  139. const ObjectDownloadPath = "/object/download"
  140. type ObjectDownload struct {
  141. UserID cdssdk.UserID `form:"userID" json:"userID" binding:"required"`
  142. ObjectID cdssdk.ObjectID `form:"objectID" json:"objectID" binding:"required"`
  143. Offset int64 `form:"offset" json:"offset,omitempty"`
  144. Length *int64 `form:"length" json:"length,omitempty"`
  145. }
  146. type DownloadingObject struct {
  147. Path string
  148. File io.ReadCloser
  149. }
  150. func (c *ObjectService) Download(req ObjectDownload) (*DownloadingObject, error) {
  151. url, err := url.JoinPath(c.baseURL, ObjectDownloadPath)
  152. if err != nil {
  153. return nil, err
  154. }
  155. resp, err := http2.GetJSON(url, http2.RequestParam{
  156. Query: req,
  157. })
  158. if err != nil {
  159. return nil, err
  160. }
  161. contType := resp.Header.Get("Content-Type")
  162. if strings.Contains(contType, http2.ContentTypeJSON) {
  163. var codeResp response[any]
  164. if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil {
  165. return nil, fmt.Errorf("parsing response: %w", err)
  166. }
  167. return nil, codeResp.ToError()
  168. }
  169. _, params, err := mime.ParseMediaType(resp.Header.Get("Content-Disposition"))
  170. if err != nil {
  171. return nil, fmt.Errorf("parsing content disposition: %w", err)
  172. }
  173. return &DownloadingObject{
  174. Path: params["filename"],
  175. File: resp.Body,
  176. }, nil
  177. }
  178. const ObjectDownloadByPathPath = "/object/downloadByPath"
  179. type ObjectDownloadByPath struct {
  180. UserID cdssdk.UserID `form:"userID" json:"userID" binding:"required"`
  181. PackageID cdssdk.PackageID `form:"packageID" json:"packageID" binding:"required"`
  182. Path string `form:"path" json:"path" binding:"required"`
  183. Offset int64 `form:"offset" json:"offset,omitempty"`
  184. Length *int64 `form:"length" json:"length,omitempty"`
  185. }
  186. func (c *ObjectService) DownloadByPath(req ObjectDownloadByPath) (*DownloadingObject, error) {
  187. url, err := url.JoinPath(c.baseURL, ObjectDownloadByPathPath)
  188. if err != nil {
  189. return nil, err
  190. }
  191. resp, err := http2.GetJSON(url, http2.RequestParam{
  192. Query: req,
  193. })
  194. if err != nil {
  195. return nil, err
  196. }
  197. contType := resp.Header.Get("Content-Type")
  198. if strings.Contains(contType, http2.ContentTypeJSON) {
  199. var codeResp response[any]
  200. if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil {
  201. return nil, fmt.Errorf("parsing response: %w", err)
  202. }
  203. return nil, codeResp.ToError()
  204. }
  205. _, params, err := mime.ParseMediaType(resp.Header.Get("Content-Disposition"))
  206. if err != nil {
  207. return nil, fmt.Errorf("parsing content disposition: %w", err)
  208. }
  209. return &DownloadingObject{
  210. Path: params["filename"],
  211. File: resp.Body,
  212. }, nil
  213. }
  214. const ObjectUpdateInfoPath = "/object/updateInfo"
  215. type UpdatingObject struct {
  216. ObjectID cdssdk.ObjectID `json:"objectID" binding:"required"`
  217. UpdateTime time.Time `json:"updateTime" binding:"required"`
  218. }
  219. func (u *UpdatingObject) ApplyTo(obj *cdssdk.Object) {
  220. obj.UpdateTime = u.UpdateTime
  221. }
  222. type ObjectUpdateInfo struct {
  223. UserID cdssdk.UserID `json:"userID" binding:"required"`
  224. Updatings []UpdatingObject `json:"updatings" binding:"required"`
  225. }
  226. type ObjectUpdateInfoResp struct {
  227. Successes []cdssdk.ObjectID `json:"successes"`
  228. }
  229. func (c *ObjectService) UpdateInfo(req ObjectUpdateInfo) (*ObjectUpdateInfoResp, error) {
  230. url, err := url.JoinPath(c.baseURL, ObjectUpdateInfoPath)
  231. if err != nil {
  232. return nil, err
  233. }
  234. resp, err := http2.PostJSON(url, http2.RequestParam{
  235. Body: req,
  236. })
  237. if err != nil {
  238. return nil, err
  239. }
  240. jsonResp, err := ParseJSONResponse[response[ObjectUpdateInfoResp]](resp)
  241. if err != nil {
  242. return nil, err
  243. }
  244. if jsonResp.Code == errorcode.OK {
  245. return &jsonResp.Data, nil
  246. }
  247. return nil, jsonResp.ToError()
  248. }
  249. const ObjectUpdateInfoByPathPath = "/object/updateInfoByPath"
  250. type ObjectUpdateInfoByPath struct {
  251. UserID cdssdk.UserID `json:"userID" binding:"required"`
  252. PackageID cdssdk.PackageID `json:"packageID" binding:"required"`
  253. Path string `json:"path" binding:"required"`
  254. UpdateTime time.Time `json:"updateTime" binding:"required"`
  255. }
  256. type ObjectUpdateInfoByPathResp struct{}
  257. func (c *ObjectService) UpdateInfoByPath(req ObjectUpdateInfoByPath) (*ObjectUpdateInfoByPathResp, error) {
  258. url, err := url.JoinPath(c.baseURL, ObjectUpdateInfoByPathPath)
  259. if err != nil {
  260. return nil, err
  261. }
  262. resp, err := http2.PostJSON(url, http2.RequestParam{
  263. Body: req,
  264. })
  265. if err != nil {
  266. return nil, err
  267. }
  268. jsonResp, err := ParseJSONResponse[response[ObjectUpdateInfoByPathResp]](resp)
  269. if err != nil {
  270. return nil, err
  271. }
  272. if jsonResp.Code == errorcode.OK {
  273. return &jsonResp.Data, nil
  274. }
  275. return nil, jsonResp.ToError()
  276. }
  277. const ObjectMovePath = "/object/move"
  278. type MovingObject struct {
  279. ObjectID cdssdk.ObjectID `json:"objectID" binding:"required"`
  280. PackageID cdssdk.PackageID `json:"packageID" binding:"required"`
  281. Path string `json:"path" binding:"required"`
  282. }
  283. func (m *MovingObject) ApplyTo(obj *cdssdk.Object) {
  284. obj.PackageID = m.PackageID
  285. obj.Path = m.Path
  286. }
  287. type ObjectMove struct {
  288. UserID cdssdk.UserID `json:"userID" binding:"required"`
  289. Movings []MovingObject `json:"movings" binding:"required"`
  290. }
  291. type ObjectMoveResp struct {
  292. Successes []cdssdk.ObjectID `json:"successes"`
  293. }
  294. func (c *ObjectService) Move(req ObjectMove) (*ObjectMoveResp, error) {
  295. url, err := url.JoinPath(c.baseURL, ObjectMovePath)
  296. if err != nil {
  297. return nil, err
  298. }
  299. resp, err := http2.PostJSON(url, http2.RequestParam{
  300. Body: req,
  301. })
  302. if err != nil {
  303. return nil, err
  304. }
  305. jsonResp, err := ParseJSONResponse[response[ObjectMoveResp]](resp)
  306. if err != nil {
  307. return nil, err
  308. }
  309. if jsonResp.Code == errorcode.OK {
  310. return &jsonResp.Data, nil
  311. }
  312. return nil, jsonResp.ToError()
  313. }
  314. const ObjectDeletePath = "/object/delete"
  315. type ObjectDelete struct {
  316. UserID cdssdk.UserID `json:"userID" binding:"required"`
  317. ObjectIDs []cdssdk.ObjectID `json:"objectIDs" binding:"required"`
  318. }
  319. type ObjectDeleteResp struct{}
  320. func (c *ObjectService) Delete(req ObjectDelete) error {
  321. url, err := url.JoinPath(c.baseURL, ObjectDeletePath)
  322. if err != nil {
  323. return err
  324. }
  325. resp, err := http2.PostJSON(url, http2.RequestParam{
  326. Body: req,
  327. })
  328. if err != nil {
  329. return err
  330. }
  331. jsonResp, err := ParseJSONResponse[response[ObjectDeleteResp]](resp)
  332. if err != nil {
  333. return err
  334. }
  335. if jsonResp.Code == errorcode.OK {
  336. return nil
  337. }
  338. return jsonResp.ToError()
  339. }
  340. const ObjectDeleteByPathPath = "/object/deleteByPath"
  341. type ObjectDeleteByPath struct {
  342. UserID cdssdk.UserID `json:"userID" binding:"required"`
  343. PackageID cdssdk.PackageID `json:"packageID" binding:"required"`
  344. Path string `json:"path" binding:"required"`
  345. }
  346. type ObjectDeleteByPathResp struct{}
  347. func (c *ObjectService) DeleteByPath(req ObjectDeleteByPath) error {
  348. url, err := url.JoinPath(c.baseURL, ObjectDeleteByPathPath)
  349. if err != nil {
  350. return err
  351. }
  352. resp, err := http2.PostJSON(url, http2.RequestParam{
  353. Body: req,
  354. })
  355. if err != nil {
  356. return err
  357. }
  358. jsonResp, err := ParseJSONResponse[response[ObjectDeleteByPathResp]](resp)
  359. if err != nil {
  360. return err
  361. }
  362. if jsonResp.Code == errorcode.OK {
  363. return nil
  364. }
  365. return jsonResp.ToError()
  366. }
  367. const ObjectClonePath = "/object/clone"
  368. type ObjectClone struct {
  369. UserID cdssdk.UserID `json:"userID" binding:"required"`
  370. Clonings []CloningObject `json:"clonings" binding:"required"`
  371. }
  372. type CloningObject struct {
  373. ObjectID cdssdk.ObjectID `json:"objectID" binding:"required"`
  374. NewPath string `json:"newPath" binding:"required"`
  375. NewPackageID cdssdk.PackageID `json:"newPackageID" binding:"required"`
  376. }
  377. type ObjectCloneResp struct {
  378. Objects []*cdssdk.Object `json:"objects"`
  379. }
  380. func (c *ObjectService) Clone(req ObjectClone) (*ObjectCloneResp, error) {
  381. url, err := url.JoinPath(c.baseURL, ObjectClonePath)
  382. if err != nil {
  383. return nil, err
  384. }
  385. resp, err := http2.PostJSON(url, http2.RequestParam{
  386. Body: req,
  387. })
  388. if err != nil {
  389. return nil, err
  390. }
  391. jsonResp, err := ParseJSONResponse[response[ObjectCloneResp]](resp)
  392. if err != nil {
  393. return nil, err
  394. }
  395. if jsonResp.Code == errorcode.OK {
  396. return &jsonResp.Data, nil
  397. }
  398. return nil, jsonResp.ToError()
  399. }
  400. const ObjectGetPackageObjectsPath = "/object/getPackageObjects"
  401. type ObjectGetPackageObjects struct {
  402. UserID cdssdk.UserID `form:"userID" json:"userID" binding:"required"`
  403. PackageID cdssdk.PackageID `form:"packageID" json:"packageID" binding:"required"`
  404. }
  405. type ObjectGetPackageObjectsResp struct {
  406. Objects []cdssdk.Object `json:"objects"`
  407. }
  408. func (c *ObjectService) GetPackageObjects(req ObjectGetPackageObjects) (*ObjectGetPackageObjectsResp, error) {
  409. url, err := url.JoinPath(c.baseURL, ObjectGetPackageObjectsPath)
  410. if err != nil {
  411. return nil, err
  412. }
  413. resp, err := http2.GetForm(url, http2.RequestParam{
  414. Query: req,
  415. })
  416. if err != nil {
  417. return nil, err
  418. }
  419. jsonResp, err := ParseJSONResponse[response[ObjectGetPackageObjectsResp]](resp)
  420. if err != nil {
  421. return nil, err
  422. }
  423. if jsonResp.Code == errorcode.OK {
  424. return &jsonResp.Data, nil
  425. }
  426. return nil, jsonResp.ToError()
  427. }
  428. const ObjectNewMultipartUploadPath = "/v1/object/newMultipartUpload"
  429. type ObjectNewMultipartUpload struct {
  430. UserID cdssdk.UserID `json:"userID" binding:"required"`
  431. PackageID cdssdk.PackageID `json:"packageID" binding:"required"`
  432. Path string `json:"path" binding:"required"`
  433. }
  434. type ObjectNewMultipartUploadResp struct {
  435. Object cdssdk.Object `json:"object"`
  436. }
  437. func (c *ObjectService) NewMultipartUpload(req ObjectNewMultipartUpload) (*ObjectNewMultipartUploadResp, error) {
  438. url, err := url.JoinPath(c.baseURL, ObjectNewMultipartUploadPath)
  439. if err != nil {
  440. return nil, err
  441. }
  442. resp, err := http2.PostJSON(url, http2.RequestParam{
  443. Body: req,
  444. })
  445. if err != nil {
  446. return nil, err
  447. }
  448. jsonResp, err := ParseJSONResponse[response[ObjectNewMultipartUploadResp]](resp)
  449. if err != nil {
  450. return nil, err
  451. }
  452. if jsonResp.Code == errorcode.OK {
  453. return &jsonResp.Data, nil
  454. }
  455. return nil, jsonResp.ToError()
  456. }
  457. const ObjectUploadPartPath = "/v1/object/uploadPart"
  458. type ObjectUploadPart struct {
  459. ObjectUploadPartInfo
  460. File io.ReadCloser `json:"-"`
  461. }
  462. type ObjectUploadPartInfo struct {
  463. UserID cdssdk.UserID `json:"userID" binding:"required"`
  464. ObjectID cdssdk.ObjectID `json:"objectID" binding:"required"`
  465. Index int `json:"index"`
  466. }
  467. type ObjectUploadPartResp struct{}
  468. func (c *ObjectService) UploadPart(req ObjectUploadPart) (*ObjectUploadPartResp, error) {
  469. url, err := url.JoinPath(c.baseURL, ObjectUploadPartPath)
  470. if err != nil {
  471. return nil, err
  472. }
  473. infoJSON, err := serder.ObjectToJSON(req)
  474. if err != nil {
  475. return nil, fmt.Errorf("upload info to json: %w", err)
  476. }
  477. resp, err := http2.PostMultiPart(url, http2.MultiPartRequestParam{
  478. Form: map[string]string{"info": string(infoJSON)},
  479. Files: iterator.Array(&http2.IterMultiPartFile{
  480. FieldName: "file",
  481. File: req.File,
  482. }),
  483. })
  484. if err != nil {
  485. return nil, err
  486. }
  487. contType := resp.Header.Get("Content-Type")
  488. if strings.Contains(contType, http2.ContentTypeJSON) {
  489. var err error
  490. var codeResp response[ObjectUploadPartResp]
  491. if codeResp, err = serder.JSONToObjectStreamEx[response[ObjectUploadPartResp]](resp.Body); err != nil {
  492. return nil, fmt.Errorf("parsing response: %w", err)
  493. }
  494. if codeResp.Code == errorcode.OK {
  495. return &codeResp.Data, nil
  496. }
  497. return nil, codeResp.ToError()
  498. }
  499. return nil, fmt.Errorf("unknow response content type: %s", contType)
  500. }
  501. const ObjectCompleteMultipartUploadPath = "/v1/object/completeMultipartUpload"
  502. type ObjectCompleteMultipartUpload struct {
  503. UserID cdssdk.UserID `json:"userID" binding:"required"`
  504. ObjectID cdssdk.ObjectID `json:"objectID" binding:"required"`
  505. Indexes []int `json:"indexes" binding:"required"`
  506. }
  507. type ObjectCompleteMultipartUploadResp struct {
  508. Object cdssdk.Object `json:"object"`
  509. }
  510. func (c *ObjectService) CompleteMultipartUpload(req ObjectCompleteMultipartUpload) (*ObjectCompleteMultipartUploadResp, error) {
  511. url, err := url.JoinPath(c.baseURL, ObjectCompleteMultipartUploadPath)
  512. if err != nil {
  513. return nil, err
  514. }
  515. resp, err := http2.PostJSON(url, http2.RequestParam{
  516. Body: req,
  517. })
  518. if err != nil {
  519. return nil, err
  520. }
  521. jsonResp, err := ParseJSONResponse[response[ObjectCompleteMultipartUploadResp]](resp)
  522. if err != nil {
  523. return nil, err
  524. }
  525. if jsonResp.Code == errorcode.OK {
  526. return &jsonResp.Data, nil
  527. }
  528. return nil, jsonResp.ToError()
  529. }