changeset 5:2101c91aad43

Implement session handling
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 09 Jul 2022 16:25:07 -0700
parents 7e94d639963c
children 204877b11751
files Cargo.toml src/main.rs
diffstat 2 files changed, 45 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/Cargo.toml	Sat Jul 09 13:22:42 2022 -0700
+++ b/Cargo.toml	Sat Jul 09 16:25:07 2022 -0700
@@ -14,4 +14,5 @@
 rocket_db_pools = { version = "0.1.0-rc.2", features = ["sqlx_sqlite"] }
 rocket_dyn_templates = { version = "0.1.0-rc.2", features = ["handlebars"] }
 sha256 = "1.0.3"
+time = "0.3.11"
 tokio = { version = "1.19.2", features = ["fs"] }
--- a/src/main.rs	Sat Jul 09 13:22:42 2022 -0700
+++ b/src/main.rs	Sat Jul 09 16:25:07 2022 -0700
@@ -56,6 +56,7 @@
     S6: AsRef<str>,
 >(
     conn: &mut PoolConnection<Sqlite>,
+    session: Option<u32>,
     ip: S1,
     domain: S2,
     path: S3,
@@ -65,8 +66,9 @@
     ua: S6,
     ntags: u32,
 ) -> Result<u32, Error> {
-    let q = sqlx::query("INSERT INTO RequestLog (ip, atime, domain, path, status, pagename, refer, ua, ntags) VALUES (?, strftime('%s', 'now'), ?, ?, ?, ?, ?, ?, ?) RETURNING id");
+    let q = sqlx::query("INSERT INTO RequestLog (session, ip, atime, domain, path, status, pagename, refer, ua, ntags) VALUES (?, ?, strftime('%s', 'now'), ?, ?, ?, ?, ?, ?, ?) RETURNING id");
     let q = q
+        .bind(session)
         .bind(ip.as_ref())
         .bind(domain.as_ref())
         .bind(path.as_ref())
@@ -101,6 +103,20 @@
     Ok(ntags)
 }
 
+async fn start_session(conn: &mut PoolConnection<Sqlite>) -> Result<u32, Error> {
+    Ok(sqlx::query("INSERT INTO Sessions (start, last) VALUES (strftime('%s', 'now'), strftime('%s', 'now')) RETURNING id")
+        .fetch_one(conn)
+        .await?.get(0))
+}
+
+async fn update_session_time(conn: &mut PoolConnection<Sqlite>, id: u32) -> Result<(), Error> {
+    sqlx::query("UPDATE Sessions SET last = strftime('%s', 'now') WHERE id = ?")
+        .bind(id)
+        .execute(conn)
+        .await?;
+    Ok(())
+}
+
 const USER_ID_COOKIE_KEY: &str = "user_id";
 
 struct LoggedInGuard(String);
@@ -235,7 +251,8 @@
 // TODO: ignore requests when logged in.
 #[rocket::get("/log?<host>&<status>&<path>&<pagename>&<referer>&<tags>")]
 async fn route_log(
-    conn: Connection<LogsDB>,
+    mut conn: Connection<LogsDB>,
+    cookies: &CookieJar<'_>,
     host: Option<String>,
     status: Option<u16>,
     path: Option<String>,
@@ -245,6 +262,30 @@
     ip: IpAddr,
     headers: HeadersGuard<'_>,
 ) -> (Status, Either<NamedFile, &'static str>) {
+    let mut session_id = None;
+    // Get session ID from cookie, or start new session.
+    if let Some(sessioncookie) = cookies.get_private("analyrics_session") {
+        if let Ok(id) = u32::from_str_radix(sessioncookie.value(), 10) {
+            session_id = Some(id);
+            match update_session_time(&mut conn, id).await {
+                Ok(()) => {}
+                Err(e) => error!("Couldn't update session time: {}", e),
+            }
+        }
+    }
+    if session_id.is_none() {
+        match start_session(&mut conn).await {
+            Ok(id) => {
+                session_id = Some(id);
+                let c = Cookie::build("analyrics_session", id.to_string())
+                    .max_age(time::Duration::hours(12))
+                    .finish();
+                cookies.add_private(c);
+            }
+            Err(e) => error!("Couldn't start session: {}", e),
+        }
+    }
+
     let mut conn = conn.into_inner();
     let ntags = tags.len() as u32;
     let ua = headers.0.get_one("user-agent").unwrap_or("");
@@ -260,6 +301,7 @@
     );
     match log_request(
         &mut conn,
+        session_id,
         ip.to_string(),
         host,
         path.unwrap_or(String::new()),