Esempio n. 1
0
def sync_collection(username, password, full_sync="upload"):
    from anki.sync import Syncer, RemoteServer, FullSyncer, MediaSyncer, RemoteMediaServer

    collection = open_or_create_collection(username)

    server = RemoteServer(None)
    app.logger.info("u: %s,pass: %s" % (username, password))
    hkey = server.hostKey(username, password)
    syncer = Syncer(collection, server)
    ret = syncer.sync()
    app.logger.info("syncer return: %s" % ret)

    if (ret == "fullSync"):
        # app.logger.info("trying to do fullSync - upload - Not tested")
        client = FullSyncer(collection, hkey, server.client)
        if full_sync == "download":
            client.download()
        else:
            client.upload()

    if ret not in ("noChanges", "fullSync", "success"):
        collection.close()
        return False

    mediaserver = RemoteMediaServer(collection, hkey, server.client)
    mediaclient = MediaSyncer(collection, mediaserver)
    mediaret = mediaclient.sync()
    app.logger.info("mediasync returned: %s" % mediaret)
    collection.save()
    collection.close()

    return True
Esempio n. 2
0
    def sync(self):
        """Sync collection to AnkiWeb"""
        if self.pm is None:
            return

        hkey = self.pm.sync_key()
        hostNum = self.pm.sync_shard()
        if not hkey:
            click.echo('No sync auth registered in profile')
            return

        # Initialize servers and sync clients
        server = RemoteServer(hkey, hostNum=hostNum)
        main_client = Syncer(self.col, server)

        # Perform main sync
        try:
            click.echo('Syncing deck ... ', nl=False)
            ret = main_client.sync()
        except Exception as e:
            if 'sync cancelled' in str(e):
                server.abort()
            click.secho('Error during sync!', fg='red')
            click.echo(e)
            raise click.Abort()

        # Parse return value
        if ret == "noChanges":
            click.echo('done (no changes)!')
        elif ret == "success":
            click.echo('done!')
        elif ret == "serverAbort":
            click.echo('aborted!')
            return
        elif ret == "fullSync":
            click.echo('aborted!')
            click.secho('Full sync required!', fg='red')
            return
        else:
            click.echo('failed!')
            click.echo(f'Message: {ret}')
            return

        # Perform media sync
        try:
            debug_output = 'media=debug' in os.environ.get('RUST_LOG', '')

            with cd(self.col.media.dir()):
                if debug_output:
                    click.echo('Syncing media:')
                else:
                    click.echo('Syncing media ... ', nl=False)
                self.col.backend.sync_media(
                    hkey, f"https://sync{hostNum}.ankiweb.net/msync/")
                if not debug_output:
                    click.echo('done!')
        except Exception as e:
            if "sync cancelled" in str(e):
                return
            raise
Esempio n. 3
0
def test_threeway():
    test_sync()
    deck1.close(save=False)
    d3path = deck1.path.replace(".anki", "2.anki")
    shutil.copy2(deck1.path, d3path)
    deck1.reopen()
    deck3 = aopen(d3path)
    client2 = Syncer(deck3, server)
    assert client2.sync() == "noChanges"
    # client 1 adds a card at time 1
    time.sleep(1)
    f = deck1.newNote()
    f['Front'] = "1"
    deck1.addNote(f)
    deck1.save()
    # at time 2, client 2 syncs to server
    time.sleep(1)
    deck3.setMod()
    deck3.save()
    assert client2.sync() == "success"
    # at time 3, client 1 syncs, adding the older note
    time.sleep(1)
    assert client.sync() == "success"
    assert deck1.noteCount() == deck2.noteCount()
    # syncing client2 should pick it up
    assert client2.sync() == "success"
    assert deck1.noteCount() == deck2.noteCount() == deck3.noteCount()
Esempio n. 4
0
def test_threeway():
    test_sync()
    deck1.close(save=False)
    d3path = deck1.path.replace(".anki", "2.anki")
    shutil.copy2(deck1.path, d3path)
    deck1.reopen()
    deck3 = aopen(d3path)
    client2 = Syncer(deck3, server)
    assert client2.sync() == "noChanges"
    # client 1 adds a card at time 1
    time.sleep(1)
    f = deck1.newNote()
    f['Front'] = u"1";
    deck1.addNote(f)
    deck1.save()
    # at time 2, client 2 syncs to server
    time.sleep(1)
    deck3.setMod()
    deck3.save()
    assert client2.sync() == "success"
    # at time 3, client 1 syncs, adding the older note
    time.sleep(1)
    assert client.sync() == "success"
    assert deck1.noteCount() == deck2.noteCount()
    # syncing client2 should pick it up
    assert client2.sync() == "success"
    assert deck1.noteCount() == deck2.noteCount() == deck3.noteCount()
Esempio n. 5
0
def setup_basic():
    global deck1, deck2, client, server
    deck1 = getEmptyCol()
    # add a note to deck 1
    f = deck1.newNote()
    f['Front'] = "foo"
    f['Back'] = "bar"
    f.tags = ["foo"]
    deck1.addNote(f)
    # answer it
    deck1.reset()
    deck1.sched.answerCard(deck1.sched.getCard(), 4)
    # repeat for deck2
    deck2 = getEmptyDeckWith(server=True)
    f = deck2.newNote()
    f['Front'] = "bar"
    f['Back'] = "bar"
    f.tags = ["bar"]
    deck2.addNote(f)
    deck2.reset()
    deck2.sched.answerCard(deck2.sched.getCard(), 4)
    # start with same schema and sync time
    deck1.scm = deck2.scm = 0
    # and same mod time, so sync does nothing
    t = intTime(1000)
    deck1.save(mod=t)
    deck2.save(mod=t)
    server = LocalServer(deck2)
    client = Syncer(deck1, server)
Esempio n. 6
0
def _test_speed():
    t = time.time()
    deck1 = aopen(os.path.expanduser("~/rapid.anki"))
    for tbl in "revlog", "cards", "notes", "graves":
        deck1.db.execute("update %s set usn = -1 where usn != -1"%tbl)
    for m in deck1.models.all():
        m['usn'] = -1
    for tx in deck1.tags.all():
        deck1.tags.tags[tx] = -1
    deck1._usn = -1
    deck1.save()
    deck2 = getEmptyDeck(server=True)
    deck1.scm = deck2.scm = 0
    server = LocalServer(deck2)
    client = Syncer(deck1, server)
    print "load %d" % ((time.time() - t)*1000); t = time.time()
    assert client.sync() == "success"
    print "sync %d" % ((time.time() - t)*1000); t = time.time()
Esempio n. 7
0
def _test_speed():
    t = time.time()
    deck1 = aopen(os.path.expanduser("~/rapid.anki"))
    for tbl in "revlog", "cards", "notes", "graves":
        deck1.db.execute("update %s set usn = -1 where usn != -1"%tbl)
    for m in deck1.models.all():
        m['usn'] = -1
    for tx in deck1.tags.all():
        deck1.tags.tags[tx] = -1
    deck1._usn = -1
    deck1.save()
    deck2 = getEmptyDeck(server=True)
    deck1.scm = deck2.scm = 0
    server = LocalServer(deck2)
    client = Syncer(deck1, server)
    print "load %d" % ((time.time() - t)*1000); t = time.time()
    assert client.sync() == "success"
    print "sync %d" % ((time.time() - t)*1000); t = time.time()
Esempio n. 8
0
    def run(self):
        # init this first so an early crash doesn't cause an error
        # in the main thread
        self.syncMsg = ""
        self.uname = ""
        try:
            self.col = Collection(self.path, log=True)
        except:
            self.fireEvent("corrupt")
            return
        self.server = RemoteServer(self.hkey)
        self.client = Syncer(self.col, self.server)
        self.sentTotal = 0
        self.recvTotal = 0
        # throttle updates; qt doesn't handle lots of posted events well
        self.byteUpdate = time.time()

        def syncEvent(type):
            self.fireEvent("sync", type)

        def syncMsg(msg):
            self.fireEvent("syncMsg", msg)

        def canPost():
            if (time.time() - self.byteUpdate) > 0.1:
                self.byteUpdate = time.time()
                return True

        def sendEvent(bytes):
            self.sentTotal += bytes
            if canPost():
                self.fireEvent("send", str(self.sentTotal))

        def recvEvent(bytes):
            self.recvTotal += bytes
            if canPost():
                self.fireEvent("recv", str(self.recvTotal))

        addHook("sync", syncEvent)
        addHook("syncMsg", syncMsg)
        addHook("httpSend", sendEvent)
        addHook("httpRecv", recvEvent)
        # run sync and catch any errors
        try:
            self._sync()
        except:
            err = traceback.format_exc()
            self.fireEvent("error", err)
        finally:
            # don't bump mod time unless we explicitly save
            self.col.close(save=False)
            remHook("sync", syncEvent)
            remHook("syncMsg", syncMsg)
            remHook("httpSend", sendEvent)
            remHook("httpRecv", recvEvent)
Esempio n. 9
0
    def run(self):
        # init this first so an early crash doesn't cause an error
        # in the main thread
        self.syncMsg = ""
        self.uname = ""
        try:
            self.col = Collection(self.path, log=True)
        except:
            self.fireEvent("corrupt")
            return
        self.server = RemoteServer(self.hkey, hostNum=self.hostNum)
        self.client = Syncer(self.col, self.server)
        self.sentTotal = 0
        self.recvTotal = 0

        def syncEvent(type):
            self.fireEvent("sync", type)

        def syncMsg(msg):
            self.fireEvent("syncMsg", msg)

        def sendEvent(bytes):
            if not self._abort:
                self.sentTotal += bytes
                self.fireEvent("send", str(self.sentTotal))
            elif self._abort == 1:
                self._abort = 2
                raise Exception("sync cancelled")

        def recvEvent(bytes):
            if not self._abort:
                self.recvTotal += bytes
                self.fireEvent("recv", str(self.recvTotal))
            elif self._abort == 1:
                self._abort = 2
                raise Exception("sync cancelled")

        addHook("sync", syncEvent)
        addHook("syncMsg", syncMsg)
        addHook("httpSend", sendEvent)
        addHook("httpRecv", recvEvent)
        # run sync and catch any errors
        try:
            self._sync()
        except:
            err = traceback.format_exc()
            self.fireEvent("error", err)
        finally:
            # don't bump mod time unless we explicitly save
            self.col.close(save=False)
            remHook("sync", syncEvent)
            remHook("syncMsg", syncMsg)
            remHook("httpSend", sendEvent)
            remHook("httpRecv", recvEvent)
Esempio n. 10
0
 def sync(self):
     server= RemoteServer(self.pm.profile['syncKey'])
     client = Syncer(self.collection, server)
     ret = None
     try:
         print client.sync()
     except Exception, e:
         log = traceback.format_exc()
         try:
             err = unicode(e[0], "utf8", "ignore")
         except:
             # number, exception with no args, etc
             err = ""
         if "Unable to find the server" in err:
             print "offline"
             return
         else:
             if not isinstance(log, unicode):
                 err = unicode(log, "utf8", "replace")
                 print "error", log
         return
Esempio n. 11
0
    def run(self):
        # init this first so an early crash doesn't cause an error
        # in the main thread
        self.syncMsg = ""
        self.uname = ""
        try:
            self.col = Collection(self.path)
        except:
            self.fireEvent("corrupt")
            return
        self.server = RemoteServer(self.hkey, hostNum=self.hostNum)
        self.client = Syncer(self.col, self.server)
        self.sentTotal = 0
        self.recvTotal = 0

        def syncEvent(type):
            self.fireEvent("sync", type)

        def syncMsg(msg):
            self.fireEvent("syncMsg", msg)

        def http_progress(upload: int, download: int) -> None:
            if not self._abort:
                self.sentTotal += upload
                self.recvTotal += download
                self.progress_event.emit(self.sentTotal,
                                         self.recvTotal)  # type: ignore
            elif self._abort == 1:
                self._abort = 2
                raise Exception("sync cancelled")

        self.server.client.progress_hook = http_progress

        hooks.sync_stage_did_change.append(syncEvent)
        hooks.sync_progress_did_change.append(syncMsg)
        # run sync and catch any errors
        try:
            self._sync()
        except:
            err = traceback.format_exc()
            self.fireEvent("error", err)
        finally:
            # don't bump mod time unless we explicitly save
            self.col.close(save=False, downgrade=False)
            hooks.sync_stage_did_change.remove(syncEvent)
            hooks.sync_progress_did_change.remove(syncMsg)
Esempio n. 12
0
 def sync_server(self):
     server = RemoteServer(self.profile['syncKey'], self.profile['hostNum'])
     client = Syncer(self.col, server)
     res = client.sync()
     if res in ['success', 'noChanges']:
         pass
     elif res == 'fullSync':
         print('FULL SYNC')
         client = FullSyncer(self.col, self.profile['syncKey'],
                             server.client, self.profile['hostNum'])
         client.download()
         self.col.reopen()
Esempio n. 13
0
 def run(self):
     self.col = Collection(self.path)
     self.server = RemoteServer(self.hkey)
     self.client = Syncer(self.col, self.server)
     self.sentTotal = 0
     self.recvTotal = 0
     # throttle updates; qt doesn't handle lots of posted events well
     self.byteUpdate = time.time()
     def syncEvent(type):
         self.fireEvent("sync", type)
     def canPost():
         if (time.time() - self.byteUpdate) > 0.1:
             self.byteUpdate = time.time()
             return True
     def sendEvent(bytes):
         self.sentTotal += bytes
         if canPost():
             self.fireEvent("send", self.sentTotal)
     def recvEvent(bytes):
         self.recvTotal += bytes
         if canPost():
             self.fireEvent("recv", self.recvTotal)
     addHook("sync", syncEvent)
     addHook("httpSend", sendEvent)
     addHook("httpRecv", recvEvent)
     # run sync and catch any errors
     try:
         self._sync()
     except:
         err = traceback.format_exc()
         print err
         self.fireEvent("error", err)
     finally:
         # don't bump mod time unless we explicitly save
         self.col.close(save=False)
         remHook("sync", syncEvent)
         remHook("httpSend", sendEvent)
         remHook("httpRecv", recvEvent)
Esempio n. 14
0
 def __init__(self, col):
     # So that 'server' (the 3rd argument) can't get set
     Syncer.__init__(self, col)
Esempio n. 15
0
def test_threeway2():
    # for this test we want ms precision of notes so we don't have to
    # sleep a lot
    import anki.notes
    intTime = anki.notes.intTime
    anki.notes.intTime = lambda x=1: intTime(1000)

    def setup():
        # create collection 1 with a single note
        c1 = getEmptyCol()
        f = c1.newNote()
        f['Front'] = "startingpoint"
        nid = f.id
        c1.addNote(f)
        cid = f.cards()[0].id
        c1.beforeUpload()
        # start both clients and server off in this state
        s1path = c1.path.replace(".anki2", "-s1.anki2")
        c2path = c1.path.replace(".anki2", "-c2.anki2")
        shutil.copy2(c1.path, s1path)
        shutil.copy2(c1.path, c2path)
        # open them
        c1 = Collection(c1.path)
        c2 = Collection(c2path)
        s1 = Collection(s1path, server=True)
        return c1, c2, s1, nid, cid

    c1, c2, s1, nid, cid = setup()
    # modify c1 then sync c1->s1
    n = c1.getNote(nid)
    t = "firstmod"
    n['Front'] = t
    n.flush()
    c1.db.execute("update cards set mod=1, usn=-1")
    srv = LocalServer(s1)
    clnt1 = Syncer(c1, srv)
    clnt1.sync()
    n.load()
    assert n['Front'] == t
    assert s1.getNote(nid)['Front'] == t
    assert s1.db.scalar("select mod from cards") == 1
    # sync s1->c2
    clnt2 = Syncer(c2, srv)
    clnt2.sync()
    assert c2.getNote(nid)['Front'] == t
    assert c2.db.scalar("select mod from cards") == 1
    # modify c1 and sync
    time.sleep(0.001)
    t = "secondmod"
    n = c1.getNote(nid)
    n['Front'] = t
    n.flush()
    c1.db.execute("update cards set mod=2, usn=-1")
    clnt1.sync()
    # modify c2 and sync - both c2 and server should be the same
    time.sleep(0.001)
    t2 = "thirdmod"
    n = c2.getNote(nid)
    n['Front'] = t2
    n.flush()
    c2.db.execute("update cards set mod=3, usn=-1")
    clnt2.sync()
    n.load()
    assert n['Front'] == t2
    assert c2.db.scalar("select mod from cards") == 3
    n = s1.getNote(nid)
    assert n['Front'] == t2
    assert s1.db.scalar("select mod from cards") == 3
    # and syncing c1 again should yield the updated note as well
    clnt1.sync()
    n = s1.getNote(nid)
    assert n['Front'] == t2
    assert s1.db.scalar("select mod from cards") == 3
    n = c1.getNote(nid)
    assert n['Front'] == t2
    assert c1.db.scalar("select mod from cards") == 3
Esempio n. 16
0
    def sync(self):
        """Sync collection to AnkiWeb"""
        if self.pm is None:
            return

        import click

        if not self.pm.profile['syncKey']:
            click.echo('No sync auth registered in profile')
            return

        from anki.sync import (Syncer, MediaSyncer, RemoteServer,
                               RemoteMediaServer)

        # Initialize servers and sync clients
        hkey = self.pm.profile['syncKey']
        hostNum = self.pm.profile.get('hostNum')
        server = RemoteServer(hkey, hostNum=hostNum)
        main_client = Syncer(self.col, server)
        media_client = MediaSyncer(
            self.col,
            RemoteMediaServer(self.col, hkey, server.client, hostNum=hostNum))

        # Perform main sync
        try:
            click.echo('Syncing deck ... ', nl=False)
            ret = main_client.sync()
        except Exception as e:
            if 'sync cancelled' in str(e):
                server.abort()
            click.secho('Error during sync!', fg='red')
            click.echo(e)
            raise click.Abort()

        # Parse return value
        if ret == "noChanges":
            click.echo('done (no changes)!')
        elif ret == "success":
            click.echo('done!')
        elif ret == "serverAbort":
            click.echo('aborted!')
            return
        elif ret == "fullSync":
            click.echo('aborted!')
            click.secho('Full sync required!', fg='red')
            return
        else:
            click.echo('failed!')
            click.echo(f'Message: {ret}')
            return

        # Perform media sync
        try:
            click.echo('Syncing media ... ', nl=False)
            save_cwd = os.getcwd()
            os.chdir(self.col.media.dir())
            ret = media_client.sync()
            os.chdir(save_cwd)
        except Exception as e:
            if "sync cancelled" in str(e):
                return
            raise

        if ret == "noChanges":
            click.echo('done (no changes)!')
        elif ret in ("sanityCheckFailed", "corruptMediaDB"):
            click.echo('failed!')
        else:
            click.echo('done!')
Esempio n. 17
0
def test_threeway2():
    # for this test we want ms precision of notes so we don't have to
    # sleep a lot
    import anki.notes
    intTime = anki.notes.intTime
    anki.notes.intTime = lambda x=1: intTime(1000)
    def setup():
        # create collection 1 with a single note
        c1 = getEmptyCol()
        f = c1.newNote()
        f['Front'] = u"startingpoint"
        nid = f.id
        c1.addNote(f)
        cid = f.cards()[0].id
        c1.beforeUpload()
        # start both clients and server off in this state
        s1path = c1.path.replace(".anki2", "-s1.anki2")
        c2path = c1.path.replace(".anki2", "-c2.anki2")
        shutil.copy2(c1.path, s1path)
        shutil.copy2(c1.path, c2path)
        # open them
        c1 = Collection(c1.path)
        c2 = Collection(c2path)
        s1 = Collection(s1path, server=True)
        return c1, c2, s1, nid, cid
    c1, c2, s1, nid, cid = setup()
    # modify c1 then sync c1->s1
    n = c1.getNote(nid)
    t = "firstmod"
    n['Front'] = t
    n.flush()
    c1.db.execute("update cards set mod=1, usn=-1")
    srv = LocalServer(s1)
    clnt1 = Syncer(c1, srv)
    clnt1.sync()
    n.load()
    assert n['Front'] == t
    assert s1.getNote(nid)['Front'] == t
    assert s1.db.scalar("select mod from cards") == 1
    # sync s1->c2
    clnt2 = Syncer(c2, srv)
    clnt2.sync()
    assert c2.getNote(nid)['Front'] == t
    assert c2.db.scalar("select mod from cards") == 1
    # modify c1 and sync
    time.sleep(0.001)
    t = "secondmod"
    n = c1.getNote(nid)
    n['Front'] = t
    n.flush()
    c1.db.execute("update cards set mod=2, usn=-1")
    clnt1.sync()
    # modify c2 and sync - both c2 and server should be the same
    time.sleep(0.001)
    t2 = "thirdmod"
    n = c2.getNote(nid)
    n['Front'] = t2
    n.flush()
    c2.db.execute("update cards set mod=3, usn=-1")
    clnt2.sync()
    n.load()
    assert n['Front'] == t2
    assert c2.db.scalar("select mod from cards") == 3
    n = s1.getNote(nid)
    assert n['Front'] == t2
    assert s1.db.scalar("select mod from cards") == 3
    # and syncing c1 again should yield the updated note as well
    clnt1.sync()
    n = s1.getNote(nid)
    assert n['Front'] == t2
    assert s1.db.scalar("select mod from cards") == 3
    n = c1.getNote(nid)
    assert n['Front'] == t2
    assert c1.db.scalar("select mod from cards") == 3
Esempio n. 18
0
 def __init__(self, col):
     # So that 'server' (the 3rd argument) can't get set
     Syncer.__init__(self, col)