use std::time::SystemTime;
use dex_protocol::dex::{
FlowDefinitionUpload, FlowDefinitionUploadOutcome as ProtoFlowDefinitionUploadOutcome,
FlowDefinitionUploadResult as ProtoFlowDefinitionUploadResult, UploadFlowDefinitionsRequest,
UploadFlowDefinitionsResponse,
};
#[cfg(test)]
mod conformance_tests;
mod definition_sources;
mod generated_at;
mod source_path;
mod worker_upload;
#[cfg(test)]
mod worker_upload_tests;
pub(crate) use definition_sources::{collect_flow_definitions, validate_document};
pub(crate) use source_path::{current_working_directory, rewrite_source_paths};
pub(crate) use worker_upload::upload_flow_definitions_at_worker_start;
const MAX_DEFINITIONS_PER_REQUEST: usize = 256;
const MAX_CONTENT_BYTES_PER_REQUEST: usize = 16 * 1024 * 1024;
#[derive(Clone, PartialEq, Eq)]
pub struct FlowDefinitionDocument {
flow_type: String,
content: Vec<u8>,
generated_at: SystemTime,
}
impl FlowDefinitionDocument {
pub fn new(
flow_type: impl Into<String>,
content: impl Into<Vec<u8>>,
generated_at: SystemTime,
) -> Self {
Self {
flow_type: flow_type.into(),
content: content.into(),
generated_at,
}
}
pub fn flow_type(&self) -> &str {
&self.flow_type
}
pub fn content(&self) -> &[u8] {
&self.content
}
pub fn generated_at(&self) -> SystemTime {
self.generated_at
}
}
impl std::fmt::Debug for FlowDefinitionDocument {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("FlowDefinitionDocument")
.field("flow_type", &self.flow_type)
.field("content_bytes", &self.content.len())
.field("generated_at", &self.generated_at)
.finish()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum FlowDefinitionUploadOutcome {
Created,
Replaced,
Unchanged,
KeptExisting,
Unknown,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FlowDefinitionUploadResult {
flow_type: String,
outcome: FlowDefinitionUploadOutcome,
stored_digest: String,
stored_generated_at: Option<SystemTime>,
}
impl FlowDefinitionUploadResult {
pub fn flow_type(&self) -> &str {
&self.flow_type
}
pub fn outcome(&self) -> FlowDefinitionUploadOutcome {
self.outcome
}
pub fn stored_digest(&self) -> &str {
&self.stored_digest
}
pub fn stored_generated_at(&self) -> Option<SystemTime> {
self.stored_generated_at
}
}
fn uploader() -> String {
format!("sdk-rust/{}", crate::server_protocol::SDK_VERSION)
}
pub(crate) fn upload_requests(
documents: Vec<FlowDefinitionDocument>,
force: bool,
) -> Vec<UploadFlowDefinitionsRequest> {
let mut requests: Vec<UploadFlowDefinitionsRequest> = Vec::new();
for document in documents {
let needs_new_request = requests.last().is_none_or(|request| {
request.definitions.len() == MAX_DEFINITIONS_PER_REQUEST
|| request_content_bytes(request) + document.content.len()
> MAX_CONTENT_BYTES_PER_REQUEST
});
if needs_new_request {
requests.push(UploadFlowDefinitionsRequest {
definitions: Vec::new(),
uploader: uploader(),
force,
});
}
let request = requests
.last_mut()
.expect("a request was pushed for this document");
request.definitions.push(FlowDefinitionUpload {
flow_type: document.flow_type,
content: document.content,
generated_at: Some(generated_at::truncate_timestamp_to_millis(
prost_types::Timestamp::from(document.generated_at),
)),
});
}
requests
}
fn request_content_bytes(request: &UploadFlowDefinitionsRequest) -> usize {
request
.definitions
.iter()
.map(|definition| definition.content.len())
.sum()
}
pub(crate) fn map_upload_results(
response: UploadFlowDefinitionsResponse,
) -> Vec<FlowDefinitionUploadResult> {
response
.results
.into_iter()
.map(map_upload_result)
.collect()
}
pub(crate) fn map_upload_result(
result: ProtoFlowDefinitionUploadResult,
) -> FlowDefinitionUploadResult {
let outcome = match ProtoFlowDefinitionUploadOutcome::try_from(result.outcome) {
Ok(ProtoFlowDefinitionUploadOutcome::Created) => FlowDefinitionUploadOutcome::Created,
Ok(ProtoFlowDefinitionUploadOutcome::Replaced) => FlowDefinitionUploadOutcome::Replaced,
Ok(ProtoFlowDefinitionUploadOutcome::Unchanged) => FlowDefinitionUploadOutcome::Unchanged,
Ok(ProtoFlowDefinitionUploadOutcome::KeptExisting) => {
FlowDefinitionUploadOutcome::KeptExisting
}
Ok(ProtoFlowDefinitionUploadOutcome::Unspecified) | Err(_) => {
FlowDefinitionUploadOutcome::Unknown
}
};
FlowDefinitionUploadResult {
flow_type: result.flow_type,
outcome,
stored_digest: result.stored_digest,
stored_generated_at: result
.stored_generated_at
.and_then(|timestamp| SystemTime::try_from(timestamp).ok()),
}
}