I guess cookie session https://docs.rs/actix-session/0.1.1/actix_session/struct.CookieSession.html ?
I've never implemented session storage before. jwk's stored in local storage make a lot more sense to me. But i'm trying to build a app that doesn't use javascript.
Just some notes for myself
This is the general algorithm,
First I start with the data set of 92,000ish in csv format.
Then, I convert them all to a sqlite file for parsing. I just import the thing in sqlightbrowser on linux.
Then in rust I parse it for unique email addresses. looks like around 2 to 3 thousand people donated more than once.
Interesting.
Rust code looks like this,
```rust
use rusqlite::{Connection, Result,Statement};
use serde::{Deserialize, Serialize};
pub type Pool = r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>;
type PersonAggResult = Result<Vec<Person>, rusqlite::Error>;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use uuid::Uuid;
#[derive(Debug, Clone)]
struct Person {
donation_first_name: Option<String>,
donation_last_name: Option<String>,
donation_email: Option<String>,
}
#[derive(Debug, Clone)]
struct Name {
first_name: Option<String>,
last_name: Option<String>,
}
fn get_emails(mut statement: Statement) -> PersonAggResult {
statement
.query_map([], |row| {
Ok(Person {
donation_first_name: row.get(0)?,
donation_last_name: row.get(1)?,
donation_email:row.get(2)?,
})
})
.and_then(Iterator::collect)
}
fn get_data(conn: &Connection) -> PersonAggResult {
let stmt = conn.prepare(
"
SELECT donation_first_name,donation_last_name,donation_email from donations",
)?;
get_emails(stmt)
}
fn main() -> Result<()> {
let mut person_list:HashMap<String,Vec<Name>> = HashMap::new();
println!("Starting read!");
let conn = Connection::open("crud.db")?;
let rows = get_data(&conn);
let mut counter = 0;
match rows {
Ok(list) => {
counter = list.len();
for r in list {
match r.donation_email {
Some(email)=>{
let name = Name{first_name:r.donation_first_name,last_name:r.donation_last_name};
let _ = match person_list.entry(email) {
Vacant(e) =>{
let mut l: Vec<Name> = Vec::new();
l.push(name);
e.insert(l);
},
Occupied(mut e) =>{
e.get_mut().push(name);
}
};
},
None=>{}
}
}
},
Err(err) =>{
println!("error:{}",err)
}
}
println!("Done reading in data for {} records. Beginning insertion.",counter);
let mut counter = 1;
for(key,value) in &person_list {
let remainder = counter % 1000;
if remainder == 0 {
println!("{}",counter);
}
counter = counter +1;
let mut firstname:String = "".to_string();
let mut lastname:String = "".to_string();
// Just pick a first name from
for v in value {
match &v.first_name {
Some(x) => {
firstname = x.to_string();
}
_=>{}
}
match &v.last_name {
Some(x) => {
lastname = x.to_string();
}
_=>{}
}
}
conn.execute(
"INSERT INTO users (id,email,subscribed,first_name,last_name) values (?1,?2,?3,?4,?5)"
, [Uuid::new_v4().to_string(),key.to_string(),1.to_string(),firstname,lastname])?;
}
_ = conn.close();
Ok(())
}
```
Note this isn't optimized at all. And isn't clean code. My rust isn't nearly as good as my cpp yet. Takes about 10 minutes to run because it does a separate write for each row. That's fine 10 seconds or 10 minutes doesn't really matter in this case.
Then I copy that sql file as a back up so I don't have to that again and load it up in a seperate project to allow users to update their email preferences.