opendal 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (548) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +49 -37
  3. data/Cargo.toml +1 -1
  4. data/DEPENDENCIES.rust.tsv +39 -28
  5. data/core/CHANGELOG.md +100 -0
  6. data/core/Cargo.lock +184 -266
  7. data/core/Cargo.toml +99 -93
  8. data/core/DEPENDENCIES.rust.tsv +20 -20
  9. data/core/benches/metadata/README.md +21 -0
  10. data/core/benches/metadata/main.rs +541 -0
  11. data/core/benches/vs_fs/Cargo.toml +1 -1
  12. data/core/benches/vs_s3/Cargo.toml +1 -1
  13. data/core/core/CHANGELOG.md +6027 -0
  14. data/core/core/Cargo.toml +6 -1
  15. data/core/core/src/blocking/delete.rs +5 -1
  16. data/core/core/src/blocking/operator.rs +12 -0
  17. data/core/core/src/blocking/read/std_reader.rs +25 -0
  18. data/core/core/src/docs/concepts.rs +70 -94
  19. data/core/core/src/docs/internals/accessor.rs +62 -293
  20. data/core/core/src/docs/internals/layer.rs +43 -59
  21. data/core/core/src/docs/internals/mod.rs +21 -23
  22. data/core/core/src/docs/mod.rs +11 -7
  23. data/core/core/src/docs/performance/concurrent_write.md +92 -55
  24. data/core/core/src/docs/performance/http_optimization.md +120 -104
  25. data/core/core/src/docs/performance/mod.rs +8 -6
  26. data/core/core/src/docs/rfcs/5485_conditional_reader.md +4 -0
  27. data/core/core/src/docs/rfcs/7182_restore_api.md +139 -557
  28. data/core/core/src/docs/rfcs/7945_limited_read.md +210 -0
  29. data/core/core/src/docs/rfcs/8109_writer_copy_from.md +330 -0
  30. data/core/core/src/docs/rfcs/8145_conflict_error_kind.md +210 -0
  31. data/core/core/src/docs/rfcs/8147_write_if_not_changed.md +233 -0
  32. data/core/core/src/docs/rfcs/8188_compose_api.md +292 -0
  33. data/core/core/src/docs/rfcs/8194_compact_metadata_and_operation_args.md +444 -0
  34. data/core/core/src/docs/rfcs/README.md +14 -3
  35. data/core/core/src/docs/rfcs/mod.rs +46 -26
  36. data/core/core/src/docs/specs/README.md +34 -0
  37. data/core/core/src/docs/specs/conditional-operations.md +156 -0
  38. data/core/core/src/docs/specs/metadata.md +63 -0
  39. data/core/core/src/docs/specs/mod.rs +26 -0
  40. data/core/core/src/docs/upgrade.md +114 -1
  41. data/core/core/src/layers/capability_override.rs +15 -2
  42. data/core/core/src/layers/complete.rs +347 -43
  43. data/core/core/src/layers/correctness_check.rs +718 -51
  44. data/core/core/src/layers/error_context.rs +76 -2
  45. data/core/core/src/layers/simulate.rs +91 -28
  46. data/core/core/src/lib.rs +1 -0
  47. data/core/core/src/raw/accessor.rs +91 -15
  48. data/core/core/src/raw/enum_utils.rs +7 -0
  49. data/core/core/src/raw/http_util/header.rs +22 -17
  50. data/core/core/src/raw/oio/compose/api.rs +92 -0
  51. data/core/core/src/raw/oio/compose/mod.rs +19 -0
  52. data/core/core/src/raw/oio/copy/api.rs +3 -3
  53. data/core/core/src/raw/oio/copy/block_copy.rs +32 -4
  54. data/core/core/src/raw/oio/copy/multipart_copy.rs +36 -7
  55. data/core/core/src/raw/oio/entry.rs +48 -22
  56. data/core/core/src/raw/oio/list/flat_list.rs +1 -1
  57. data/core/core/src/raw/oio/list/hierarchy_list.rs +3 -2
  58. data/core/core/src/raw/oio/mod.rs +3 -0
  59. data/core/core/src/raw/oio/write/api.rs +40 -0
  60. data/core/core/src/raw/oio/write/append_write.rs +4 -4
  61. data/core/core/src/raw/oio/write/block_write.rs +2 -2
  62. data/core/core/src/raw/oio/write/multipart_write.rs +180 -47
  63. data/core/core/src/raw/oio/write/position_write.rs +1 -1
  64. data/core/core/src/raw/operation.rs +6 -0
  65. data/core/core/src/raw/ops.rs +1187 -455
  66. data/core/core/src/raw/rps.rs +11 -0
  67. data/core/core/src/raw/time.rs +14 -3
  68. data/core/core/src/services/memory/backend.rs +5 -10
  69. data/core/core/src/services/memory/lister.rs +4 -4
  70. data/core/core/src/services/memory/writer.rs +7 -6
  71. data/core/core/src/types/capability.rs +65 -0
  72. data/core/core/src/types/compact.rs +329 -0
  73. data/core/core/src/types/compose/composer.rs +183 -0
  74. data/core/core/src/types/compose/input.rs +57 -0
  75. data/core/core/src/types/compose/mod.rs +23 -0
  76. data/core/core/src/types/context/read.rs +16 -11
  77. data/core/core/src/types/context/write.rs +149 -1
  78. data/core/core/src/types/copy.rs +5 -3
  79. data/core/core/src/types/delete/deleter.rs +20 -12
  80. data/core/core/src/types/delete/input.rs +22 -64
  81. data/core/core/src/types/delete/mod.rs +0 -1
  82. data/core/core/src/types/entry.rs +8 -14
  83. data/core/core/src/types/error.rs +28 -11
  84. data/core/core/src/types/metadata.rs +709 -322
  85. data/core/core/src/types/mod.rs +9 -1
  86. data/core/core/src/types/operator/operator.rs +278 -29
  87. data/core/core/src/types/operator/operator_futures.rs +460 -102
  88. data/core/core/src/types/options.rs +621 -154
  89. data/core/core/src/types/read/futures_async_reader.rs +663 -50
  90. data/core/core/src/types/read/reader.rs +14 -5
  91. data/core/core/src/types/write/futures_async_writer.rs +27 -0
  92. data/core/core/src/types/write/writer.rs +47 -5
  93. data/core/http-transports/reqwest/Cargo.toml +1 -1
  94. data/core/layers/async-backtrace/Cargo.toml +2 -2
  95. data/core/layers/async-backtrace/src/lib.rs +21 -2
  96. data/core/layers/await-tree/Cargo.toml +2 -2
  97. data/core/layers/await-tree/src/lib.rs +25 -2
  98. data/core/layers/capability-check/Cargo.toml +2 -2
  99. data/core/layers/capability-check/src/lib.rs +98 -10
  100. data/core/layers/chaos/Cargo.toml +2 -2
  101. data/core/layers/chaos/src/lib.rs +18 -3
  102. data/core/layers/concurrent-limit/Cargo.toml +2 -2
  103. data/core/layers/concurrent-limit/src/lib.rs +50 -10
  104. data/core/layers/dtrace/Cargo.toml +2 -2
  105. data/core/layers/dtrace/src/lib.rs +29 -2
  106. data/core/layers/fastmetrics/Cargo.toml +3 -3
  107. data/core/layers/fastrace/Cargo.toml +2 -2
  108. data/core/layers/fastrace/src/lib.rs +28 -2
  109. data/core/layers/foyer/Cargo.toml +2 -2
  110. data/core/layers/foyer/src/full.rs +16 -19
  111. data/core/layers/foyer/src/lib.rs +67 -14
  112. data/core/layers/hotpath/Cargo.toml +2 -2
  113. data/core/layers/hotpath/src/lib.rs +20 -2
  114. data/core/layers/immutable-index/Cargo.toml +2 -2
  115. data/core/layers/immutable-index/src/lib.rs +48 -24
  116. data/core/layers/logging/Cargo.toml +2 -2
  117. data/core/layers/logging/src/lib.rs +46 -2
  118. data/core/layers/metrics/Cargo.toml +3 -3
  119. data/core/layers/mime-guess/Cargo.toml +2 -2
  120. data/core/layers/mime-guess/src/lib.rs +31 -4
  121. data/core/layers/observe-metrics-common/Cargo.toml +2 -2
  122. data/core/layers/observe-metrics-common/src/lib.rs +55 -2
  123. data/core/layers/otelmetrics/Cargo.toml +3 -3
  124. data/core/layers/oteltrace/Cargo.toml +2 -2
  125. data/core/layers/oteltrace/src/lib.rs +27 -2
  126. data/core/layers/prometheus/Cargo.toml +3 -3
  127. data/core/layers/prometheus-client/Cargo.toml +3 -3
  128. data/core/layers/retry/Cargo.toml +4 -4
  129. data/core/layers/retry/src/lib.rs +76 -19
  130. data/core/layers/route/Cargo.toml +3 -3
  131. data/core/layers/route/src/lib.rs +34 -7
  132. data/core/layers/tail-cut/Cargo.toml +2 -2
  133. data/core/layers/tail-cut/src/lib.rs +28 -2
  134. data/core/layers/throttle/Cargo.toml +2 -2
  135. data/core/layers/throttle/src/lib.rs +19 -2
  136. data/core/layers/timeout/Cargo.toml +3 -3
  137. data/core/layers/timeout/src/lib.rs +38 -13
  138. data/core/layers/tracing/Cargo.toml +2 -2
  139. data/core/layers/tracing/src/lib.rs +24 -3
  140. data/core/services/aliyun-drive/Cargo.toml +1 -1
  141. data/core/services/aliyun-drive/src/backend.rs +33 -23
  142. data/core/services/aliyun-drive/src/core.rs +142 -53
  143. data/core/services/aliyun-drive/src/lister.rs +19 -18
  144. data/core/services/aliyun-drive/src/reader.rs +4 -1
  145. data/core/services/aliyun-drive/src/writer.rs +3 -3
  146. data/core/services/alluxio/Cargo.toml +1 -1
  147. data/core/services/alluxio/src/backend.rs +1 -1
  148. data/core/services/alluxio/src/core.rs +113 -94
  149. data/core/services/alluxio/src/reader.rs +7 -3
  150. data/core/services/alluxio/src/writer.rs +2 -2
  151. data/core/services/azblob/Cargo.toml +2 -2
  152. data/core/services/azblob/src/backend.rs +16 -9
  153. data/core/services/azblob/src/copier.rs +41 -15
  154. data/core/services/azblob/src/core.rs +353 -135
  155. data/core/services/azblob/src/deleter.rs +41 -18
  156. data/core/services/azblob/src/lister.rs +16 -10
  157. data/core/services/azblob/src/reader.rs +4 -1
  158. data/core/services/azblob/src/writer.rs +48 -15
  159. data/core/services/azdls/Cargo.toml +2 -2
  160. data/core/services/azdls/src/backend.rs +45 -15
  161. data/core/services/azdls/src/config.rs +4 -1
  162. data/core/services/azdls/src/core.rs +276 -88
  163. data/core/services/azdls/src/deleter.rs +13 -4
  164. data/core/services/azdls/src/lister.rs +18 -12
  165. data/core/services/azdls/src/reader.rs +6 -2
  166. data/core/services/azdls/src/writer.rs +43 -22
  167. data/core/services/azfile/Cargo.toml +2 -2
  168. data/core/services/azfile/src/backend.rs +24 -8
  169. data/core/services/azfile/src/core.rs +194 -76
  170. data/core/services/azfile/src/deleter.rs +8 -1
  171. data/core/services/azfile/src/lister.rs +20 -14
  172. data/core/services/azfile/src/reader.rs +5 -2
  173. data/core/services/azfile/src/writer.rs +27 -15
  174. data/core/services/azure-common/Cargo.toml +1 -1
  175. data/core/services/b2/Cargo.toml +1 -1
  176. data/core/services/b2/src/backend.rs +17 -7
  177. data/core/services/b2/src/core.rs +133 -119
  178. data/core/services/b2/src/deleter.rs +1 -1
  179. data/core/services/b2/src/lister.rs +5 -2
  180. data/core/services/b2/src/reader.rs +5 -2
  181. data/core/services/b2/src/writer.rs +29 -12
  182. data/core/services/cacache/Cargo.toml +1 -1
  183. data/core/services/cacache/src/backend.rs +4 -5
  184. data/core/services/cacache/src/reader.rs +4 -1
  185. data/core/services/cacache/src/writer.rs +6 -2
  186. data/core/services/cloudflare-kv/Cargo.toml +1 -1
  187. data/core/services/cloudflare-kv/src/backend.rs +26 -15
  188. data/core/services/cloudflare-kv/src/config.rs +13 -2
  189. data/core/services/cloudflare-kv/src/core.rs +62 -56
  190. data/core/services/cloudflare-kv/src/deleter.rs +12 -3
  191. data/core/services/cloudflare-kv/src/lister.rs +18 -15
  192. data/core/services/cloudflare-kv/src/reader.rs +14 -9
  193. data/core/services/cloudflare-kv/src/writer.rs +10 -7
  194. data/core/services/compfs/Cargo.toml +1 -1
  195. data/core/services/compfs/src/backend.rs +11 -7
  196. data/core/services/compfs/src/lister.rs +7 -7
  197. data/core/services/compfs/src/writer.rs +1 -1
  198. data/core/services/cos/Cargo.toml +1 -1
  199. data/core/services/cos/src/backend.rs +38 -8
  200. data/core/services/cos/src/core.rs +176 -76
  201. data/core/services/cos/src/deleter.rs +4 -1
  202. data/core/services/cos/src/lister.rs +42 -27
  203. data/core/services/cos/src/reader.rs +6 -2
  204. data/core/services/cos/src/writer.rs +44 -20
  205. data/core/services/d1/Cargo.toml +1 -1
  206. data/core/services/d1/src/backend.rs +6 -5
  207. data/core/services/d1/src/core.rs +76 -60
  208. data/core/services/d1/src/reader.rs +4 -1
  209. data/core/services/d1/src/writer.rs +6 -2
  210. data/core/services/dashmap/Cargo.toml +1 -1
  211. data/core/services/dashmap/src/backend.rs +2 -2
  212. data/core/services/dashmap/src/reader.rs +4 -1
  213. data/core/services/dashmap/src/writer.rs +11 -8
  214. data/core/services/dbfs/Cargo.toml +1 -1
  215. data/core/services/dbfs/src/backend.rs +21 -15
  216. data/core/services/dbfs/src/core.rs +60 -55
  217. data/core/services/dbfs/src/deleter.rs +4 -1
  218. data/core/services/dbfs/src/lister.rs +8 -9
  219. data/core/services/dbfs/src/writer.rs +6 -3
  220. data/core/services/dropbox/Cargo.toml +1 -1
  221. data/core/services/dropbox/src/backend.rs +29 -22
  222. data/core/services/dropbox/src/core.rs +64 -62
  223. data/core/services/dropbox/src/deleter.rs +1 -1
  224. data/core/services/dropbox/src/lister.rs +17 -8
  225. data/core/services/dropbox/src/reader.rs +4 -1
  226. data/core/services/dropbox/src/writer.rs +13 -10
  227. data/core/services/etcd/Cargo.toml +1 -1
  228. data/core/services/etcd/src/backend.rs +8 -5
  229. data/core/services/etcd/src/core.rs +5 -11
  230. data/core/services/etcd/src/lister.rs +6 -1
  231. data/core/services/etcd/src/reader.rs +4 -1
  232. data/core/services/etcd/src/writer.rs +6 -3
  233. data/core/services/foundationdb/Cargo.toml +1 -1
  234. data/core/services/foundationdb/src/backend.rs +6 -5
  235. data/core/services/foundationdb/src/reader.rs +4 -1
  236. data/core/services/foundationdb/src/writer.rs +6 -2
  237. data/core/services/foyer/Cargo.toml +3 -3
  238. data/core/services/foyer/src/backend.rs +6 -5
  239. data/core/services/foyer/src/reader.rs +4 -1
  240. data/core/services/foyer/src/writer.rs +6 -2
  241. data/core/services/fs/Cargo.toml +1 -1
  242. data/core/services/fs/src/backend.rs +4 -3
  243. data/core/services/fs/src/core.rs +44 -26
  244. data/core/services/fs/src/lister.rs +9 -6
  245. data/core/services/fs/src/writer.rs +20 -13
  246. data/core/services/ftp/Cargo.toml +4 -6
  247. data/core/services/ftp/src/backend.rs +9 -5
  248. data/core/services/ftp/src/core.rs +9 -7
  249. data/core/services/ftp/src/lister.rs +7 -8
  250. data/core/services/ftp/src/reader.rs +3 -3
  251. data/core/services/ftp/src/writer.rs +3 -3
  252. data/core/services/gcs/Cargo.toml +4 -2
  253. data/core/services/gcs/src/backend.rs +53 -7
  254. data/core/services/gcs/src/composer.rs +705 -0
  255. data/core/services/gcs/src/copier.rs +14 -4
  256. data/core/services/gcs/src/core.rs +944 -126
  257. data/core/services/gcs/src/deleter.rs +33 -18
  258. data/core/services/gcs/src/lib.rs +1 -0
  259. data/core/services/gcs/src/lister.rs +21 -12
  260. data/core/services/gcs/src/reader.rs +12 -5
  261. data/core/services/gcs/src/writer.rs +632 -10
  262. data/core/services/gcs-grpc/Cargo.toml +58 -0
  263. data/core/services/gcs-grpc/README.md +19 -0
  264. data/core/services/gcs-grpc/proto/README.md +23 -0
  265. data/core/services/gcs-grpc/proto/google/storage/v2/storage.proto +171 -0
  266. data/core/services/gcs-grpc/proto/upstream-descriptor.bin +0 -0
  267. data/core/services/gcs-grpc/src/backend.rs +449 -0
  268. data/core/services/gcs-grpc/src/config.rs +116 -0
  269. data/core/services/gcs-grpc/src/copier.rs +98 -0
  270. data/core/services/gcs-grpc/src/core.rs +298 -0
  271. data/core/services/gcs-grpc/src/deleter.rs +65 -0
  272. data/core/services/gcs-grpc/src/docs.md +19 -0
  273. data/core/services/gcs-grpc/src/generated/google.storage.v2.rs +541 -0
  274. data/core/services/gcs-grpc/src/generated/mod.rs +24 -0
  275. data/core/services/gcs-grpc/src/lib.rs +43 -0
  276. data/core/services/gcs-grpc/src/lister.rs +125 -0
  277. data/core/services/gcs-grpc/src/reader.rs +140 -0
  278. data/core/services/gcs-grpc/src/writer.rs +780 -0
  279. data/core/services/gdrive/Cargo.toml +1 -1
  280. data/core/services/gdrive/src/backend.rs +122 -68
  281. data/core/services/gdrive/src/core.rs +86 -68
  282. data/core/services/gdrive/src/deleter.rs +8 -2
  283. data/core/services/gdrive/src/lister.rs +36 -24
  284. data/core/services/gdrive/src/reader.rs +9 -3
  285. data/core/services/gdrive/src/writer.rs +13 -7
  286. data/core/services/ghac/Cargo.toml +2 -2
  287. data/core/services/ghac/src/backend.rs +5 -2
  288. data/core/services/ghac/src/core.rs +59 -37
  289. data/core/services/ghac/src/reader.rs +5 -2
  290. data/core/services/ghac/src/writer.rs +16 -6
  291. data/core/services/github/Cargo.toml +1 -1
  292. data/core/services/github/src/backend.rs +16 -8
  293. data/core/services/github/src/core.rs +88 -76
  294. data/core/services/github/src/lister.rs +16 -14
  295. data/core/services/github/src/reader.rs +5 -2
  296. data/core/services/github/src/writer.rs +12 -6
  297. data/core/services/goosefs/Cargo.toml +3 -3
  298. data/core/services/goosefs/src/backend.rs +380 -51
  299. data/core/services/goosefs/src/config.rs +18 -10
  300. data/core/services/goosefs/src/core.rs +291 -208
  301. data/core/services/goosefs/src/docs.md +34 -3
  302. data/core/services/goosefs/src/lister.rs +2 -3
  303. data/core/services/goosefs/src/reader.rs +7 -3
  304. data/core/services/goosefs/src/writer.rs +21 -10
  305. data/core/services/goosefs/tests/master_addr_resolution.rs +103 -0
  306. data/core/services/goosefs/tests/safe_conditional_put.rs +37 -0
  307. data/core/services/gridfs/Cargo.toml +1 -1
  308. data/core/services/gridfs/src/backend.rs +6 -5
  309. data/core/services/gridfs/src/reader.rs +4 -1
  310. data/core/services/gridfs/src/writer.rs +6 -2
  311. data/core/services/hdfs/Cargo.toml +1 -1
  312. data/core/services/hdfs/src/backend.rs +1 -1
  313. data/core/services/hdfs/src/core.rs +7 -4
  314. data/core/services/hdfs/src/lister.rs +7 -9
  315. data/core/services/hdfs/src/writer.rs +5 -1
  316. data/core/services/hdfs-native/Cargo.toml +1 -1
  317. data/core/services/hdfs-native/src/backend.rs +1 -1
  318. data/core/services/hdfs-native/src/core.rs +44 -50
  319. data/core/services/hdfs-native/src/lister.rs +8 -10
  320. data/core/services/hdfs-native/src/writer.rs +5 -1
  321. data/core/services/hf/Cargo.toml +4 -3
  322. data/core/services/hf/src/backend.rs +3 -3
  323. data/core/services/hf/src/core.rs +892 -142
  324. data/core/services/hf/src/lister.rs +16 -6
  325. data/core/services/hf/src/reader.rs +377 -57
  326. data/core/services/hf/src/writer.rs +6 -2
  327. data/core/services/http/Cargo.toml +3 -3
  328. data/core/services/http/src/backend.rs +8 -6
  329. data/core/services/http/src/core.rs +57 -35
  330. data/core/services/http/src/reader.rs +5 -2
  331. data/core/services/ipfs/Cargo.toml +1 -1
  332. data/core/services/ipfs/src/backend.rs +6 -3
  333. data/core/services/ipfs/src/core.rs +43 -34
  334. data/core/services/ipfs/src/reader.rs +5 -2
  335. data/core/services/ipmfs/Cargo.toml +1 -1
  336. data/core/services/ipmfs/src/backend.rs +17 -8
  337. data/core/services/ipmfs/src/core.rs +66 -60
  338. data/core/services/ipmfs/src/deleter.rs +5 -2
  339. data/core/services/ipmfs/src/lister.rs +8 -8
  340. data/core/services/ipmfs/src/reader.rs +5 -2
  341. data/core/services/ipmfs/src/writer.rs +6 -3
  342. data/core/services/koofr/Cargo.toml +1 -1
  343. data/core/services/koofr/src/backend.rs +44 -15
  344. data/core/services/koofr/src/core.rs +62 -46
  345. data/core/services/koofr/src/deleter.rs +4 -1
  346. data/core/services/koofr/src/lister.rs +11 -10
  347. data/core/services/koofr/src/reader.rs +5 -2
  348. data/core/services/koofr/src/writer.rs +13 -7
  349. data/core/services/lakefs/Cargo.toml +1 -1
  350. data/core/services/lakefs/src/backend.rs +25 -8
  351. data/core/services/lakefs/src/core.rs +78 -72
  352. data/core/services/lakefs/src/deleter.rs +4 -1
  353. data/core/services/lakefs/src/lister.rs +11 -11
  354. data/core/services/lakefs/src/reader.rs +5 -2
  355. data/core/services/lakefs/src/writer.rs +11 -10
  356. data/core/services/memcached/Cargo.toml +1 -1
  357. data/core/services/memcached/src/backend.rs +57 -7
  358. data/core/services/memcached/src/config.rs +13 -2
  359. data/core/services/memcached/src/core.rs +11 -1
  360. data/core/services/memcached/src/reader.rs +4 -1
  361. data/core/services/memcached/src/writer.rs +6 -2
  362. data/core/services/mini_moka/Cargo.toml +1 -1
  363. data/core/services/mini_moka/src/backend.rs +8 -8
  364. data/core/services/mini_moka/src/reader.rs +4 -1
  365. data/core/services/mini_moka/src/writer.rs +11 -7
  366. data/core/services/moka/Cargo.toml +1 -1
  367. data/core/services/moka/src/backend.rs +7 -7
  368. data/core/services/moka/src/reader.rs +4 -1
  369. data/core/services/moka/src/writer.rs +10 -6
  370. data/core/services/mongodb/Cargo.toml +1 -1
  371. data/core/services/mongodb/src/backend.rs +6 -5
  372. data/core/services/mongodb/src/reader.rs +4 -1
  373. data/core/services/mongodb/src/writer.rs +6 -2
  374. data/core/services/monoiofs/Cargo.toml +2 -2
  375. data/core/services/monoiofs/src/backend.rs +16 -10
  376. data/core/services/monoiofs/src/core.rs +8 -9
  377. data/core/services/monoiofs/src/reader.rs +8 -10
  378. data/core/services/monoiofs/src/writer.rs +19 -24
  379. data/core/services/mysql/Cargo.toml +1 -1
  380. data/core/services/mysql/src/backend.rs +6 -5
  381. data/core/services/mysql/src/lister.rs +7 -3
  382. data/core/services/mysql/src/reader.rs +4 -1
  383. data/core/services/mysql/src/writer.rs +6 -2
  384. data/core/services/obs/Cargo.toml +1 -1
  385. data/core/services/obs/src/backend.rs +29 -11
  386. data/core/services/obs/src/core.rs +80 -81
  387. data/core/services/obs/src/deleter.rs +4 -1
  388. data/core/services/obs/src/lister.rs +12 -5
  389. data/core/services/obs/src/reader.rs +5 -2
  390. data/core/services/obs/src/writer.rs +40 -19
  391. data/core/services/onedrive/Cargo.toml +1 -1
  392. data/core/services/onedrive/src/backend.rs +19 -7
  393. data/core/services/onedrive/src/core.rs +178 -70
  394. data/core/services/onedrive/src/deleter.rs +5 -2
  395. data/core/services/onedrive/src/lister.rs +19 -13
  396. data/core/services/onedrive/src/reader.rs +6 -2
  397. data/core/services/onedrive/src/writer.rs +26 -15
  398. data/core/services/opfs/Cargo.toml +1 -1
  399. data/core/services/opfs/src/backend.rs +6 -13
  400. data/core/services/opfs/src/core.rs +33 -37
  401. data/core/services/opfs/src/lister.rs +4 -4
  402. data/core/services/opfs/src/writer.rs +1 -3
  403. data/core/services/oss/Cargo.toml +1 -1
  404. data/core/services/oss/src/backend.rs +40 -8
  405. data/core/services/oss/src/core.rs +169 -81
  406. data/core/services/oss/src/deleter.rs +16 -6
  407. data/core/services/oss/src/lister.rs +43 -27
  408. data/core/services/oss/src/reader.rs +6 -2
  409. data/core/services/oss/src/writer.rs +36 -12
  410. data/core/services/pcloud/Cargo.toml +1 -1
  411. data/core/services/pcloud/src/backend.rs +40 -6
  412. data/core/services/pcloud/src/core.rs +78 -66
  413. data/core/services/pcloud/src/deleter.rs +8 -1
  414. data/core/services/pcloud/src/lister.rs +4 -1
  415. data/core/services/pcloud/src/reader.rs +5 -2
  416. data/core/services/pcloud/src/writer.rs +6 -3
  417. data/core/services/persy/Cargo.toml +1 -1
  418. data/core/services/persy/src/backend.rs +6 -5
  419. data/core/services/persy/src/core.rs +60 -15
  420. data/core/services/persy/src/reader.rs +4 -1
  421. data/core/services/persy/src/writer.rs +6 -2
  422. data/core/services/postgresql/Cargo.toml +1 -1
  423. data/core/services/postgresql/src/backend.rs +6 -5
  424. data/core/services/postgresql/src/reader.rs +4 -1
  425. data/core/services/postgresql/src/writer.rs +6 -2
  426. data/core/services/redb/Cargo.toml +1 -1
  427. data/core/services/redb/src/backend.rs +6 -5
  428. data/core/services/redb/src/reader.rs +4 -1
  429. data/core/services/redb/src/writer.rs +6 -2
  430. data/core/services/redis/Cargo.toml +1 -1
  431. data/core/services/redis/src/backend.rs +18 -8
  432. data/core/services/redis/src/config.rs +13 -2
  433. data/core/services/redis/src/reader.rs +8 -4
  434. data/core/services/redis/src/writer.rs +6 -2
  435. data/core/services/rocksdb/Cargo.toml +1 -1
  436. data/core/services/rocksdb/src/backend.rs +6 -5
  437. data/core/services/rocksdb/src/lister.rs +6 -5
  438. data/core/services/rocksdb/src/reader.rs +4 -1
  439. data/core/services/rocksdb/src/writer.rs +6 -2
  440. data/core/services/s3/Cargo.toml +5 -4
  441. data/core/services/s3/src/backend.rs +966 -22
  442. data/core/services/s3/src/copier.rs +190 -55
  443. data/core/services/s3/src/core.rs +299 -190
  444. data/core/services/s3/src/deleter.rs +26 -7
  445. data/core/services/s3/src/docs.md +57 -0
  446. data/core/services/s3/src/lister.rs +55 -36
  447. data/core/services/s3/src/reader.rs +8 -5
  448. data/core/services/s3/src/writer.rs +154 -32
  449. data/core/services/seafile/Cargo.toml +1 -1
  450. data/core/services/seafile/src/backend.rs +2 -2
  451. data/core/services/seafile/src/core.rs +104 -78
  452. data/core/services/seafile/src/lister.rs +11 -8
  453. data/core/services/seafile/src/reader.rs +5 -2
  454. data/core/services/seafile/src/writer.rs +6 -3
  455. data/core/services/sftp/Cargo.toml +1 -1
  456. data/core/services/sftp/src/backend.rs +19 -4
  457. data/core/services/sftp/src/core.rs +51 -46
  458. data/core/services/sftp/src/lister.rs +4 -4
  459. data/core/services/sftp/src/writer.rs +1 -1
  460. data/core/services/sled/Cargo.toml +1 -1
  461. data/core/services/sled/src/backend.rs +6 -5
  462. data/core/services/sled/src/core.rs +28 -6
  463. data/core/services/sled/src/lister.rs +6 -5
  464. data/core/services/sled/src/reader.rs +4 -1
  465. data/core/services/sled/src/writer.rs +6 -2
  466. data/core/services/sqlite/Cargo.toml +1 -1
  467. data/core/services/sqlite/src/backend.rs +11 -6
  468. data/core/services/sqlite/src/reader.rs +4 -1
  469. data/core/services/sqlite/src/writer.rs +7 -3
  470. data/core/services/surrealdb/Cargo.toml +1 -1
  471. data/core/services/surrealdb/src/backend.rs +6 -5
  472. data/core/services/surrealdb/src/reader.rs +4 -1
  473. data/core/services/surrealdb/src/writer.rs +6 -2
  474. data/core/services/swift/Cargo.toml +1 -1
  475. data/core/services/swift/src/backend.rs +38 -8
  476. data/core/services/swift/src/core.rs +62 -66
  477. data/core/services/swift/src/deleter.rs +8 -2
  478. data/core/services/swift/src/lister.rs +11 -8
  479. data/core/services/swift/src/reader.rs +5 -2
  480. data/core/services/swift/src/writer.rs +17 -8
  481. data/core/services/tikv/Cargo.toml +1 -1
  482. data/core/services/tikv/src/backend.rs +6 -5
  483. data/core/services/tikv/src/core.rs +30 -13
  484. data/core/services/tikv/src/reader.rs +4 -1
  485. data/core/services/tikv/src/writer.rs +6 -2
  486. data/core/services/tos/Cargo.toml +1 -1
  487. data/core/services/tos/src/backend.rs +14 -14
  488. data/core/services/tos/src/copier.rs +44 -17
  489. data/core/services/tos/src/core.rs +112 -111
  490. data/core/services/tos/src/deleter.rs +9 -3
  491. data/core/services/tos/src/lister.rs +43 -28
  492. data/core/services/tos/src/reader.rs +5 -2
  493. data/core/services/tos/src/writer.rs +37 -16
  494. data/core/services/upyun/Cargo.toml +1 -1
  495. data/core/services/upyun/src/backend.rs +30 -7
  496. data/core/services/upyun/src/core.rs +97 -88
  497. data/core/services/upyun/src/deleter.rs +4 -1
  498. data/core/services/upyun/src/lister.rs +10 -10
  499. data/core/services/upyun/src/reader.rs +5 -2
  500. data/core/services/upyun/src/writer.rs +19 -7
  501. data/core/services/vercel-artifacts/Cargo.toml +1 -1
  502. data/core/services/vercel-artifacts/src/backend.rs +6 -3
  503. data/core/services/vercel-artifacts/src/core.rs +32 -27
  504. data/core/services/vercel-artifacts/src/reader.rs +5 -2
  505. data/core/services/vercel-artifacts/src/writer.rs +6 -3
  506. data/core/services/vercel-blob/Cargo.toml +1 -1
  507. data/core/services/vercel-blob/src/backend.rs +23 -6
  508. data/core/services/vercel-blob/src/core.rs +83 -77
  509. data/core/services/vercel-blob/src/reader.rs +5 -2
  510. data/core/services/vercel-blob/src/writer.rs +19 -7
  511. data/core/services/webdav/Cargo.toml +1 -1
  512. data/core/services/webdav/src/backend.rs +25 -5
  513. data/core/services/webdav/src/core.rs +116 -59
  514. data/core/services/webdav/src/deleter.rs +4 -1
  515. data/core/services/webdav/src/lister.rs +4 -1
  516. data/core/services/webdav/src/reader.rs +6 -2
  517. data/core/services/webdav/src/writer.rs +17 -7
  518. data/core/services/webhdfs/Cargo.toml +1 -1
  519. data/core/services/webhdfs/src/backend.rs +23 -10
  520. data/core/services/webhdfs/src/core.rs +97 -96
  521. data/core/services/webhdfs/src/deleter.rs +5 -2
  522. data/core/services/webhdfs/src/lister.rs +21 -9
  523. data/core/services/webhdfs/src/reader.rs +5 -2
  524. data/core/services/webhdfs/src/writer.rs +42 -13
  525. data/core/services/yandex-disk/Cargo.toml +1 -1
  526. data/core/services/yandex-disk/src/backend.rs +28 -6
  527. data/core/services/yandex-disk/src/core.rs +97 -79
  528. data/core/services/yandex-disk/src/deleter.rs +4 -1
  529. data/core/services/yandex-disk/src/lister.rs +5 -2
  530. data/core/services/yandex-disk/src/reader.rs +5 -2
  531. data/core/services/yandex-disk/src/writer.rs +6 -3
  532. data/core/src/lib.rs +5 -0
  533. data/core/testkit/Cargo.toml +4 -4
  534. data/core/tests/behavior/async_compose.rs +297 -0
  535. data/core/tests/behavior/async_copy.rs +162 -1
  536. data/core/tests/behavior/async_delete.rs +364 -3
  537. data/core/tests/behavior/async_read.rs +86 -0
  538. data/core/tests/behavior/async_restore.rs +162 -0
  539. data/core/tests/behavior/async_stat.rs +90 -0
  540. data/core/tests/behavior/async_write.rs +219 -10
  541. data/core/tests/behavior/main.rs +4 -0
  542. data/core/upgrade.md +114 -1
  543. data/src/capability.rs +0 -1
  544. data/src/io.rs +0 -1
  545. data/src/lister.rs +0 -1
  546. data/src/metadata.rs +0 -1
  547. data/src/operator_info.rs +0 -1
  548. metadata +42 -2
@@ -19,8 +19,8 @@ use std::sync::Arc;
19
19
 
20
20
  use http::StatusCode;
21
21
 
22
- use super::core::AzfileCore;
23
22
  use super::core::parse_error;
23
+ use super::core::{AzfileCore, ErrorContext};
24
24
  use opendal_core::raw::*;
25
25
  use opendal_core::*;
26
26
 
@@ -50,17 +50,17 @@ impl AzfileWriter {
50
50
  }
51
51
 
52
52
  fn parse_metadata(headers: &http::HeaderMap) -> Result<Metadata> {
53
- let mut metadata = Metadata::default();
53
+ let mut metadata = MetadataBuilder::unknown();
54
54
 
55
55
  if let Some(last_modified) = parse_last_modified(headers)? {
56
- metadata.set_last_modified(last_modified);
56
+ metadata.last_modified(last_modified);
57
57
  }
58
58
  let etag = parse_etag(headers)?;
59
59
  if let Some(etag) = etag {
60
- metadata.set_etag(etag);
60
+ metadata.etag(etag);
61
61
  }
62
62
 
63
- Ok(metadata)
63
+ Ok(metadata.build())
64
64
  }
65
65
  }
66
66
 
@@ -78,7 +78,10 @@ impl oio::OneShotWrite for AzfileWriter {
78
78
  match status {
79
79
  StatusCode::OK | StatusCode::CREATED => {}
80
80
  _ => {
81
- return Err(parse_error(resp).with_operation("Backend::azfile_create_file"));
81
+ return Err(
82
+ parse_error(ErrorContext::new(ServiceOperation("CreateFile")), resp)
83
+ .with_operation("Backend::azfile_create_file"),
84
+ );
82
85
  }
83
86
  }
84
87
 
@@ -87,11 +90,14 @@ impl oio::OneShotWrite for AzfileWriter {
87
90
  .azfile_update(&self.ctx, &self.path, size as u64, 0, bs)
88
91
  .await?;
89
92
  let status = resp.status();
90
- let mut meta = AzfileWriter::parse_metadata(resp.headers())?;
91
- meta.set_content_length(size as u64);
93
+ let mut meta = AzfileWriter::parse_metadata(resp.headers())?.into_builder();
94
+ meta.set_file(size as u64);
92
95
  match status {
93
- StatusCode::OK | StatusCode::CREATED => Ok(meta),
94
- _ => Err(parse_error(resp).with_operation("Backend::azfile_update")),
96
+ StatusCode::OK | StatusCode::CREATED => Ok(meta.build()),
97
+ _ => Err(
98
+ parse_error(ErrorContext::new(ServiceOperation("PutRange")), resp)
99
+ .with_operation("Backend::azfile_update"),
100
+ ),
95
101
  }
96
102
  }
97
103
  }
@@ -109,7 +115,10 @@ impl oio::AppendWrite for AzfileWriter {
109
115
 
110
116
  match status {
111
117
  StatusCode::OK => Ok(parse_content_length(resp.headers())?.unwrap_or_default()),
112
- _ => Err(parse_error(resp)),
118
+ _ => Err(parse_error(
119
+ ErrorContext::new(ServiceOperation("GetFileProperties")),
120
+ resp,
121
+ )),
113
122
  }
114
123
  }
115
124
 
@@ -120,11 +129,14 @@ impl oio::AppendWrite for AzfileWriter {
120
129
  .await?;
121
130
 
122
131
  let status = resp.status();
123
- let mut meta = AzfileWriter::parse_metadata(resp.headers())?;
124
- meta.set_content_length(offset + size);
132
+ let mut meta = AzfileWriter::parse_metadata(resp.headers())?.into_builder();
133
+ meta.set_file(offset + size);
125
134
  match status {
126
- StatusCode::OK | StatusCode::CREATED => Ok(meta),
127
- _ => Err(parse_error(resp).with_operation("Backend::azfile_update")),
135
+ StatusCode::OK | StatusCode::CREATED => Ok(meta.build()),
136
+ _ => Err(
137
+ parse_error(ErrorContext::new(ServiceOperation("PutRange")), resp)
138
+ .with_operation("Backend::azfile_update"),
139
+ ),
128
140
  }
129
141
  }
130
142
  }
@@ -33,4 +33,4 @@ all-features = true
33
33
 
34
34
  [dependencies]
35
35
  http = { workspace = true }
36
- opendal-core = { path = "../../core", version = "0.58.2", default-features = false }
36
+ opendal-core = { path = "../../core", version = "0.59.1", default-features = false }
@@ -36,7 +36,7 @@ asyncband = { workspace = true }
36
36
  bytes = { workspace = true }
37
37
  http = { workspace = true }
38
38
  log = { workspace = true }
39
- opendal-core = { path = "../../core", version = "0.58.2", default-features = false }
39
+ opendal-core = { path = "../../core", version = "0.59.1", default-features = false }
40
40
  serde = { workspace = true, features = ["derive"] }
41
41
  serde_json = { workspace = true }
42
42
 
@@ -25,11 +25,11 @@ use log::debug;
25
25
 
26
26
  use super::B2_SCHEME;
27
27
  use super::config::B2Config;
28
- use super::core::B2Core;
29
28
  use super::core::B2Signer;
30
29
  use super::core::constants;
31
30
  use super::core::parse_error;
32
31
  use super::core::parse_file_info;
32
+ use super::core::{B2Core, ErrorContext};
33
33
  use super::deleter::B2Deleter;
34
34
  use super::lister::B2Lister;
35
35
  use super::reader::*;
@@ -224,6 +224,7 @@ impl Service for B2Backend {
224
224
  type Lister = oio::PageLister<B2Lister>;
225
225
  type Deleter = oio::OneShotDeleter<B2Deleter>;
226
226
  type Copier = oio::OneShotCopier;
227
+ type Composer = ();
227
228
 
228
229
  fn info(&self) -> ServiceInfo {
229
230
  self.core.info.clone()
@@ -250,7 +251,7 @@ impl Service for B2Backend {
250
251
  async fn stat(&self, ctx: &OperationContext, path: &str, _args: OpStat) -> Result<RpStat> {
251
252
  // Stat root always returns a DIR.
252
253
  if path == "/" {
253
- return Ok(RpStat::new(Metadata::new(EntryMode::DIR)));
254
+ return Ok(RpStat::new(MetadataBuilder::dir().build()));
254
255
  }
255
256
 
256
257
  let delimiter = if path.ends_with('/') { Some("/") } else { None };
@@ -317,7 +318,6 @@ impl Service for B2Backend {
317
318
  from: &str,
318
319
  to: &str,
319
320
  _args: OpCopy,
320
- _opts: OpCopier,
321
321
  ) -> Result<Self::Copier> {
322
322
  let core = self.core.clone();
323
323
  let ctx = ctx.clone();
@@ -327,6 +327,7 @@ impl Service for B2Backend {
327
327
  Ok(oio::OneShotCopier::new(async move {
328
328
  let file_info = core.get_file_info(&ctx, &from, None).await?;
329
329
  let source_file_id = file_info.file_id;
330
+ let source_content_length = file_info.content_length;
330
331
 
331
332
  let Some(source_file_id) = source_file_id else {
332
333
  return Err(Error::new(ErrorKind::IsADirectory, "is a directory"));
@@ -337,8 +338,14 @@ impl Service for B2Backend {
337
338
  let status = resp.status();
338
339
 
339
340
  match status {
340
- StatusCode::OK => Ok(Metadata::default()),
341
- _ => Err(parse_error(resp)),
341
+ StatusCode::OK => {
342
+ let metadata = MetadataBuilder::file(source_content_length);
343
+ Ok(metadata.build())
344
+ }
345
+ _ => Err(parse_error(
346
+ ErrorContext::new(ServiceOperation("CopyFile")),
347
+ resp,
348
+ )),
342
349
  }
343
350
  }))
344
351
  }
@@ -393,7 +400,7 @@ impl Service for B2Backend {
393
400
  parts.headers,
394
401
  )))
395
402
  }
396
- PresignOperation::Read(_, _) => {
403
+ PresignOperation::Read(range, _) => {
397
404
  let resp = self
398
405
  .core
399
406
  .get_download_authorization(ctx, path, args.expire())
@@ -410,7 +417,10 @@ impl Service for B2Backend {
410
417
  resp.authorization_token
411
418
  );
412
419
 
413
- let req = Request::get(url);
420
+ let mut req = Request::get(url);
421
+ if !range.is_full() {
422
+ req = req.header(http::header::RANGE, range.to_header());
423
+ }
414
424
 
415
425
  let req = req.body(Buffer::new()).map_err(new_request_build_error)?;
416
426
 
@@ -120,7 +120,10 @@ impl B2Core {
120
120
  };
121
121
  }
122
122
  _ => {
123
- return Err(parse_error(resp));
123
+ return Err(parse_error(
124
+ ErrorContext::new(ServiceOperation("AuthorizeAccount")),
125
+ resp,
126
+ ));
124
127
  }
125
128
  }
126
129
  Ok(signer.auth_info.clone())
@@ -196,7 +199,10 @@ impl B2Core {
196
199
  .map_err(new_json_deserialize_error)?;
197
200
  Ok(resp)
198
201
  }
199
- _ => Err(parse_error(resp)),
202
+ _ => Err(parse_error(
203
+ ErrorContext::new(ServiceOperation("GetUploadUrl")),
204
+ resp,
205
+ )),
200
206
  }
201
207
  }
202
208
 
@@ -241,7 +247,10 @@ impl B2Core {
241
247
  .map_err(new_json_deserialize_error)?;
242
248
  Ok(resp)
243
249
  }
244
- _ => Err(parse_error(resp)),
250
+ _ => Err(parse_error(
251
+ ErrorContext::new(ServiceOperation("GetDownloadAuthorization")),
252
+ resp,
253
+ )),
245
254
  }
246
255
  }
247
256
 
@@ -331,7 +340,7 @@ impl B2Core {
331
340
  // B2 uses fileInfo field for custom file info in start_large_file API.
332
341
  if let Some(user_metadata) = args.user_metadata() {
333
342
  let file_info: HashMap<String, String> = user_metadata
334
- .iter()
343
+ .into_iter()
335
344
  .map(|(k, v)| (k.to_string(), percent_encode_path(v)))
336
345
  .collect();
337
346
  start_large_file_request.file_info = Some(file_info);
@@ -385,7 +394,10 @@ impl B2Core {
385
394
  .map_err(new_json_deserialize_error)?;
386
395
  Ok(resp)
387
396
  }
388
- _ => Err(parse_error(resp)),
397
+ _ => Err(parse_error(
398
+ ErrorContext::new(ServiceOperation("GetUploadPartUrl")),
399
+ resp,
400
+ )),
389
401
  }
390
402
  }
391
403
 
@@ -505,7 +517,10 @@ impl B2Core {
505
517
  }
506
518
  Ok(resp.files.swap_remove(0))
507
519
  }
508
- _ => Err(parse_error(resp)),
520
+ _ => Err(parse_error(
521
+ ErrorContext::new(ServiceOperation("ListFileNames")),
522
+ resp,
523
+ )),
509
524
  }
510
525
  }
511
526
 
@@ -783,19 +798,17 @@ pub struct File {
783
798
 
784
799
  pub(super) fn parse_file_info(file: &File) -> Metadata {
785
800
  if file.file_name.ends_with('/') {
786
- return Metadata::new(EntryMode::DIR);
801
+ return MetadataBuilder::dir().build();
787
802
  }
788
803
 
789
- let mut metadata = Metadata::new(EntryMode::FILE);
790
-
791
- metadata.set_content_length(file.content_length);
804
+ let mut metadata = MetadataBuilder::file(file.content_length);
792
805
 
793
806
  if let Some(content_md5) = &file.content_md5 {
794
- metadata.set_content_md5(content_md5);
807
+ metadata.content_md5(content_md5);
795
808
  }
796
809
 
797
810
  if let Some(content_type) = &file.content_type {
798
- metadata.set_content_type(content_type);
811
+ metadata.content_type(content_type);
799
812
  }
800
813
 
801
814
  // Parse user metadata from file_info
@@ -808,11 +821,11 @@ pub(super) fn parse_file_info(file: &File) -> Metadata {
808
821
  .map(|(k, v)| (k.to_lowercase(), percent_decode_path(v)))
809
822
  .collect();
810
823
  if !user_metadata.is_empty() {
811
- metadata = metadata.with_user_metadata(user_metadata);
824
+ metadata.user_metadata(user_metadata);
812
825
  }
813
826
  }
814
827
 
815
- metadata
828
+ metadata.build()
816
829
  }
817
830
 
818
831
  #[derive(Debug, Serialize)]
@@ -843,123 +856,124 @@ pub struct GetDownloadAuthorizationResponse {
843
856
  pub authorization_token: String,
844
857
  }
845
858
 
846
- mod error {
847
- use bytes::Buf;
848
- use http::Response;
849
- use serde::Deserialize;
850
-
851
- use opendal_core::raw::*;
852
- use opendal_core::*;
853
-
854
- /// the error response of b2
855
- #[derive(Default, Debug, Deserialize)]
856
- #[allow(dead_code)]
857
- struct B2Error {
858
- status: u32,
859
- code: String,
860
- message: String,
861
- }
862
-
863
- /// Parse error response into Error.
864
- pub(crate) fn parse_error(resp: Response<Buffer>) -> Error {
865
- let (parts, body) = resp.into_parts();
866
- let bs = body.to_bytes();
867
-
868
- let (mut kind, mut retryable) = match parts.status.as_u16() {
869
- 403 => (ErrorKind::PermissionDenied, false),
870
- 404 => (ErrorKind::NotFound, false),
871
- 304 | 412 => (ErrorKind::ConditionNotMatch, false),
872
- // Service b2 could return 403, show the authorization error
873
- 401 => (ErrorKind::PermissionDenied, true),
874
- 429 => (ErrorKind::RateLimited, true),
875
- 500 | 502 | 503 | 504 => (ErrorKind::Unexpected, true),
876
- _ => (ErrorKind::Unexpected, false),
877
- };
878
-
879
- let (message, b2_err) = serde_json::from_reader::<_, B2Error>(bs.clone().reader())
880
- .map(|b2_err| (format!("{b2_err:?}"), Some(b2_err)))
881
- .unwrap_or_else(|_| (String::from_utf8_lossy(&bs).into_owned(), None));
882
-
883
- if let Some(b2_err) = b2_err {
884
- (kind, retryable) =
885
- parse_b2_error_code(b2_err.code.as_str()).unwrap_or((kind, retryable));
886
- };
887
-
888
- let mut err = Error::new(kind, message);
859
+ /// the error response of b2
860
+ #[derive(Default, Debug, Deserialize)]
861
+ #[allow(dead_code)]
862
+ struct B2Error {
863
+ status: u32,
864
+ code: String,
865
+ message: String,
866
+ }
889
867
 
890
- err = with_error_response_context(err, parts);
868
+ /// Context needed to classify an error from this service.
869
+ #[derive(Clone, Copy, Debug)]
870
+ pub(crate) struct ErrorContext {
871
+ service_operation: ServiceOperation,
872
+ }
891
873
 
892
- if retryable {
893
- err = err.set_temporary();
894
- }
874
+ impl ErrorContext {
875
+ pub(crate) const fn new(service_operation: ServiceOperation) -> Self {
876
+ Self { service_operation }
877
+ }
878
+ }
895
879
 
896
- err
880
+ /// Parse an error response using its service request context.
881
+ pub(crate) fn parse_error(ctx: ErrorContext, resp: Response<Buffer>) -> Error {
882
+ let (parts, body) = resp.into_parts();
883
+ let bs = body.to_bytes();
884
+
885
+ let (mut kind, mut retryable) = match parts.status.as_u16() {
886
+ 403 => (ErrorKind::PermissionDenied, false),
887
+ 404 => (ErrorKind::NotFound, false),
888
+ 304 | 412 => (ErrorKind::ConditionNotMatch, false),
889
+ // Service b2 could return 403, show the authorization error
890
+ 401 => (ErrorKind::PermissionDenied, true),
891
+ 429 => (ErrorKind::RateLimited, true),
892
+ 500 | 502 | 503 | 504 => (ErrorKind::Unexpected, true),
893
+ _ => (ErrorKind::Unexpected, false),
894
+ };
895
+
896
+ let (message, b2_err) = serde_json::from_reader::<_, B2Error>(bs.clone().reader())
897
+ .map(|b2_err| (format!("{b2_err:?}"), Some(b2_err)))
898
+ .unwrap_or_else(|_| (String::from_utf8_lossy(&bs).into_owned(), None));
899
+
900
+ if let Some(b2_err) = b2_err {
901
+ (kind, retryable) = parse_b2_error_code(b2_err.code.as_str()).unwrap_or((kind, retryable));
902
+ };
903
+
904
+ let mut err = Error::new(kind, message);
905
+
906
+ err = err.with_context("service_operation", ctx.service_operation.0);
907
+ err = with_error_response_context(err, parts);
908
+
909
+ if retryable {
910
+ err = err.set_temporary();
897
911
  }
898
912
 
899
- /// Returns the `Error kind` of this code and whether the error is retryable.
900
- pub(crate) fn parse_b2_error_code(code: &str) -> Option<(ErrorKind, bool)> {
901
- match code {
902
- "already_hidden" => Some((ErrorKind::AlreadyExists, false)),
903
- "no_such_file" => Some((ErrorKind::NotFound, false)),
904
- _ => None,
905
- }
913
+ err
914
+ }
915
+
916
+ /// Returns the `Error kind` of this code and whether the error is retryable.
917
+ pub(crate) fn parse_b2_error_code(code: &str) -> Option<(ErrorKind, bool)> {
918
+ match code {
919
+ "already_hidden" => Some((ErrorKind::AlreadyExists, false)),
920
+ "no_such_file" => Some((ErrorKind::NotFound, false)),
921
+ _ => None,
906
922
  }
923
+ }
907
924
 
908
- #[cfg(test)]
909
- mod test {
910
- use http::StatusCode;
925
+ #[cfg(test)]
926
+ mod tests {
927
+ use http::StatusCode;
911
928
 
912
- use super::*;
929
+ use super::*;
913
930
 
914
- #[test]
915
- fn test_parse_b2_error_code() {
916
- let code = "already_hidden";
917
- assert_eq!(
918
- parse_b2_error_code(code),
919
- Some((opendal_core::ErrorKind::AlreadyExists, false))
920
- );
931
+ #[test]
932
+ fn test_parse_b2_error_code() {
933
+ let code = "already_hidden";
934
+ assert_eq!(
935
+ parse_b2_error_code(code),
936
+ Some((opendal_core::ErrorKind::AlreadyExists, false))
937
+ );
921
938
 
922
- let code = "no_such_file";
923
- assert_eq!(
924
- parse_b2_error_code(code),
925
- Some((opendal_core::ErrorKind::NotFound, false))
926
- );
939
+ let code = "no_such_file";
940
+ assert_eq!(
941
+ parse_b2_error_code(code),
942
+ Some((opendal_core::ErrorKind::NotFound, false))
943
+ );
927
944
 
928
- let code = "not_found";
929
- assert_eq!(parse_b2_error_code(code), None);
930
- }
945
+ let code = "not_found";
946
+ assert_eq!(parse_b2_error_code(code), None);
947
+ }
931
948
 
932
- #[tokio::test]
933
- async fn test_parse_error() {
934
- let err_res = vec![
935
- (
936
- r#"{"status": 403, "code": "access_denied", "message":"The provided customer-managed encryption key is wrong."}"#,
937
- ErrorKind::PermissionDenied,
938
- StatusCode::FORBIDDEN,
939
- ),
940
- (
941
- r#"{"status": 404, "code": "not_found", "message":"File is not in B2 Cloud Storage."}"#,
942
- ErrorKind::NotFound,
943
- StatusCode::NOT_FOUND,
944
- ),
945
- (
946
- r#"{"status": 401, "code": "bad_auth_token", "message":"The auth token used is not valid. Call b2_authorize_account again to either get a new one, or an error message describing the problem."}"#,
947
- ErrorKind::PermissionDenied,
948
- StatusCode::UNAUTHORIZED,
949
- ),
950
- ];
951
-
952
- for res in err_res {
953
- let bs = bytes::Bytes::from(res.0);
954
- let body = Buffer::from(bs);
955
- let resp = Response::builder().status(res.2).body(body).unwrap();
956
-
957
- let err = parse_error(resp);
958
-
959
- assert_eq!(err.kind(), res.1);
960
- }
949
+ #[tokio::test]
950
+ async fn test_parse_error() {
951
+ let err_res = vec![
952
+ (
953
+ r#"{"status": 403, "code": "access_denied", "message":"The provided customer-managed encryption key is wrong."}"#,
954
+ ErrorKind::PermissionDenied,
955
+ StatusCode::FORBIDDEN,
956
+ ),
957
+ (
958
+ r#"{"status": 404, "code": "not_found", "message":"File is not in B2 Cloud Storage."}"#,
959
+ ErrorKind::NotFound,
960
+ StatusCode::NOT_FOUND,
961
+ ),
962
+ (
963
+ r#"{"status": 401, "code": "bad_auth_token", "message":"The auth token used is not valid. Call b2_authorize_account again to either get a new one, or an error message describing the problem."}"#,
964
+ ErrorKind::PermissionDenied,
965
+ StatusCode::UNAUTHORIZED,
966
+ ),
967
+ ];
968
+
969
+ for res in err_res {
970
+ let bs = bytes::Bytes::from(res.0);
971
+ let body = Buffer::from(bs);
972
+ let resp = Response::builder().status(res.2).body(body).unwrap();
973
+
974
+ let err = parse_error(ErrorContext::new(ServiceOperation("Test")), resp);
975
+
976
+ assert_eq!(err.kind(), res.1);
961
977
  }
962
978
  }
963
979
  }
964
-
965
- pub(super) use error::*;
@@ -44,7 +44,7 @@ impl oio::OneShotDelete for B2Deleter {
44
44
  match status {
45
45
  StatusCode::OK => Ok(()),
46
46
  _ => {
47
- let err = parse_error(resp);
47
+ let err = parse_error(ErrorContext::new(ServiceOperation("HideFile")), resp);
48
48
  match err.kind() {
49
49
  ErrorKind::NotFound => Ok(()),
50
50
  // Representative deleted
@@ -19,10 +19,10 @@ use std::sync::Arc;
19
19
 
20
20
  use bytes::Buf;
21
21
 
22
- use super::core::B2Core;
23
22
  use super::core::ListFileNamesResponse;
24
23
  use super::core::parse_error;
25
24
  use super::core::parse_file_info;
25
+ use super::core::{B2Core, ErrorContext};
26
26
  use opendal_core::raw::*;
27
27
  use opendal_core::*;
28
28
 
@@ -80,7 +80,10 @@ impl oio::PageList for B2Lister {
80
80
  .await?;
81
81
 
82
82
  if resp.status() != http::StatusCode::OK {
83
- return Err(parse_error(resp));
83
+ return Err(parse_error(
84
+ ErrorContext::new(ServiceOperation("ListFileNames")),
85
+ resp,
86
+ ));
84
87
  }
85
88
 
86
89
  let bs = resp.into_body();
@@ -16,7 +16,7 @@
16
16
  // under the License.
17
17
 
18
18
  use super::backend::*;
19
- use super::core::parse_error;
19
+ use super::core::{ErrorContext, parse_error};
20
20
  use http::Response;
21
21
  use http::StatusCode;
22
22
  use opendal_core::raw::*;
@@ -60,7 +60,10 @@ impl oio::StreamRead for B2Reader {
60
60
  _ => {
61
61
  let (part, mut body) = resp.into_parts();
62
62
  let buf = body.to_buffer().await?;
63
- return Err(parse_error(Response::from_parts(part, buf)));
63
+ return Err(parse_error(
64
+ ErrorContext::new(ServiceOperation("DownloadFileByName")),
65
+ Response::from_parts(part, buf),
66
+ ));
64
67
  }
65
68
  };
66
69
 
@@ -20,11 +20,11 @@ use std::sync::Arc;
20
20
  use bytes::Buf;
21
21
  use http::StatusCode;
22
22
 
23
- use super::core::B2Core;
24
23
  use super::core::StartLargeFileResponse;
25
24
  use super::core::UploadPartResponse;
26
25
  use super::core::UploadResponse;
27
26
  use super::core::parse_error;
27
+ use super::core::{B2Core, ErrorContext};
28
28
  use opendal_core::raw::*;
29
29
  use opendal_core::*;
30
30
 
@@ -49,19 +49,21 @@ impl B2Writer {
49
49
  }
50
50
 
51
51
  pub fn parse_body_into_meta(path: &str, resp: UploadResponse) -> Metadata {
52
- let mut meta = Metadata::new(EntryMode::from_path(path));
52
+ let mut meta = if path.ends_with('/') {
53
+ MetadataBuilder::dir()
54
+ } else {
55
+ MetadataBuilder::file(resp.content_length)
56
+ };
53
57
 
54
58
  if let Some(md5) = resp.content_md5 {
55
- meta.set_content_md5(&md5);
59
+ meta.content_md5(&md5);
56
60
  }
57
61
 
58
62
  if let Some(content_type) = resp.content_type {
59
- meta.set_content_type(&content_type);
63
+ meta.content_type(&content_type);
60
64
  }
61
65
 
62
- meta.set_content_length(resp.content_length);
63
-
64
- meta
66
+ meta.build()
65
67
  }
66
68
  }
67
69
 
@@ -85,7 +87,10 @@ impl oio::MultipartWrite for B2Writer {
85
87
 
86
88
  Ok(meta)
87
89
  }
88
- _ => Err(parse_error(resp)),
90
+ _ => Err(parse_error(
91
+ ErrorContext::new(ServiceOperation("UploadFile")),
92
+ resp,
93
+ )),
89
94
  }
90
95
  }
91
96
 
@@ -106,7 +111,10 @@ impl oio::MultipartWrite for B2Writer {
106
111
 
107
112
  Ok(result.file_id)
108
113
  }
109
- _ => Err(parse_error(resp)),
114
+ _ => Err(parse_error(
115
+ ErrorContext::new(ServiceOperation("StartLargeFile")),
116
+ resp,
117
+ )),
110
118
  }
111
119
  }
112
120
 
@@ -141,7 +149,10 @@ impl oio::MultipartWrite for B2Writer {
141
149
  size: None,
142
150
  })
143
151
  }
144
- _ => Err(parse_error(resp)),
152
+ _ => Err(parse_error(
153
+ ErrorContext::new(ServiceOperation("UploadPart")),
154
+ resp,
155
+ )),
145
156
  }
146
157
  }
147
158
 
@@ -180,7 +191,10 @@ impl oio::MultipartWrite for B2Writer {
180
191
 
181
192
  Ok(meta)
182
193
  }
183
- _ => Err(parse_error(resp)),
194
+ _ => Err(parse_error(
195
+ ErrorContext::new(ServiceOperation("FinishLargeFile")),
196
+ resp,
197
+ )),
184
198
  }
185
199
  }
186
200
 
@@ -189,7 +203,10 @@ impl oio::MultipartWrite for B2Writer {
189
203
  match resp.status() {
190
204
  // b2 returns code 200 if abort succeeds.
191
205
  StatusCode::OK => Ok(()),
192
- _ => Err(parse_error(resp)),
206
+ _ => Err(parse_error(
207
+ ErrorContext::new(ServiceOperation("CancelLargeFile")),
208
+ resp,
209
+ )),
193
210
  }
194
211
  }
195
212
  }