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, result="QVariant")
|
||||||
@pyqtSlot(str, bool, result="QVariant")
|
@pyqtSlot(str, bool, result="QVariant")
|
||||||
@futurize
|
@futurize()
|
||||||
def getUserDisplayName(self, user_id: str, can_block: bool = True) -> str:
|
def getUserDisplayName(self, user_id: str, can_block: bool = True) -> str:
|
||||||
if user_id in self._queried_displaynames:
|
if user_id in self._queried_displaynames:
|
||||||
return self._queried_displaynames[user_id]
|
return self._queried_displaynames[user_id]
|
||||||
|
@ -77,14 +77,14 @@ class Client(QObject):
|
|||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
@pyqtSlot(str, str)
|
@pyqtSlot(str, str)
|
||||||
@futurize
|
@futurize()
|
||||||
def login(self, password: str, device_name: str = "") -> None:
|
def login(self, password: str, device_name: str = "") -> None:
|
||||||
response = self.net.talk(self.nio.login, password, device_name)
|
response = self.net.talk(self.nio.login, password, device_name)
|
||||||
self.nio_sync.receive_response(response)
|
self.nio_sync.receive_response(response)
|
||||||
|
|
||||||
|
|
||||||
@pyqtSlot(str, str, str)
|
@pyqtSlot(str, str, str)
|
||||||
@futurize
|
@futurize()
|
||||||
def resumeSession(self, user_id: str, token: str, device_id: str
|
def resumeSession(self, user_id: str, token: str, device_id: str
|
||||||
) -> None:
|
) -> None:
|
||||||
response = nr.LoginResponse(user_id, device_id, token)
|
response = nr.LoginResponse(user_id, device_id, token)
|
||||||
@ -93,7 +93,7 @@ class Client(QObject):
|
|||||||
|
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@futurize
|
@futurize()
|
||||||
def logout(self) -> None:
|
def logout(self) -> None:
|
||||||
self._stop_sync.set()
|
self._stop_sync.set()
|
||||||
self.net.http_disconnect()
|
self.net.http_disconnect()
|
||||||
@ -101,7 +101,7 @@ class Client(QObject):
|
|||||||
|
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@futurize
|
@futurize()
|
||||||
def startSyncing(self) -> None:
|
def startSyncing(self) -> None:
|
||||||
while True:
|
while True:
|
||||||
self._on_sync(self.net_sync.talk(
|
self._on_sync(self.net_sync.talk(
|
||||||
@ -141,7 +141,7 @@ class Client(QObject):
|
|||||||
self.roomLeft.emit(room_id)
|
self.roomLeft.emit(room_id)
|
||||||
|
|
||||||
|
|
||||||
@futurize
|
@futurize()
|
||||||
def loadPastEvents(self, room_id: str, start_token: str, limit: int = 100
|
def loadPastEvents(self, room_id: str, start_token: str, limit: int = 100
|
||||||
) -> None:
|
) -> None:
|
||||||
# From QML, use Backend.loastPastEvents instead
|
# From QML, use Backend.loastPastEvents instead
|
||||||
@ -170,7 +170,7 @@ class Client(QObject):
|
|||||||
|
|
||||||
|
|
||||||
@pyqtSlot(str, bool)
|
@pyqtSlot(str, bool)
|
||||||
@futurize
|
@futurize(max_instances=1)
|
||||||
def setTypingState(self, room_id: str, typing: bool) -> None:
|
def setTypingState(self, room_id: str, typing: bool) -> None:
|
||||||
set_for_secs = 5
|
set_for_secs = 5
|
||||||
last_set, last_time = self._last_typing_set[room_id]
|
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())
|
self._last_typing_set[room_id] = (typing, time.time())
|
||||||
|
|
||||||
|
print("send", typing)
|
||||||
self.net.talk(
|
self.net.talk(
|
||||||
self.nio.room_typing,
|
self.nio.room_typing,
|
||||||
room_id = room_id,
|
room_id = room_id,
|
||||||
@ -192,7 +193,7 @@ class Client(QObject):
|
|||||||
|
|
||||||
|
|
||||||
@pyqtSlot(str, str)
|
@pyqtSlot(str, str)
|
||||||
@futurize
|
@futurize()
|
||||||
def sendMarkdown(self, room_id: str, text: str) -> None:
|
def sendMarkdown(self, room_id: str, text: str) -> None:
|
||||||
html = self.manager.backend.htmlFilter.fromMarkdown(text)
|
html = self.manager.backend.htmlFilter.fromMarkdown(text)
|
||||||
content = {
|
content = {
|
||||||
|
@ -5,9 +5,8 @@ import functools
|
|||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from concurrent.futures import Future
|
from concurrent.futures import Executor, Future
|
||||||
from threading import currentThread
|
from typing import Callable, List, Optional, Tuple, Union
|
||||||
from typing import Callable, Optional, Union
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
|
||||||
|
|
||||||
@ -63,17 +62,33 @@ class PyQtFuture(QObject):
|
|||||||
self.future.add_done_callback(fn)
|
self.future.add_done_callback(fn)
|
||||||
|
|
||||||
|
|
||||||
def futurize(func: Callable) -> Callable:
|
_RUNNING: List[Tuple[Executor, Callable, tuple, dict]] = []
|
||||||
@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)
|
|
||||||
|
|
||||||
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…
x
Reference in New Issue
Block a user