Skip to main content

kawa_storage/
event.rs

1//! # Event Data Structures
2//!
3//! イベントソーシングで使用するイベントデータ構造の定義。
4//! 型安全性とシリアライゼーション効率を重視した設計。
5
6use crate::{Topic, Partition, Offset};
7use derive_more::{Deref, DerefMut, From, Into};
8use serde::{Deserialize, Serialize};
9use std::time::{SystemTime, UNIX_EPOCH};
10use uuid::Uuid;
11
12/// イベントID(UUIDベース)
13/// 
14/// 各イベントの一意識別子。UUIDv4を使用してグローバルに一意性を保証。
15/// 
16/// # Example
17/// ```rust
18/// use kawa_storage::EventId;
19/// 
20/// let event_id = EventId::new();
21/// println!("Event ID: {}", event_id);
22/// ```
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Deref, DerefMut, From, Into)]
24pub struct EventId(pub Uuid);
25
26impl EventId {
27    /// 新しいイベントIDを生成
28    pub fn new() -> Self {
29        Self(Uuid::new_v4())
30    }
31    
32    /// UUIDからイベントIDを作成
33    pub fn from_uuid(uuid: Uuid) -> Self {
34        Self(uuid)
35    }
36}
37
38impl Default for EventId {
39    fn default() -> Self {
40        Self::new()
41    }
42}
43
44impl std::fmt::Display for EventId {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        write!(f, "{}", self.0)
47    }
48}
49
50/// イベントデータのペイロード
51/// 
52/// 実際のイベント内容を格納。バイナリデータとして扱い、
53/// 上位層でのデシリアライゼーションに対応。
54/// 
55/// # @todo
56/// - [ ] 圧縮サポート
57/// - [ ] スキーマバージョニング
58/// - [ ] 暗号化サポート
59#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Deref, DerefMut, From, Into)]
60pub struct EventData(pub Vec<u8>);
61
62impl EventData {
63    /// 新しいイベントデータを作成
64    pub fn new(data: Vec<u8>) -> Self {
65        Self(data)
66    }
67    
68    /// バイト配列からイベントデータを作成
69    pub fn from_bytes(bytes: impl Into<Vec<u8>>) -> Self {
70        Self(bytes.into())
71    }
72    
73    /// JSON文字列からイベントデータを作成
74    pub fn from_json(json: &str) -> Self {
75        Self(json.as_bytes().to_vec())
76    }
77    
78    /// イベントデータのサイズを取得
79    pub fn len(&self) -> usize {
80        self.0.len()
81    }
82    
83    /// イベントデータが空かどうかを確認
84    pub fn is_empty(&self) -> bool {
85        self.0.is_empty()
86    }
87    
88    /// イベントデータをバイト配列として取得
89    pub fn as_bytes(&self) -> &[u8] {
90        &self.0
91    }
92    
93    /// UTF-8文字列として解釈を試行
94    pub fn as_str(&self) -> Option<&str> {
95        std::str::from_utf8(&self.0).ok()
96    }
97    
98    /// イベントデータをJSON文字列として取得
99    /// 
100    /// # Returns
101    /// * `String` - UTF-8文字列として解釈されたイベントデータ
102    /// 
103    /// # Note
104    /// データが有効なUTF-8でない場合、base64エンコードされた文字列を返す
105    pub fn to_json(&self) -> String {
106        match std::str::from_utf8(&self.0) {
107            Ok(s) => s.to_string(),
108            Err(_) => {
109                // バイナリデータの場合はbase64エンコード
110                use base64::Engine;
111                base64::engine::general_purpose::STANDARD.encode(&self.0)
112            }
113        }
114    }
115    
116    /// イベントデータをJSONオブジェクトとして解析
117    /// 
118    /// # Returns
119    /// * `Result<serde_json::Value, serde_json::Error>` - 解析されたJSONオブジェクト
120    pub fn to_json_value(&self) -> Result<serde_json::Value, serde_json::Error> {
121        match std::str::from_utf8(&self.0) {
122            Ok(s) => serde_json::from_str(s),
123            Err(_) => {
124                // バイナリデータの場合はbase64文字列としてJSONにラップ
125                use base64::Engine;
126                let base64_str = base64::engine::general_purpose::STANDARD.encode(&self.0);
127                Ok(serde_json::Value::String(base64_str))
128            }
129        }
130    }
131    
132    /// JSON文字列からイベントデータを作成(バリデーション付き)
133    /// 
134    /// # Arguments
135    /// * `json` - JSON文字列
136    /// 
137    /// # Returns
138    /// * `Result<EventData, serde_json::Error>` - 作成されたイベントデータ
139    pub fn from_json_validated(json: &str) -> Result<Self, serde_json::Error> {
140        // JSONの構文チェック
141        let _: serde_json::Value = serde_json::from_str(json)?;
142        Ok(Self::from_json(json))
143    }
144    
145    /// イベントデータをプレーンテキストとして取得
146    /// 
147    /// # Returns
148    /// * `String` - プレーンテキストとして解釈されたデータ
149    pub fn to_text(&self) -> String {
150        match std::str::from_utf8(&self.0) {
151            Ok(s) => s.to_string(),
152            Err(_) => format!("<binary data: {} bytes>", self.0.len()),
153        }
154    }
155}
156
157/// タイムスタンプ型(Newtypeパターン)
158/// 
159/// UNIXタイムスタンプ(ミリ秒精度)を表現。
160#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Deref, DerefMut, From, Into)]
161pub struct Timestamp(pub u64);
162
163impl Timestamp {
164    /// 現在時刻のタイムスタンプを作成
165    pub fn now() -> Self {
166        let duration = SystemTime::now()
167            .duration_since(UNIX_EPOCH)
168            .unwrap_or_default();
169        Self(duration.as_millis() as u64)
170    }
171    
172    /// ミリ秒値からタイムスタンプを作成
173    pub fn from_millis(millis: u64) -> Self {
174        Self(millis)
175    }
176    
177    /// タイムスタンプをミリ秒値として取得
178    pub fn as_millis(&self) -> u64 {
179        self.0
180    }
181}
182
183impl Default for Timestamp {
184    fn default() -> Self {
185        Self::now()
186    }
187}
188
189/// イベントメタデータ
190/// 
191/// イベントの追加情報を格納。将来の拡張性を考慮した設計。
192/// 
193/// # @todo
194/// - [ ] カスタムヘッダー対応
195/// - [ ] トレーシング情報
196/// - [ ] イベント相関ID
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct EventMetadata {
199    /// 送信者情報
200    pub producer_id: Option<String>,
201    /// コンテンツタイプ
202    pub content_type: Option<String>,
203    /// イベント種別
204    pub event_type: Option<String>,
205    /// 追加ヘッダー
206    pub headers: std::collections::HashMap<String, String>,
207}
208
209impl Default for EventMetadata {
210    fn default() -> Self {
211        Self {
212            producer_id: None,
213            content_type: None,
214            event_type: None,
215            headers: std::collections::HashMap::new(),
216        }
217    }
218}
219
220/// イベント構造体
221/// 
222/// ストレージに永続化される完全なイベント情報。
223/// Kafka互換のメッセージ構造を参考にした設計。
224/// 
225/// # Fields
226/// - `id`: イベントの一意識別子
227/// - `topic`: イベントが属するトピック
228/// - `partition`: パーティション番号
229/// - `offset`: パーティション内での順序位置
230/// - `timestamp`: イベント作成時刻
231/// - `data`: イベントのペイロード
232/// - `metadata`: 追加メタデータ
233/// 
234/// # Example
235/// ```rust
236/// use kawa_storage::{Event, EventId, EventData, Topic, Partition};
237/// 
238/// let event = Event::new(
239///     EventId::new(),
240///     Topic::new("user-events"),
241///     Partition::new(0),
242///     EventData::from_json(r#"{"user_id": 123, "action": "login"}"#)
243/// );
244/// ```
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct Event {
247    /// イベントID
248    pub id: EventId,
249    /// トピック名
250    pub topic: Topic,
251    /// パーティション番号
252    pub partition: Partition,
253    /// オフセット(ストレージによって設定)
254    pub offset: Option<Offset>,
255    /// タイムスタンプ
256    pub timestamp: Timestamp,
257    /// イベントデータ
258    pub data: EventData,
259    /// メタデータ
260    pub metadata: EventMetadata,
261}
262
263impl Event {
264    /// 新しいイベントを作成
265    /// 
266    /// # Arguments
267    /// * `id` - イベントID
268    /// * `topic` - トピック名
269    /// * `partition` - パーティション番号
270    /// * `data` - イベントデータ
271    /// 
272    /// # Returns
273    /// * `Event` - 作成されたイベント
274    pub fn new(
275        id: EventId,
276        topic: Topic,
277        partition: Partition,
278        data: EventData,
279    ) -> Self {
280        Self {
281            id,
282            topic,
283            partition,
284            offset: None,
285            timestamp: Timestamp::now(),
286            data,
287            metadata: EventMetadata::default(),
288        }
289    }
290    
291    /// メタデータ付きでイベントを作成
292    pub fn with_metadata(
293        id: EventId,
294        topic: Topic,
295        partition: Partition,
296        data: EventData,
297        metadata: EventMetadata,
298    ) -> Self {
299        Self {
300            id,
301            topic,
302            partition,
303            offset: None,
304            timestamp: Timestamp::now(),
305            data,
306            metadata,
307        }
308    }
309    
310    /// オフセットを設定(ストレージ内部で使用)
311    pub fn set_offset(&mut self, offset: Offset) {
312        self.offset = Some(offset);
313    }
314    
315    /// イベントのサイズを計算(概算)
316    /// 
317    /// # Returns
318    /// * `usize` - イベントのバイトサイズ(概算)
319    /// 
320    /// # @todo
321    /// - [ ] より正確なサイズ計算
322    pub fn estimated_size(&self) -> usize {
323        // 基本フィールドのサイズ + データサイズ + メタデータサイズ(概算)
324        std::mem::size_of::<EventId>()
325            + self.topic.len()
326            + std::mem::size_of::<Partition>()
327            + std::mem::size_of::<Option<Offset>>()
328            + std::mem::size_of::<Timestamp>()
329            + self.data.len()
330            + self.metadata.headers.len() * 50 // ヘッダーの概算サイズ
331    }
332    
333    /// イベントをキーでソート用の比較キーを取得
334    pub fn sort_key(&self) -> (Timestamp, EventId) {
335        (self.timestamp, self.id)
336    }
337}