1use crate::origin::Origin;
2use crate::RayConfig;
3use serde::Serialize;
4use std::borrow::Cow;
5use std::sync::Arc;
6use uuid::Uuid;
7
8#[derive(Debug, Clone, Serialize)]
26pub struct Request {
27 pub uuid: Uuid,
28 pub payloads: Vec<PayloadEnvelope>,
29 #[serde(skip_serializing_if = "meta_is_empty")]
30 pub meta: Arc<Meta>,
31}
32
33fn meta_is_empty(meta: &Arc<Meta>) -> bool {
34 meta.is_empty()
35}
36
37impl Request {
38 pub fn new(uuid: Uuid, payloads: Vec<PayloadEnvelope>, meta: Arc<Meta>) -> Self {
40 Self {
41 uuid,
42 payloads,
43 meta,
44 }
45 }
46}
47
48#[derive(Debug, Clone, Serialize)]
59pub struct PayloadEnvelope {
60 #[serde(rename = "type")]
61 pub type_name: Cow<'static, str>,
62 pub content: serde_json::Value,
63 pub origin: Arc<Origin>,
64}
65
66impl PayloadEnvelope {
67 pub fn new(
69 type_name: impl Into<Cow<'static, str>>,
70 content: serde_json::Value,
71 origin: Arc<Origin>,
72 ) -> Self {
73 Self {
74 type_name: type_name.into(),
75 content,
76 origin,
77 }
78 }
79}
80
81#[derive(Debug, Clone, Serialize, Default)]
82pub struct Meta {
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub rustc_version: Option<String>,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub project_name: Option<String>,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub project_version: Option<&'static str>,
91
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub ray_package_version: Option<&'static str>,
94}
95
96impl Meta {
97 pub fn from_config(config: &RayConfig) -> Self {
99 if !config.send_meta {
100 return Self::default();
101 }
102
103 let rustc_version = rustc_version::version_meta()
104 .ok()
105 .map(|m| m.semver.to_string());
106
107 Self {
108 rustc_version,
109 project_name: config
110 .project_name
111 .clone()
112 .or_else(|| Some(env!("CARGO_PKG_NAME").to_string())),
113 project_version: Some(env!("CARGO_PKG_VERSION")),
114 ray_package_version: Some(env!("CARGO_PKG_VERSION")),
115 }
116 }
117
118 fn is_empty(&self) -> bool {
119 self.rustc_version.is_none()
120 && self.project_name.is_none()
121 && self.project_version.is_none()
122 && self.ray_package_version.is_none()
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use crate::{Client, Origin, PayloadEnvelope, RayConfig};
130 use serde_json::json;
131 use std::num::NonZeroU16;
132 use std::sync::Arc;
133
134 #[test]
135 fn meta_is_omitted_when_send_meta_disabled() {
136 let config = RayConfig {
137 enabled: true,
138 host: "localhost".to_string(),
139 port: NonZeroU16::new(23517).expect("port must be non-zero"),
140 send_meta: false,
141 ..RayConfig::default()
142 };
143 let client = Client::new(config);
144 let origin = Arc::new(Origin::default());
145 let payload = PayloadEnvelope::new("log", json!({}), origin);
146 let request = Request::new(uuid::Uuid::new_v4(), vec![payload], client.meta().clone());
147
148 let serialized = serde_json::to_value(&request).expect("request must serialize");
149 assert!(serialized.get("meta").is_none());
150 }
151}