| import logging |
| from dataclasses import dataclass |
| from datetime import datetime, timedelta |
| from typing import Optional, Tuple |
| from uuid import uuid1 |
|
|
| from selenium.webdriver.chrome.webdriver import WebDriver |
|
|
| import utils |
|
|
|
|
| @dataclass |
| class Session: |
| session_id: str |
| driver: WebDriver |
| created_at: datetime |
|
|
| def lifetime(self) -> timedelta: |
| return datetime.now() - self.created_at |
|
|
|
|
| class SessionsStorage: |
| """SessionsStorage creates, stores and process all the sessions""" |
|
|
| def __init__(self): |
| self.sessions = {} |
|
|
| def create(self, session_id: Optional[str] = None, proxy: Optional[dict] = None, |
| force_new: Optional[bool] = False) -> Tuple[Session, bool]: |
| """create creates new instance of WebDriver if necessary, |
| assign defined (or newly generated) session_id to the instance |
| and returns the session object. If a new session has been created |
| second argument is set to True. |
| |
| Note: The function is idempotent, so in case if session_id |
| already exists in the storage a new instance of WebDriver won't be created |
| and existing session will be returned. Second argument defines if |
| new session has been created (True) or an existing one was used (False). |
| """ |
| session_id = session_id or str(uuid1()) |
|
|
| if force_new: |
| self.destroy(session_id) |
|
|
| if self.exists(session_id): |
| return self.sessions[session_id], False |
|
|
| driver = utils.get_webdriver(proxy) |
| created_at = datetime.now() |
| session = Session(session_id, driver, created_at) |
|
|
| self.sessions[session_id] = session |
|
|
| return session, True |
|
|
| def exists(self, session_id: str) -> bool: |
| return session_id in self.sessions |
|
|
| def destroy(self, session_id: str) -> bool: |
| """destroy closes the driver instance and removes session from the storage. |
| The function is noop if session_id doesn't exist. |
| The function returns True if session was found and destroyed, |
| and False if session_id wasn't found. |
| """ |
| if not self.exists(session_id): |
| return False |
|
|
| session = self.sessions.pop(session_id) |
| if utils.PLATFORM_VERSION == "nt": |
| session.driver.close() |
| session.driver.quit() |
| return True |
|
|
| def get(self, session_id: str, ttl: Optional[timedelta] = None) -> Tuple[Session, bool]: |
| session, fresh = self.create(session_id) |
|
|
| if ttl is not None and not fresh and session.lifetime() > ttl: |
| logging.debug(f'session\'s lifetime has expired, so the session is recreated (session_id={session_id})') |
| session, fresh = self.create(session_id, force_new=True) |
|
|
| return session, fresh |
|
|
| def session_ids(self) -> list[str]: |
| return list(self.sessions.keys()) |
|
|