use super::MessageStorage;
use crate::messages::message::Message;
use crate::messages::utils::bisect::bisect_keep_right;
use std::collections::VecDeque;
pub struct CookieStorage {
messages: VecDeque<Message>,
cookie_name: String,
max_cookie_size: usize,
not_finished: Vec<Message>,
}
impl CookieStorage {
pub const DEFAULT_MAX_SIZE: usize = 4096;
pub fn new() -> Self {
Self {
messages: VecDeque::new(),
cookie_name: "messages".to_string(),
max_cookie_size: Self::DEFAULT_MAX_SIZE,
not_finished: Vec::new(),
}
}
pub fn with_cookie_name(mut self, name: impl Into<String>) -> Self {
self.cookie_name = name.into();
self
}
pub fn with_max_size(mut self, size: usize) -> Self {
self.max_cookie_size = size;
self
}
pub fn cookie_name(&self) -> &str {
&self.cookie_name
}
pub fn max_cookie_size(&self) -> usize {
self.max_cookie_size
}
pub fn serialize(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(&self.messages)
}
pub fn deserialize(&mut self, data: &str) -> Result<(), serde_json::Error> {
self.messages = serde_json::from_str(data)?;
Ok(())
}
pub fn update_cookie(&mut self) -> Result<Vec<Message>, serde_json::Error> {
let mut serialized = self.serialize()?;
let mut removed = Vec::new();
if serialized.len() <= self.max_cookie_size {
return Ok(removed);
}
let messages_vec: Vec<_> = self.messages.iter().cloned().collect();
let keep = bisect_keep_right(&messages_vec, self.max_cookie_size, |msgs| {
serde_json::to_vec(msgs).unwrap_or_default()
});
while self.messages.len() > keep {
if let Some(msg) = self.messages.pop_front() {
removed.push(msg);
}
}
serialized = self.serialize()?;
while serialized.len() > self.max_cookie_size && !self.messages.is_empty() {
if let Some(msg) = self.messages.pop_front() {
removed.push(msg);
}
serialized = self.serialize()?;
}
Ok(removed)
}
pub fn update(&mut self) -> Vec<Message> {
match self.update_cookie() {
Ok(removed) => removed,
Err(_) => {
self.get_all()
}
}
}
pub fn get_cookie_value(&mut self) -> Result<(String, Vec<Message>), serde_json::Error> {
let unstored = self.update_cookie()?;
let cookie_value = self.serialize()?;
Ok((cookie_value, unstored))
}
pub fn load_from_cookie(&mut self, cookie_data: &str) -> Result<(), serde_json::Error> {
if cookie_data.is_empty() {
return Ok(());
}
match self.deserialize(cookie_data) {
Ok(_) => Ok(()),
Err(_) => {
self.clear();
Ok(())
}
}
}
pub fn encode_for_cookie(text: &str) -> String {
let mut result = String::with_capacity(text.len() * 2);
for c in text.chars() {
match c {
',' => result.push_str("%2C"),
';' => result.push_str("%3B"),
'\\' => result.push_str("%5C"),
'"' => result.push_str("%22"),
_ => result.push(c),
}
}
result
}
}
impl Default for CookieStorage {
fn default() -> Self {
Self::new()
}
}
impl MessageStorage for CookieStorage {
fn add(&mut self, message: Message) {
self.messages.push_back(message);
}
fn get_all(&mut self) -> Vec<Message> {
self.messages.drain(..).collect()
}
fn peek(&self) -> Vec<Message> {
self.messages.iter().cloned().collect()
}
fn clear(&mut self) {
self.messages.clear();
self.not_finished.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::messages::levels::Level;
#[test]
fn test_cookie_storage_basic() {
let mut storage = CookieStorage::new();
storage.add(Message::new(Level::Info, "Test message"));
assert_eq!(storage.peek().len(), 1);
let messages = storage.get_all();
assert_eq!(messages.len(), 1);
assert_eq!(storage.peek().len(), 0);
}
#[test]
fn test_cookie_storage_custom_name() {
let storage = CookieStorage::new().with_cookie_name("custom_messages");
assert_eq!(storage.cookie_name(), "custom_messages");
}
#[test]
fn test_cookie_storage_max_size() {
let storage = CookieStorage::new().with_max_size(8192);
assert_eq!(storage.max_cookie_size(), 8192);
}
#[test]
fn test_cookie_storage_serialize() {
let mut storage = CookieStorage::new();
storage.add(Message::new(Level::Info, "Test"));
let serialized = storage.serialize().unwrap();
assert!(serialized.contains("Test"));
}
#[test]
fn test_cookie_storage_deserialize() {
let mut storage = CookieStorage::new();
storage.add(Message::new(Level::Info, "Test"));
let serialized = storage.serialize().unwrap();
let mut storage2 = CookieStorage::new();
storage2.deserialize(&serialized).unwrap();
assert_eq!(storage2.peek().len(), 1);
}
}