1use crate::error::{Error, Result};
3use crate::protocol::Message;
4use bytes::Bytes;
5use futures::stream::Stream;
6use std::pin::Pin;
7use std::task::{Context, Poll};
8use tokio::sync::mpsc;
9pub struct MessageStream {
11 receiver: mpsc::UnboundedReceiver<Message>,
12}
13impl MessageStream {
14 pub fn new(receiver: mpsc::UnboundedReceiver<Message>) -> Self {
16 Self { receiver }
17 }
18 pub async fn next_message(&mut self) -> Option<Message> {
20 self.receiver.recv().await
21 }
22}
23impl Stream for MessageStream {
24 type Item = Message;
25 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
26 self.receiver.poll_recv(cx)
27 }
28}
29pub struct TileStream {
31 receiver: mpsc::UnboundedReceiver<TileData>,
32}
33impl TileStream {
34 pub fn new(receiver: mpsc::UnboundedReceiver<TileData>) -> Self {
36 Self { receiver }
37 }
38 pub async fn next_tile(&mut self) -> Option<TileData> {
40 self.receiver.recv().await
41 }
42}
43impl Stream for TileStream {
44 type Item = TileData;
45 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
46 self.receiver.poll_recv(cx)
47 }
48}
49#[derive(Debug, Clone)]
51pub struct TileData {
52 pub x: u32,
54 pub y: u32,
56 pub zoom: u8,
58 pub data: Bytes,
60 pub mime_type: String,
62}
63impl TileData {
64 pub fn new(x: u32, y: u32, zoom: u8, data: Vec<u8>, mime_type: String) -> Self {
66 Self {
67 x,
68 y,
69 zoom,
70 data: Bytes::from(data),
71 mime_type,
72 }
73 }
74 pub fn coords(&self) -> (u32, u32, u8) {
76 (self.x, self.y, self.zoom)
77 }
78 pub fn size(&self) -> usize {
80 self.data.len()
81 }
82}
83pub struct FeatureStream {
85 receiver: mpsc::UnboundedReceiver<FeatureData>,
86}
87impl FeatureStream {
88 pub fn new(receiver: mpsc::UnboundedReceiver<FeatureData>) -> Self {
90 Self { receiver }
91 }
92 pub async fn next_feature(&mut self) -> Option<FeatureData> {
94 self.receiver.recv().await
95 }
96}
97impl Stream for FeatureStream {
98 type Item = FeatureData;
99 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
100 self.receiver.poll_recv(cx)
101 }
102}
103#[derive(Debug, Clone)]
105pub struct FeatureData {
106 pub geojson: String,
108 pub change_type: crate::protocol::ChangeType,
110 pub layer: Option<String>,
112}
113impl FeatureData {
114 pub fn new(
116 geojson: String,
117 change_type: crate::protocol::ChangeType,
118 layer: Option<String>,
119 ) -> Self {
120 Self {
121 geojson,
122 change_type,
123 layer,
124 }
125 }
126 pub fn parse_json(&self) -> Result<serde_json::Value> {
128 serde_json::from_str(&self.geojson).map_err(Into::into)
129 }
130}
131pub struct EventStream {
133 receiver: mpsc::UnboundedReceiver<EventData>,
134}
135impl EventStream {
136 pub fn new(receiver: mpsc::UnboundedReceiver<EventData>) -> Self {
138 Self { receiver }
139 }
140 pub async fn next_event(&mut self) -> Option<EventData> {
142 self.receiver.recv().await
143 }
144}
145impl Stream for EventStream {
146 type Item = EventData;
147 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
148 self.receiver.poll_recv(cx)
149 }
150}
151#[derive(Debug, Clone)]
153pub struct EventData {
154 pub event_type: crate::protocol::EventType,
156 pub payload: serde_json::Value,
158 pub timestamp: chrono::DateTime<chrono::Utc>,
160}
161impl EventData {
162 pub fn new(event_type: crate::protocol::EventType, payload: serde_json::Value) -> Self {
164 Self {
165 event_type,
166 payload,
167 timestamp: chrono::Utc::now(),
168 }
169 }
170 pub fn with_timestamp(
172 event_type: crate::protocol::EventType,
173 payload: serde_json::Value,
174 timestamp: chrono::DateTime<chrono::Utc>,
175 ) -> Self {
176 Self {
177 event_type,
178 payload,
179 timestamp,
180 }
181 }
182}
183pub struct BackpressureController {
185 max_buffer_size: usize,
187 current_buffer_size: usize,
189 high_watermark: f64,
191 low_watermark: f64,
193 state: BackpressureState,
195}
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198pub enum BackpressureState {
199 Normal,
201 High,
203 Critical,
205}
206impl BackpressureController {
207 pub fn new(max_buffer_size: usize) -> Self {
209 Self {
210 max_buffer_size,
211 current_buffer_size: 0,
212 high_watermark: 0.7,
213 low_watermark: 0.3,
214 state: BackpressureState::Normal,
215 }
216 }
217 pub fn update(&mut self, buffer_size: usize) -> BackpressureState {
219 self.current_buffer_size = buffer_size;
220 let ratio = buffer_size as f64 / self.max_buffer_size as f64;
221 self.state = if ratio >= 0.9 {
222 BackpressureState::Critical
223 } else if ratio >= self.high_watermark {
224 BackpressureState::High
225 } else if ratio <= self.low_watermark {
226 BackpressureState::Normal
227 } else {
228 self.state
229 };
230 self.state
231 }
232 pub fn state(&self) -> BackpressureState {
234 self.state
235 }
236 pub fn should_throttle(&self) -> bool {
238 matches!(
239 self.state,
240 BackpressureState::High | BackpressureState::Critical
241 )
242 }
243 pub fn should_drop(&self) -> bool {
245 self.state == BackpressureState::Critical
246 }
247}
248const DELTA_TAG_RAW: u8 = 0x00;
250const DELTA_TAG_DELTA: u8 = 0x01;
253const MAX_VARINT_SHIFT: u32 = 35;
256
257fn write_varint(buf: &mut Vec<u8>, mut value: u32) {
259 loop {
260 let mut byte = (value & 0x7f) as u8;
261 value >>= 7;
262 if value != 0 {
263 byte |= 0x80;
264 }
265 buf.push(byte);
266 if value == 0 {
267 break;
268 }
269 }
270}
271
272fn read_varint(data: &[u8], pos: &mut usize) -> Result<u32> {
275 let mut result: u32 = 0;
276 let mut shift: u32 = 0;
277 loop {
278 let byte = *data
279 .get(*pos)
280 .ok_or_else(|| Error::Deserialization("truncated varint in delta payload".into()))?;
281 *pos += 1;
282 result |= ((byte & 0x7f) as u32) << shift;
283 if byte & 0x80 == 0 {
284 break;
285 }
286 shift += 7;
287 if shift >= MAX_VARINT_SHIFT {
288 return Err(Error::Deserialization(
289 "varint too long in delta payload".into(),
290 ));
291 }
292 }
293 Ok(result)
294}
295
296pub struct DeltaEncoder {
306 cache: dashmap::DashMap<(u32, u32, u8), Bytes>,
308}
309impl DeltaEncoder {
310 pub fn new() -> Self {
312 Self {
313 cache: dashmap::DashMap::new(),
314 }
315 }
316 pub fn encode(&self, tile: &TileData) -> Result<Vec<u8>> {
322 let key = tile.coords();
323 let delta = match self.cache.get(&key) {
330 Some(prev_data) => Some(Self::compute_delta(&prev_data, &tile.data)?),
331 None => None,
332 };
333 self.cache.insert(key, tile.data.clone());
334 match delta {
335 Some(delta) => Ok(delta),
336 None => Ok(Self::tag_raw(&tile.data)),
337 }
338 }
339 fn tag_raw(data: &[u8]) -> Vec<u8> {
341 let mut out = Vec::with_capacity(1 + data.len());
342 out.push(DELTA_TAG_RAW);
343 out.extend_from_slice(data);
344 out
345 }
346 fn encode_diff_payload(old: &[u8], new: &[u8]) -> Vec<u8> {
349 let mut payload = Vec::new();
350 write_varint(&mut payload, new.len() as u32);
351 let mut last_index: i64 = -1;
352 let common = old.len().min(new.len());
353 for i in 0..new.len() {
354 let changed = if i < common { old[i] != new[i] } else { true };
355 if changed {
356 let gap = (i as i64 - last_index - 1) as u32;
360 write_varint(&mut payload, gap);
361 payload.push(new[i]);
362 last_index = i as i64;
363 }
364 }
365 payload
366 }
367 fn compute_delta(old: &[u8], new: &[u8]) -> Result<Vec<u8>> {
370 let diff_payload = Self::encode_diff_payload(old, new);
371 if diff_payload.len() < new.len() {
372 let mut out = Vec::with_capacity(1 + diff_payload.len());
373 out.push(DELTA_TAG_DELTA);
374 out.extend_from_slice(&diff_payload);
375 Ok(out)
376 } else {
377 Ok(Self::tag_raw(new))
378 }
379 }
380 pub fn apply_delta(old: &[u8], encoded: &[u8]) -> Result<Vec<u8>> {
388 let mut pos = 0usize;
389 let tag = *encoded
390 .first()
391 .ok_or_else(|| Error::Deserialization("empty delta payload".into()))?;
392 pos += 1;
393 match tag {
394 DELTA_TAG_RAW => Ok(encoded[pos..].to_vec()),
395 DELTA_TAG_DELTA => {
396 let new_len = read_varint(encoded, &mut pos)? as usize;
397 let mut out = vec![0u8; new_len];
398 let common = old.len().min(new_len);
399 out[..common].copy_from_slice(&old[..common]);
400 let mut index: i64 = -1;
401 while pos < encoded.len() {
402 let gap = read_varint(encoded, &mut pos)?;
403 let byte = *encoded.get(pos).ok_or_else(|| {
404 Error::Deserialization("truncated delta value byte".into())
405 })?;
406 pos += 1;
407 index += 1 + gap as i64;
408 let idx = usize::try_from(index)
409 .map_err(|_| Error::Deserialization("invalid delta index".into()))?;
410 if idx >= new_len {
411 return Err(Error::Deserialization("delta index out of range".into()));
412 }
413 out[idx] = byte;
414 }
415 Ok(out)
416 }
417 other => Err(Error::Deserialization(format!(
418 "unknown delta format tag: {other}"
419 ))),
420 }
421 }
422 pub fn clear(&self) {
424 self.cache.clear();
425 }
426 pub fn cache_size(&self) -> usize {
428 self.cache.len()
429 }
430}
431impl Default for DeltaEncoder {
432 fn default() -> Self {
433 Self::new()
434 }
435}
436#[cfg(test)]
437mod tests {
438 use super::*;
439 #[tokio::test]
440 async fn test_message_stream() {
441 let (tx, rx) = mpsc::unbounded_channel();
442 let mut stream = MessageStream::new(rx);
443 let send_result = tx.send(Message::Ping { id: 1 });
444 assert!(send_result.is_ok());
445 let msg = stream.next_message().await;
446 assert!(msg.is_some());
447 if let Some(Message::Ping { id }) = msg {
448 assert_eq!(id, 1);
449 }
450 }
451 #[tokio::test]
452 async fn test_tile_stream() {
453 let (tx, rx) = mpsc::unbounded_channel();
454 let mut stream = TileStream::new(rx);
455 let tile = TileData::new(0, 0, 5, vec![1, 2, 3], "application/x-protobuf".to_string());
456 let send_result = tx.send(tile.clone());
457 assert!(send_result.is_ok());
458 let received = stream.next_tile().await;
459 assert!(received.is_some());
460 if let Some(tile) = received {
461 assert_eq!(tile.coords(), (0, 0, 5));
462 assert_eq!(tile.size(), 3);
463 }
464 }
465 #[test]
466 fn test_backpressure_controller() {
467 let mut controller = BackpressureController::new(100);
468 assert_eq!(controller.update(30), BackpressureState::Normal);
469 assert!(!controller.should_throttle());
470 assert_eq!(controller.update(75), BackpressureState::High);
471 assert!(controller.should_throttle());
472 assert_eq!(controller.update(95), BackpressureState::Critical);
473 assert!(controller.should_drop());
474 assert_eq!(controller.update(25), BackpressureState::Normal);
475 assert!(!controller.should_throttle());
476 }
477 #[test]
478 fn test_delta_encoder() {
479 let encoder = DeltaEncoder::new();
480 let tile1 = TileData::new(
481 0,
482 0,
483 5,
484 vec![1, 2, 3, 4, 5],
485 "application/x-protobuf".to_string(),
486 );
487 let delta1 = encoder.encode(&tile1);
488 assert!(delta1.is_ok());
489 if let Ok(data) = delta1 {
492 assert_eq!(data.len(), 6);
493 assert_eq!(data[0], DELTA_TAG_RAW);
494 }
495 let tile2 = TileData::new(
496 0,
497 0,
498 5,
499 vec![1, 2, 9, 4, 5],
500 "application/x-protobuf".to_string(),
501 );
502 let delta2 = encoder.encode(&tile2);
503 assert!(delta2.is_ok());
504 if let Ok(data) = delta2 {
505 assert!(data.len() < tile2.size());
508 assert_eq!(data[0], DELTA_TAG_DELTA);
509 let restored = DeltaEncoder::apply_delta(&tile1.data, &data);
511 assert!(restored.is_ok());
512 if let Ok(restored) = restored {
513 assert_eq!(restored, tile2.data.to_vec());
514 }
515 }
516 }
517
518 #[test]
519 fn test_delta_encoder_raw_fallback_when_diff_would_expand() {
520 let old = vec![0u8; 5];
524 let new = vec![9u8; 5];
525 let encoded = DeltaEncoder::compute_delta(&old, &new);
526 assert!(encoded.is_ok());
527 if let Ok(data) = encoded {
528 assert_eq!(data[0], DELTA_TAG_RAW);
529 assert_eq!(data.len(), 1 + new.len());
530 let restored = DeltaEncoder::apply_delta(&old, &data);
531 assert!(restored.is_ok());
532 if let Ok(restored) = restored {
533 assert_eq!(restored, new);
534 }
535 }
536 }
537
538 #[test]
539 fn test_delta_encoder_grow_and_shrink_round_trip() {
540 let old = vec![1, 2, 3];
541 let grown = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
542 let encoded = DeltaEncoder::compute_delta(&old, &grown);
543 assert!(encoded.is_ok());
544 if let Ok(data) = encoded {
545 let restored = DeltaEncoder::apply_delta(&old, &data);
546 assert!(restored.is_ok());
547 if let Ok(restored) = restored {
548 assert_eq!(restored, grown);
549 }
550 }
551 let shrunk = vec![1, 99];
552 let encoded = DeltaEncoder::compute_delta(&grown, &shrunk);
553 assert!(encoded.is_ok());
554 if let Ok(data) = encoded {
555 let restored = DeltaEncoder::apply_delta(&grown, &data);
556 assert!(restored.is_ok());
557 if let Ok(restored) = restored {
558 assert_eq!(restored, shrunk);
559 }
560 }
561 }
562
563 #[test]
564 fn test_delta_encoder_apply_delta_rejects_malformed_input() {
565 assert!(DeltaEncoder::apply_delta(&[], &[]).is_err());
567 assert!(DeltaEncoder::apply_delta(&[], &[0xff]).is_err());
569 assert!(DeltaEncoder::apply_delta(&[], &[DELTA_TAG_DELTA]).is_err());
571 assert!(DeltaEncoder::apply_delta(&[1, 2, 3], &[DELTA_TAG_DELTA, 3, 0]).is_err());
573 }
574}