manager.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import asyncio
  2. import time
  3. from fastapi import WebSocket
  4. from opendevin.core.config import AppConfig
  5. from opendevin.core.logger import opendevin_logger as logger
  6. from opendevin.storage.files import FileStore
  7. from .session import Session
  8. class SessionManager:
  9. _sessions: dict[str, Session] = {}
  10. cleanup_interval: int = 300
  11. session_timeout: int = 600
  12. def __init__(self, config: AppConfig, file_store: FileStore):
  13. asyncio.create_task(self._cleanup_sessions())
  14. self.config = config
  15. self.file_store = file_store
  16. def add_or_restart_session(self, sid: str, ws_conn: WebSocket) -> Session:
  17. if sid in self._sessions:
  18. asyncio.create_task(self._sessions[sid].close())
  19. self._sessions[sid] = Session(
  20. sid=sid, file_store=self.file_store, ws=ws_conn, config=self.config
  21. )
  22. return self._sessions[sid]
  23. def get_session(self, sid: str) -> Session | None:
  24. if sid not in self._sessions:
  25. return None
  26. return self._sessions.get(sid)
  27. async def send(self, sid: str, data: dict[str, object]) -> bool:
  28. """Sends data to the client."""
  29. if sid not in self._sessions:
  30. return False
  31. return await self._sessions[sid].send(data)
  32. async def send_error(self, sid: str, message: str) -> bool:
  33. """Sends an error message to the client."""
  34. return await self.send(sid, {'error': True, 'message': message})
  35. async def send_message(self, sid: str, message: str) -> bool:
  36. """Sends a message to the client."""
  37. return await self.send(sid, {'message': message})
  38. async def _cleanup_sessions(self):
  39. while True:
  40. current_time = time.time()
  41. session_ids_to_remove = []
  42. for sid, session in list(self._sessions.items()):
  43. # if session inactive for a long time, remove it
  44. if (
  45. not session.is_alive
  46. and current_time - session.last_active_ts > self.session_timeout
  47. ):
  48. session_ids_to_remove.append(sid)
  49. for sid in session_ids_to_remove:
  50. to_del_session: Session | None = self._sessions.pop(sid, None)
  51. if to_del_session is not None:
  52. await to_del_session.close()
  53. logger.info(
  54. f'Session {sid} and related resource have been removed due to inactivity.'
  55. )
  56. await asyncio.sleep(self.cleanup_interval)