montana/Русский/Экономика/банк_времени/код/presence_cache.py

152 lines
4.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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}")