1use crate::error::Error;
2use crate::types::*;
3use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
4
5pub struct FakeCloud {
7 base_url: String,
8 client: reqwest::Client,
9}
10
11impl FakeCloud {
12 pub fn new(base_url: &str) -> Self {
14 Self {
15 base_url: base_url.trim_end_matches('/').to_string(),
16 client: reqwest::Client::new(),
17 }
18 }
19
20 pub async fn health(&self) -> Result<HealthResponse, Error> {
24 let resp = self
25 .client
26 .get(format!("{}/_fakecloud/health", self.base_url))
27 .send()
28 .await?;
29 Self::parse(resp).await
30 }
31
32 pub async fn reset(&self) -> Result<ResetResponse, Error> {
34 let resp = self
35 .client
36 .post(format!("{}/_reset", self.base_url))
37 .send()
38 .await?;
39 Self::parse(resp).await
40 }
41
42 pub async fn create_admin(
47 &self,
48 account_id: &str,
49 user_name: &str,
50 ) -> Result<CreateAdminResponse, Error> {
51 let resp = self
52 .client
53 .post(format!("{}/_fakecloud/iam/create-admin", self.base_url))
54 .json(&CreateAdminRequest {
55 account_id: account_id.to_string(),
56 user_name: user_name.to_string(),
57 })
58 .send()
59 .await?;
60 Self::parse(resp).await
61 }
62
63 pub async fn reset_service(&self, service: &str) -> Result<ResetServiceResponse, Error> {
65 let resp = self
66 .client
67 .post(format!("{}/_fakecloud/reset/{}", self.base_url, service))
68 .send()
69 .await?;
70 Self::parse(resp).await
71 }
72
73 pub async fn reset_service_for_account(
75 &self,
76 service: &str,
77 account_id: &str,
78 ) -> Result<ResetServiceResponse, Error> {
79 let resp = self
80 .client
81 .post(format!(
82 "{}/_fakecloud/reset/{}/{}",
83 self.base_url, service, account_id
84 ))
85 .send()
86 .await?;
87 Self::parse(resp).await
88 }
89
90 pub fn lambda(&self) -> LambdaClient<'_> {
93 LambdaClient { fc: self }
94 }
95
96 pub fn ses(&self) -> SesClient<'_> {
97 SesClient { fc: self }
98 }
99
100 pub fn sns(&self) -> SnsClient<'_> {
101 SnsClient { fc: self }
102 }
103
104 pub fn sqs(&self) -> SqsClient<'_> {
105 SqsClient { fc: self }
106 }
107
108 pub fn events(&self) -> EventsClient<'_> {
109 EventsClient { fc: self }
110 }
111
112 pub fn s3(&self) -> S3Client<'_> {
113 S3Client { fc: self }
114 }
115
116 pub fn dynamodb(&self) -> DynamoDbClient<'_> {
117 DynamoDbClient { fc: self }
118 }
119
120 pub fn secretsmanager(&self) -> SecretsManagerClient<'_> {
121 SecretsManagerClient { fc: self }
122 }
123
124 pub fn cognito(&self) -> CognitoClient<'_> {
125 CognitoClient { fc: self }
126 }
127
128 pub fn rds(&self) -> RdsClient<'_> {
129 RdsClient { fc: self }
130 }
131
132 pub fn elasticache(&self) -> ElastiCacheClient<'_> {
133 ElastiCacheClient { fc: self }
134 }
135
136 pub fn apigatewayv2(&self) -> ApiGatewayV2Client<'_> {
137 ApiGatewayV2Client { fc: self }
138 }
139
140 pub fn stepfunctions(&self) -> StepFunctionsClient<'_> {
141 StepFunctionsClient { fc: self }
142 }
143
144 pub fn bedrock(&self) -> BedrockClient<'_> {
145 BedrockClient { fc: self }
146 }
147
148 pub fn bedrock_agent(&self) -> BedrockAgentClient<'_> {
149 BedrockAgentClient { fc: self }
150 }
151
152 pub fn bedrock_agent_runtime(&self) -> BedrockAgentRuntimeClient<'_> {
153 BedrockAgentRuntimeClient { fc: self }
154 }
155
156 pub fn ecs(&self) -> EcsClient<'_> {
157 EcsClient { fc: self }
158 }
159
160 pub fn application_autoscaling(&self) -> ApplicationAutoScalingClient<'_> {
161 ApplicationAutoScalingClient { fc: self }
162 }
163
164 pub fn athena(&self) -> AthenaClient<'_> {
165 AthenaClient { fc: self }
166 }
167
168 pub fn organizations(&self) -> OrganizationsClient<'_> {
169 OrganizationsClient { fc: self }
170 }
171
172 pub fn acm(&self) -> AcmClient<'_> {
173 AcmClient { fc: self }
174 }
175
176 pub fn ecr(&self) -> EcrClient<'_> {
177 EcrClient { fc: self }
178 }
179
180 pub fn elbv2(&self) -> Elbv2Client<'_> {
181 Elbv2Client { fc: self }
182 }
183
184 pub fn glue(&self) -> GlueClient<'_> {
185 GlueClient { fc: self }
186 }
187
188 pub fn logs(&self) -> LogsClient<'_> {
189 LogsClient { fc: self }
190 }
191
192 pub fn route53(&self) -> Route53Client<'_> {
193 Route53Client { fc: self }
194 }
195
196 pub fn scheduler(&self) -> SchedulerClient<'_> {
197 SchedulerClient { fc: self }
198 }
199
200 pub fn ssm(&self) -> SsmClient<'_> {
201 SsmClient { fc: self }
202 }
203
204 pub fn kms(&self) -> KmsClient<'_> {
205 KmsClient { fc: self }
206 }
207
208 pub fn wafv2(&self) -> WafV2Client<'_> {
209 WafV2Client { fc: self }
210 }
211
212 pub fn cloudfront(&self) -> CloudFrontClient<'_> {
213 CloudFrontClient { fc: self }
214 }
215
216 async fn parse<T: serde::de::DeserializeOwned>(resp: reqwest::Response) -> Result<T, Error> {
219 let status = resp.status().as_u16();
220 if !resp.status().is_success() {
221 let body = resp.text().await.unwrap_or_default();
222 return Err(Error::Api { status, body });
223 }
224 Ok(resp.json::<T>().await?)
225 }
226}
227
228pub struct RdsClient<'a> {
231 fc: &'a FakeCloud,
232}
233
234impl RdsClient<'_> {
235 pub async fn get_instances(&self) -> Result<RdsInstancesResponse, Error> {
237 let resp = self
238 .fc
239 .client
240 .get(format!("{}/_fakecloud/rds/instances", self.fc.base_url))
241 .send()
242 .await?;
243 FakeCloud::parse(resp).await
244 }
245
246 pub async fn lambda_invoke(
251 &self,
252 req: &RdsLambdaInvokeRequest,
253 ) -> Result<RdsLambdaInvokeResponse, Error> {
254 let resp = self
255 .fc
256 .client
257 .post(format!("{}/_fakecloud/rds/lambda-invoke", self.fc.base_url))
258 .json(req)
259 .send()
260 .await?;
261 let status = resp.status().as_u16();
262 if status == 502 || resp.status().is_success() {
266 return Ok(resp.json::<RdsLambdaInvokeResponse>().await?);
267 }
268 let body = resp.text().await.unwrap_or_default();
269 Err(Error::Api { status, body })
270 }
271
272 pub async fn s3_import(&self, req: &RdsS3ImportRequest) -> Result<RdsS3ImportResponse, Error> {
275 let resp = self
276 .fc
277 .client
278 .post(format!("{}/_fakecloud/rds/s3-import", self.fc.base_url))
279 .json(req)
280 .send()
281 .await?;
282 FakeCloud::parse(resp).await
283 }
284
285 pub async fn s3_export(&self, req: &RdsS3ExportRequest) -> Result<RdsS3ExportResponse, Error> {
288 let resp = self
289 .fc
290 .client
291 .post(format!("{}/_fakecloud/rds/s3-export", self.fc.base_url))
292 .json(req)
293 .send()
294 .await?;
295 FakeCloud::parse(resp).await
296 }
297}
298
299pub struct ElastiCacheClient<'a> {
302 fc: &'a FakeCloud,
303}
304
305impl ElastiCacheClient<'_> {
306 pub async fn get_clusters(&self) -> Result<ElastiCacheClustersResponse, Error> {
308 let resp = self
309 .fc
310 .client
311 .get(format!(
312 "{}/_fakecloud/elasticache/clusters",
313 self.fc.base_url
314 ))
315 .send()
316 .await?;
317 FakeCloud::parse(resp).await
318 }
319
320 pub async fn get_replication_groups(
322 &self,
323 ) -> Result<ElastiCacheReplicationGroupsResponse, Error> {
324 let resp = self
325 .fc
326 .client
327 .get(format!(
328 "{}/_fakecloud/elasticache/replication-groups",
329 self.fc.base_url
330 ))
331 .send()
332 .await?;
333 FakeCloud::parse(resp).await
334 }
335
336 pub async fn get_serverless_caches(
338 &self,
339 ) -> Result<ElastiCacheServerlessCachesResponse, Error> {
340 let resp = self
341 .fc
342 .client
343 .get(format!(
344 "{}/_fakecloud/elasticache/serverless-caches",
345 self.fc.base_url
346 ))
347 .send()
348 .await?;
349 FakeCloud::parse(resp).await
350 }
351
352 pub async fn get_acls(&self) -> Result<ElastiCacheAclsResponse, Error> {
355 let resp = self
356 .fc
357 .client
358 .get(format!("{}/_fakecloud/elasticache/acls", self.fc.base_url))
359 .send()
360 .await?;
361 FakeCloud::parse(resp).await
362 }
363}
364
365pub struct LambdaClient<'a> {
368 fc: &'a FakeCloud,
369}
370
371impl LambdaClient<'_> {
372 pub async fn get_invocations(&self) -> Result<LambdaInvocationsResponse, Error> {
374 let resp = self
375 .fc
376 .client
377 .get(format!(
378 "{}/_fakecloud/lambda/invocations",
379 self.fc.base_url
380 ))
381 .send()
382 .await?;
383 FakeCloud::parse(resp).await
384 }
385
386 pub async fn get_warm_containers(&self) -> Result<WarmContainersResponse, Error> {
388 let resp = self
389 .fc
390 .client
391 .get(format!(
392 "{}/_fakecloud/lambda/warm-containers",
393 self.fc.base_url
394 ))
395 .send()
396 .await?;
397 FakeCloud::parse(resp).await
398 }
399
400 pub async fn evict_container(
402 &self,
403 function_name: &str,
404 ) -> Result<EvictContainerResponse, Error> {
405 let resp = self
406 .fc
407 .client
408 .post(format!(
409 "{}/_fakecloud/lambda/{}/evict-container",
410 self.fc.base_url, function_name
411 ))
412 .send()
413 .await?;
414 FakeCloud::parse(resp).await
415 }
416
417 pub async fn download_function_code(
421 &self,
422 account_id: &str,
423 function_name: &str,
424 qualifier_or_latest: &str,
425 ) -> Result<Vec<u8>, Error> {
426 let resp = self
427 .fc
428 .client
429 .get(format!(
430 "{}/_fakecloud/lambda/function-code/{}/{}/{}.zip",
431 self.fc.base_url, account_id, function_name, qualifier_or_latest
432 ))
433 .send()
434 .await?;
435 let status = resp.status().as_u16();
436 if !resp.status().is_success() {
437 let body = resp.text().await.unwrap_or_default();
438 return Err(Error::Api { status, body });
439 }
440 Ok(resp.bytes().await?.to_vec())
441 }
442
443 pub async fn download_layer_content(
445 &self,
446 account_id: &str,
447 layer_name: &str,
448 version: i64,
449 ) -> Result<Vec<u8>, Error> {
450 let resp = self
451 .fc
452 .client
453 .get(format!(
454 "{}/_fakecloud/lambda/layer-content/{}/{}/{}.zip",
455 self.fc.base_url, account_id, layer_name, version
456 ))
457 .send()
458 .await?;
459 let status = resp.status().as_u16();
460 if !resp.status().is_success() {
461 let body = resp.text().await.unwrap_or_default();
462 return Err(Error::Api { status, body });
463 }
464 Ok(resp.bytes().await?.to_vec())
465 }
466}
467
468pub struct SesClient<'a> {
471 fc: &'a FakeCloud,
472}
473
474impl SesClient<'_> {
475 pub async fn get_emails(&self) -> Result<SesEmailsResponse, Error> {
477 let resp = self
478 .fc
479 .client
480 .get(format!("{}/_fakecloud/ses/emails", self.fc.base_url))
481 .send()
482 .await?;
483 FakeCloud::parse(resp).await
484 }
485
486 pub async fn simulate_inbound(
488 &self,
489 req: &InboundEmailRequest,
490 ) -> Result<InboundEmailResponse, Error> {
491 let resp = self
492 .fc
493 .client
494 .post(format!("{}/_fakecloud/ses/inbound", self.fc.base_url))
495 .json(req)
496 .send()
497 .await?;
498 FakeCloud::parse(resp).await
499 }
500
501 pub async fn get_metrics(&self) -> Result<SesMetricsResponse, Error> {
504 let resp = self
505 .fc
506 .client
507 .get(format!("{}/_fakecloud/ses/metrics", self.fc.base_url))
508 .send()
509 .await?;
510 FakeCloud::parse(resp).await
511 }
512
513 pub async fn get_bounces(&self) -> Result<SesBouncesResponse, Error> {
515 let resp = self
516 .fc
517 .client
518 .get(format!("{}/_fakecloud/ses/bounces", self.fc.base_url))
519 .send()
520 .await?;
521 FakeCloud::parse(resp).await
522 }
523
524 pub async fn set_sandbox(&self, sandbox: bool) -> Result<SesSandboxResponse, Error> {
528 let resp = self
529 .fc
530 .client
531 .post(format!(
532 "{}/_fakecloud/ses/account/sandbox",
533 self.fc.base_url
534 ))
535 .json(&SesSandboxRequest { sandbox })
536 .send()
537 .await?;
538 FakeCloud::parse(resp).await
539 }
540
541 pub async fn get_event_destination_deliveries(
544 &self,
545 ) -> Result<SesEventDestinationDeliveriesResponse, Error> {
546 let resp = self
547 .fc
548 .client
549 .get(format!(
550 "{}/_fakecloud/ses/event-destinations/deliveries",
551 self.fc.base_url
552 ))
553 .send()
554 .await?;
555 FakeCloud::parse(resp).await
556 }
557
558 pub async fn get_dkim_public_key(
561 &self,
562 identity: &str,
563 ) -> Result<SesDkimPublicKeyResponse, Error> {
564 let resp = self
565 .fc
566 .client
567 .get(format!(
568 "{}/_fakecloud/ses/identities/{}/dkim-public-key",
569 self.fc.base_url, identity
570 ))
571 .send()
572 .await?;
573 FakeCloud::parse(resp).await
574 }
575
576 pub async fn set_mail_from_status(
579 &self,
580 identity: &str,
581 status: &str,
582 ) -> Result<SesMailFromStatusResponse, Error> {
583 let resp = self
584 .fc
585 .client
586 .post(format!(
587 "{}/_fakecloud/ses/identities/{}/mail-from-status",
588 self.fc.base_url, identity
589 ))
590 .json(&SesMailFromStatusRequest {
591 status: status.to_string(),
592 })
593 .send()
594 .await?;
595 FakeCloud::parse(resp).await
596 }
597
598 pub async fn get_message_insights(
601 &self,
602 message_id: &str,
603 ) -> Result<SesMessageInsightsResponse, Error> {
604 let resp = self
605 .fc
606 .client
607 .get(format!(
608 "{}/_fakecloud/ses/messages/{}/insights",
609 self.fc.base_url, message_id
610 ))
611 .send()
612 .await?;
613 FakeCloud::parse(resp).await
614 }
615
616 pub async fn get_smtp_submissions(&self) -> Result<SesSmtpSubmissionsResponse, Error> {
618 let resp = self
619 .fc
620 .client
621 .get(format!(
622 "{}/_fakecloud/ses/smtp/submissions",
623 self.fc.base_url
624 ))
625 .send()
626 .await?;
627 FakeCloud::parse(resp).await
628 }
629}
630
631pub struct SnsClient<'a> {
634 fc: &'a FakeCloud,
635}
636
637impl SnsClient<'_> {
638 pub async fn get_messages(&self) -> Result<SnsMessagesResponse, Error> {
640 let resp = self
641 .fc
642 .client
643 .get(format!("{}/_fakecloud/sns/messages", self.fc.base_url))
644 .send()
645 .await?;
646 FakeCloud::parse(resp).await
647 }
648
649 pub async fn get_pending_confirmations(&self) -> Result<PendingConfirmationsResponse, Error> {
651 let resp = self
652 .fc
653 .client
654 .get(format!(
655 "{}/_fakecloud/sns/pending-confirmations",
656 self.fc.base_url
657 ))
658 .send()
659 .await?;
660 FakeCloud::parse(resp).await
661 }
662
663 pub async fn confirm_subscription(
665 &self,
666 req: &ConfirmSubscriptionRequest,
667 ) -> Result<ConfirmSubscriptionResponse, Error> {
668 let resp = self
669 .fc
670 .client
671 .post(format!(
672 "{}/_fakecloud/sns/confirm-subscription",
673 self.fc.base_url
674 ))
675 .json(req)
676 .send()
677 .await?;
678 FakeCloud::parse(resp).await
679 }
680
681 pub async fn cert_pem(&self) -> Result<String, Error> {
686 let resp = self
687 .fc
688 .client
689 .get(format!("{}/_fakecloud/sns/cert.pem", self.fc.base_url))
690 .send()
691 .await?;
692 let status = resp.status().as_u16();
693 if !resp.status().is_success() {
694 let body = resp.text().await.unwrap_or_default();
695 return Err(Error::Api { status, body });
696 }
697 Ok(resp.text().await?)
698 }
699
700 pub async fn sms(&self) -> Result<SnsSmsResponse, Error> {
702 let resp = self
703 .fc
704 .client
705 .get(format!("{}/_fakecloud/sns/sms", self.fc.base_url))
706 .send()
707 .await?;
708 FakeCloud::parse(resp).await
709 }
710}
711
712pub struct SqsClient<'a> {
715 fc: &'a FakeCloud,
716}
717
718impl SqsClient<'_> {
719 pub async fn get_messages(&self) -> Result<SqsMessagesResponse, Error> {
721 let resp = self
722 .fc
723 .client
724 .get(format!("{}/_fakecloud/sqs/messages", self.fc.base_url))
725 .send()
726 .await?;
727 FakeCloud::parse(resp).await
728 }
729
730 pub async fn tick_expiration(&self) -> Result<ExpirationTickResponse, Error> {
732 let resp = self
733 .fc
734 .client
735 .post(format!(
736 "{}/_fakecloud/sqs/expiration-processor/tick",
737 self.fc.base_url
738 ))
739 .send()
740 .await?;
741 FakeCloud::parse(resp).await
742 }
743
744 pub async fn force_dlq(&self, queue_name: &str) -> Result<ForceDlqResponse, Error> {
746 let resp = self
747 .fc
748 .client
749 .post(format!(
750 "{}/_fakecloud/sqs/{}/force-dlq",
751 self.fc.base_url, queue_name
752 ))
753 .send()
754 .await?;
755 FakeCloud::parse(resp).await
756 }
757}
758
759pub struct ApplicationAutoScalingClient<'a> {
762 fc: &'a FakeCloud,
763}
764
765impl ApplicationAutoScalingClient<'_> {
766 pub async fn tick(&self) -> Result<AppAsTickResponse, Error> {
771 let resp = self
772 .fc
773 .client
774 .post(format!(
775 "{}/_fakecloud/application-autoscaling/tick",
776 self.fc.base_url
777 ))
778 .send()
779 .await?;
780 FakeCloud::parse(resp).await
781 }
782
783 pub async fn scheduled_tick(&self) -> Result<AppAsScheduledTickResponse, Error> {
788 let resp = self
789 .fc
790 .client
791 .post(format!(
792 "{}/_fakecloud/application-autoscaling/scheduled-tick",
793 self.fc.base_url
794 ))
795 .send()
796 .await?;
797 FakeCloud::parse(resp).await
798 }
799}
800
801pub struct EventsClient<'a> {
804 fc: &'a FakeCloud,
805}
806
807impl EventsClient<'_> {
808 pub async fn get_history(&self) -> Result<EventHistoryResponse, Error> {
810 let resp = self
811 .fc
812 .client
813 .get(format!("{}/_fakecloud/events/history", self.fc.base_url))
814 .send()
815 .await?;
816 FakeCloud::parse(resp).await
817 }
818
819 pub async fn fire_rule(&self, req: &FireRuleRequest) -> Result<FireRuleResponse, Error> {
821 let resp = self
822 .fc
823 .client
824 .post(format!("{}/_fakecloud/events/fire-rule", self.fc.base_url))
825 .json(req)
826 .send()
827 .await?;
828 FakeCloud::parse(resp).await
829 }
830}
831
832pub struct S3Client<'a> {
835 fc: &'a FakeCloud,
836}
837
838impl S3Client<'_> {
839 pub async fn get_notifications(&self) -> Result<S3NotificationsResponse, Error> {
841 let resp = self
842 .fc
843 .client
844 .get(format!("{}/_fakecloud/s3/notifications", self.fc.base_url))
845 .send()
846 .await?;
847 FakeCloud::parse(resp).await
848 }
849
850 pub async fn tick_lifecycle(&self) -> Result<LifecycleTickResponse, Error> {
852 let resp = self
853 .fc
854 .client
855 .post(format!(
856 "{}/_fakecloud/s3/lifecycle-processor/tick",
857 self.fc.base_url
858 ))
859 .send()
860 .await?;
861 FakeCloud::parse(resp).await
862 }
863
864 pub async fn get_access_points(&self) -> Result<S3AccessPointsResponse, Error> {
866 let resp = self
867 .fc
868 .client
869 .get(format!("{}/_fakecloud/s3/access-points", self.fc.base_url))
870 .send()
871 .await?;
872 FakeCloud::parse(resp).await
873 }
874
875 pub async fn get_object_lambda_responses(
877 &self,
878 ) -> Result<S3ObjectLambdaResponsesResponse, Error> {
879 let resp = self
880 .fc
881 .client
882 .get(format!(
883 "{}/_fakecloud/s3/object-lambda-responses",
884 self.fc.base_url
885 ))
886 .send()
887 .await?;
888 FakeCloud::parse(resp).await
889 }
890}
891
892pub struct DynamoDbClient<'a> {
895 fc: &'a FakeCloud,
896}
897
898impl DynamoDbClient<'_> {
899 pub async fn tick_ttl(&self) -> Result<TtlTickResponse, Error> {
901 let resp = self
902 .fc
903 .client
904 .post(format!(
905 "{}/_fakecloud/dynamodb/ttl-processor/tick",
906 self.fc.base_url
907 ))
908 .send()
909 .await?;
910 FakeCloud::parse(resp).await
911 }
912}
913
914pub struct SecretsManagerClient<'a> {
917 fc: &'a FakeCloud,
918}
919
920impl SecretsManagerClient<'_> {
921 pub async fn tick_rotation(&self) -> Result<RotationTickResponse, Error> {
923 let resp = self
924 .fc
925 .client
926 .post(format!(
927 "{}/_fakecloud/secretsmanager/rotation-scheduler/tick",
928 self.fc.base_url
929 ))
930 .send()
931 .await?;
932 FakeCloud::parse(resp).await
933 }
934}
935
936pub struct CognitoClient<'a> {
939 fc: &'a FakeCloud,
940}
941
942impl CognitoClient<'_> {
943 pub async fn get_user_codes(
945 &self,
946 pool_id: &str,
947 username: &str,
948 ) -> Result<UserConfirmationCodes, Error> {
949 let resp = self
950 .fc
951 .client
952 .get(format!(
953 "{}/_fakecloud/cognito/confirmation-codes/{}/{}",
954 self.fc.base_url, pool_id, username
955 ))
956 .send()
957 .await?;
958 FakeCloud::parse(resp).await
959 }
960
961 pub async fn get_confirmation_codes(&self) -> Result<ConfirmationCodesResponse, Error> {
963 let resp = self
964 .fc
965 .client
966 .get(format!(
967 "{}/_fakecloud/cognito/confirmation-codes",
968 self.fc.base_url
969 ))
970 .send()
971 .await?;
972 FakeCloud::parse(resp).await
973 }
974
975 pub async fn confirm_user(
977 &self,
978 req: &ConfirmUserRequest,
979 ) -> Result<ConfirmUserResponse, Error> {
980 let resp = self
981 .fc
982 .client
983 .post(format!(
984 "{}/_fakecloud/cognito/confirm-user",
985 self.fc.base_url
986 ))
987 .json(req)
988 .send()
989 .await?;
990 let status = resp.status().as_u16();
991 let body: ConfirmUserResponse = resp.json().await?;
992 if status >= 400 {
993 return Err(Error::Api {
994 status,
995 body: body.error.unwrap_or_default(),
996 });
997 }
998 Ok(body)
999 }
1000
1001 pub async fn get_tokens(&self) -> Result<TokensResponse, Error> {
1003 let resp = self
1004 .fc
1005 .client
1006 .get(format!("{}/_fakecloud/cognito/tokens", self.fc.base_url))
1007 .send()
1008 .await?;
1009 FakeCloud::parse(resp).await
1010 }
1011
1012 pub async fn expire_tokens(
1014 &self,
1015 req: &ExpireTokensRequest,
1016 ) -> Result<ExpireTokensResponse, Error> {
1017 let resp = self
1018 .fc
1019 .client
1020 .post(format!(
1021 "{}/_fakecloud/cognito/expire-tokens",
1022 self.fc.base_url
1023 ))
1024 .json(req)
1025 .send()
1026 .await?;
1027 FakeCloud::parse(resp).await
1028 }
1029
1030 pub async fn get_auth_events(&self) -> Result<AuthEventsResponse, Error> {
1032 let resp = self
1033 .fc
1034 .client
1035 .get(format!(
1036 "{}/_fakecloud/cognito/auth-events",
1037 self.fc.base_url
1038 ))
1039 .send()
1040 .await?;
1041 FakeCloud::parse(resp).await
1042 }
1043
1044 pub async fn get_pre_token_gen_invocations(
1050 &self,
1051 ) -> Result<PreTokenGenInvocationsResponse, Error> {
1052 let resp = self
1053 .fc
1054 .client
1055 .get(format!(
1056 "{}/_fakecloud/cognito/pretokengen/invocations",
1057 self.fc.base_url
1058 ))
1059 .send()
1060 .await?;
1061 FakeCloud::parse(resp).await
1062 }
1063
1064 pub async fn mint_authorization_code(
1068 &self,
1069 req: &MintAuthorizationCodeRequest,
1070 ) -> Result<MintAuthorizationCodeResponse, Error> {
1071 let resp = self
1072 .fc
1073 .client
1074 .post(format!(
1075 "{}/_fakecloud/cognito/authorization-codes",
1076 self.fc.base_url
1077 ))
1078 .json(req)
1079 .send()
1080 .await?;
1081 FakeCloud::parse(resp).await
1082 }
1083
1084 pub async fn set_compromised_passwords(
1089 &self,
1090 req: &CognitoCompromisedPasswordsRequest,
1091 ) -> Result<CompromisedPasswordsResponse, Error> {
1092 let resp = self
1093 .fc
1094 .client
1095 .post(format!(
1096 "{}/_fakecloud/cognito/compromised-passwords",
1097 self.fc.base_url
1098 ))
1099 .json(req)
1100 .send()
1101 .await?;
1102 FakeCloud::parse(resp).await
1103 }
1104
1105 pub async fn get_webauthn_credentials(&self) -> Result<WebAuthnCredentialsResponse, Error> {
1107 let resp = self
1108 .fc
1109 .client
1110 .get(format!(
1111 "{}/_fakecloud/cognito/webauthn-credentials",
1112 self.fc.base_url
1113 ))
1114 .send()
1115 .await?;
1116 FakeCloud::parse(resp).await
1117 }
1118}
1119
1120pub struct ApiGatewayV2Client<'a> {
1123 fc: &'a FakeCloud,
1124}
1125
1126impl ApiGatewayV2Client<'_> {
1127 pub async fn get_requests(&self) -> Result<ApiGatewayV2RequestsResponse, Error> {
1129 let resp = self
1130 .fc
1131 .client
1132 .get(format!(
1133 "{}/_fakecloud/apigatewayv2/requests",
1134 self.fc.base_url
1135 ))
1136 .send()
1137 .await?;
1138 FakeCloud::parse(resp).await
1139 }
1140
1141 pub async fn connections(&self) -> Result<ApiGatewayV2ConnectionsResponse, Error> {
1144 let resp = self
1145 .fc
1146 .client
1147 .get(format!(
1148 "{}/_fakecloud/apigatewayv2/connections",
1149 self.fc.base_url
1150 ))
1151 .send()
1152 .await?;
1153 FakeCloud::parse(resp).await
1154 }
1155
1156 pub async fn mtls_info(&self, name: &str) -> Result<serde_json::Value, Error> {
1160 let resp = self
1161 .fc
1162 .client
1163 .get(format!(
1164 "{}/_fakecloud/apigatewayv2/domain-names/{}/mtls-info",
1165 self.fc.base_url, name
1166 ))
1167 .send()
1168 .await?;
1169 FakeCloud::parse(resp).await
1170 }
1171
1172 pub fn ws_url(&self, api_id: &str, stage: Option<&str>) -> String {
1176 let base = self
1177 .fc
1178 .base_url
1179 .replacen("https://", "wss://", 1)
1180 .replacen("http://", "ws://", 1);
1181 let url = reqwest::Url::parse(&format!("{}/_fakecloud/apigatewayv2/ws/{}", base, api_id))
1185 .expect("base url + api id form a valid URL");
1186 match stage {
1187 Some(s) => {
1188 let mut u = url;
1189 u.query_pairs_mut().append_pair("stage", s);
1190 u.to_string()
1191 }
1192 None => url.to_string(),
1193 }
1194 }
1195}
1196
1197pub struct StepFunctionsClient<'a> {
1200 fc: &'a FakeCloud,
1201}
1202
1203impl StepFunctionsClient<'_> {
1204 pub async fn get_executions(&self) -> Result<StepFunctionsExecutionsResponse, Error> {
1206 let resp = self
1207 .fc
1208 .client
1209 .get(format!(
1210 "{}/_fakecloud/stepfunctions/executions",
1211 self.fc.base_url
1212 ))
1213 .send()
1214 .await?;
1215 FakeCloud::parse(resp).await
1216 }
1217
1218 pub async fn get_sync_executions(&self) -> Result<StepFunctionsSyncExecutionsResponse, Error> {
1222 let resp = self
1223 .fc
1224 .client
1225 .get(format!(
1226 "{}/_fakecloud/stepfunctions/sync-executions",
1227 self.fc.base_url
1228 ))
1229 .send()
1230 .await?;
1231 FakeCloud::parse(resp).await
1232 }
1233
1234 pub async fn enqueue_activity_task(
1242 &self,
1243 req: &SfnEnqueueActivityTaskRequest,
1244 ) -> Result<SfnEnqueueActivityTaskResponse, Error> {
1245 let resp = self
1246 .fc
1247 .client
1248 .post(format!(
1249 "{}/_fakecloud/stepfunctions/enqueue-activity-task",
1250 self.fc.base_url
1251 ))
1252 .json(req)
1253 .send()
1254 .await?;
1255 FakeCloud::parse(resp).await
1256 }
1257
1258 pub async fn get_execution_tree(
1259 &self,
1260 execution_arn: &str,
1261 ) -> Result<StepFunctionsExecutionTreeResponse, Error> {
1262 let mut encoded = String::with_capacity(execution_arn.len());
1263 for b in execution_arn.bytes() {
1264 match b {
1265 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
1266 encoded.push(b as char);
1267 }
1268 _ => encoded.push_str(&format!("%{:02X}", b)),
1269 }
1270 }
1271 let resp = self
1272 .fc
1273 .client
1274 .get(format!(
1275 "{}/_fakecloud/stepfunctions/execution-tree/{}",
1276 self.fc.base_url, encoded
1277 ))
1278 .send()
1279 .await?;
1280 FakeCloud::parse(resp).await
1281 }
1282}
1283
1284pub struct BedrockClient<'a> {
1287 fc: &'a FakeCloud,
1288}
1289
1290impl BedrockClient<'_> {
1291 pub async fn get_invocations(&self) -> Result<BedrockInvocationsResponse, Error> {
1294 let resp = self
1295 .fc
1296 .client
1297 .get(format!(
1298 "{}/_fakecloud/bedrock/invocations",
1299 self.fc.base_url
1300 ))
1301 .send()
1302 .await?;
1303 FakeCloud::parse(resp).await
1304 }
1305
1306 pub async fn set_model_response(
1308 &self,
1309 model_id: &str,
1310 response: &str,
1311 ) -> Result<BedrockModelResponseConfig, Error> {
1312 let resp = self
1313 .fc
1314 .client
1315 .post(format!(
1316 "{}/_fakecloud/bedrock/models/{}/response",
1317 self.fc.base_url, model_id
1318 ))
1319 .header("content-type", "text/plain")
1320 .body(response.to_string())
1321 .send()
1322 .await?;
1323 FakeCloud::parse(resp).await
1324 }
1325
1326 pub async fn set_response_rules(
1328 &self,
1329 model_id: &str,
1330 rules: &[BedrockResponseRule],
1331 ) -> Result<BedrockModelResponseConfig, Error> {
1332 let body = serde_json::json!({ "rules": rules });
1333 let resp = self
1334 .fc
1335 .client
1336 .post(format!(
1337 "{}/_fakecloud/bedrock/models/{}/responses",
1338 self.fc.base_url, model_id
1339 ))
1340 .json(&body)
1341 .send()
1342 .await?;
1343 FakeCloud::parse(resp).await
1344 }
1345
1346 pub async fn clear_response_rules(
1348 &self,
1349 model_id: &str,
1350 ) -> Result<BedrockModelResponseConfig, Error> {
1351 let resp = self
1352 .fc
1353 .client
1354 .delete(format!(
1355 "{}/_fakecloud/bedrock/models/{}/responses",
1356 self.fc.base_url, model_id
1357 ))
1358 .send()
1359 .await?;
1360 FakeCloud::parse(resp).await
1361 }
1362
1363 pub async fn queue_fault(
1365 &self,
1366 rule: &BedrockFaultRule,
1367 ) -> Result<BedrockStatusResponse, Error> {
1368 let resp = self
1369 .fc
1370 .client
1371 .post(format!("{}/_fakecloud/bedrock/faults", self.fc.base_url))
1372 .json(rule)
1373 .send()
1374 .await?;
1375 FakeCloud::parse(resp).await
1376 }
1377
1378 pub async fn get_faults(&self) -> Result<BedrockFaultsResponse, Error> {
1380 let resp = self
1381 .fc
1382 .client
1383 .get(format!("{}/_fakecloud/bedrock/faults", self.fc.base_url))
1384 .send()
1385 .await?;
1386 FakeCloud::parse(resp).await
1387 }
1388
1389 pub async fn clear_faults(&self) -> Result<BedrockStatusResponse, Error> {
1391 let resp = self
1392 .fc
1393 .client
1394 .delete(format!("{}/_fakecloud/bedrock/faults", self.fc.base_url))
1395 .send()
1396 .await?;
1397 FakeCloud::parse(resp).await
1398 }
1399}
1400
1401pub struct BedrockAgentClient<'a> {
1404 fc: &'a FakeCloud,
1405}
1406
1407impl BedrockAgentClient<'_> {
1408 pub async fn get_agents(&self) -> Result<BedrockAgentAgentsResponse, Error> {
1412 let resp = self
1413 .fc
1414 .client
1415 .get(format!(
1416 "{}/_fakecloud/bedrock-agent/agents",
1417 self.fc.base_url
1418 ))
1419 .send()
1420 .await?;
1421 FakeCloud::parse(resp).await
1422 }
1423}
1424
1425pub struct BedrockAgentRuntimeClient<'a> {
1428 fc: &'a FakeCloud,
1429}
1430
1431impl BedrockAgentRuntimeClient<'_> {
1432 pub async fn get_invocations(&self) -> Result<BedrockAgentRuntimeInvocationsResponse, Error> {
1435 let resp = self
1436 .fc
1437 .client
1438 .get(format!(
1439 "{}/_fakecloud/bedrock-agent-runtime/invocations",
1440 self.fc.base_url
1441 ))
1442 .send()
1443 .await?;
1444 FakeCloud::parse(resp).await
1445 }
1446}
1447
1448pub struct EcsClient<'a> {
1451 fc: &'a FakeCloud,
1452}
1453
1454impl EcsClient<'_> {
1455 pub async fn get_clusters(&self) -> Result<EcsClustersResponse, Error> {
1459 let resp = self
1460 .fc
1461 .client
1462 .get(format!("{}/_fakecloud/ecs/clusters", self.fc.base_url))
1463 .send()
1464 .await?;
1465 FakeCloud::parse(resp).await
1466 }
1467
1468 pub async fn get_tasks(
1471 &self,
1472 cluster: Option<&str>,
1473 status: Option<&str>,
1474 ) -> Result<EcsTasksResponse, Error> {
1475 fn encode(s: &str) -> String {
1476 let mut out = String::with_capacity(s.len());
1477 for b in s.bytes() {
1478 match b {
1479 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
1480 out.push(b as char);
1481 }
1482 _ => out.push_str(&format!("%{:02X}", b)),
1483 }
1484 }
1485 out
1486 }
1487 let mut url = format!("{}/_fakecloud/ecs/tasks", self.fc.base_url);
1488 let mut sep = '?';
1489 if let Some(c) = cluster {
1490 url.push(sep);
1491 url.push_str("cluster=");
1492 url.push_str(&encode(c));
1493 sep = '&';
1494 }
1495 if let Some(s) = status {
1496 url.push(sep);
1497 url.push_str("status=");
1498 url.push_str(&encode(s));
1499 }
1500 let resp = self.fc.client.get(url).send().await?;
1501 FakeCloud::parse(resp).await
1502 }
1503
1504 pub async fn get_task_logs(&self, task_id: &str) -> Result<EcsTaskLogsResponse, Error> {
1508 let resp = self
1509 .fc
1510 .client
1511 .get(format!(
1512 "{}/_fakecloud/ecs/tasks/{}/logs",
1513 self.fc.base_url, task_id
1514 ))
1515 .send()
1516 .await?;
1517 FakeCloud::parse(resp).await
1518 }
1519
1520 pub async fn force_stop_task(&self, task_id: &str) -> Result<EcsTask, Error> {
1522 let resp = self
1523 .fc
1524 .client
1525 .post(format!(
1526 "{}/_fakecloud/ecs/tasks/{}/force-stop",
1527 self.fc.base_url, task_id
1528 ))
1529 .send()
1530 .await?;
1531 FakeCloud::parse(resp).await
1532 }
1533
1534 pub async fn mark_task_failed(
1537 &self,
1538 task_id: &str,
1539 req: &EcsMarkFailedRequest,
1540 ) -> Result<EcsTask, Error> {
1541 let resp = self
1542 .fc
1543 .client
1544 .post(format!(
1545 "{}/_fakecloud/ecs/tasks/{}/mark-failed",
1546 self.fc.base_url, task_id
1547 ))
1548 .json(req)
1549 .send()
1550 .await?;
1551 FakeCloud::parse(resp).await
1552 }
1553
1554 pub async fn get_events(&self) -> Result<EcsEventsResponse, Error> {
1556 let resp = self
1557 .fc
1558 .client
1559 .get(format!("{}/_fakecloud/ecs/events", self.fc.base_url))
1560 .send()
1561 .await?;
1562 FakeCloud::parse(resp).await
1563 }
1564
1565 pub async fn get_metadata_by_arn(&self, task_arn: &str) -> Result<serde_json::Value, Error> {
1572 let mut encoded = String::with_capacity(task_arn.len());
1573 for b in task_arn.bytes() {
1574 match b {
1575 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
1576 encoded.push(b as char);
1577 }
1578 _ => encoded.push_str(&format!("%{:02X}", b)),
1579 }
1580 }
1581 let resp = self
1582 .fc
1583 .client
1584 .get(format!(
1585 "{}/_fakecloud/ecs/metadata/{}",
1586 self.fc.base_url, encoded
1587 ))
1588 .send()
1589 .await?;
1590 FakeCloud::parse(resp).await
1591 }
1592
1593 pub async fn task_credentials(
1598 &self,
1599 task_id: &str,
1600 ) -> Result<EcsTaskCredentialsResponse, Error> {
1601 let resp = self
1602 .fc
1603 .client
1604 .get(format!(
1605 "{}/_fakecloud/ecs/creds/{}",
1606 self.fc.base_url, task_id
1607 ))
1608 .send()
1609 .await?;
1610 FakeCloud::parse(resp).await
1611 }
1612
1613 pub async fn task_metadata_v3(&self, task_id: &str) -> Result<serde_json::Value, Error> {
1619 let resp = self
1620 .fc
1621 .client
1622 .get(format!(
1623 "{}/_fakecloud/ecs/v3/{}",
1624 self.fc.base_url, task_id
1625 ))
1626 .send()
1627 .await?;
1628 FakeCloud::parse(resp).await
1629 }
1630
1631 pub async fn task_metadata_v4(&self, task_id: &str) -> Result<serde_json::Value, Error> {
1635 let resp = self
1636 .fc
1637 .client
1638 .get(format!(
1639 "{}/_fakecloud/ecs/v4/{}",
1640 self.fc.base_url, task_id
1641 ))
1642 .send()
1643 .await?;
1644 FakeCloud::parse(resp).await
1645 }
1646}
1647
1648pub struct Route53Client<'a> {
1651 fc: &'a FakeCloud,
1652}
1653
1654impl Route53Client<'_> {
1655 pub async fn dnssec_material(
1659 &self,
1660 zone_id: &str,
1661 ) -> Result<Route53DnssecMaterialResponse, Error> {
1662 let resp = self
1663 .fc
1664 .client
1665 .get(format!(
1666 "{}/_fakecloud/route53/zones/{}/dnssec",
1667 self.fc.base_url, zone_id
1668 ))
1669 .send()
1670 .await?;
1671 FakeCloud::parse(resp).await
1672 }
1673
1674 pub async fn dnssec_sign(
1678 &self,
1679 zone_id: &str,
1680 req: &Route53DnssecSignRequest,
1681 ) -> Result<Route53DnssecSignResponse, Error> {
1682 let resp = self
1683 .fc
1684 .client
1685 .post(format!(
1686 "{}/_fakecloud/route53/zones/{}/dnssec/sign",
1687 self.fc.base_url, zone_id
1688 ))
1689 .json(req)
1690 .send()
1691 .await?;
1692 FakeCloud::parse(resp).await
1693 }
1694}
1695
1696pub struct AthenaClient<'a> {
1699 fc: &'a FakeCloud,
1700}
1701
1702impl AthenaClient<'_> {
1703 pub async fn get_named_queries(&self) -> Result<AthenaNamedQueriesResponse, Error> {
1708 let resp = self
1709 .fc
1710 .client
1711 .get(format!(
1712 "{}/_fakecloud/athena/named-queries",
1713 self.fc.base_url
1714 ))
1715 .send()
1716 .await?;
1717 FakeCloud::parse(resp).await
1718 }
1719}
1720
1721pub struct OrganizationsClient<'a> {
1724 fc: &'a FakeCloud,
1725}
1726
1727impl OrganizationsClient<'_> {
1728 pub async fn get_accounts(&self) -> Result<OrganizationsAccountsResponse, Error> {
1733 let resp = self
1734 .fc
1735 .client
1736 .get(format!(
1737 "{}/_fakecloud/organizations/accounts",
1738 self.fc.base_url
1739 ))
1740 .send()
1741 .await?;
1742 FakeCloud::parse(resp).await
1743 }
1744}
1745
1746pub struct AcmClient<'a> {
1749 fc: &'a FakeCloud,
1750}
1751
1752impl AcmClient<'_> {
1753 fn certificate_id(arn_or_id: &str) -> String {
1754 match arn_or_id.rfind("certificate/") {
1755 Some(idx) => arn_or_id[idx + "certificate/".len()..].to_string(),
1756 None => arn_or_id.to_string(),
1757 }
1758 }
1759
1760 pub async fn set_certificate_status(
1765 &self,
1766 arn_or_id: &str,
1767 req: &AcmCertificateStatusRequest,
1768 ) -> Result<(), Error> {
1769 let id = Self::certificate_id(arn_or_id);
1770 let resp = self
1771 .fc
1772 .client
1773 .post(format!(
1774 "{}/_fakecloud/acm/certificates/{}/status",
1775 self.fc.base_url, id
1776 ))
1777 .json(req)
1778 .send()
1779 .await?;
1780 if !resp.status().is_success() {
1781 let status = resp.status().as_u16();
1782 let body = resp.text().await.unwrap_or_default();
1783 return Err(Error::Api { status, body });
1784 }
1785 Ok(())
1786 }
1787
1788 pub async fn get_certificate_chain_info(
1792 &self,
1793 arn_or_id: &str,
1794 ) -> Result<AcmCertificateChainInfo, Error> {
1795 let id = Self::certificate_id(arn_or_id);
1796 let resp = self
1797 .fc
1798 .client
1799 .get(format!(
1800 "{}/_fakecloud/acm/certificates/{}/chain-info",
1801 self.fc.base_url, id
1802 ))
1803 .send()
1804 .await?;
1805 FakeCloud::parse(resp).await
1806 }
1807
1808 pub async fn approve_certificate(&self, arn_or_id: &str) -> Result<(), Error> {
1812 let id = Self::certificate_id(arn_or_id);
1813 let resp = self
1814 .fc
1815 .client
1816 .post(format!(
1817 "{}/_fakecloud/acm/certificates/{}/approve",
1818 self.fc.base_url, id
1819 ))
1820 .send()
1821 .await?;
1822 if !resp.status().is_success() {
1823 let status = resp.status().as_u16();
1824 let body = resp.text().await.unwrap_or_default();
1825 return Err(Error::Api { status, body });
1826 }
1827 Ok(())
1828 }
1829}
1830
1831pub struct EcrClient<'a> {
1834 fc: &'a FakeCloud,
1835}
1836
1837impl EcrClient<'_> {
1838 pub async fn get_images(&self) -> Result<EcrImagesResponse, Error> {
1840 let resp = self
1841 .fc
1842 .client
1843 .get(format!("{}/_fakecloud/ecr/images", self.fc.base_url))
1844 .send()
1845 .await?;
1846 FakeCloud::parse(resp).await
1847 }
1848
1849 pub async fn get_repositories(&self) -> Result<EcrRepositoriesResponse, Error> {
1851 let resp = self
1852 .fc
1853 .client
1854 .get(format!("{}/_fakecloud/ecr/repositories", self.fc.base_url))
1855 .send()
1856 .await?;
1857 FakeCloud::parse(resp).await
1858 }
1859
1860 pub async fn get_pull_through_rules(&self) -> Result<EcrPullThroughRulesResponse, Error> {
1862 let resp = self
1863 .fc
1864 .client
1865 .get(format!(
1866 "{}/_fakecloud/ecr/pull-through-rules",
1867 self.fc.base_url
1868 ))
1869 .send()
1870 .await?;
1871 FakeCloud::parse(resp).await
1872 }
1873}
1874
1875pub struct Elbv2Client<'a> {
1878 fc: &'a FakeCloud,
1879}
1880
1881impl Elbv2Client<'_> {
1882 pub async fn get_load_balancers(&self) -> Result<Elbv2LoadBalancersResponse, Error> {
1884 let resp = self
1885 .fc
1886 .client
1887 .get(format!(
1888 "{}/_fakecloud/elbv2/load-balancers",
1889 self.fc.base_url
1890 ))
1891 .send()
1892 .await?;
1893 FakeCloud::parse(resp).await
1894 }
1895
1896 pub async fn get_listeners(&self) -> Result<Elbv2ListenersResponse, Error> {
1898 let resp = self
1899 .fc
1900 .client
1901 .get(format!("{}/_fakecloud/elbv2/listeners", self.fc.base_url))
1902 .send()
1903 .await?;
1904 FakeCloud::parse(resp).await
1905 }
1906
1907 pub async fn get_rules(&self) -> Result<Elbv2RulesResponse, Error> {
1909 let resp = self
1910 .fc
1911 .client
1912 .get(format!("{}/_fakecloud/elbv2/rules", self.fc.base_url))
1913 .send()
1914 .await?;
1915 FakeCloud::parse(resp).await
1916 }
1917
1918 pub async fn get_target_groups(&self) -> Result<Elbv2TargetGroupsResponse, Error> {
1921 let resp = self
1922 .fc
1923 .client
1924 .get(format!(
1925 "{}/_fakecloud/elbv2/target-groups",
1926 self.fc.base_url
1927 ))
1928 .send()
1929 .await?;
1930 FakeCloud::parse(resp).await
1931 }
1932
1933 pub async fn flush_access_logs(&self) -> Result<Elbv2AccessLogsFlushResponse, Error> {
1936 let resp = self
1937 .fc
1938 .client
1939 .post(format!(
1940 "{}/_fakecloud/elbv2/access-logs/flush",
1941 self.fc.base_url
1942 ))
1943 .send()
1944 .await?;
1945 FakeCloud::parse(resp).await
1946 }
1947}
1948
1949pub struct GlueClient<'a> {
1952 fc: &'a FakeCloud,
1953}
1954
1955impl GlueClient<'_> {
1956 pub async fn get_jobs(&self) -> Result<GlueJobsResponse, Error> {
1958 let resp = self
1959 .fc
1960 .client
1961 .get(format!("{}/_fakecloud/glue/jobs", self.fc.base_url))
1962 .send()
1963 .await?;
1964 FakeCloud::parse(resp).await
1965 }
1966
1967 pub async fn get_job_runs(&self, job_name: Option<&str>) -> Result<GlueJobRunsResponse, Error> {
1970 fn encode(s: &str) -> String {
1971 let mut out = String::with_capacity(s.len());
1972 for b in s.bytes() {
1973 match b {
1974 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
1975 out.push(b as char);
1976 }
1977 _ => out.push_str(&format!("%{:02X}", b)),
1978 }
1979 }
1980 out
1981 }
1982 let mut url = format!("{}/_fakecloud/glue/job-runs", self.fc.base_url);
1983 if let Some(name) = job_name {
1984 url.push_str("?job_name=");
1985 url.push_str(&encode(name));
1986 }
1987 let resp = self.fc.client.get(url).send().await?;
1988 FakeCloud::parse(resp).await
1989 }
1990}
1991
1992pub struct LogsClient<'a> {
1995 fc: &'a FakeCloud,
1996}
1997
1998impl LogsClient<'_> {
1999 pub async fn inject_anomaly(
2003 &self,
2004 req: &LogsAnomalyInjectRequest,
2005 ) -> Result<LogsAnomalyInjectResponse, Error> {
2006 let resp = self
2007 .fc
2008 .client
2009 .post(format!(
2010 "{}/_fakecloud/logs/anomalies/inject",
2011 self.fc.base_url
2012 ))
2013 .json(req)
2014 .send()
2015 .await?;
2016 FakeCloud::parse(resp).await
2017 }
2018
2019 pub async fn get_delivery_config(&self) -> Result<LogsDeliveryConfigResponse, Error> {
2023 let resp = self
2024 .fc
2025 .client
2026 .get(format!(
2027 "{}/_fakecloud/logs/delivery-config",
2028 self.fc.base_url
2029 ))
2030 .send()
2031 .await?;
2032 FakeCloud::parse(resp).await
2033 }
2034
2035 pub async fn get_field_indexes(
2039 &self,
2040 log_group_name: &str,
2041 ) -> Result<LogsFieldIndexesResponse, Error> {
2042 let resp = self
2043 .fc
2044 .client
2045 .get(format!(
2046 "{}/_fakecloud/logs/field-indexes/{}",
2047 self.fc.base_url,
2048 utf8_percent_encode(log_group_name, NON_ALPHANUMERIC)
2049 ))
2050 .send()
2051 .await?;
2052 FakeCloud::parse(resp).await
2053 }
2054}
2055
2056impl Route53Client<'_> {
2057 pub async fn set_health_check_status(
2062 &self,
2063 id: &str,
2064 req: &Route53HealthCheckStatusRequest,
2065 ) -> Result<(), Error> {
2066 let resp = self
2067 .fc
2068 .client
2069 .post(format!(
2070 "{}/_fakecloud/route53/health-checks/{}/status",
2071 self.fc.base_url, id
2072 ))
2073 .json(req)
2074 .send()
2075 .await?;
2076 if !resp.status().is_success() {
2077 let status = resp.status().as_u16();
2078 let body = resp.text().await.unwrap_or_default();
2079 return Err(Error::Api { status, body });
2080 }
2081 Ok(())
2082 }
2083}
2084
2085pub struct SchedulerClient<'a> {
2088 fc: &'a FakeCloud,
2089}
2090
2091impl SchedulerClient<'_> {
2092 pub async fn get_schedules(&self) -> Result<SchedulerSchedulesResponse, Error> {
2095 let resp = self
2096 .fc
2097 .client
2098 .get(format!(
2099 "{}/_fakecloud/scheduler/schedules",
2100 self.fc.base_url
2101 ))
2102 .send()
2103 .await?;
2104 FakeCloud::parse(resp).await
2105 }
2106
2107 pub async fn fire_schedule(
2111 &self,
2112 group: &str,
2113 name: &str,
2114 ) -> Result<FireScheduleResponse, Error> {
2115 let resp = self
2116 .fc
2117 .client
2118 .post(format!(
2119 "{}/_fakecloud/scheduler/fire/{}/{}",
2120 self.fc.base_url, group, name
2121 ))
2122 .send()
2123 .await?;
2124 FakeCloud::parse(resp).await
2125 }
2126}
2127
2128pub struct SsmClient<'a> {
2131 fc: &'a FakeCloud,
2132}
2133
2134impl SsmClient<'_> {
2135 pub async fn set_command_status(
2138 &self,
2139 command_id: &str,
2140 req: &SetSsmCommandStatusRequest,
2141 ) -> Result<SetSsmCommandStatusResponse, Error> {
2142 let resp = self
2143 .fc
2144 .client
2145 .post(format!(
2146 "{}/_fakecloud/ssm/commands/{}/status",
2147 self.fc.base_url, command_id
2148 ))
2149 .json(req)
2150 .send()
2151 .await?;
2152 FakeCloud::parse(resp).await
2153 }
2154
2155 pub async fn fail_command(
2159 &self,
2160 command_id: &str,
2161 req: Option<&FailSsmCommandRequest>,
2162 ) -> Result<FailSsmCommandResponse, Error> {
2163 let mut builder = self.fc.client.post(format!(
2164 "{}/_fakecloud/ssm/commands/{}/fail",
2165 self.fc.base_url, command_id
2166 ));
2167 if let Some(body) = req {
2168 builder = builder.json(body);
2169 }
2170 let resp = builder.send().await?;
2171 FakeCloud::parse(resp).await
2172 }
2173
2174 pub async fn parameter_policy_events(
2177 &self,
2178 account_id: Option<&str>,
2179 ) -> Result<SsmParameterPolicyEventsResponse, Error> {
2180 let mut url = format!(
2181 "{}/_fakecloud/ssm/parameter-policy-events",
2182 self.fc.base_url
2183 );
2184 if let Some(id) = account_id {
2185 url.push_str("?accountId=");
2186 url.push_str(id);
2187 }
2188 let resp = self.fc.client.get(url).send().await?;
2189 FakeCloud::parse(resp).await
2190 }
2191
2192 pub async fn inject_session(
2196 &self,
2197 req: &InjectSsmSessionRequest,
2198 ) -> Result<InjectSsmSessionResponse, Error> {
2199 let resp = self
2200 .fc
2201 .client
2202 .post(format!(
2203 "{}/_fakecloud/ssm/sessions/inject",
2204 self.fc.base_url
2205 ))
2206 .json(req)
2207 .send()
2208 .await?;
2209 FakeCloud::parse(resp).await
2210 }
2211}
2212
2213pub struct KmsClient<'a> {
2216 fc: &'a FakeCloud,
2217}
2218
2219impl KmsClient<'_> {
2220 pub async fn usage(&self) -> Result<KmsUsageResponse, Error> {
2222 let resp = self
2223 .fc
2224 .client
2225 .get(format!("{}/_fakecloud/kms/usage", self.fc.base_url))
2226 .send()
2227 .await?;
2228 FakeCloud::parse(resp).await
2229 }
2230}
2231
2232pub struct WafV2Client<'a> {
2235 fc: &'a FakeCloud,
2236}
2237
2238impl WafV2Client<'_> {
2239 pub async fn evaluate(&self, body: &serde_json::Value) -> Result<serde_json::Value, Error> {
2244 let resp = self
2245 .fc
2246 .client
2247 .post(format!("{}/_fakecloud/wafv2/evaluate", self.fc.base_url))
2248 .json(body)
2249 .send()
2250 .await?;
2251 FakeCloud::parse(resp).await
2252 }
2253}
2254
2255pub struct CloudFrontClient<'a> {
2258 fc: &'a FakeCloud,
2259}
2260
2261impl CloudFrontClient<'_> {
2262 pub async fn set_distribution_status(
2266 &self,
2267 distribution_id: &str,
2268 req: &CloudFrontDistributionStatusRequest,
2269 ) -> Result<(), Error> {
2270 let resp = self
2271 .fc
2272 .client
2273 .post(format!(
2274 "{}/_fakecloud/cloudfront/distributions/{}/status",
2275 self.fc.base_url, distribution_id
2276 ))
2277 .json(req)
2278 .send()
2279 .await?;
2280 let status = resp.status().as_u16();
2281 if !resp.status().is_success() {
2282 let body = resp.text().await.unwrap_or_default();
2283 return Err(Error::Api { status, body });
2284 }
2285 Ok(())
2286 }
2287}
2288
2289impl Elbv2Client<'_> {
2290 pub async fn waf_counts(&self) -> Result<Elbv2WafCountsResponse, Error> {
2294 let resp = self
2295 .fc
2296 .client
2297 .get(format!("{}/_fakecloud/elbv2/waf-counts", self.fc.base_url))
2298 .send()
2299 .await?;
2300 FakeCloud::parse(resp).await
2301 }
2302}