1#[cfg(feature = "_hidden")]
2use crate::client::Connect;
3use crate::{
4 api::{AccountClient, BaseClient, BasinClient},
5 producer::{Producer, ProducerConfig},
6 session::{self, AppendSession, AppendSessionConfig, ReadSession},
7 types::{
8 AccessTokenId, AccessTokenInfo, AppendAck, AppendInput, BasinConfig, BasinInfo, BasinName,
9 CreateBasinInput, CreateStreamInput, DeleteBasinInput, DeleteStreamInput, EncryptionKey,
10 EnsureBasinInput, EnsureOutput, EnsureStreamInput, GetAccountMetricsInput,
11 GetBasinMetricsInput, GetStreamMetricsInput, IssueAccessTokenInput, ListAccessTokensInput,
12 ListAllAccessTokensInput, ListAllBasinsInput, ListAllStreamsInput, ListBasinsInput,
13 ListStreamsInput, LocationInfo, LocationName, Metric, Page, ReadBatch, ReadInput,
14 ReconfigureBasinInput, ReconfigureStreamInput, S2Config, S2Error, StreamConfig, StreamInfo,
15 StreamName, StreamPosition, Streaming,
16 },
17};
18
19#[derive(Debug, Clone)]
20pub struct S2 {
22 client: AccountClient,
23}
24
25impl S2 {
26 pub fn new(config: S2Config) -> Result<Self, S2Error> {
28 let base_client = BaseClient::init(&config)?;
29 Ok(Self {
30 client: AccountClient::init(config, base_client),
31 })
32 }
33
34 #[doc(hidden)]
35 #[cfg(feature = "_hidden")]
36 pub fn new_with_connector<C>(config: S2Config, connector: C) -> Result<Self, S2Error>
37 where
38 C: Connect + Clone + Send + Sync + 'static,
39 {
40 let base_client = BaseClient::init_with_connector(&config, connector)?;
41 Ok(Self {
42 client: AccountClient::init(config, base_client),
43 })
44 }
45
46 pub fn basin(&self, name: BasinName) -> S2Basin {
48 S2Basin {
49 client: self.client.basin_client(name),
50 }
51 }
52
53 pub async fn list_basins(&self, input: ListBasinsInput) -> Result<Page<BasinInfo>, S2Error> {
57 let response = self.client.list_basins(input.into()).await?;
58 Ok(Page::new(
59 response
60 .basins
61 .into_iter()
62 .map(TryInto::try_into)
63 .collect::<Result<Vec<_>, _>>()?,
64 response.has_more,
65 ))
66 }
67
68 pub fn list_all_basins(&self, input: ListAllBasinsInput) -> Streaming<BasinInfo> {
70 let s2 = self.clone();
71 let prefix = input.prefix;
72 let start_after = input.start_after;
73 let include_deleted = input.include_deleted;
74 let mut input = ListBasinsInput::new()
75 .with_prefix(prefix)
76 .with_start_after(start_after);
77 Box::pin(async_stream::try_stream! {
78 loop {
79 let page = s2.list_basins(input.clone()).await?;
80 let start_after = page.values.last().map(|info| info.name.clone().into());
81
82 for info in page.values {
83 if !include_deleted && info.deleted_at.is_some() {
84 continue;
85 }
86 yield info;
87 }
88
89 if page.has_more && let Some(start_after) = start_after {
90 input = input.with_start_after(start_after);
91 } else {
92 break;
93 }
94 }
95 })
96 }
97
98 pub async fn create_basin(&self, input: CreateBasinInput) -> Result<BasinInfo, S2Error> {
100 let (request, idempotency_token) = input.into();
101 let info = self.client.create_basin(request, idempotency_token).await?;
102 Ok(info.try_into()?)
103 }
104
105 pub async fn ensure_basin(
113 &self,
114 input: EnsureBasinInput,
115 ) -> Result<EnsureOutput<BasinInfo>, S2Error> {
116 let (name, request) = input.into();
117 Ok(self
118 .client
119 .ensure_basin(name, request)
120 .await?
121 .try_map(BasinInfo::try_from)?
122 .into())
123 }
124
125 pub async fn get_basin_config(&self, name: BasinName) -> Result<BasinConfig, S2Error> {
127 let config = self.client.get_basin_config(name).await?;
128 Ok(config.into())
129 }
130
131 #[doc(hidden)]
132 #[cfg(feature = "_hidden")]
133 pub async fn get_basin_config_api(
134 &self,
135 name: BasinName,
136 ) -> Result<s2_api::v1::config::BasinConfig, S2Error> {
137 Ok(self.client.get_basin_config(name).await?)
138 }
139
140 pub async fn delete_basin(&self, input: DeleteBasinInput) -> Result<(), S2Error> {
142 Ok(self
143 .client
144 .delete_basin(input.name, input.ignore_not_found)
145 .await?)
146 }
147
148 pub async fn reconfigure_basin(
150 &self,
151 input: ReconfigureBasinInput,
152 ) -> Result<BasinConfig, S2Error> {
153 let config = self
154 .client
155 .reconfigure_basin(input.name, input.config.into())
156 .await?;
157 Ok(config.into())
158 }
159
160 pub async fn list_access_tokens(
164 &self,
165 input: ListAccessTokensInput,
166 ) -> Result<Page<AccessTokenInfo>, S2Error> {
167 let response = self.client.list_access_tokens(input.into()).await?;
168 Ok(Page::new(
169 response
170 .access_tokens
171 .into_iter()
172 .map(TryInto::try_into)
173 .collect::<Result<Vec<_>, _>>()?,
174 response.has_more,
175 ))
176 }
177
178 #[doc(hidden)]
179 #[cfg(feature = "_hidden")]
180 pub async fn list_access_tokens_api(
181 &self,
182 input: ListAccessTokensInput,
183 ) -> Result<s2_api::v1::access::ListAccessTokensResponse, S2Error> {
184 Ok(self.client.list_access_tokens(input.into()).await?)
185 }
186
187 pub fn list_all_access_tokens(
189 &self,
190 input: ListAllAccessTokensInput,
191 ) -> Streaming<AccessTokenInfo> {
192 let s2 = self.clone();
193 let prefix = input.prefix;
194 let start_after = input.start_after;
195 let mut input = ListAccessTokensInput::new()
196 .with_prefix(prefix)
197 .with_start_after(start_after);
198 Box::pin(async_stream::try_stream! {
199 loop {
200 let page = s2.list_access_tokens(input.clone()).await?;
201
202 let start_after = page.values.last().map(|info| info.id.clone().into());
203 for info in page.values {
204 yield info;
205 }
206
207 if page.has_more && let Some(start_after) = start_after {
208 input = input.with_start_after(start_after);
209 } else {
210 break;
211 }
212 }
213 })
214 }
215
216 pub async fn issue_access_token(
218 &self,
219 input: IssueAccessTokenInput,
220 ) -> Result<String, S2Error> {
221 let response = self.client.issue_access_token(input.into()).await?;
222 Ok(response.access_token)
223 }
224
225 pub async fn revoke_access_token(&self, id: AccessTokenId) -> Result<(), S2Error> {
227 Ok(self.client.revoke_access_token(id).await?)
228 }
229
230 pub async fn list_locations(&self) -> Result<Vec<LocationInfo>, S2Error> {
232 let response = self.client.list_locations().await?;
233 Ok(response.into_iter().map(Into::into).collect())
234 }
235
236 pub async fn get_default_location(&self) -> Result<LocationInfo, S2Error> {
238 Ok(self.client.get_default_location().await?.into())
239 }
240
241 pub async fn set_default_location(
243 &self,
244 location: LocationName,
245 ) -> Result<LocationInfo, S2Error> {
246 Ok(self.client.set_default_location(location).await?.into())
247 }
248
249 pub async fn get_account_metrics(
251 &self,
252 input: GetAccountMetricsInput,
253 ) -> Result<Vec<Metric>, S2Error> {
254 let response = self.client.get_account_metrics(input.into()).await?;
255 Ok(response.values.into_iter().map(Into::into).collect())
256 }
257
258 pub async fn get_basin_metrics(
260 &self,
261 input: GetBasinMetricsInput,
262 ) -> Result<Vec<Metric>, S2Error> {
263 let (name, request) = input.into();
264 let response = self.client.get_basin_metrics(name, request).await?;
265 Ok(response.values.into_iter().map(Into::into).collect())
266 }
267
268 pub async fn get_stream_metrics(
270 &self,
271 input: GetStreamMetricsInput,
272 ) -> Result<Vec<Metric>, S2Error> {
273 let (basin_name, stream_name, request) = input.into();
274 let response = self
275 .client
276 .get_stream_metrics(basin_name, stream_name, request)
277 .await?;
278 Ok(response.values.into_iter().map(Into::into).collect())
279 }
280}
281
282#[derive(Debug, Clone)]
283pub struct S2Basin {
287 client: BasinClient,
288}
289
290impl S2Basin {
291 pub fn stream(&self, name: StreamName) -> S2Stream {
293 S2Stream {
294 client: self.client.clone(),
295 name,
296 encryption: None,
297 }
298 }
299
300 pub async fn list_streams(&self, input: ListStreamsInput) -> Result<Page<StreamInfo>, S2Error> {
304 let response = self.client.list_streams(input.into()).await?;
305 Ok(Page::new(
306 response
307 .streams
308 .into_iter()
309 .map(TryInto::try_into)
310 .collect::<Result<Vec<_>, _>>()?,
311 response.has_more,
312 ))
313 }
314
315 pub fn list_all_streams(&self, input: ListAllStreamsInput) -> Streaming<StreamInfo> {
317 let basin = self.clone();
318 let prefix = input.prefix;
319 let start_after = input.start_after;
320 let include_deleted = input.include_deleted;
321 let mut input = ListStreamsInput::new()
322 .with_prefix(prefix)
323 .with_start_after(start_after);
324 Box::pin(async_stream::try_stream! {
325 loop {
326 let page = basin.list_streams(input.clone()).await?;
327 let start_after = page.values.last().map(|info| info.name.clone().into());
328
329 for info in page.values {
330 if !include_deleted && info.deleted_at.is_some() {
331 continue;
332 }
333 yield info;
334 }
335
336 if page.has_more && let Some(start_after) = start_after {
337 input = input.with_start_after(start_after);
338 } else {
339 break;
340 }
341 }
342 })
343 }
344
345 pub async fn create_stream(&self, input: CreateStreamInput) -> Result<StreamInfo, S2Error> {
347 let (request, idempotency_token) = input.into();
348 let info = self
349 .client
350 .create_stream(request, idempotency_token)
351 .await?;
352 Ok(info.try_into()?)
353 }
354
355 pub async fn ensure_stream(
363 &self,
364 input: EnsureStreamInput,
365 ) -> Result<EnsureOutput<StreamInfo>, S2Error> {
366 let (name, config) = input.into();
367 Ok(self
368 .client
369 .ensure_stream(name, config)
370 .await?
371 .try_map(StreamInfo::try_from)?
372 .into())
373 }
374
375 pub async fn get_stream_config(&self, name: StreamName) -> Result<StreamConfig, S2Error> {
377 let config = self.client.get_stream_config(name).await?;
378 Ok(config.into())
379 }
380
381 #[doc(hidden)]
382 #[cfg(feature = "_hidden")]
383 pub async fn get_stream_config_api(
384 &self,
385 name: StreamName,
386 ) -> Result<s2_api::v1::config::StreamConfig, S2Error> {
387 Ok(self.client.get_stream_config(name).await?)
388 }
389
390 pub async fn delete_stream(&self, input: DeleteStreamInput) -> Result<(), S2Error> {
392 Ok(self
393 .client
394 .delete_stream(input.name, input.ignore_not_found)
395 .await?)
396 }
397
398 pub async fn reconfigure_stream(
400 &self,
401 input: ReconfigureStreamInput,
402 ) -> Result<StreamConfig, S2Error> {
403 let config = self
404 .client
405 .reconfigure_stream(input.name, input.config.into())
406 .await?;
407 Ok(config.into())
408 }
409}
410
411#[derive(Debug, Clone)]
412pub struct S2Stream {
416 client: BasinClient,
417 name: StreamName,
418 encryption: Option<EncryptionKey>,
419}
420
421impl S2Stream {
422 pub fn with_encryption_key(self, encryption: EncryptionKey) -> Self {
424 Self {
425 encryption: Some(encryption),
426 ..self
427 }
428 }
429
430 pub async fn check_tail(&self) -> Result<StreamPosition, S2Error> {
432 let response = self.client.check_tail(&self.name).await?;
433 Ok(response.tail.into())
434 }
435
436 pub async fn append(&self, input: AppendInput) -> Result<AppendAck, S2Error> {
438 let ack = self
439 .client
440 .append(
441 &self.name,
442 input.into(),
443 self.encryption.as_ref(),
444 self.client.config.retry.append_retry_policy,
445 )
446 .await?;
447 Ok(ack.into())
448 }
449
450 pub async fn read(&self, input: ReadInput) -> Result<ReadBatch, S2Error> {
452 let batch = self
453 .client
454 .read(
455 &self.name,
456 input.start.into(),
457 input.stop.into(),
458 self.encryption.as_ref(),
459 )
460 .await?;
461 let mut batch = ReadBatch::from_api(batch);
462 if input.ignore_command_records {
463 batch.records.retain(|r| !r.is_command_record());
464 }
465 Ok(batch)
466 }
467
468 pub fn append_session(&self, config: AppendSessionConfig) -> AppendSession {
470 AppendSession::new(
471 self.client.clone(),
472 self.name.clone(),
473 self.encryption.clone(),
474 config,
475 )
476 }
477
478 pub fn producer(&self, config: ProducerConfig) -> Producer {
480 Producer::new(
481 self.client.clone(),
482 self.name.clone(),
483 self.encryption.clone(),
484 config,
485 )
486 }
487
488 pub async fn read_session(&self, input: ReadInput) -> Result<ReadSession, S2Error> {
490 Ok(session::read_session(
491 self.client.clone(),
492 self.name.clone(),
493 self.encryption.clone(),
494 input.start.into(),
495 input.stop.into(),
496 input.ignore_command_records,
497 )
498 .await?)
499 }
500}