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 pub async fn delete_basin(&self, input: DeleteBasinInput) -> Result<(), S2Error> {
133 Ok(self
134 .client
135 .delete_basin(input.name, input.ignore_not_found)
136 .await?)
137 }
138
139 pub async fn reconfigure_basin(
141 &self,
142 input: ReconfigureBasinInput,
143 ) -> Result<BasinConfig, S2Error> {
144 let config = self
145 .client
146 .reconfigure_basin(input.name, input.config.into())
147 .await?;
148 Ok(config.into())
149 }
150
151 pub async fn list_access_tokens(
155 &self,
156 input: ListAccessTokensInput,
157 ) -> Result<Page<AccessTokenInfo>, S2Error> {
158 let response = self.client.list_access_tokens(input.into()).await?;
159 Ok(Page::new(
160 response
161 .access_tokens
162 .into_iter()
163 .map(TryInto::try_into)
164 .collect::<Result<Vec<_>, _>>()?,
165 response.has_more,
166 ))
167 }
168
169 pub fn list_all_access_tokens(
171 &self,
172 input: ListAllAccessTokensInput,
173 ) -> Streaming<AccessTokenInfo> {
174 let s2 = self.clone();
175 let prefix = input.prefix;
176 let start_after = input.start_after;
177 let mut input = ListAccessTokensInput::new()
178 .with_prefix(prefix)
179 .with_start_after(start_after);
180 Box::pin(async_stream::try_stream! {
181 loop {
182 let page = s2.list_access_tokens(input.clone()).await?;
183
184 let start_after = page.values.last().map(|info| info.id.clone().into());
185 for info in page.values {
186 yield info;
187 }
188
189 if page.has_more && let Some(start_after) = start_after {
190 input = input.with_start_after(start_after);
191 } else {
192 break;
193 }
194 }
195 })
196 }
197
198 pub async fn issue_access_token(
200 &self,
201 input: IssueAccessTokenInput,
202 ) -> Result<String, S2Error> {
203 let response = self.client.issue_access_token(input.into()).await?;
204 Ok(response.access_token)
205 }
206
207 pub async fn revoke_access_token(&self, id: AccessTokenId) -> Result<(), S2Error> {
209 Ok(self.client.revoke_access_token(id).await?)
210 }
211
212 pub async fn list_locations(&self) -> Result<Vec<LocationInfo>, S2Error> {
214 let response = self.client.list_locations().await?;
215 Ok(response.into_iter().map(Into::into).collect())
216 }
217
218 pub async fn get_default_location(&self) -> Result<LocationInfo, S2Error> {
220 Ok(self.client.get_default_location().await?.into())
221 }
222
223 pub async fn set_default_location(
225 &self,
226 location: LocationName,
227 ) -> Result<LocationInfo, S2Error> {
228 Ok(self.client.set_default_location(location).await?.into())
229 }
230
231 pub async fn get_account_metrics(
233 &self,
234 input: GetAccountMetricsInput,
235 ) -> Result<Vec<Metric>, S2Error> {
236 let response = self.client.get_account_metrics(input.into()).await?;
237 Ok(response.values.into_iter().map(Into::into).collect())
238 }
239
240 pub async fn get_basin_metrics(
242 &self,
243 input: GetBasinMetricsInput,
244 ) -> Result<Vec<Metric>, S2Error> {
245 let (name, request) = input.into();
246 let response = self.client.get_basin_metrics(name, request).await?;
247 Ok(response.values.into_iter().map(Into::into).collect())
248 }
249
250 pub async fn get_stream_metrics(
252 &self,
253 input: GetStreamMetricsInput,
254 ) -> Result<Vec<Metric>, S2Error> {
255 let (basin_name, stream_name, request) = input.into();
256 let response = self
257 .client
258 .get_stream_metrics(basin_name, stream_name, request)
259 .await?;
260 Ok(response.values.into_iter().map(Into::into).collect())
261 }
262}
263
264#[derive(Debug, Clone)]
265pub struct S2Basin {
269 client: BasinClient,
270}
271
272impl S2Basin {
273 pub fn stream(&self, name: StreamName) -> S2Stream {
275 S2Stream {
276 client: self.client.clone(),
277 name,
278 encryption: None,
279 }
280 }
281
282 pub async fn list_streams(&self, input: ListStreamsInput) -> Result<Page<StreamInfo>, S2Error> {
286 let response = self.client.list_streams(input.into()).await?;
287 Ok(Page::new(
288 response
289 .streams
290 .into_iter()
291 .map(TryInto::try_into)
292 .collect::<Result<Vec<_>, _>>()?,
293 response.has_more,
294 ))
295 }
296
297 pub fn list_all_streams(&self, input: ListAllStreamsInput) -> Streaming<StreamInfo> {
299 let basin = self.clone();
300 let prefix = input.prefix;
301 let start_after = input.start_after;
302 let include_deleted = input.include_deleted;
303 let mut input = ListStreamsInput::new()
304 .with_prefix(prefix)
305 .with_start_after(start_after);
306 Box::pin(async_stream::try_stream! {
307 loop {
308 let page = basin.list_streams(input.clone()).await?;
309 let start_after = page.values.last().map(|info| info.name.clone().into());
310
311 for info in page.values {
312 if !include_deleted && info.deleted_at.is_some() {
313 continue;
314 }
315 yield info;
316 }
317
318 if page.has_more && let Some(start_after) = start_after {
319 input = input.with_start_after(start_after);
320 } else {
321 break;
322 }
323 }
324 })
325 }
326
327 pub async fn create_stream(&self, input: CreateStreamInput) -> Result<StreamInfo, S2Error> {
329 let (request, idempotency_token) = input.into();
330 let info = self
331 .client
332 .create_stream(request, idempotency_token)
333 .await?;
334 Ok(info.try_into()?)
335 }
336
337 pub async fn ensure_stream(
345 &self,
346 input: EnsureStreamInput,
347 ) -> Result<EnsureOutput<StreamInfo>, S2Error> {
348 let (name, config) = input.into();
349 Ok(self
350 .client
351 .ensure_stream(name, config)
352 .await?
353 .try_map(StreamInfo::try_from)?
354 .into())
355 }
356
357 pub async fn get_stream_config(&self, name: StreamName) -> Result<StreamConfig, S2Error> {
359 let config = self.client.get_stream_config(name).await?;
360 Ok(config.into())
361 }
362
363 pub async fn delete_stream(&self, input: DeleteStreamInput) -> Result<(), S2Error> {
365 Ok(self
366 .client
367 .delete_stream(input.name, input.ignore_not_found)
368 .await?)
369 }
370
371 pub async fn reconfigure_stream(
373 &self,
374 input: ReconfigureStreamInput,
375 ) -> Result<StreamConfig, S2Error> {
376 let config = self
377 .client
378 .reconfigure_stream(input.name, input.config.into())
379 .await?;
380 Ok(config.into())
381 }
382}
383
384#[derive(Debug, Clone)]
385pub struct S2Stream {
389 client: BasinClient,
390 name: StreamName,
391 encryption: Option<EncryptionKey>,
392}
393
394impl S2Stream {
395 pub fn with_encryption_key(self, encryption: EncryptionKey) -> Self {
397 Self {
398 encryption: Some(encryption),
399 ..self
400 }
401 }
402
403 pub async fn check_tail(&self) -> Result<StreamPosition, S2Error> {
405 let response = self.client.check_tail(&self.name).await?;
406 Ok(response.tail.into())
407 }
408
409 pub async fn append(&self, input: AppendInput) -> Result<AppendAck, S2Error> {
411 let ack = self
412 .client
413 .append(
414 &self.name,
415 input.into(),
416 self.encryption.as_ref(),
417 self.client.config.retry.append_retry_policy,
418 )
419 .await?;
420 Ok(ack.into())
421 }
422
423 pub async fn read(&self, input: ReadInput) -> Result<ReadBatch, S2Error> {
425 let batch = self
426 .client
427 .read(
428 &self.name,
429 input.start.into(),
430 input.stop.into(),
431 self.encryption.as_ref(),
432 )
433 .await?;
434 let mut batch = ReadBatch::from_api(batch);
435 if input.ignore_command_records {
436 batch.records.retain(|r| !r.is_command_record());
437 }
438 Ok(batch)
439 }
440
441 pub fn append_session(&self, config: AppendSessionConfig) -> AppendSession {
443 AppendSession::new(
444 self.client.clone(),
445 self.name.clone(),
446 self.encryption.clone(),
447 config,
448 )
449 }
450
451 pub fn producer(&self, config: ProducerConfig) -> Producer {
453 Producer::new(
454 self.client.clone(),
455 self.name.clone(),
456 self.encryption.clone(),
457 config,
458 )
459 }
460
461 pub async fn read_session(&self, input: ReadInput) -> Result<ReadSession, S2Error> {
463 Ok(session::read_session(
464 self.client.clone(),
465 self.name.clone(),
466 self.encryption.clone(),
467 input.start.into(),
468 input.stop.into(),
469 input.ignore_command_records,
470 )
471 .await?)
472 }
473}