partial sync cancellation
each time we send or receive a chunk of data we check to see if the user wants to cancel sync in the case of a hung connection, it will still take a minute to time out
This commit is contained in:
parent
4380705992
commit
02975d43ad
@ -84,14 +84,31 @@ Your pysqlite2 is too old. Anki will appear frozen during long operations.""")
|
|||||||
if evt.key() == Qt.Key_Escape:
|
if evt.key() == Qt.Key_Escape:
|
||||||
evt.ignore()
|
evt.ignore()
|
||||||
|
|
||||||
def start(self, max=0, min=0, label=None, parent=None, immediate=False):
|
class ProgressCancellable(QProgressDialog):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
QProgressDialog.__init__(self, *args, **kwargs)
|
||||||
|
self.ankiCancel = False
|
||||||
|
def closeEvent(self, evt):
|
||||||
|
# avoid standard Qt flag as we don't want to close until we're ready
|
||||||
|
self.ankiCancel = True
|
||||||
|
evt.ignore()
|
||||||
|
def keyPressEvent(self, evt):
|
||||||
|
if evt.key() == Qt.Key_Escape:
|
||||||
|
evt.ignore()
|
||||||
|
self.ankiCancel = True
|
||||||
|
|
||||||
|
def start(self, max=0, min=0, label=None, parent=None, immediate=False, cancellable=False):
|
||||||
self._levels += 1
|
self._levels += 1
|
||||||
if self._levels > 1:
|
if self._levels > 1:
|
||||||
return
|
return
|
||||||
# setup window
|
# setup window
|
||||||
parent = parent or self.app.activeWindow() or self.mw
|
parent = parent or self.app.activeWindow() or self.mw
|
||||||
label = label or _("Processing...")
|
label = label or _("Processing...")
|
||||||
self._win = self.ProgressNoCancel(label, "", min, max, parent)
|
if cancellable:
|
||||||
|
klass = self.ProgressCancellable
|
||||||
|
else:
|
||||||
|
klass = self.ProgressNoCancel
|
||||||
|
self._win = klass(label, "", min, max, parent)
|
||||||
self._win.setWindowTitle("Anki")
|
self._win.setWindowTitle("Anki")
|
||||||
self._win.setCancelButton(None)
|
self._win.setCancelButton(None)
|
||||||
self._win.setAutoClose(False)
|
self._win.setAutoClose(False)
|
||||||
@ -112,6 +129,7 @@ Your pysqlite2 is too old. Anki will appear frozen during long operations.""")
|
|||||||
self._firstTime = time.time()
|
self._firstTime = time.time()
|
||||||
self._lastUpdate = time.time()
|
self._lastUpdate = time.time()
|
||||||
self._disabled = False
|
self._disabled = False
|
||||||
|
return self._win
|
||||||
|
|
||||||
def update(self, label=None, value=None, process=True, maybeShow=True):
|
def update(self, label=None, value=None, process=True, maybeShow=True):
|
||||||
#print self._min, self._counter, self._max, label, time.time() - self._lastTime
|
#print self._min, self._counter, self._max, label, time.time() - self._lastTime
|
||||||
|
65
aqt/sync.py
65
aqt/sync.py
@ -1,7 +1,6 @@
|
|||||||
# Copyright: Damien Elmes <anki@ichi2.net>
|
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
import socket
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import gc
|
import gc
|
||||||
@ -47,11 +46,17 @@ class SyncManager(QObject):
|
|||||||
auth=auth, media=self.pm.profile['syncMedia'])
|
auth=auth, media=self.pm.profile['syncMedia'])
|
||||||
t.event.connect(self.onEvent)
|
t.event.connect(self.onEvent)
|
||||||
self.label = _("Connecting...")
|
self.label = _("Connecting...")
|
||||||
self.mw.progress.start(immediate=True, label=self.label)
|
prog = self.mw.progress.start(immediate=True, label=self.label, cancellable=True)
|
||||||
self.sentBytes = self.recvBytes = 0
|
self.sentBytes = self.recvBytes = 0
|
||||||
self._updateLabel()
|
self._updateLabel()
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
while not self.thread.isFinished():
|
while not self.thread.isFinished():
|
||||||
|
if prog.ankiCancel:
|
||||||
|
self.thread.flagAbort()
|
||||||
|
# make sure we don't display 'upload success' msg
|
||||||
|
self._didFullUp = False
|
||||||
|
# abort may take a while
|
||||||
|
self.mw.progress.update(_("Stopping..."))
|
||||||
self.mw.app.processEvents()
|
self.mw.app.processEvents()
|
||||||
self.thread.wait(100)
|
self.thread.wait(100)
|
||||||
self.mw.progress.finish()
|
self.mw.progress.finish()
|
||||||
@ -289,6 +294,10 @@ class SyncThread(QThread):
|
|||||||
self.hkey = hkey
|
self.hkey = hkey
|
||||||
self.auth = auth
|
self.auth = auth
|
||||||
self.media = media
|
self.media = media
|
||||||
|
self._abort = 0 # 1=flagged, 2=aborting
|
||||||
|
|
||||||
|
def flagAbort(self):
|
||||||
|
self._abort = 1
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# init this first so an early crash doesn't cause an error
|
# init this first so an early crash doesn't cause an error
|
||||||
@ -309,11 +318,19 @@ class SyncThread(QThread):
|
|||||||
def syncMsg(msg):
|
def syncMsg(msg):
|
||||||
self.fireEvent("syncMsg", msg)
|
self.fireEvent("syncMsg", msg)
|
||||||
def sendEvent(bytes):
|
def sendEvent(bytes):
|
||||||
self.sentTotal += bytes
|
if not self._abort:
|
||||||
self.fireEvent("send", str(self.sentTotal))
|
self.sentTotal += bytes
|
||||||
|
self.fireEvent("send", str(self.sentTotal))
|
||||||
|
elif self._abort == 1:
|
||||||
|
self._abort = 2
|
||||||
|
raise Exception("sync cancelled")
|
||||||
def recvEvent(bytes):
|
def recvEvent(bytes):
|
||||||
self.recvTotal += bytes
|
if not self._abort:
|
||||||
self.fireEvent("recv", str(self.recvTotal))
|
self.recvTotal += bytes
|
||||||
|
self.fireEvent("recv", str(self.recvTotal))
|
||||||
|
elif self._abort == 1:
|
||||||
|
self._abort = 2
|
||||||
|
raise Exception("sync cancelled")
|
||||||
addHook("sync", syncEvent)
|
addHook("sync", syncEvent)
|
||||||
addHook("syncMsg", syncMsg)
|
addHook("syncMsg", syncMsg)
|
||||||
addHook("httpSend", sendEvent)
|
addHook("httpSend", sendEvent)
|
||||||
@ -332,6 +349,16 @@ class SyncThread(QThread):
|
|||||||
remHook("httpSend", sendEvent)
|
remHook("httpSend", sendEvent)
|
||||||
remHook("httpRecv", recvEvent)
|
remHook("httpRecv", recvEvent)
|
||||||
|
|
||||||
|
def _abortingSync(self):
|
||||||
|
try:
|
||||||
|
return self.client.sync()
|
||||||
|
except Exception as e:
|
||||||
|
if "sync cancelled" in str(e):
|
||||||
|
self.server.abort()
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
def _sync(self):
|
def _sync(self):
|
||||||
if self.auth:
|
if self.auth:
|
||||||
# need to authenticate and obtain host key
|
# need to authenticate and obtain host key
|
||||||
@ -344,13 +371,15 @@ class SyncThread(QThread):
|
|||||||
self.fireEvent("newKey", self.hkey)
|
self.fireEvent("newKey", self.hkey)
|
||||||
# run sync and check state
|
# run sync and check state
|
||||||
try:
|
try:
|
||||||
ret = self.client.sync()
|
ret = self._abortingSync()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log = traceback.format_exc()
|
log = traceback.format_exc()
|
||||||
err = repr(str(e))
|
err = repr(str(e))
|
||||||
if ("Unable to find the server" in err or
|
if ("Unable to find the server" in err or
|
||||||
"Errno 2" in err):
|
"Errno 2" in err):
|
||||||
self.fireEvent("offline")
|
self.fireEvent("offline")
|
||||||
|
elif "sync cancelled" in err:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
if not err:
|
if not err:
|
||||||
err = log
|
err = log
|
||||||
@ -391,11 +420,16 @@ class SyncThread(QThread):
|
|||||||
if f == "cancel":
|
if f == "cancel":
|
||||||
return
|
return
|
||||||
self.client = FullSyncer(self.col, self.hkey, self.server.client)
|
self.client = FullSyncer(self.col, self.hkey, self.server.client)
|
||||||
if f == "upload":
|
try:
|
||||||
if not self.client.upload():
|
if f == "upload":
|
||||||
self.fireEvent("upbad")
|
if not self.client.upload():
|
||||||
else:
|
self.fireEvent("upbad")
|
||||||
self.client.download()
|
else:
|
||||||
|
self.client.download()
|
||||||
|
except Exception as e:
|
||||||
|
if "sync cancelled" in str(e):
|
||||||
|
return
|
||||||
|
raise
|
||||||
# reopen db and move on to media sync
|
# reopen db and move on to media sync
|
||||||
self.col.reopen()
|
self.col.reopen()
|
||||||
self._syncMedia()
|
self._syncMedia()
|
||||||
@ -405,7 +439,12 @@ class SyncThread(QThread):
|
|||||||
return
|
return
|
||||||
self.server = RemoteMediaServer(self.col, self.hkey, self.server.client)
|
self.server = RemoteMediaServer(self.col, self.hkey, self.server.client)
|
||||||
self.client = MediaSyncer(self.col, self.server)
|
self.client = MediaSyncer(self.col, self.server)
|
||||||
ret = self.client.sync()
|
try:
|
||||||
|
ret = self.client.sync()
|
||||||
|
except Exception as e:
|
||||||
|
if "sync cancelled" in str(e):
|
||||||
|
return
|
||||||
|
raise
|
||||||
if ret == "noChanges":
|
if ret == "noChanges":
|
||||||
self.fireEvent("noMediaChanges")
|
self.fireEvent("noMediaChanges")
|
||||||
elif ret == "sanityCheckFailed":
|
elif ret == "sanityCheckFailed":
|
||||||
|
Loading…
Reference in New Issue
Block a user