1#![allow(dead_code)]
43
44use reqwest::{Client, Error};
45use serde::{Deserialize, Serialize};
46use serde_json::Value;
47
48#[derive(Debug, Clone)]
50pub struct MeterClient {
51 base_url: String,
52 token: String,
53 http_client: Client,
54}
55
56impl MeterClient {
57 pub fn new(base_url: String, token: String) -> Self {
59 MeterClient {
60 base_url,
61 token,
62 http_client: Client::new(),
63 }
64 }
65
66 fn get_auth_header(&self) -> String {
67 format!("Bearer {}", self.token)
68 }
69
70 pub async fn create_meter(&self, body: &CreateMeterRequest) -> Result<Meter, Error> {
74 let url = format!("{}/api/v1/meters", self.base_url);
75 let resp = self
76 .http_client
77 .post(url)
78 .header("Authorization", self.get_auth_header())
79 .header("Content-Type", "application/json")
80 .json(&body)
81 .send()
82 .await?
83 .error_for_status()?;
84
85 Ok(resp.json::<Meter>().await?)
86 }
87
88 pub async fn delete_meter(&self, meter_id_or_slug: &str) -> Result<(), Error> {
92 let url = format!("{}/api/v1/meters/{}", self.base_url, meter_id_or_slug);
93 self.http_client
94 .delete(url)
95 .header("Authorization", self.get_auth_header())
96 .send()
97 .await?
98 .error_for_status()?;
99
100 Ok(())
101 }
102
103 pub async fn get_meter(&self, meter_id_or_slug: &str) -> Result<Meter, Error> {
107 let url = format!("{}/api/v1/meters/{}", self.base_url, meter_id_or_slug);
108 let resp = self
109 .http_client
110 .get(url)
111 .header("Authorization", self.get_auth_header())
112 .send()
113 .await?
114 .error_for_status()?;
115
116 Ok(resp.json::<Meter>().await?)
117 }
118
119 pub async fn list_meters(&self) -> Result<Vec<Meter>, Error> {
123 let url = format!("{}/api/v1/meters", self.base_url);
124 let resp = self
125 .http_client
126 .get(url)
127 .header("Authorization", self.get_auth_header())
128 .send()
129 .await?
130 .error_for_status()?;
131
132 Ok(resp.json::<Vec<Meter>>().await?)
133 }
134
135 pub async fn list_meter_subjects(&self, meter_id_or_slug: &str) -> Result<Vec<String>, Error> {
139 let url = format!(
140 "{}/api/v1/meters/{}/subjects",
141 self.base_url, meter_id_or_slug
142 );
143 let resp = self
144 .http_client
145 .get(url)
146 .header("Authorization", self.get_auth_header())
147 .send()
148 .await?
149 .error_for_status()?;
150
151 Ok(resp.json::<Vec<String>>().await?)
152 }
153
154 pub async fn query_meter(
166 &self,
167 meter_id_or_slug: &str,
168 params: &QueryParams,
169 ) -> Result<QueryResponse, Error> {
170 let url = format!("{}/api/v1/meters/{}/query", self.base_url, meter_id_or_slug);
171 let request_builder = self
172 .http_client
173 .get(url)
174 .header("Authorization", self.get_auth_header());
175
176 let mut query_params = vec![];
178 if let Some(ref from) = params.from {
179 query_params.push(("from", from.clone()));
180 }
181 if let Some(ref to) = params.to {
182 query_params.push(("to", to.clone()));
183 }
184 if let Some(ref window_size) = params.window_size {
185 query_params.push(("windowSize", window_size.clone()));
186 }
187 if let Some(ref window_tz) = params.window_time_zone {
188 query_params.push(("windowTimeZone", window_tz.clone()));
189 }
190 if let Some(subjects) = ¶ms.subject {
191 for s in subjects {
192 query_params.push(("subject", s.clone()));
193 }
194 }
195 let resp = request_builder
198 .query(&query_params)
199 .send()
200 .await?
201 .error_for_status()?;
202
203 Ok(resp.json::<QueryResponse>().await?)
204 }
205
206 pub async fn update_meter(
210 &self,
211 meter_id_or_slug: &str,
212 body: &UpdateMeterRequest,
213 ) -> Result<Meter, Error> {
214 let url = format!("{}/api/v1/meters/{}", self.base_url, meter_id_or_slug);
215 let resp = self
216 .http_client
217 .put(url)
218 .header("Authorization", self.get_auth_header())
219 .header("Content-Type", "application/json")
220 .json(&body)
221 .send()
222 .await?
223 .error_for_status()?;
224
225 Ok(resp.json::<Meter>().await?)
226 }
227
228 pub async fn ingest_events(&self, events: &[CloudEvent]) -> Result<(), Error> {
236 let url = format!("{}/api/v1/events", self.base_url);
237 self.http_client
240 .post(url)
241 .header("Authorization", self.get_auth_header())
242 .header("Content-Type", "application/json")
243 .json(&events)
244 .send()
245 .await?
246 .error_for_status()?;
247
248 Ok(())
249 }
250
251 pub async fn list_events(
262 &self,
263 params: &ListEventsParams,
264 ) -> Result<Vec<IngestedEvent>, Error> {
265 let url = format!("{}/api/v1/events", self.base_url);
266 let mut query_params = vec![];
267
268 if let Some(ref client_id) = params.client_id {
269 query_params.push(("clientId", client_id.clone()));
270 }
271 if let Some(ref ingested_at_from) = params.ingested_at_from {
272 query_params.push(("ingestedAtFrom", ingested_at_from.clone()));
273 }
274 if let Some(ref ingested_at_to) = params.ingested_at_to {
275 query_params.push(("ingestedAtTo", ingested_at_to.clone()));
276 }
277 if let Some(ref id) = params.id {
278 query_params.push(("id", id.clone()));
279 }
280 if let Some(ref subject) = params.subject {
281 query_params.push(("subject", subject.clone()));
282 }
283 if let Some(ref from) = params.from {
284 query_params.push(("from", from.clone()));
285 }
286 if let Some(ref to) = params.to {
287 query_params.push(("to", to.clone()));
288 }
289 if let Some(limit) = params.limit {
290 query_params.push(("limit", format!("{}", limit)));
291 }
292
293 let resp = self
294 .http_client
295 .get(url)
296 .header("Authorization", self.get_auth_header())
297 .query(&query_params)
298 .send()
299 .await?
300 .error_for_status()?;
301
302 Ok(resp.json::<Vec<IngestedEvent>>().await?)
303 }
304
305 pub async fn create_entitlement(
313 &self,
314 subject_id_or_key: &str,
315 req: CreateEntitlementRequest,
316 ) -> Result<Entitlement, Error> {
317 let url = format!(
318 "{}/api/v1/subjects/{}/entitlements",
319 self.base_url, subject_id_or_key
320 );
321 let resp = self
322 .http_client
323 .post(url)
324 .header("Authorization", self.get_auth_header())
325 .json(&req)
326 .send()
327 .await?
328 .error_for_status()?;
329
330 Ok(resp.json::<Entitlement>().await?)
331 }
332
333 pub async fn create_feature(&self, req: CreateFeatureRequest) -> Result<Feature, Error> {
337 let url = format!("{}/api/v1/features", self.base_url);
338 let resp = self
339 .http_client
340 .post(url)
341 .header("Authorization", self.get_auth_header())
342 .json(&req)
343 .send()
344 .await?
345 .error_for_status()?;
346
347 Ok(resp.json::<Feature>().await?)
348 }
349
350 pub async fn create_grant(
354 &self,
355 subject_id_or_key: &str,
356 entitlement_id_or_feature_key: &str,
357 req: GrantRequest,
358 ) -> Result<Grant, Error> {
359 let url = format!(
360 "{}/api/v1/subjects/{}/entitlements/{}/grants",
361 self.base_url, subject_id_or_key, entitlement_id_or_feature_key
362 );
363 let resp = self
364 .http_client
365 .post(url)
366 .header("Authorization", self.get_auth_header())
367 .json(&req)
368 .send()
369 .await?
370 .error_for_status()?;
371
372 Ok(resp.json::<Grant>().await?)
373 }
374
375 pub async fn delete_entitlement(
379 &self,
380 subject_id_or_key: &str,
381 entitlement_id: &str,
382 ) -> Result<(), Error> {
383 let url = format!(
384 "{}/api/v1/subjects/{}/entitlements/{}",
385 self.base_url, subject_id_or_key, entitlement_id
386 );
387 self.http_client
388 .delete(url)
389 .header("Authorization", self.get_auth_header())
390 .send()
391 .await?
392 .error_for_status()?;
393 Ok(())
394 }
395
396 pub async fn delete_feature(&self, feature_id: &str) -> Result<(), Error> {
400 let url = format!("{}/api/v1/features/{}", self.base_url, feature_id);
401 self.http_client
402 .delete(url)
403 .header("Authorization", self.get_auth_header())
404 .send()
405 .await?
406 .error_for_status()?;
407 Ok(())
408 }
409
410 pub async fn get_entitlement(
414 &self,
415 subject_id_or_key: &str,
416 entitlement_id: &str,
417 ) -> Result<Entitlement, Error> {
418 let url = format!(
419 "{}/api/v1/subjects/{}/entitlements/{}",
420 self.base_url, subject_id_or_key, entitlement_id
421 );
422 let resp = self
423 .http_client
424 .get(url)
425 .header("Authorization", self.get_auth_header())
426 .send()
427 .await?
428 .error_for_status()?;
429
430 Ok(resp.json::<Entitlement>().await?)
431 }
432
433 pub async fn get_entitlement_by_id(&self, entitlement_id: &str) -> Result<Entitlement, Error> {
437 let url = format!("{}/api/v1/entitlements/{}", self.base_url, entitlement_id);
438 let resp = self
439 .http_client
440 .get(url)
441 .header("Authorization", self.get_auth_header())
442 .send()
443 .await?
444 .error_for_status()?;
445
446 Ok(resp.json::<Entitlement>().await?)
447 }
448
449 pub async fn get_entitlement_history(
453 &self,
454 subject_id_or_key: &str,
455 entitlement_id: &str,
456 from: Option<String>,
457 to: Option<String>,
458 window_size: String, window_time_zone: Option<String>,
460 ) -> Result<Value, Error> {
461 let url = format!(
462 "{}/api/v1/subjects/{}/entitlements/{}/history",
463 self.base_url, subject_id_or_key, entitlement_id
464 );
465
466 let mut query_params = vec![("windowSize", window_size)];
467 if let Some(f) = from {
468 query_params.push(("from", f));
469 }
470 if let Some(t) = to {
471 query_params.push(("to", t));
472 }
473 if let Some(tz) = window_time_zone {
474 query_params.push(("windowTimeZone", tz));
475 }
476
477 let resp = self
478 .http_client
479 .get(url)
480 .header("Authorization", self.get_auth_header())
481 .query(&query_params)
482 .send()
483 .await?
484 .error_for_status()?;
485
486 Ok(resp.json::<Value>().await?)
487 }
488
489 pub async fn get_entitlement_value(
493 &self,
494 subject_id_or_key: &str,
495 entitlement_id_or_feature_key: &str,
496 time: Option<String>,
497 ) -> Result<Value, Error> {
498 let url = format!(
499 "{}/api/v1/subjects/{}/entitlements/{}/value",
500 self.base_url, subject_id_or_key, entitlement_id_or_feature_key
501 );
502
503 let mut query_params = vec![];
504 if let Some(t) = time {
505 query_params.push(("time", t));
506 }
507
508 let resp = self
509 .http_client
510 .get(url)
511 .header("Authorization", self.get_auth_header())
512 .query(&query_params)
513 .send()
514 .await?
515 .error_for_status()?;
516
517 Ok(resp.json::<Value>().await?)
518 }
519
520 pub async fn get_feature(&self, feature_id: &str) -> Result<Feature, Error> {
524 let url = format!("{}/api/v1/features/{}", self.base_url, feature_id);
525 let resp = self
526 .http_client
527 .get(url)
528 .header("Authorization", self.get_auth_header())
529 .send()
530 .await?
531 .error_for_status()?;
532
533 Ok(resp.json::<Feature>().await?)
534 }
535
536 pub async fn list_all_entitlements(&self) -> Result<Vec<Entitlement>, Error> {
540 let url = format!("{}/api/v1/entitlements", self.base_url);
541 let resp = self
542 .http_client
543 .get(url)
544 .header("Authorization", self.get_auth_header())
545 .send()
546 .await?
547 .error_for_status()?;
548
549 Ok(resp.json::<Vec<Entitlement>>().await?)
550 }
551
552 pub async fn list_entitlement_grants(
556 &self,
557 subject_id_or_key: &str,
558 entitlement_id_or_feature_key: &str,
559 ) -> Result<Vec<Grant>, Error> {
560 let url = format!(
561 "{}/api/v1/subjects/{}/entitlements/{}/grants",
562 self.base_url, subject_id_or_key, entitlement_id_or_feature_key
563 );
564 let resp = self
565 .http_client
566 .get(url)
567 .header("Authorization", self.get_auth_header())
568 .send()
569 .await?
570 .error_for_status()?;
571
572 Ok(resp.json::<Vec<Grant>>().await?)
573 }
574
575 pub async fn list_entitlements(
579 &self,
580 subject_id_or_key: &str,
581 ) -> Result<Vec<Entitlement>, Error> {
582 let url = format!(
583 "{}/api/v1/subjects/{}/entitlements",
584 self.base_url, subject_id_or_key
585 );
586 let resp = self
587 .http_client
588 .get(url)
589 .header("Authorization", self.get_auth_header())
590 .send()
591 .await?
592 .error_for_status()?;
593
594 Ok(resp.json::<Vec<Entitlement>>().await?)
595 }
596
597 pub async fn list_features(&self) -> Result<Vec<Feature>, Error> {
601 let url = format!("{}/api/v1/features", self.base_url);
602 let resp = self
603 .http_client
604 .get(url)
605 .header("Authorization", self.get_auth_header())
606 .send()
607 .await?
608 .error_for_status()?;
609
610 Ok(resp.json::<Vec<Feature>>().await?)
611 }
612
613 pub async fn list_grants(&self) -> Result<Vec<Grant>, Error> {
617 let url = format!("{}/api/v1/grants", self.base_url);
618 let resp = self
619 .http_client
620 .get(url)
621 .header("Authorization", self.get_auth_header())
622 .send()
623 .await?
624 .error_for_status()?;
625
626 Ok(resp.json::<Vec<Grant>>().await?)
627 }
628
629 pub async fn override_entitlement(
633 &self,
634 subject_id_or_key: &str,
635 entitlement_id_or_feature_key: &str,
636 req: CreateEntitlementRequest,
637 ) -> Result<Entitlement, Error> {
638 let url = format!(
639 "{}/api/v1/subjects/{}/entitlements/{}/override",
640 self.base_url, subject_id_or_key, entitlement_id_or_feature_key
641 );
642 let resp = self
643 .http_client
644 .put(url)
645 .header("Authorization", self.get_auth_header())
646 .json(&req)
647 .send()
648 .await?
649 .error_for_status()?;
650
651 Ok(resp.json::<Entitlement>().await?)
652 }
653
654 pub async fn reset_entitlement(
658 &self,
659 subject_id_or_key: &str,
660 entitlement_id: &str,
661 req: ResetEntitlementRequest,
662 ) -> Result<(), Error> {
663 let url = format!(
664 "{}/api/v1/subjects/{}/entitlements/{}/reset",
665 self.base_url, subject_id_or_key, entitlement_id
666 );
667 self.http_client
668 .post(url)
669 .header("Authorization", self.get_auth_header())
670 .json(&req)
671 .send()
672 .await?
673 .error_for_status()?;
674 Ok(())
675 }
676
677 pub async fn void_grant(&self, grant_id: &str) -> Result<(), Error> {
681 let url = format!("{}/api/v1/grants/{}", self.base_url, grant_id);
682 self.http_client
683 .delete(url)
684 .header("Authorization", self.get_auth_header())
685 .send()
686 .await?
687 .error_for_status()?;
688 Ok(())
689 }
690}
691
692#[derive(Debug, Serialize, Deserialize)]
696pub struct CreateMeterRequest {
697 #[serde(rename = "slug")]
700 pub slug: String,
701
702 #[serde(rename = "name")]
705 pub name: Option<String>,
706
707 #[serde(rename = "description")]
709 pub description: Option<String>,
710
711 #[serde(rename = "aggregation")]
713 pub aggregation: String,
714
715 #[serde(rename = "eventType")]
717 pub event_type: String,
718
719 #[serde(rename = "eventFrom")]
722 pub event_from: Option<String>,
723
724 #[serde(rename = "valueProperty")]
726 pub value_property: Option<String>,
727
728 #[serde(rename = "groupBy")]
730 pub group_by: Option<Value>,
731
732 #[serde(rename = "metadata")]
734 pub metadata: Option<Value>,
735}
736
737#[derive(Debug, Serialize, Deserialize)]
741pub struct UpdateMeterRequest {
742 #[serde(rename = "name")]
744 pub name: Option<String>,
745
746 #[serde(rename = "description")]
748 pub description: Option<String>,
749
750 #[serde(rename = "groupBy")]
752 pub group_by: Option<Value>,
753
754 #[serde(rename = "metadata")]
756 pub metadata: Option<Value>,
757}
758
759#[derive(Debug, Serialize, Deserialize)]
761pub struct Meter {
762 pub id: String,
763 pub slug: String,
764 pub name: String,
765 pub description: Option<String>,
766 pub aggregation: String,
767 pub eventType: String,
768 pub valueProperty: Option<String>,
769 pub groupBy: Option<Value>,
770 pub createdAt: String,
771 pub updatedAt: String,
772}
773
774#[derive(Debug, Default)]
776pub struct QueryParams {
777 pub from: Option<String>,
778 pub to: Option<String>,
779 pub window_size: Option<String>,
780 pub window_time_zone: Option<String>,
781 pub subject: Option<Vec<String>>,
783 }
785
786#[derive(Debug, Serialize, Deserialize)]
788pub struct QueryResponse {
789 pub from: String,
790 pub to: String,
791 pub windowSize: Option<String>,
792 pub data: Vec<QueryData>,
793}
794
795#[derive(Debug, Serialize, Deserialize)]
797pub struct QueryData {
798 pub value: f64,
799 pub windowStart: Option<String>,
800 pub windowEnd: Option<String>,
801 pub subject: Option<String>,
802
803 #[serde(default)]
805 pub groupBy: Option<Value>,
806}
807
808#[derive(Debug, Serialize, Deserialize)]
816pub struct CloudEvent {
817 pub id: String,
819
820 pub source: String,
822
823 pub specversion: String,
825
826 #[serde(rename = "type")]
828 pub r#type: String,
829
830 pub subject: String,
832
833 pub time: Option<String>,
835
836 pub dataschema: Option<String>,
838
839 pub datacontenttype: Option<String>,
841
842 pub data: Option<Value>,
844}
845
846#[derive(Debug, Default)]
850pub struct ListEventsParams {
851 pub client_id: Option<String>,
852 pub ingested_at_from: Option<String>,
853 pub ingested_at_to: Option<String>,
854 pub id: Option<String>,
855 pub subject: Option<String>,
856 pub from: Option<String>,
857 pub to: Option<String>,
858 pub limit: Option<u32>,
859}
860
861#[derive(Debug, Serialize, Deserialize)]
863pub struct IngestedEvent {
864 pub event: CloudEvent,
865 pub ingestedAt: String,
866 pub storedAt: String,
867}
868
869#[derive(Debug, Serialize, Deserialize)]
875#[serde(rename_all = "camelCase")]
876pub struct CreateEntitlementRequest {
877 pub feature_key: String,
879
880 pub feature_id: Option<String>,
882
883 pub r#type: String,
885
886 #[serde(skip_serializing_if = "Option::is_none")]
888 pub is_soft_limit: Option<bool>,
889
890 #[serde(skip_serializing_if = "Option::is_none")]
891 pub is_unlimited: Option<bool>,
892
893 #[serde(skip_serializing_if = "Option::is_none")]
894 pub usage_period: Option<Value>, #[serde(skip_serializing_if = "Option::is_none")]
897 pub measure_usage_from: Option<String>, #[serde(skip_serializing_if = "Option::is_none")]
900 pub metadata: Option<Value>,
901}
902
903#[derive(Debug, Serialize, Deserialize)]
905#[serde(rename_all = "camelCase")]
906pub struct Entitlement {
907 pub id: String,
908 pub feature_id: String,
909 pub feature_key: String,
910 pub subject_key: String,
911 pub r#type: String,
912 pub is_soft_limit: bool,
913 pub is_unlimited: bool,
914 pub created_at: String,
915 #[serde(skip_serializing_if = "Option::is_none")]
916 pub deleted_at: Option<String>,
917 }
919
920#[derive(Debug, Serialize, Deserialize)]
922#[serde(rename_all = "camelCase")]
923pub struct CreateFeatureRequest {
924 pub key: String,
925 pub name: String,
926 #[serde(skip_serializing_if = "Option::is_none")]
927 pub meter_slug: Option<String>,
928 #[serde(skip_serializing_if = "Option::is_none")]
929 pub meter_group_by_filters: Option<Value>,
930 #[serde(skip_serializing_if = "Option::is_none")]
931 pub metadata: Option<Value>,
932}
933
934#[derive(Debug, Serialize, Deserialize)]
936#[serde(rename_all = "camelCase")]
937pub struct Feature {
938 pub id: String,
939 pub key: String,
940 pub name: String,
941 #[serde(skip_serializing_if = "Option::is_none")]
942 pub deleted_at: Option<String>,
943 }
945
946#[derive(Debug, Default, Serialize, Deserialize)]
948#[serde(rename_all = "camelCase")]
949pub struct GrantRequest {
950 pub amount: f64,
951 #[serde(skip_serializing_if = "Option::is_none")]
952 pub priority: Option<u8>,
953 pub effective_at: String,
954 #[serde(skip_serializing_if = "Option::is_none")]
955 pub expiration: Option<Value>,
956 #[serde(skip_serializing_if = "Option::is_none")]
957 pub max_rollover_amount: Option<f64>,
958 #[serde(skip_serializing_if = "Option::is_none")]
959 pub min_rollover_amount: Option<f64>,
960 #[serde(skip_serializing_if = "Option::is_none")]
961 pub metadata: Option<Value>,
962 #[serde(skip_serializing_if = "Option::is_none")]
963 pub recurrence: Option<Value>,
964}
965
966#[derive(Debug, Serialize, Deserialize)]
968#[serde(rename_all = "camelCase")]
969pub struct Grant {
970 pub id: String,
971 pub entitlement_id: String,
972 pub amount: f64,
973 pub effective_at: String,
974 #[serde(skip_serializing_if = "Option::is_none")]
975 pub deleted_at: Option<String>,
976 }
978
979#[derive(Debug, Serialize, Deserialize)]
981#[serde(rename_all = "camelCase")]
982pub struct ResetEntitlementRequest {
983 #[serde(skip_serializing_if = "Option::is_none")]
984 pub effective_at: Option<String>,
985 #[serde(skip_serializing_if = "Option::is_none")]
986 pub retain_anchor: Option<bool>,
987 #[serde(skip_serializing_if = "Option::is_none")]
988 pub preserve_overage: Option<bool>,
989}