chore: stylize sse code; fix: add sseclient-py to requirements

This commit is contained in:
firedotguy
2026-02-10 17:53:48 +03:00
parent 51518ce0d7
commit 8e8b0b3bb9
5 changed files with 30 additions and 45 deletions

View File

@@ -2,8 +2,8 @@ from uuid import UUID
from _io import BufferedReader
from typing import cast, Iterator
from datetime import datetime
import json
import time
from json import JSONDecodeError, loads
from time import sleep
from requests.exceptions import ConnectionError, HTTPError
from sseclient import SSEClient
@@ -1105,59 +1105,59 @@ class Client:
@refresh_on_error
def stream_notifications(self) -> Iterator[StreamConnect | StreamNotification]:
"""Слушать SSE поток уведомлений
Yields:
StreamConnect | StreamNotification: События подключения или уведомления
Example:
```python
from itd import ITDClient
client = ITDClient(cookies='refresh_token=...')
# Запуск прослушивания
for event in client.stream_notifications():
if isinstance(event, StreamConnect):
print(f'Подключено: {event.user_id}')
else:
print(f'Уведомление: {event.type} от {event.actor.username}')
# Остановка из другого потока или обработчика
# client.stop_stream()
```
"""
self._stream_active = True
while self._stream_active:
try:
response = stream_notifications(self.token)
response.raise_for_status()
client = SSEClient(response)
for event in client.events():
if not self._stream_active:
response.close()
return
try:
if not event.data or event.data.strip() == '':
continue
data = json.loads(event.data)
data = loads(event.data)
if 'userId' in data and 'timestamp' in data and 'type' not in data:
yield StreamConnect.model_validate(data)
else:
yield StreamNotification.model_validate(data)
except json.JSONDecodeError:
except JSONDecodeError:
print(f'Не удалось распарсить сообщение: {event.data}')
continue
except Exception as e:
print(f'Ошибка обработки события: {e}')
continue
except Unauthorized:
if self.cookies and self._stream_active:
print('Токен истек, обновляем...')
@@ -1169,27 +1169,27 @@ class Client:
if not self._stream_active:
return
print(f'Ошибка соединения: {e}, переподключение через 5 секунд...')
time.sleep(5)
sleep(5)
continue
def stop_stream(self):
"""Остановить прослушивание SSE потока
Example:
```python
import threading
from itd import ITDClient
client = ITDClient(cookies='refresh_token=...')
# Запуск в отдельном потоке
def listen():
for event in client.stream_notifications():
print(event)
thread = threading.Thread(target=listen)
thread.start()
# Остановка через 10 секунд
import time
time.sleep(10)
@@ -1197,4 +1197,5 @@ class Client:
thread.join()
```
"""
print('stop event')
self._stream_active = False

View File

@@ -1,11 +1,8 @@
from uuid import UUID
from datetime import datetime
from typing import Literal
from pydantic import BaseModel, Field
from itd.enums import NotificationType, NotificationTargetType
from itd.models.user import UserNotification
from itd.models.notification import Notification
class StreamConnect(BaseModel):
@@ -14,20 +11,7 @@ class StreamConnect(BaseModel):
timestamp: int
class StreamNotification(BaseModel):
class StreamNotification(Notification):
"""Уведомление из SSE потока"""
id: UUID
type: NotificationType
target_type: NotificationTargetType | None = Field(None, alias='targetType')
target_id: UUID | None = Field(None, alias='targetId')
preview: str | None = None
read_at: datetime | None = Field(None, alias='readAt')
created_at: datetime = Field(alias='createdAt')
user_id: UUID = Field(alias='userId')
actor: UserNotification
read: bool = False
sound: bool = True

View File

@@ -16,7 +16,7 @@ def get_unread_notifications_count(token: str):
def stream_notifications(token: str):
"""Получить SSE поток уведомлений
Returns:
Response: Streaming response для SSE
"""

View File

@@ -12,6 +12,6 @@ authors = [
]
license = "MIT"
dependencies = [
"requests", "pydantic"
"requests", "pydantic", "sseclient-py"
]
requires-python = ">=3.9"

View File

@@ -5,7 +5,7 @@ setup(
version='1.1.0',
packages=find_packages(),
install_requires=[
'requests', 'pydantic'
'requests', 'pydantic', 'sseclient-py'
],
python_requires=">=3.9"
)