#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct LongPollResponse {
pub sequence_id: u64,
pub body: Vec<u8>,
pub content_type: String,
pub timeout_ms: u32,
pub is_final: bool,
}
#[derive(Debug, Default)]
pub struct LongPollExport {
pub responses: Vec<LongPollResponse>,
pub poll_endpoint: String,
pub next_seq: u64,
}
pub fn new_long_poll_export(endpoint: &str) -> LongPollExport {
LongPollExport {
responses: Vec::new(),
poll_endpoint: endpoint.to_owned(),
next_seq: 0,
}
}
pub fn lp_add_json(export: &mut LongPollExport, json: &str, timeout_ms: u32) {
let seq = export.next_seq;
export.next_seq += 1;
export.responses.push(LongPollResponse {
sequence_id: seq,
body: json.as_bytes().to_vec(),
content_type: "application/json".to_owned(),
timeout_ms,
is_final: false,
});
}
pub fn lp_add_binary(export: &mut LongPollExport, data: Vec<u8>, timeout_ms: u32, is_final: bool) {
let seq = export.next_seq;
export.next_seq += 1;
export.responses.push(LongPollResponse {
sequence_id: seq,
body: data,
content_type: "application/octet-stream".to_owned(),
timeout_ms,
is_final,
});
}
pub fn lp_response_count(export: &LongPollExport) -> usize {
export.responses.len()
}
pub fn total_lp_bytes(export: &LongPollExport) -> usize {
export.responses.iter().map(|r| r.body.len()).sum()
}
pub fn find_lp_response(export: &LongPollExport, seq: u64) -> Option<&LongPollResponse> {
export.responses.iter().find(|r| r.sequence_id == seq)
}
pub fn final_response_count(export: &LongPollExport) -> usize {
export.responses.iter().filter(|r| r.is_final).count()
}
pub fn average_timeout_ms(export: &LongPollExport) -> f64 {
if export.responses.is_empty() {
return 0.0;
}
let sum: u64 = export.responses.iter().map(|r| r.timeout_ms as u64).sum();
sum as f64 / export.responses.len() as f64
}
pub fn lp_export_to_json(export: &LongPollExport) -> String {
format!(
r#"{{"endpoint":"{}", "response_count":{}, "total_bytes":{}}}"#,
export.poll_endpoint,
lp_response_count(export),
total_lp_bytes(export)
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_export_empty() {
let e = new_long_poll_export("/poll");
assert_eq!(lp_response_count(&e), 0);
}
#[test]
fn add_json_increments_count() {
let mut e = new_long_poll_export("/poll");
lp_add_json(&mut e, r#"{"v":1}"#, 30000);
assert_eq!(lp_response_count(&e), 1);
}
#[test]
fn sequence_ids_auto_increment() {
let mut e = new_long_poll_export("/poll");
lp_add_json(&mut e, "{}", 1000);
lp_add_json(&mut e, "{}", 1000);
assert_eq!(e.responses[0].sequence_id, 0);
assert_eq!(e.responses[1].sequence_id, 1);
}
#[test]
fn find_by_sequence() {
let mut e = new_long_poll_export("/poll");
lp_add_json(&mut e, "{}", 1000);
assert!(find_lp_response(&e, 0).is_some());
}
#[test]
fn find_missing_seq_none() {
let e = new_long_poll_export("/poll");
assert!(find_lp_response(&e, 99).is_none());
}
#[test]
fn total_bytes_correct() {
let mut e = new_long_poll_export("/poll");
lp_add_json(&mut e, r#"{"a":1}"#, 1000);
assert_eq!(total_lp_bytes(&e), 7);
}
#[test]
fn final_response_counted() {
let mut e = new_long_poll_export("/poll");
lp_add_binary(&mut e, vec![], 1000, true);
lp_add_binary(&mut e, vec![], 1000, false);
assert_eq!(final_response_count(&e), 1);
}
#[test]
fn average_timeout_correct() {
let mut e = new_long_poll_export("/poll");
lp_add_json(&mut e, "{}", 1000);
lp_add_json(&mut e, "{}", 3000);
assert!((average_timeout_ms(&e) - 2000.0).abs() < 1.0);
}
#[test]
fn json_contains_endpoint() {
let e = new_long_poll_export("/api/poll");
assert!(lp_export_to_json(&e).contains("/api/poll"));
}
}