cdp_core/page/
session.rs

1use super::page_core::Page;
2use crate::error::Result;
3use crate::network::cookies::{Cookie, CookieManager, SetCookieParams};
4use crate::storage::manager::{StorageManager, StorageType};
5use async_trait::async_trait;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::sync::Arc;
9
10/// Complete page session state including cookies and storage
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct PageSession {
13    /// Current page URL
14    pub url: String,
15    /// All cookies
16    pub cookies: Vec<Cookie>,
17    /// localStorage items
18    pub local_storage: HashMap<String, String>,
19    /// sessionStorage items
20    pub session_storage: HashMap<String, String>,
21    /// Timestamp when session was captured
22    pub timestamp: u64,
23}
24
25impl PageSession {
26    /// Create a new empty session
27    pub fn new(url: String) -> Self {
28        Self {
29            url,
30            cookies: Vec::new(),
31            local_storage: HashMap::new(),
32            session_storage: HashMap::new(),
33            timestamp: std::time::SystemTime::now()
34                .duration_since(std::time::UNIX_EPOCH)
35                .unwrap_or_default()
36                .as_secs(),
37        }
38    }
39
40    /// Serialize session to JSON string
41    pub fn to_json(&self) -> Result<String> {
42        Ok(serde_json::to_string_pretty(self)?)
43    }
44
45    /// Deserialize session from JSON string
46    pub fn from_json(json: &str) -> Result<Self> {
47        Ok(serde_json::from_str(json)?)
48    }
49
50    /// Save session to file
51    pub fn save_to_file(&self, path: &std::path::Path) -> Result<()> {
52        let json = self.to_json()?;
53        std::fs::write(path, json)?;
54        Ok(())
55    }
56
57    /// Load session from file
58    pub fn load_from_file(path: &std::path::Path) -> Result<Self> {
59        let json = std::fs::read_to_string(path)?;
60        Self::from_json(&json)
61    }
62}
63
64/// Session management trait for Page
65#[async_trait]
66pub trait PageSessionManager {
67    /// Export complete page session (cookies + storage)
68    async fn export_session(self: &Arc<Self>) -> Result<PageSession>;
69
70    /// Import complete page session (cookies + storage)
71    /// Note: This will navigate to the session URL first
72    async fn import_session(self: &Arc<Self>, session: &PageSession) -> Result<()>;
73
74    /// Export session and save to file
75    async fn export_session_to_file(
76        self: &Arc<Self>,
77        path: &std::path::Path,
78    ) -> Result<PageSession>;
79
80    /// Load session from file and import
81    async fn import_session_from_file(self: &Arc<Self>, path: &std::path::Path) -> Result<()>;
82}
83
84#[async_trait]
85impl PageSessionManager for Page {
86    async fn export_session(self: &Arc<Self>) -> Result<PageSession> {
87        // Get current URL from main frame
88        let main_frame = self.main_frame().await?;
89        let url = main_frame.url().await?;
90
91        // Get all cookies
92        let cookies = self.get_cookies(None).await?;
93
94        // Get localStorage items
95        let local_storage_items = self.get_storage_items(StorageType::Local).await?;
96        let local_storage: HashMap<String, String> = local_storage_items
97            .into_iter()
98            .map(|item| (item.key, item.value))
99            .collect();
100
101        // Get sessionStorage items
102        let session_storage_items = self.get_storage_items(StorageType::Session).await?;
103        let session_storage: HashMap<String, String> = session_storage_items
104            .into_iter()
105            .map(|item| (item.key, item.value))
106            .collect();
107
108        Ok(PageSession {
109            url,
110            cookies,
111            local_storage,
112            session_storage,
113            timestamp: std::time::SystemTime::now()
114                .duration_since(std::time::UNIX_EPOCH)
115                .unwrap_or_default()
116                .as_secs(),
117        })
118    }
119
120    async fn import_session(self: &Arc<Self>, session: &PageSession) -> Result<()> {
121        // Navigate to the session URL first
122        self.navigate(&session.url).await?;
123
124        // Clear existing state
125        self.clear_browser_cookies().await?;
126        self.clear_storage(StorageType::Local).await?;
127        self.clear_storage(StorageType::Session).await?;
128
129        // Import cookies - convert Cookie to SetCookieParams
130        for cookie in &session.cookies {
131            let set_cookie_params = SetCookieParams {
132                name: cookie.name.clone(),
133                value: cookie.value.clone(),
134                url: Some(session.url.clone()),
135                domain: Some(cookie.domain.clone()),
136                path: Some(cookie.path.clone()),
137                secure: Some(cookie.secure),
138                http_only: Some(cookie.http_only),
139                same_site: cookie.same_site.clone(),
140                expires: Some(cookie.expires),
141                priority: Some(cookie.priority.clone()),
142            };
143            self.set_cookie(set_cookie_params).await?;
144        }
145
146        // Import localStorage
147        for (key, value) in &session.local_storage {
148            self.set_storage_item(StorageType::Local, key, value)
149                .await?;
150        }
151
152        // Import sessionStorage
153        for (key, value) in &session.session_storage {
154            self.set_storage_item(StorageType::Session, key, value)
155                .await?;
156        }
157
158        Ok(())
159    }
160
161    async fn export_session_to_file(
162        self: &Arc<Self>,
163        path: &std::path::Path,
164    ) -> Result<PageSession> {
165        let session = self.export_session().await?;
166        session.save_to_file(path)?;
167        Ok(session)
168    }
169
170    async fn import_session_from_file(self: &Arc<Self>, path: &std::path::Path) -> Result<()> {
171        let session = PageSession::load_from_file(path)?;
172        self.import_session(&session).await?;
173        Ok(())
174    }
175}
176
177/// Convenient methods for session snapshots
178#[async_trait]
179pub trait PageSessionSnapshot {
180    /// Create a quick snapshot of current session
181    async fn snapshot(self: &Arc<Self>) -> Result<PageSession>;
182
183    /// Restore from a snapshot
184    async fn restore(self: &Arc<Self>, snapshot: &PageSession) -> Result<()>;
185
186    /// Clone current session to another page
187    async fn clone_session_to(self: &Arc<Self>, target: &Arc<Page>) -> Result<()>;
188}
189
190#[async_trait]
191impl PageSessionSnapshot for Page {
192    async fn snapshot(self: &Arc<Self>) -> Result<PageSession> {
193        self.export_session().await
194    }
195
196    async fn restore(self: &Arc<Self>, snapshot: &PageSession) -> Result<()> {
197        self.import_session(snapshot).await
198    }
199
200    async fn clone_session_to(self: &Arc<Self>, target: &Arc<Page>) -> Result<()> {
201        let session = self.export_session().await?;
202        target.import_session(&session).await?;
203        Ok(())
204    }
205}