server: add support for .json .csv and ?all=true

This commit is contained in:
k
2024-10-16 18:38:43 +02:00
parent 4cdc9ef9b3
commit 608ccafc70
66 changed files with 12150 additions and 11014 deletions

View File

@@ -1,6 +1,6 @@
use std::{
iter::Sum,
ops::{Add, Div, Mul, RangeInclusive, Sub},
ops::{Add, Div, Mul, Sub},
};
use allocative::Allocative;
@@ -36,30 +36,30 @@ where
}
}
pub fn date_insert_sum_range(&mut self, date: Date, date_blocks_range: &RangeInclusive<u32>)
where
Value: Sum,
{
self.date
.insert(date, self.height.sum_range(date_blocks_range));
}
// pub fn date_insert_sum_range(&mut self, date: Date, date_blocks_range: &RangeInclusive<u32>)
// where
// Value: Sum,
// {
// self.date
// .insert(date, self.height.sum_range(date_blocks_range));
// }
pub fn multi_date_insert_sum_range(
&mut self,
dates: &[Date],
first_height: &mut DateMap<Height>,
last_height: &mut DateMap<Height>,
) where
Value: Sum,
{
dates.iter().for_each(|date| {
let first_height = first_height.get_or_import(date).unwrap();
let last_height = last_height.get_or_import(date).unwrap();
let range = (*first_height)..=(*last_height);
// pub fn multi_date_insert_sum_range(
// &mut self,
// dates: &[Date],
// first_height: &mut DateMap<Height>,
// last_height: &mut DateMap<Height>,
// ) where
// Value: Sum,
// {
// dates.iter().for_each(|date| {
// let first_height = first_height.get_or_import(date).unwrap();
// let last_height = last_height.get_or_import(date).unwrap();
// let range = (*first_height)..=(*last_height);
self.date.insert(*date, self.height.sum_range(&range));
})
}
// self.date.insert(*date, self.height.sum_range(&range));
// })
// }
pub fn multi_insert_const(&mut self, heights: &[Height], dates: &[Date], constant: Value) {
self.height.multi_insert_const(heights, constant);
@@ -176,6 +176,7 @@ where
.multi_insert_percentage(dates, &mut divided.date, &mut divider.date);
}
#[allow(unused)]
pub fn multi_insert_cumulative<K>(
&mut self,
heights: &[Height],
@@ -192,27 +193,6 @@ where
self.date.multi_insert_cumulative(dates, &mut source.date);
}
pub fn multi_insert_last_x_sum<K>(
&mut self,
heights: &[Height],
dates: &[Date],
source: &mut BiMap<K>,
days: usize,
) where
K: MapValue,
Value: LossyFrom<K>,
Value: Add<Output = Value> + Sub<Output = Value>,
{
self.height.multi_insert_last_x_sum(
heights,
&mut source.height,
TARGET_BLOCKS_PER_DAY * days,
);
self.date
.multi_insert_last_x_sum(dates, &mut source.date, days);
}
pub fn multi_insert_simple_average<K>(
&mut self,
heights: &[Height],
@@ -251,6 +231,7 @@ where
.multi_insert_net_change(dates, &mut source.date, days);
}
#[allow(unused)]
pub fn multi_insert_median(
&mut self,
heights: &[Height],

View File

@@ -45,9 +45,8 @@ impl Config {
const PATH: &'static str = "./config.toml";
pub fn import() -> color_eyre::Result<Self> {
let mut config_saved =
fs::read_to_string(Self::PATH).map_or(Config::default(), |contents| {
dbg!(&contents);
let mut config_saved = fs::read_to_string(Self::PATH)
.map_or(Config::default(), |contents| {
toml::from_str(&contents).unwrap_or_default()
});

View File

@@ -1,4 +1,4 @@
use std::{fmt, str::FromStr};
use std::{cmp::Ordering, fmt, str::FromStr};
use allocative::{Allocative, Visitor};
use bincode::{
@@ -7,11 +7,13 @@ use bincode::{
error::{DecodeError, EncodeError},
BorrowDecode, Decode, Encode,
};
use chrono::{Datelike, Days, NaiveDate};
use chrono::{Datelike, Days, NaiveDate, NaiveDateTime};
use derive_deref::{Deref, DerefMut};
use serde::{Deserialize, Serialize};
use super::{DateMapChunkId, MapKey};
use crate::utils::ONE_DAY_IN_S;
use super::{DateMapChunkId, MapKey, Timestamp};
const NUMBER_OF_UNSAFE_DATES: usize = 2;
const MIN_YEAR: i32 = 2009;
@@ -49,6 +51,28 @@ impl Date {
pub fn difference_in_days_between(&self, older: Self) -> u32 {
(**self - *older).num_days() as u32
}
pub fn to_timestamp(self) -> Timestamp {
Timestamp::wrap(NaiveDateTime::from(*self).and_utc().timestamp() as u32)
}
/// Returns value between 0.0 and 1.0 depending on its completion
///
/// Any date before today (utc) will return 1.0
///
/// Any date after today (utc) will panic even though it should return 0.0, as it shouldn't happen in the code
///
/// Any date equal to today will have a completion between 0.0 and 1.0
pub fn get_day_completion(self) -> f64 {
let now = Timestamp::now();
let today = Date::today();
match self.cmp(&today) {
Ordering::Less => 1.0,
Ordering::Equal => *(now - self.to_timestamp()) as f64 / ONE_DAY_IN_S as f64,
Ordering::Greater => unreachable!("0.0 but shouldn't be called"),
}
}
}
impl MapKey<DateMapChunkId> for Date {

View File

@@ -1,17 +1,19 @@
use std::iter::Sum;
use crate::{Date, HeightMap};
use super::{AnyMap, DateMapChunkId, GenericMap, Height, MapValue, SerializedBTreeMap};
pub type DateMap<Value> = GenericMap<Date, Value, DateMapChunkId, SerializedBTreeMap<Date, Value>>;
impl<T> DateMap<T>
impl<Value> DateMap<Value>
where
T: MapValue,
Value: MapValue,
{
pub fn multi_insert_last(
&mut self,
dates: &[Date],
source: &mut HeightMap<T>,
source: &mut HeightMap<Value>,
last_height: &mut DateMap<Height>,
) {
dates.iter().for_each(|date| {
@@ -23,6 +25,24 @@ where
);
});
}
pub fn multi_insert_sum_range(
&mut self,
dates: &[Date],
height_map: &HeightMap<Value>,
first_height: &mut DateMap<Height>,
last_height: &mut DateMap<Height>,
) where
Value: Sum,
{
dates.iter().for_each(|date| {
let first_height = first_height.get_or_import(date).unwrap();
let last_height = last_height.get_or_import(date).unwrap();
let range = (*first_height)..=(*last_height);
self.insert(*date, height_map.sum_range(&range));
})
}
}
pub trait AnyDateMap: AnyMap {

View File

@@ -413,11 +413,11 @@ where
&mut self,
keys: &[Key],
source: &mut GenericMap<Key, SourceValue, ChunkId, SourceSerialized>,
transform: F,
mut transform: F,
) where
SourceValue: MapValue,
SourceSerialized: MapSerialized<Key, SourceValue, ChunkId>,
F: Fn(SourceValue, &Key) -> Value,
F: FnMut(SourceValue, &Key) -> Value,
{
keys.iter().for_each(|key| {
self.insert(*key, transform(source.get_or_import(key).unwrap(), key));

View File

@@ -23,6 +23,7 @@ pub trait MapValue:
{
}
impl MapValue for u8 {}
impl MapValue for u16 {}
impl MapValue for u32 {}
impl MapValue for u64 {}

View File

@@ -1,10 +1,12 @@
use std::{collections::BTreeMap, fmt::Debug};
use std::{collections::BTreeMap, fmt::Debug, path::Path};
use allocative::Allocative;
use bincode::{Decode, Encode};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use super::{MapChunkId, MapKey, MapSerialized, MapValue};
use crate::Serialization;
use super::{DateMap, MapChunkId, MapKey, MapSerialized, MapValue};
#[derive(Debug, Default, Serialize, Deserialize, Encode, Decode, Allocative)]
pub struct SerializedBTreeMap<Key, Value>
@@ -12,7 +14,37 @@ where
Key: Ord,
{
version: u32,
map: BTreeMap<Key, Value>,
pub map: BTreeMap<Key, Value>,
}
impl<Key, Value> SerializedBTreeMap<Key, Value>
where
Key: Ord,
{
pub fn import_all<ChunkId>(path: &Path, serialization: &Serialization) -> Self
where
Self: Debug + Serialize + DeserializeOwned + Encode + Decode,
ChunkId: MapChunkId,
Key: MapKey<ChunkId>,
Value: MapValue,
{
let mut s = None;
DateMap::<usize>::_read_dir(path, serialization)
.iter()
.for_each(|(_, path)| {
let map = serialization.import::<Self>(path).unwrap();
if s.is_none() {
s.replace(map);
} else {
#[allow(clippy::unnecessary_unwrap)]
s.as_mut().unwrap().map.extend(map.map);
}
});
s.unwrap()
}
}
impl<Key, Value, ChunkId> MapSerialized<Key, Value, ChunkId> for SerializedBTreeMap<Key, Value>

View File

@@ -1,15 +1,42 @@
use std::{cmp::Ordering, collections::BTreeMap, fmt::Debug};
use std::{cmp::Ordering, collections::BTreeMap, fmt::Debug, path::Path};
use allocative::Allocative;
use bincode::{Decode, Encode};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use super::{MapChunkId, MapKey, MapSerialized, MapValue};
use crate::Serialization;
use super::{HeightMap, MapChunkId, MapKey, MapSerialized, MapValue};
#[derive(Debug, Default, Serialize, Deserialize, Encode, Decode, Allocative)]
pub struct SerializedVec<Value> {
version: u32,
map: Vec<Value>,
pub map: Vec<Value>,
}
impl<Value> SerializedVec<Value> {
pub fn import_all(path: &Path, serialization: &Serialization) -> Self
where
Self: Debug + Serialize + DeserializeOwned + Encode + Decode,
Value: MapValue,
{
let mut s = None;
HeightMap::<usize>::_read_dir(path, serialization)
.iter()
.for_each(|(_, path)| {
let mut map = serialization.import::<Self>(path).unwrap();
if s.is_none() {
s.replace(map);
} else {
#[allow(clippy::unnecessary_unwrap)]
s.as_mut().unwrap().map.append(&mut map.map);
}
});
s.unwrap()
}
}
impl<Key, Value, ChunkId> MapSerialized<Key, Value, ChunkId> for SerializedVec<Value>

View File

@@ -36,6 +36,10 @@ impl Timestamp {
Self(timestamp)
}
pub fn now() -> Self {
Self(chrono::offset::Utc::now().timestamp() as u32)
}
pub fn to_date(self) -> Date {
Date::wrap(
Utc.timestamp_opt(i64::from(self.0), 0)