tosnativeclient 1.0.0__tar.gz → 1.0.2__tar.gz

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.

Potentially problematic release.


This version of tosnativeclient might be problematic. Click here for more details.

@@ -472,6 +472,12 @@ version = "0.5.0"
472
472
  source = "registry+https://github.com/rust-lang/crates.io-index"
473
473
  checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
474
474
 
475
+ [[package]]
476
+ name = "hermit-abi"
477
+ version = "0.5.2"
478
+ source = "registry+https://github.com/rust-lang/crates.io-index"
479
+ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
480
+
475
481
  [[package]]
476
482
  name = "hex"
477
483
  version = "0.4.3"
@@ -859,6 +865,16 @@ dependencies = [
859
865
  "autocfg",
860
866
  ]
861
867
 
868
+ [[package]]
869
+ name = "num_cpus"
870
+ version = "1.17.0"
871
+ source = "registry+https://github.com/rust-lang/crates.io-index"
872
+ checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
873
+ dependencies = [
874
+ "hermit-abi",
875
+ "libc",
876
+ ]
877
+
862
878
  [[package]]
863
879
  name = "object"
864
880
  version = "0.36.7"
@@ -1505,13 +1521,14 @@ dependencies = [
1505
1521
 
1506
1522
  [[package]]
1507
1523
  name = "tosnativeclient"
1508
- version = "1.0.0"
1524
+ version = "1.0.2"
1509
1525
  dependencies = [
1510
1526
  "arc-swap",
1511
1527
  "async-channel",
1512
1528
  "async-trait",
1513
1529
  "bytes",
1514
1530
  "futures-util",
1531
+ "num_cpus",
1515
1532
  "pyo3",
1516
1533
  "tokio",
1517
1534
  "tracing",
@@ -1704,6 +1721,8 @@ dependencies = [
1704
1721
  "serde",
1705
1722
  "serde_json",
1706
1723
  "sha2",
1724
+ "tokio",
1725
+ "tokio-util",
1707
1726
  "tracing",
1708
1727
  "tracing-appender",
1709
1728
  "tracing-subscriber",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "tosnativeclient"
3
- version = "1.0.0"
3
+ version = "1.0.2"
4
4
  edition = "2021"
5
5
  publish = false
6
6
  authors = ["xiangshijian"]
@@ -15,7 +15,7 @@ crate-type = ["cdylib"]
15
15
  [dependencies]
16
16
  arc-swap = "1.7.1"
17
17
  pyo3 = { version = "0.25.0", features = ["extension-module"] }
18
- ve-tos-rust-sdk = "2.3.0"
18
+ ve-tos-rust-sdk = { version = "2.3.0", features = ["async-file"] }
19
19
  tracing-appender = "0.2.3"
20
20
  bytes = "1.10.1"
21
21
  tokio = { version = "1.36.0", features = ["rt-multi-thread"] }
@@ -23,3 +23,4 @@ async-trait = "0.1.88"
23
23
  futures-util = "0.3.30"
24
24
  async-channel = "2.3.1"
25
25
  tracing = { version = "0.1.41", features = ["log"] }
26
+ num_cpus = "1.17.0"
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tosnativeclient
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
7
+ Classifier: License :: OSI Approved :: Apache Software License
7
8
  Summary: python native client for tos
8
9
  Author: xiangshijian
9
10
  License: Apache-2.0
@@ -10,6 +10,7 @@ classifiers = [
10
10
  "Programming Language :: Rust",
11
11
  "Programming Language :: Python :: Implementation :: CPython",
12
12
  "Programming Language :: Python :: Implementation :: PyPy",
13
+ "License :: OSI Approved :: Apache Software License",
13
14
  ]
14
15
  dynamic = ["version"]
15
16
  [tool.maturin]
@@ -0,0 +1,25 @@
1
+ from .tosnativeclient import TosClient, ListStream, ListObjectsResult, TosObject, ReadStream, WriteStream, TosError, \
2
+ TosException, TosRawClient, \
3
+ HeadObjectInput, HeadObjectOutput, GetObjectOutput, DeleteObjectInput, DeleteObjectOutput, GetObjectInput, \
4
+ PutObjectFromBufferInput, PutObjectFromFileInput, PutObjectOutput
5
+
6
+ __all__ = [
7
+ 'TosError',
8
+ 'TosException',
9
+ 'TosClient',
10
+ 'ListStream',
11
+ 'ListObjectsResult',
12
+ 'TosObject',
13
+ 'ReadStream',
14
+ 'WriteStream',
15
+ 'TosRawClient',
16
+ 'HeadObjectInput',
17
+ 'HeadObjectOutput',
18
+ 'DeleteObjectInput',
19
+ 'DeleteObjectOutput',
20
+ 'GetObjectInput',
21
+ 'GetObjectOutput',
22
+ 'PutObjectFromBufferInput',
23
+ 'PutObjectFromFileInput',
24
+ 'PutObjectOutput'
25
+ ]
@@ -0,0 +1,211 @@
1
+ from typing import List, Dict
2
+
3
+ from typing import Optional
4
+
5
+
6
+ class TosError(object):
7
+ message: str
8
+ status_code: Optional[int]
9
+ ec: str
10
+ request_id: str
11
+
12
+
13
+ class TosException(Exception):
14
+ args: List[TosError]
15
+
16
+
17
+ class TosObject(object):
18
+ bucket: str
19
+ key: str
20
+ size: int
21
+ etag: str
22
+
23
+
24
+ class ListObjectsResult(object):
25
+ contents: List[TosObject]
26
+ common_prefixes: List[str]
27
+
28
+
29
+ class ListStream(object):
30
+ bucket: str
31
+ prefix: str
32
+ delimiter: str
33
+ max_keys: int
34
+
35
+ def __iter__(self) -> ListStream: ...
36
+
37
+ def __next__(self) -> ListObjectsResult: ...
38
+
39
+ def close(self) -> None: ...
40
+
41
+
42
+ class ReadStream(object):
43
+ bucket: str
44
+ key: str
45
+ size: int
46
+ etag: str
47
+
48
+ def read(self, offset: int, length: int) -> bytes:
49
+ ...
50
+
51
+ def close(self) -> None:
52
+ ...
53
+
54
+
55
+ class WriteStream(object):
56
+ bucket: str
57
+ key: str
58
+ storage_class: Optional[str]
59
+
60
+ def write(self, data: bytes) -> int:
61
+ ...
62
+
63
+ def close(self) -> None:
64
+ ...
65
+
66
+
67
+ class TosClient(object):
68
+ region: str
69
+ endpoint: str
70
+ ak: str
71
+ sk: str
72
+ part_size: int
73
+ max_retry_count: int
74
+ max_prefetch_tasks: int
75
+
76
+ def __init__(self, region: str, endpoint: str, ak: str = '', sk: str = '', part_size: int = 8388608,
77
+ max_retry_count: int = 3, max_prefetch_tasks: int = 3, directives: str = '', directory: str = '',
78
+ file_name_prefix: str = '', shared_prefetch_tasks: int = 20):
79
+ ...
80
+
81
+ def list_objects(self, bucket: str, prefix: str = '', max_keys: int = 1000, delimiter: str = '') -> ListStream:
82
+ ...
83
+
84
+ def head_object(self, bucket: str, key: str) -> TosObject:
85
+ ...
86
+
87
+ def get_object(self, bucket: str, key: str, etag: str, size: int) -> ReadStream:
88
+ ...
89
+
90
+ def put_object(self, bucket: str, key: str, storage_class: Optional[str] = '') -> WriteStream:
91
+ ...
92
+
93
+
94
+ class HeadObjectInput(object):
95
+ bucket: str
96
+ key: str
97
+ version_id: str
98
+
99
+ def __init__(self, bucket: str, key: str, version_id: str = ''):
100
+ ...
101
+
102
+
103
+ class HeadObjectOutput(object):
104
+ request_id: str
105
+ status_code: int
106
+ header: Dict[str, str]
107
+ content_length: int
108
+ etag: str
109
+ version_id: str
110
+ hash_crc64ecma: int
111
+
112
+
113
+ class DeleteObjectInput(object):
114
+ bucket: str
115
+ key: str
116
+ version_id: str
117
+
118
+ def __init__(self, bucket: str, key: str, version_id: str = ''):
119
+ ...
120
+
121
+
122
+ class DeleteObjectOutput(object):
123
+ request_id: str
124
+ status_code: int
125
+ header: Dict[str, str]
126
+ delete_marker: bool
127
+ version_id: str
128
+
129
+
130
+ class GetObjectInput(object):
131
+ bucket: str
132
+ key: str
133
+ version_id: str
134
+ range: str
135
+
136
+ def __init__(self, bucket: str, key: str, version_id: str = '', range: str = ''):
137
+ ...
138
+
139
+
140
+ class GetObjectOutput(object):
141
+ request_id: str
142
+ status_code: int
143
+ header: Dict[str, str]
144
+ content_length: int
145
+ etag: str
146
+ version_id: str
147
+ content_range: str
148
+ hash_crc64ecma: int
149
+
150
+ def read_all(self) -> bytes:
151
+ ...
152
+
153
+ def read(self) -> bytes:
154
+ ...
155
+
156
+
157
+ class PutObjectFromBufferInput(object):
158
+ bucket: str
159
+ key: str
160
+ content: bytes
161
+
162
+ def __init__(self, bucket: str, key: str, content: bytes):
163
+ ...
164
+
165
+
166
+ class PutObjectFromFileInput(object):
167
+ bucket: str
168
+ key: str
169
+ file_path: str
170
+
171
+ def __init__(self, bucket: str, key: str, file_path: str):
172
+ ...
173
+
174
+
175
+ class PutObjectOutput(object):
176
+ request_id: str
177
+ status_code: int
178
+ header: Dict[str, str]
179
+ etag: str
180
+ version_id: str
181
+ hash_crc64ecma: int
182
+
183
+
184
+ class TosRawClient(object):
185
+ region: str
186
+ endpoint: str
187
+ ak: str
188
+ sk: str
189
+ connection_timeout: int
190
+ request_timeout: int
191
+ max_connections: int
192
+ max_retry_count: int
193
+
194
+ def __init__(self, region: str, endpoint: str, ak: str = '', sk: str = '', connection_timeout: int = 10000,
195
+ request_timeout: int = 120000, max_connections: int = 1024, max_retry_count: int = 3):
196
+ ...
197
+
198
+ def head_object(self, input: HeadObjectInput) -> HeadObjectOutput:
199
+ ...
200
+
201
+ def delete_object(self, input: DeleteObjectInput) -> DeleteObjectOutput:
202
+ ...
203
+
204
+ def get_object(self, input: GetObjectInput) -> GetObjectOutput:
205
+ ...
206
+
207
+ def put_object_from_buffer(self, input: PutObjectFromBufferInput) -> PutObjectOutput:
208
+ ...
209
+
210
+ def put_object_from_file(self, input: PutObjectFromFileInput) -> PutObjectOutput:
211
+ ...
@@ -3,6 +3,11 @@ use crate::read_stream::ReadStream;
3
3
  use crate::tos_client::TosClient;
4
4
  use crate::tos_error::{TosError, TosException};
5
5
  use crate::tos_model::{ListObjectsResult, TosObject};
6
+ use crate::tos_raw_client::{
7
+ DeleteObjectInput, DeleteObjectOutput, GetObjectInput, GetObjectOutput, HeadObjectInput,
8
+ HeadObjectOutput, PutObjectFromBufferInput, PutObjectFromFileInput, PutObjectOutput,
9
+ TosRawClient,
10
+ };
6
11
  use crate::write_stream::WriteStream;
7
12
  use pyo3::prelude::*;
8
13
 
@@ -11,11 +16,22 @@ mod read_stream;
11
16
  mod tos_client;
12
17
  mod tos_error;
13
18
  mod tos_model;
19
+ mod tos_raw_client;
14
20
  mod write_stream;
15
21
 
16
22
  #[pymodule]
17
23
  #[pyo3(name = "tosnativeclient")]
18
24
  fn main(m: &Bound<'_, PyModule>) -> PyResult<()> {
25
+ m.add_class::<TosRawClient>()?;
26
+ m.add_class::<HeadObjectInput>()?;
27
+ m.add_class::<HeadObjectOutput>()?;
28
+ m.add_class::<DeleteObjectInput>()?;
29
+ m.add_class::<DeleteObjectOutput>()?;
30
+ m.add_class::<GetObjectInput>()?;
31
+ m.add_class::<GetObjectOutput>()?;
32
+ m.add_class::<PutObjectFromBufferInput>()?;
33
+ m.add_class::<PutObjectFromFileInput>()?;
34
+ m.add_class::<PutObjectOutput>()?;
19
35
  m.add_class::<TosClient>()?;
20
36
  m.add_class::<ListStream>()?;
21
37
  m.add_class::<ListObjectsResult>()?;
@@ -1,5 +1,5 @@
1
1
  use crate::tos_client::InnerTosClient;
2
- use crate::tos_error::{map_error, map_error_from_string};
2
+ use crate::tos_error::{map_error_from_string, map_tos_error};
3
3
  use crate::tos_model::ListObjectsResult;
4
4
  use arc_swap::ArcSwap;
5
5
  use async_channel::Receiver;
@@ -46,14 +46,11 @@ impl ListStream {
46
46
  return Err(map_error_from_string("ListStream is closed"));
47
47
  }
48
48
 
49
- {
50
- let mut pg = slf.paginator.write().unwrap();
51
- if pg.is_none() {
52
- *pg = slf.list_background(slf.py());
53
- }
49
+ let mut pg = slf.paginator.write().unwrap();
50
+ if pg.is_none() {
51
+ *pg = slf.list_background(slf.py());
54
52
  }
55
-
56
- slf.next_page(slf.paginator.read().unwrap().as_ref(), slf.py())
53
+ slf.next_page(pg.as_ref(), slf.py())
57
54
  }
58
55
 
59
56
  pub fn close(&self) {
@@ -100,67 +97,54 @@ impl ListStream {
100
97
  py.allow_threads(|| {
101
98
  self.runtime.spawn(async move {
102
99
  let mut need_break = false;
103
- if input.delimiter() == "/" {
104
- let mut prefixes = Vec::with_capacity(16);
105
- let mut last_page_end = false;
100
+ if input.delimiter() == "" {
106
101
  loop {
107
- if last_page_end {
108
- if prefixes.is_empty() {
109
- let _ = sender
110
- .send((
111
- true,
112
- Err(TosError::TosClientError {
113
- message: "invalid status error".to_string(),
114
- cause: None,
115
- }),
116
- ))
117
- .await;
118
- break;
119
- }
120
-
121
- let prefix = prefixes.remove(0);
122
- input.set_prefix(prefix);
123
- input.set_start_after("");
124
- input.set_continuation_token("");
125
- last_page_end = false;
126
- }
127
102
  let result = client.list_objects_type2(&input).await;
128
103
  if let Ok(ref o) = result {
129
104
  if o.is_truncated() {
130
105
  input.set_continuation_token(o.next_continuation_token());
131
106
  } else {
132
- last_page_end = true;
133
- }
134
-
135
- for cp in o.common_prefixes() {
136
- prefixes.push(cp.prefix().to_string());
107
+ need_break = true;
137
108
  }
138
- need_break = last_page_end && prefixes.is_empty();
139
109
  } else {
140
110
  need_break = true;
141
111
  }
142
-
143
112
  if let Err(_) = sender.send((need_break, result)).await {
144
- need_break = true;
113
+ need_break = true
145
114
  }
146
115
  if need_break {
147
116
  break;
148
117
  }
149
118
  }
150
119
  } else {
120
+ let mut prefixes = Vec::with_capacity(16);
121
+ let mut last_page_end = false;
151
122
  loop {
123
+ if last_page_end {
124
+ let prefix = prefixes.remove(0);
125
+ input.set_prefix(prefix);
126
+ input.set_start_after("");
127
+ input.set_continuation_token("");
128
+ last_page_end = false;
129
+ }
152
130
  let result = client.list_objects_type2(&input).await;
153
131
  if let Ok(ref o) = result {
154
132
  if o.is_truncated() {
155
133
  input.set_continuation_token(o.next_continuation_token());
156
134
  } else {
157
- need_break = true;
135
+ last_page_end = true;
136
+ }
137
+
138
+ for cp in o.common_prefixes() {
139
+ prefixes.push(cp.prefix().to_string());
158
140
  }
141
+ need_break = last_page_end && prefixes.is_empty();
159
142
  } else {
160
143
  need_break = true;
161
144
  }
145
+
162
146
  if let Err(_) = sender.send((need_break, result)).await {
163
- need_break = true
147
+ need_break = true;
164
148
  }
165
149
  if need_break {
166
150
  break;
@@ -169,7 +153,6 @@ impl ListStream {
169
153
  }
170
154
  });
171
155
  });
172
-
173
156
  Some(Paginator {
174
157
  is_end: ArcSwap::new(Arc::new(false)),
175
158
  last_err: ArcSwap::new(Arc::new(None)),
@@ -187,7 +170,7 @@ impl ListStream {
187
170
  None => Ok(None),
188
171
  Some(pg) => {
189
172
  match pg.has_next() {
190
- Err(ex) => return Err(map_error(ex)),
173
+ Err(ex) => return Err(map_tos_error(ex)),
191
174
  Ok(has_next) => {
192
175
  if !has_next {
193
176
  return Ok(None);
@@ -199,7 +182,7 @@ impl ListStream {
199
182
  self.runtime.block_on(async {
200
183
  match pg.next_page().await {
201
184
  Ok(output) => Ok(Some(ListObjectsResult::new(output))),
202
- Err(ex) => Err(map_error(ex)),
185
+ Err(ex) => Err(map_tos_error(ex)),
203
186
  }
204
187
  })
205
188
  })
@@ -1,5 +1,5 @@
1
1
  use crate::tos_client::{InnerTosClient, SharedPrefetchContext};
2
- use crate::tos_error::map_error;
2
+ use crate::tos_error::map_tos_error;
3
3
  use crate::tos_model::TosObject;
4
4
  use async_channel::{Receiver, Sender};
5
5
  use bytes::Bytes;
@@ -52,7 +52,7 @@ impl ReadStream {
52
52
  .py()
53
53
  .allow_threads(|| runtime.block_on(async move { fetcher.read(offset, length).await }))
54
54
  {
55
- Err(ex) => Err(map_error(ex)),
55
+ Err(ex) => Err(map_tos_error(ex)),
56
56
  Ok(result) => match result {
57
57
  None => Ok(None),
58
58
  Some(data) => Ok(Some(PyBytes::new(slf.py(), data.as_ref()))),
@@ -1,6 +1,6 @@
1
1
  use crate::list_stream::ListStream;
2
2
  use crate::read_stream::ReadStream;
3
- use crate::tos_error::map_error;
3
+ use crate::tos_error::map_tos_error;
4
4
  use crate::tos_model::TosObject;
5
5
  use crate::write_stream::WriteStream;
6
6
  use async_trait::async_trait;
@@ -10,8 +10,7 @@ use std::future::Future;
10
10
  use std::sync::atomic::{AtomicIsize, Ordering};
11
11
  use std::sync::Arc;
12
12
  use std::time::Duration;
13
- use tokio::runtime;
14
- use tokio::runtime::{Handle, Runtime};
13
+ use tokio::runtime::{Builder, Handle, Runtime};
15
14
  use tracing_appender::non_blocking::WorkerGuard;
16
15
  use ve_tos_rust_sdk::asynchronous::object::ObjectAPI;
17
16
  use ve_tos_rust_sdk::asynchronous::tos;
@@ -101,7 +100,12 @@ impl TosClient {
101
100
  _guard = Some(init_tracing_log(directives, directory, file_name_prefix));
102
101
  }
103
102
 
104
- let runtime = Arc::new(runtime::Builder::new_multi_thread().enable_all().build()?);
103
+ let logical_cores = num_cpus::get();
104
+ let mut builder = Builder::new_multi_thread();
105
+ if logical_cores > 0 {
106
+ builder.worker_threads(logical_cores);
107
+ }
108
+ let runtime = Arc::new(builder.enable_all().build()?);
105
109
  let mut clients = Vec::with_capacity(2);
106
110
  for _ in 0..2 {
107
111
  match tos::builder()
@@ -118,7 +122,7 @@ impl TosClient {
118
122
  })
119
123
  .build()
120
124
  {
121
- Err(ex) => return Err(map_error(ex)),
125
+ Err(ex) => return Err(map_tos_error(ex)),
122
126
  Ok(client) => {
123
127
  clients.push(client);
124
128
  }
@@ -165,7 +169,7 @@ impl TosClient {
165
169
  slf.py().allow_threads(|| {
166
170
  runtime.block_on(async move {
167
171
  match client.head_object(&input).await {
168
- Err(ex) => Err(map_error(ex)),
172
+ Err(ex) => Err(map_tos_error(ex)),
169
173
  Ok(output) => Ok(TosObject::new(input.bucket(), input.key(), output)),
170
174
  }
171
175
  })
@@ -188,22 +192,23 @@ impl TosClient {
188
192
 
189
193
  #[pyo3(signature = (bucket, key, storage_class=None))]
190
194
  pub fn put_object(
191
- &self,
195
+ slf: PyRef<'_, Self>,
192
196
  bucket: String,
193
197
  key: String,
194
198
  storage_class: Option<String>,
195
199
  ) -> PyResult<WriteStream> {
196
- match WriteStream::new(
197
- self.wclient.clone(),
198
- self.runtime.clone(),
199
- bucket,
200
- key,
201
- storage_class,
202
- self.part_size,
203
- ) {
204
- Err(ex) => Err(map_error(ex)),
205
- Ok(ws) => Ok(ws),
206
- }
200
+ let client = slf.wclient.clone();
201
+ let runtime = slf.runtime.clone();
202
+ let part_size = slf.part_size;
203
+ slf.py().allow_threads(|| {
204
+ runtime.clone().block_on(async move {
205
+ match WriteStream::new(client, runtime, bucket, key, storage_class, part_size).await
206
+ {
207
+ Err(ex) => Err(map_tos_error(ex)),
208
+ Ok(ws) => Ok(ws),
209
+ }
210
+ })
211
+ })
207
212
  }
208
213
  }
209
214
 
@@ -1,5 +1,6 @@
1
1
  use pyo3::exceptions::PyException;
2
2
  use pyo3::{create_exception, pyclass, pymethods, PyErr};
3
+ use std::error::Error;
3
4
 
4
5
  #[pyclass]
5
6
  #[derive(Clone)]
@@ -55,7 +56,11 @@ pub(crate) fn map_error_from_string(message: impl Into<String>) -> PyErr {
55
56
  ))
56
57
  }
57
58
 
58
- pub(crate) fn map_error(err: ve_tos_rust_sdk::error::TosError) -> PyErr {
59
+ pub(crate) fn map_error(err: impl Error) -> PyErr {
60
+ PyErr::new::<TosException, _>(TosError::message(err.to_string()))
61
+ }
62
+
63
+ pub(crate) fn map_tos_error(err: ve_tos_rust_sdk::error::TosError) -> PyErr {
59
64
  match err {
60
65
  ve_tos_rust_sdk::error::TosError::TosClientError { message, .. } => {
61
66
  PyErr::new::<TosException, _>(TosError::message(message))
@@ -0,0 +1,436 @@
1
+ use crate::tos_client::{InnerTosClient, TokioRuntime};
2
+ use crate::tos_error::{map_error, map_tos_error};
3
+ use bytes::Buf;
4
+ use futures_util::StreamExt;
5
+ use pyo3::{pyclass, pymethods, PyRef, PyRefMut, PyResult};
6
+ use std::collections::HashMap;
7
+ use std::sync::Arc;
8
+ use tokio::runtime;
9
+ use tokio::runtime::Runtime;
10
+ use tokio::sync::Mutex;
11
+ use ve_tos_rust_sdk::asynchronous::object::{ObjectAPI, ObjectContent};
12
+ use ve_tos_rust_sdk::asynchronous::tos;
13
+
14
+ #[pyclass(name = "TosRawClient")]
15
+ pub struct TosRawClient {
16
+ client: Arc<InnerTosClient>,
17
+ runtime: Arc<Runtime>,
18
+ #[pyo3(get)]
19
+ region: String,
20
+ #[pyo3(get)]
21
+ endpoint: String,
22
+ #[pyo3(get)]
23
+ ak: String,
24
+ #[pyo3(get)]
25
+ sk: String,
26
+ #[pyo3(get)]
27
+ connection_timeout: isize,
28
+ #[pyo3(get)]
29
+ request_timeout: isize,
30
+ #[pyo3(get)]
31
+ max_connections: isize,
32
+ #[pyo3(get)]
33
+ max_retry_count: isize,
34
+ }
35
+
36
+ #[pymethods]
37
+ impl TosRawClient {
38
+ #[new]
39
+ #[pyo3(signature = (region, endpoint, ak="", sk="", connection_timeout=10000, request_timeout=120000, max_connections=1024, max_retry_count=3)
40
+ )]
41
+ pub fn new(
42
+ region: &str,
43
+ endpoint: &str,
44
+ ak: &str,
45
+ sk: &str,
46
+ connection_timeout: isize,
47
+ request_timeout: isize,
48
+ max_connections: isize,
49
+ max_retry_count: isize,
50
+ ) -> PyResult<Self> {
51
+ let runtime = Arc::new(runtime::Builder::new_multi_thread().enable_all().build()?);
52
+ match tos::builder()
53
+ .connection_timeout(connection_timeout)
54
+ .request_timeout(request_timeout)
55
+ .max_connections(max_connections)
56
+ .max_retry_count(max_retry_count)
57
+ .ak(ak)
58
+ .sk(sk)
59
+ .region(region)
60
+ .endpoint(endpoint)
61
+ .async_sleeper(TokioRuntime {
62
+ runtime: Some(runtime.clone()),
63
+ })
64
+ .build()
65
+ {
66
+ Err(ex) => Err(map_tos_error(ex)),
67
+ Ok(client) => Ok(Self {
68
+ client: Arc::new(client),
69
+ runtime,
70
+ region: region.to_string(),
71
+ endpoint: endpoint.to_string(),
72
+ ak: ak.to_string(),
73
+ sk: sk.to_string(),
74
+ connection_timeout,
75
+ request_timeout,
76
+ max_connections,
77
+ max_retry_count,
78
+ }),
79
+ }
80
+ }
81
+ pub fn head_object<'py>(
82
+ slf: PyRef<'_, Self>,
83
+ input: &HeadObjectInput,
84
+ ) -> PyResult<HeadObjectOutput> {
85
+ let input = ve_tos_rust_sdk::object::HeadObjectInput::new_with_version_id(
86
+ &input.bucket,
87
+ &input.key,
88
+ &input.version_id,
89
+ );
90
+ let client = slf.client.clone();
91
+ let runtime = slf.runtime.clone();
92
+ slf.py().allow_threads(|| {
93
+ runtime.block_on(async move {
94
+ match client.head_object(&input).await {
95
+ Err(ex) => Err(map_tos_error(ex)),
96
+ Ok(output) => Ok(HeadObjectOutput {
97
+ request_id: output.request_id().to_string(),
98
+ status_code: output.status_code(),
99
+ header: output.header().clone(),
100
+ content_length: output.content_length(),
101
+ etag: output.etag().to_string(),
102
+ version_id: output.version_id().to_string(),
103
+ hash_crc64ecma: output.hash_crc64ecma(),
104
+ }),
105
+ }
106
+ })
107
+ })
108
+ }
109
+
110
+ pub fn delete_object(
111
+ slf: PyRef<'_, Self>,
112
+ input: &DeleteObjectInput,
113
+ ) -> PyResult<DeleteObjectOutput> {
114
+ let input = ve_tos_rust_sdk::object::DeleteObjectInput::new_with_version_id(
115
+ &input.bucket,
116
+ &input.key,
117
+ &input.version_id,
118
+ );
119
+ let client = slf.client.clone();
120
+ let runtime = slf.runtime.clone();
121
+ slf.py().allow_threads(|| {
122
+ runtime.block_on(async move {
123
+ match client.delete_object(&input).await {
124
+ Err(ex) => Err(map_tos_error(ex)),
125
+ Ok(output) => Ok(DeleteObjectOutput {
126
+ request_id: output.request_id().to_string(),
127
+ status_code: output.status_code(),
128
+ header: output.header().clone(),
129
+ delete_marker: output.delete_marker(),
130
+ version_id: output.version_id().to_string(),
131
+ }),
132
+ }
133
+ })
134
+ })
135
+ }
136
+
137
+ pub fn get_object(slf: PyRef<'_, Self>, input: &GetObjectInput) -> PyResult<GetObjectOutput> {
138
+ let mut rinput = ve_tos_rust_sdk::object::GetObjectInput::new_with_version_id(
139
+ &input.bucket,
140
+ &input.key,
141
+ &input.version_id,
142
+ );
143
+ rinput.set_range(&input.range);
144
+
145
+ let client = slf.client.clone();
146
+ let runtime = slf.runtime.clone();
147
+ slf.py().allow_threads(|| {
148
+ runtime.clone().block_on(async move {
149
+ match client.get_object(&rinput).await {
150
+ Err(ex) => Err(map_tos_error(ex)),
151
+ Ok(output) => Ok(GetObjectOutput {
152
+ request_id: output.request_id().to_string(),
153
+ status_code: output.status_code(),
154
+ header: output.header().clone(),
155
+ content_length: output.content_length(),
156
+ etag: output.etag().to_string(),
157
+ version_id: output.version_id().to_string(),
158
+ content_range: output.content_range().to_string(),
159
+ hash_crc64ecma: output.hash_crc64ecma(),
160
+ output: Arc::new(Mutex::new(output)),
161
+ runtime: runtime.clone(),
162
+ }),
163
+ }
164
+ })
165
+ })
166
+ }
167
+
168
+ pub fn put_object_from_buffer(
169
+ slf: PyRef<'_, Self>,
170
+ input: &PutObjectFromBufferInput,
171
+ ) -> PyResult<PutObjectOutput> {
172
+ let mut rinput =
173
+ ve_tos_rust_sdk::object::PutObjectFromBufferInput::new(&input.bucket, &input.key);
174
+ if input.content.len() > 0 {
175
+ rinput.set_content(input.content.as_slice());
176
+ }
177
+ let client = slf.client.clone();
178
+ let runtime = slf.runtime.clone();
179
+ slf.py().allow_threads(|| {
180
+ runtime.clone().block_on(async move {
181
+ match client.put_object_from_buffer(&rinput).await {
182
+ Err(ex) => Err(map_tos_error(ex)),
183
+ Ok(output) => Ok(PutObjectOutput {
184
+ request_id: output.request_id().to_string(),
185
+ status_code: output.status_code(),
186
+ header: output.header().clone(),
187
+ etag: output.etag().to_string(),
188
+ version_id: output.version_id().to_string(),
189
+ hash_crc64ecma: output.hash_crc64ecma(),
190
+ }),
191
+ }
192
+ })
193
+ })
194
+ }
195
+
196
+ pub fn put_object_from_file(
197
+ slf: PyRef<'_, Self>,
198
+ input: &PutObjectFromFileInput,
199
+ ) -> PyResult<PutObjectOutput> {
200
+ let mut rinput =
201
+ ve_tos_rust_sdk::object::PutObjectFromFileInput::new(&input.bucket, &input.key);
202
+ rinput.set_file_path(&input.file_path);
203
+ let client = slf.client.clone();
204
+ let runtime = slf.runtime.clone();
205
+ slf.py().allow_threads(|| {
206
+ runtime.clone().block_on(async move {
207
+ match client.put_object_from_file(&rinput).await {
208
+ Err(ex) => Err(map_tos_error(ex)),
209
+ Ok(output) => Ok(PutObjectOutput {
210
+ request_id: output.request_id().to_string(),
211
+ status_code: output.status_code(),
212
+ header: output.header().clone(),
213
+ etag: output.etag().to_string(),
214
+ version_id: output.version_id().to_string(),
215
+ hash_crc64ecma: output.hash_crc64ecma(),
216
+ }),
217
+ }
218
+ })
219
+ })
220
+ }
221
+ }
222
+
223
+ #[pyclass(name = "HeadObjectInput")]
224
+ pub struct HeadObjectInput {
225
+ #[pyo3(get, set)]
226
+ pub(crate) bucket: String,
227
+ #[pyo3(get, set)]
228
+ pub(crate) key: String,
229
+ #[pyo3(get, set)]
230
+ pub(crate) version_id: String,
231
+ }
232
+
233
+ #[pymethods]
234
+ impl HeadObjectInput {
235
+ #[new]
236
+ #[pyo3(signature = (bucket, key, version_id = ""))]
237
+ pub fn new(bucket: &str, key: &str, version_id: &str) -> PyResult<Self> {
238
+ Ok(Self {
239
+ bucket: bucket.to_string(),
240
+ key: key.to_string(),
241
+ version_id: version_id.to_string(),
242
+ })
243
+ }
244
+ }
245
+
246
+ #[pyclass(name = "HeadObjectOutput")]
247
+ pub struct HeadObjectOutput {
248
+ #[pyo3(get)]
249
+ pub(crate) request_id: String,
250
+ #[pyo3(get)]
251
+ pub(crate) status_code: isize,
252
+ #[pyo3(get)]
253
+ pub(crate) header: HashMap<String, String>,
254
+ #[pyo3(get)]
255
+ pub(crate) content_length: i64,
256
+ #[pyo3(get)]
257
+ pub(crate) etag: String,
258
+ #[pyo3(get)]
259
+ pub(crate) version_id: String,
260
+ #[pyo3(get)]
261
+ pub(crate) hash_crc64ecma: u64,
262
+ }
263
+
264
+ #[pyclass(name = "DeleteObjectInput")]
265
+ pub struct DeleteObjectInput {
266
+ #[pyo3(get, set)]
267
+ pub(crate) bucket: String,
268
+ #[pyo3(get, set)]
269
+ pub(crate) key: String,
270
+ #[pyo3(get, set)]
271
+ pub(crate) version_id: String,
272
+ }
273
+
274
+ #[pymethods]
275
+ impl DeleteObjectInput {
276
+ #[new]
277
+ #[pyo3(signature = (bucket, key, version_id = ""))]
278
+ pub fn new(bucket: &str, key: &str, version_id: &str) -> PyResult<Self> {
279
+ Ok(Self {
280
+ bucket: bucket.to_string(),
281
+ key: key.to_string(),
282
+ version_id: version_id.to_string(),
283
+ })
284
+ }
285
+ }
286
+
287
+ #[pyclass(name = "DeleteObjectOutput")]
288
+ pub struct DeleteObjectOutput {
289
+ #[pyo3(get)]
290
+ pub(crate) request_id: String,
291
+ #[pyo3(get)]
292
+ pub(crate) status_code: isize,
293
+ #[pyo3(get)]
294
+ pub(crate) header: HashMap<String, String>,
295
+ #[pyo3(get)]
296
+ pub(crate) delete_marker: bool,
297
+ #[pyo3(get)]
298
+ pub(crate) version_id: String,
299
+ }
300
+ #[pyclass(name = "GetObjectInput")]
301
+ pub struct GetObjectInput {
302
+ #[pyo3(get, set)]
303
+ pub(crate) bucket: String,
304
+ #[pyo3(get, set)]
305
+ pub(crate) key: String,
306
+ #[pyo3(get, set)]
307
+ pub(crate) version_id: String,
308
+ #[pyo3(get, set)]
309
+ pub(crate) range: String,
310
+ }
311
+
312
+ #[pymethods]
313
+ impl GetObjectInput {
314
+ #[new]
315
+ #[pyo3(signature = (bucket, key, version_id = "", range = ""))]
316
+ pub fn new(bucket: &str, key: &str, version_id: &str, range: &str) -> PyResult<Self> {
317
+ Ok(Self {
318
+ bucket: bucket.to_string(),
319
+ key: key.to_string(),
320
+ version_id: version_id.to_string(),
321
+ range: range.to_string(),
322
+ })
323
+ }
324
+ }
325
+
326
+ #[pyclass(name = "GetObjectOutput")]
327
+ pub struct GetObjectOutput {
328
+ #[pyo3(get)]
329
+ pub(crate) request_id: String,
330
+ #[pyo3(get)]
331
+ pub(crate) status_code: isize,
332
+ #[pyo3(get)]
333
+ pub(crate) header: HashMap<String, String>,
334
+ #[pyo3(get)]
335
+ pub(crate) content_length: i64,
336
+ #[pyo3(get)]
337
+ pub(crate) etag: String,
338
+ #[pyo3(get)]
339
+ pub(crate) version_id: String,
340
+ #[pyo3(get)]
341
+ pub(crate) content_range: String,
342
+ #[pyo3(get)]
343
+ pub(crate) hash_crc64ecma: u64,
344
+ output: Arc<Mutex<ve_tos_rust_sdk::object::GetObjectOutput>>,
345
+ runtime: Arc<Runtime>,
346
+ }
347
+
348
+ #[pymethods]
349
+ impl GetObjectOutput {
350
+ pub fn read_all(slf: PyRefMut<'_, Self>) -> PyResult<Option<Vec<u8>>> {
351
+ let runtime = slf.runtime.clone();
352
+ let output = slf.output.clone();
353
+ runtime.block_on(async move {
354
+ match output.lock().await.read_all().await {
355
+ Err(ex) => Err(map_tos_error(ex)),
356
+ Ok(buf) => Ok(Some(buf)),
357
+ }
358
+ })
359
+ }
360
+
361
+ pub fn read(slf: PyRefMut<'_, Self>) -> PyResult<Option<Vec<u8>>> {
362
+ let runtime = slf.runtime.clone();
363
+ let output = slf.output.clone();
364
+ runtime.block_on(async move {
365
+ match output.lock().await.next().await {
366
+ None => Ok(None),
367
+ Some(result) => match result {
368
+ Err(ex) => Err(map_error(ex)),
369
+ Ok(buf) => Ok(Some(buf.chunk().to_vec())),
370
+ },
371
+ }
372
+ })
373
+ }
374
+ }
375
+
376
+ #[pyclass(name = "PutObjectFromBufferInput")]
377
+ pub struct PutObjectFromBufferInput {
378
+ #[pyo3(get, set)]
379
+ pub(crate) bucket: String,
380
+ #[pyo3(get, set)]
381
+ pub(crate) key: String,
382
+ #[pyo3(get, set)]
383
+ pub(crate) content: Vec<u8>,
384
+ }
385
+
386
+ #[pymethods]
387
+ impl PutObjectFromBufferInput {
388
+ #[new]
389
+ #[pyo3(signature = (bucket, key, content))]
390
+ pub fn new(bucket: &str, key: &str, content: &[u8]) -> PyResult<Self> {
391
+ Ok(Self {
392
+ bucket: bucket.to_string(),
393
+ key: key.to_string(),
394
+ content: content.to_vec(),
395
+ })
396
+ }
397
+ }
398
+
399
+ #[pyclass(name = "PutObjectFromFileInput")]
400
+ pub struct PutObjectFromFileInput {
401
+ #[pyo3(get, set)]
402
+ pub(crate) bucket: String,
403
+ #[pyo3(get, set)]
404
+ pub(crate) key: String,
405
+ #[pyo3(get, set)]
406
+ pub(crate) file_path: String,
407
+ }
408
+
409
+ #[pymethods]
410
+ impl PutObjectFromFileInput {
411
+ #[new]
412
+ #[pyo3(signature = (bucket, key, file_path))]
413
+ pub fn new(bucket: &str, key: &str, file_path: &str) -> PyResult<Self> {
414
+ Ok(Self {
415
+ bucket: bucket.to_string(),
416
+ key: key.to_string(),
417
+ file_path: file_path.to_string(),
418
+ })
419
+ }
420
+ }
421
+
422
+ #[pyclass(name = "PutObjectOutput")]
423
+ pub struct PutObjectOutput {
424
+ #[pyo3(get)]
425
+ pub(crate) request_id: String,
426
+ #[pyo3(get)]
427
+ pub(crate) status_code: isize,
428
+ #[pyo3(get)]
429
+ pub(crate) header: HashMap<String, String>,
430
+ #[pyo3(get)]
431
+ pub(crate) etag: String,
432
+ #[pyo3(get)]
433
+ pub(crate) version_id: String,
434
+ #[pyo3(get)]
435
+ pub(crate) hash_crc64ecma: u64,
436
+ }
@@ -1,5 +1,5 @@
1
1
  use crate::tos_client::InnerTosClient;
2
- use crate::tos_error::map_error;
2
+ use crate::tos_error::map_tos_error;
3
3
  use async_channel::{Receiver, Sender};
4
4
  use futures_util::future::join_all;
5
5
  use pyo3::{pyclass, pymethods, PyRefMut, PyResult};
@@ -52,7 +52,7 @@ impl WriteStream {
52
52
  .py()
53
53
  .allow_threads(|| runtime.block_on(async move { writer.write(data, offset).await }))
54
54
  {
55
- Err(ex) => Err(map_error(ex)),
55
+ Err(ex) => Err(map_tos_error(ex)),
56
56
  Ok(written) => {
57
57
  slf.offset += written;
58
58
  Ok(written)
@@ -67,14 +67,14 @@ impl WriteStream {
67
67
  .py()
68
68
  .allow_threads(|| runtime.block_on(async move { writer.release().await }))
69
69
  {
70
- Err(ex) => Err(map_error(ex)),
70
+ Err(ex) => Err(map_tos_error(ex)),
71
71
  Ok(_) => Ok(()),
72
72
  }
73
73
  }
74
74
  }
75
75
 
76
76
  impl WriteStream {
77
- pub(crate) fn new(
77
+ pub(crate) async fn new(
78
78
  client: Arc<InnerTosClient>,
79
79
  runtime: Arc<Runtime>,
80
80
  bucket: String,
@@ -93,10 +93,8 @@ impl WriteStream {
93
93
  let _key = key.clone();
94
94
  let _storage_class = storage_class.clone();
95
95
 
96
- let object_writer = runtime.block_on(async move {
97
- ObjectWriter::new(client, _bucket, _key, _storage_class, part_size).await
98
- })?;
99
-
96
+ let object_writer =
97
+ ObjectWriter::new(client, _bucket, _key, _storage_class, part_size).await?;
100
98
  Ok(Self {
101
99
  object_writer: Arc::new(object_writer),
102
100
  runtime,
@@ -1,4 +0,0 @@
1
- from .tosnativeclient import TosClient, ListStream, ListObjectsResult, TosObject, TosError, TosException
2
-
3
- __all__ = ['TosClient', 'ListStream', 'ListObjectsResult', 'TosObject', 'TosError',
4
- 'TosException']
@@ -1,91 +0,0 @@
1
- from typing import List
2
-
3
- from typing import Optional
4
-
5
-
6
- class TosClient(object):
7
- region: str
8
- endpoint: str
9
- ak: str
10
- sk: str
11
- part_size: int
12
- max_retry_count: int
13
- max_prefetch_tasks: int
14
-
15
- def __init__(self, region: str, endpoint: str, ak: str = '', sk: str = '', part_size: int = 8388608,
16
- max_retry_count: int = 3, max_prefetch_tasks: int = 3, directives: str = '', directory: str = '',
17
- file_name_prefix: str = '', shared_prefetch_tasks: int = 20):
18
- ...
19
-
20
- def list_objects(self, bucket: str, prefix: str = '', max_keys: int = 1000, delimiter: str = '') -> ListStream:
21
- ...
22
-
23
- def head_object(self, bucket: str, key: str) -> TosObject:
24
- ...
25
-
26
- def get_object(self, bucket: str, key: str, etag: str, size: int) -> ReadStream:
27
- ...
28
-
29
- def put_object(self, bucket: str, key: str, storage_class: str = '') -> WriteStream:
30
- ...
31
-
32
-
33
- class ListStream(object):
34
- bucket: str
35
- prefix: str
36
- delimiter: str
37
- max_keys: int
38
-
39
- def __iter__(self) -> ListStream: ...
40
-
41
- def __next__(self) -> ListObjectsResult: ...
42
-
43
- def close(self) -> None: ...
44
-
45
-
46
- class ListObjectsResult(object):
47
- contents: List[TosObject]
48
- common_prefixes: List[str]
49
-
50
-
51
- class TosObject(object):
52
- bucket: str
53
- key: str
54
- size: int
55
- etag: str
56
-
57
-
58
- class ReadStream(object):
59
- bucket: str
60
- key: str
61
- size: int
62
- etag: str
63
-
64
- def read(self, offset: int, length: int) -> bytes:
65
- ...
66
-
67
- def close(self) -> None:
68
- ...
69
-
70
-
71
- class WriteStream(object):
72
- bucket: str
73
- key: str
74
- storage_class: Optional[str]
75
-
76
- def write(self, data: bytes) -> int:
77
- ...
78
-
79
- def close(self) -> None:
80
- ...
81
-
82
-
83
- class TosError(object):
84
- message: str
85
- status_code: Optional[int]
86
- ec: str
87
- request_id: str
88
-
89
-
90
- class TosException(Exception):
91
- args: List[TosError]