feldera_cloud1_client/
license.rs1use chrono::{DateTime, Utc};
3use reqwest::StatusCode;
4use serde::{Deserialize, Serialize};
5use std::time::Instant;
6use thiserror::Error as ThisError;
7use utoipa::ToSchema;
8
9use crate::source_error;
10
11#[derive(Serialize, Deserialize, Debug)]
14pub struct LicenseCheckRequest {
15 pub account_id: String,
16 pub license_key: String,
17}
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
20#[allow(dead_code)]
21pub enum DisplaySchedule {
22 Once,
24 Session,
26 Every { seconds: u64 },
28 Always,
30}
31
32#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
33pub struct LicenseInformation {
34 pub current: DateTime<Utc>,
36 pub valid_until: Option<DateTime<Utc>>,
38 pub is_trial: bool,
40 pub description_html: String,
42 pub extension_url: Option<String>,
44 pub remind_starting_at: Option<DateTime<Utc>>,
46 pub remind_schedule: DisplaySchedule,
48}
49
50#[derive(ThisError, Debug, Clone, PartialEq)]
52pub enum LicenseRetrievalError {
53 #[error("failed to serialize request to JSON due to: {error}")]
54 SerializeRequestToJsonFailed { error: String },
55 #[error("failed to send request due to: {error}")]
56 SendRequestFailed { error: String },
57 #[error("license information returned could not be deserialized due to: {error}")]
58 JsonDeserializeFailed { error: String },
59 #[error("server indicated the service is currently unavailable (503)")]
60 ServiceUnavailable,
61 #[error("server responded with an unexpected HTTP status code ({0})")]
62 UnexpectedResponseStatusCode(StatusCode),
63}
64
65#[derive(Debug, Clone, PartialEq)]
66pub enum LicenseRetrievalResult {
67 Exists(LicenseInformation),
70
71 DoesNotExistInvalid,
74
75 Unable(LicenseRetrievalError),
78}
79
80pub async fn retrieve_license(
82 cloud_api_endpoint: &str,
84 license_key: &str,
86) -> (Instant, LicenseRetrievalResult) {
87 let endpoint_license_retrieval = format!("{cloud_api_endpoint}/license");
88 let client = reqwest::Client::new();
89 let result = client
90 .get(&endpoint_license_retrieval)
91 .header(
92 reqwest::header::AUTHORIZATION,
93 format!("Bearer {}", license_key),
94 )
95 .send()
96 .await;
97 let now = Instant::now();
98 let result = match result {
99 Ok(response) => {
100 let status_code = response.status();
101 if status_code == StatusCode::OK {
102 match response.json::<LicenseInformation>().await {
103 Ok(license_information) => LicenseRetrievalResult::Exists(license_information),
104 Err(error) => LicenseRetrievalResult::Unable(
105 LicenseRetrievalError::JsonDeserializeFailed {
106 error: error.to_string(),
107 },
108 ),
109 }
110 } else if status_code == StatusCode::FORBIDDEN {
111 LicenseRetrievalResult::DoesNotExistInvalid
112 } else if status_code == StatusCode::SERVICE_UNAVAILABLE {
113 LicenseRetrievalResult::Unable(LicenseRetrievalError::ServiceUnavailable)
114 } else {
115 LicenseRetrievalResult::Unable(LicenseRetrievalError::UnexpectedResponseStatusCode(
116 status_code,
117 ))
118 }
119 }
120 Err(e) => {
121 let source_err = source_error(&e);
122 let error = format!("{e}, source: {source_err}");
123 LicenseRetrievalResult::Unable(LicenseRetrievalError::SendRequestFailed { error })
124 }
125 };
126 (now, result)
127}