Prevent queuing lots of setTypingState
@futurize() is now called with parentheses and can take a max_instances int argument. This is used for setTypingState to not have more than one queued calls per room and True/False state and avoids bombing the server with old ephemeral events after a network loss and reconnection.
This commit is contained in:
parent
188dc6be98
commit
aa55ffbc6a
@ -48,7 +48,7 @@ class Backend(QObject):
|
||||
|
||||
@pyqtSlot(str, result="QVariant")
|
||||
@pyqtSlot(str, bool, result="QVariant")
|
||||
@futurize
|
||||
@futurize()
|
||||
def getUserDisplayName(self, user_id: str, can_block: bool = True) -> str:
|
||||
if user_id in self._queried_displaynames:
|
||||
return self._queried_displaynames[user_id]
|
||||
|
@ -77,14 +77,14 @@ class Client(QObject):
|
||||
|
||||
@pyqtSlot(str)
|
||||
@pyqtSlot(str, str)
|
||||
@futurize
|
||||
@futurize()
|
||||
def login(self, password: str, device_name: str = "") -> None:
|
||||
response = self.net.talk(self.nio.login, password, device_name)
|
||||
self.nio_sync.receive_response(response)
|
||||
|
||||
|
||||
@pyqtSlot(str, str, str)
|
||||
@futurize
|
||||
@futurize()
|
||||
def resumeSession(self, user_id: str, token: str, device_id: str
|
||||
) -> None:
|
||||
response = nr.LoginResponse(user_id, device_id, token)
|
||||
@ -93,7 +93,7 @@ class Client(QObject):
|
||||
|
||||
|
||||
@pyqtSlot()
|
||||
@futurize
|
||||
@futurize()
|
||||
def logout(self) -> None:
|
||||
self._stop_sync.set()
|
||||
self.net.http_disconnect()
|
||||
@ -101,7 +101,7 @@ class Client(QObject):
|
||||
|
||||
|
||||
@pyqtSlot()
|
||||
@futurize
|
||||
@futurize()
|
||||
def startSyncing(self) -> None:
|
||||
while True:
|
||||
self._on_sync(self.net_sync.talk(
|
||||
@ -141,7 +141,7 @@ class Client(QObject):
|
||||
self.roomLeft.emit(room_id)
|
||||
|
||||
|
||||
@futurize
|
||||
@futurize()
|
||||
def loadPastEvents(self, room_id: str, start_token: str, limit: int = 100
|
||||
) -> None:
|
||||
# From QML, use Backend.loastPastEvents instead
|
||||
@ -170,7 +170,7 @@ class Client(QObject):
|
||||
|
||||
|
||||
@pyqtSlot(str, bool)
|
||||
@futurize
|
||||
@futurize(max_instances=1)
|
||||
def setTypingState(self, room_id: str, typing: bool) -> None:
|
||||
set_for_secs = 5
|
||||
last_set, last_time = self._last_typing_set[room_id]
|
||||
@ -183,6 +183,7 @@ class Client(QObject):
|
||||
|
||||
self._last_typing_set[room_id] = (typing, time.time())
|
||||
|
||||
print("send", typing)
|
||||
self.net.talk(
|
||||
self.nio.room_typing,
|
||||
room_id = room_id,
|
||||
@ -192,7 +193,7 @@ class Client(QObject):
|
||||
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
@futurize
|
||||
@futurize()
|
||||
def sendMarkdown(self, room_id: str, text: str) -> None:
|
||||
html = self.manager.backend.htmlFilter.fromMarkdown(text)
|
||||
content = {
|
||||
|
@ -5,9 +5,8 @@ import functools
|
||||
import logging
|
||||
import sys
|
||||
import traceback
|
||||
from concurrent.futures import Future
|
||||
from threading import currentThread
|
||||
from typing import Callable, Optional, Union
|
||||
from concurrent.futures import Executor, Future
|
||||
from typing import Callable, List, Optional, Tuple, Union
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
|
||||
|
||||
@ -63,17 +62,33 @@ class PyQtFuture(QObject):
|
||||
self.future.add_done_callback(fn)
|
||||
|
||||
|
||||
def futurize(func: Callable) -> Callable:
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, *args, **kwargs) -> PyQtFuture:
|
||||
def run_and_catch_errs():
|
||||
# Without this, exceptions are silently ignored
|
||||
try:
|
||||
return func(self, *args, **kwargs)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
logging.error("Exiting %s due to exception.", currentThread())
|
||||
sys.exit(1)
|
||||
_RUNNING: List[Tuple[Executor, Callable, tuple, dict]] = []
|
||||
|
||||
return PyQtFuture(self.pool.submit(run_and_catch_errs), self)
|
||||
return wrapper
|
||||
|
||||
def futurize(max_instances: Optional[int] = None) -> Callable:
|
||||
|
||||
def decorator(func: Callable) -> Callable:
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, *args, **kws) -> Optional[PyQtFuture]:
|
||||
def run_and_catch_errs():
|
||||
# Without this, exceptions are silently ignored
|
||||
try:
|
||||
return func(self, *args, **kws)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
logging.error("Exiting thread due to exception.")
|
||||
sys.exit(1)
|
||||
finally:
|
||||
del _RUNNING[_RUNNING.index((self.pool, func, args, kws))]
|
||||
|
||||
if max_instances is not None and \
|
||||
_RUNNING.count((self.pool, func, args, kws)) >= max_instances:
|
||||
return None
|
||||
|
||||
_RUNNING.append((self.pool, func, args, kws))
|
||||
return PyQtFuture(self.pool.submit(run_and_catch_errs), self)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
Loading…
Reference in New Issue
Block a user