152 lines
4.3 KiB
Python
152 lines
4.3 KiB
Python
|
|
"""
|
|||
|
|
presence_cache.py — Кэш присутствия участников
|
|||
|
|
|
|||
|
|
Montana Protocol
|
|||
|
|
Отслеживание присутствия пользователей в реальном времени
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import threading
|
|||
|
|
from typing import Dict, Optional, Any
|
|||
|
|
|
|||
|
|
|
|||
|
|
class PresenceCache:
|
|||
|
|
"""
|
|||
|
|
Кэш присутствия по адресам (telegram_id или ip)
|
|||
|
|
|
|||
|
|
Хранит информацию о присутствии каждого участника:
|
|||
|
|
- Адрес (telegram_id, ip, или другой идентификатор)
|
|||
|
|
- Секунды присутствия
|
|||
|
|
- Последняя активность
|
|||
|
|
- Статус (активен/пауза)
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self.entries: Dict[str, Dict[str, Any]] = {}
|
|||
|
|
self._lock = threading.Lock()
|
|||
|
|
|
|||
|
|
def get(self, address: str) -> Optional[Dict[str, Any]]:
|
|||
|
|
"""
|
|||
|
|
Получить запись по адресу
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
address: Адрес участника
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Dict с данными присутствия или None
|
|||
|
|
"""
|
|||
|
|
with self._lock:
|
|||
|
|
return self.entries.get(address)
|
|||
|
|
|
|||
|
|
def set(self, address: str, data: Dict[str, Any]):
|
|||
|
|
"""
|
|||
|
|
Установить запись
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
address: Адрес участника
|
|||
|
|
data: Данные присутствия
|
|||
|
|
"""
|
|||
|
|
with self._lock:
|
|||
|
|
self.entries[address] = data
|
|||
|
|
|
|||
|
|
def remove(self, address: str):
|
|||
|
|
"""
|
|||
|
|
Удалить запись
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
address: Адрес участника
|
|||
|
|
"""
|
|||
|
|
with self._lock:
|
|||
|
|
self.entries.pop(address, None)
|
|||
|
|
|
|||
|
|
def all(self) -> Dict[str, Dict[str, Any]]:
|
|||
|
|
"""
|
|||
|
|
Получить все записи (копию)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Dict всех записей присутствия
|
|||
|
|
"""
|
|||
|
|
with self._lock:
|
|||
|
|
return dict(self.entries)
|
|||
|
|
|
|||
|
|
def count_active(self) -> int:
|
|||
|
|
"""
|
|||
|
|
Подсчитать количество активных участников
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Количество участников с is_active=True
|
|||
|
|
"""
|
|||
|
|
with self._lock:
|
|||
|
|
return sum(1 for e in self.entries.values() if e.get("is_active"))
|
|||
|
|
|
|||
|
|
def total_seconds(self) -> int:
|
|||
|
|
"""
|
|||
|
|
Общее количество секунд присутствия всех участников за текущий τ₂
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Сумма t2_seconds всех участников
|
|||
|
|
"""
|
|||
|
|
with self._lock:
|
|||
|
|
return sum(e.get("t2_seconds", 0) for e in self.entries.values())
|
|||
|
|
|
|||
|
|
def clear(self):
|
|||
|
|
"""Очистить весь кэш"""
|
|||
|
|
with self._lock:
|
|||
|
|
self.entries.clear()
|
|||
|
|
|
|||
|
|
def __len__(self) -> int:
|
|||
|
|
"""Количество участников в кэше"""
|
|||
|
|
with self._lock:
|
|||
|
|
return len(self.entries)
|
|||
|
|
|
|||
|
|
def __contains__(self, address: str) -> bool:
|
|||
|
|
"""Проверить наличие адреса в кэше"""
|
|||
|
|
with self._lock:
|
|||
|
|
return address in self.entries
|
|||
|
|
|
|||
|
|
|
|||
|
|
# Экспорт
|
|||
|
|
__all__ = ['PresenceCache']
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
# Тесты
|
|||
|
|
import time
|
|||
|
|
|
|||
|
|
cache = PresenceCache()
|
|||
|
|
|
|||
|
|
# Добавляем участников
|
|||
|
|
cache.set("user_123", {
|
|||
|
|
"address": "user_123",
|
|||
|
|
"presence_seconds": 100,
|
|||
|
|
"t2_seconds": 100,
|
|||
|
|
"last_activity": time.time(),
|
|||
|
|
"is_active": True
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
cache.set("user_456", {
|
|||
|
|
"address": "user_456",
|
|||
|
|
"presence_seconds": 200,
|
|||
|
|
"t2_seconds": 200,
|
|||
|
|
"last_activity": time.time(),
|
|||
|
|
"is_active": True
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
cache.set("user_789", {
|
|||
|
|
"address": "user_789",
|
|||
|
|
"presence_seconds": 50,
|
|||
|
|
"t2_seconds": 50,
|
|||
|
|
"last_activity": time.time(),
|
|||
|
|
"is_active": False # На паузе
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
# Проверяем
|
|||
|
|
print(f"Total participants: {len(cache)}")
|
|||
|
|
print(f"Active participants: {cache.count_active()}")
|
|||
|
|
print(f"Total T2 seconds: {cache.total_seconds()}")
|
|||
|
|
print(f"Contains user_123: {'user_123' in cache}")
|
|||
|
|
|
|||
|
|
# Получаем все
|
|||
|
|
for address, entry in cache.all().items():
|
|||
|
|
status = "✅ Active" if entry['is_active'] else "⏸️ Paused"
|
|||
|
|
print(f"{address}: {entry['t2_seconds']} sec - {status}")
|