mirror of
https://github.com/chatmail/core.git
synced 2026-05-20 07:16:31 +03:00
export and import full DC database state
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import threading
|
import threading
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
import requests
|
import requests
|
||||||
@@ -46,6 +47,7 @@ class Account(object):
|
|||||||
deltachat.set_context_callback(self._dc_context, self._process_event)
|
deltachat.set_context_callback(self._dc_context, self._process_event)
|
||||||
self._threads = IOThreads(self._dc_context)
|
self._threads = IOThreads(self._dc_context)
|
||||||
self._configkeys = self.get_config("sys.config_keys").split()
|
self._configkeys = self.get_config("sys.config_keys").split()
|
||||||
|
self._imex_completed = threading.Event()
|
||||||
|
|
||||||
def _check_config_key(self, name):
|
def _check_config_key(self, name):
|
||||||
if name not in self._configkeys:
|
if name not in self._configkeys:
|
||||||
@@ -272,6 +274,32 @@ class Account(object):
|
|||||||
msg_ids = [msg.id for msg in messages]
|
msg_ids = [msg.id for msg in messages]
|
||||||
lib.dc_delete_msgs(self._dc_context, msg_ids, len(msg_ids))
|
lib.dc_delete_msgs(self._dc_context, msg_ids, len(msg_ids))
|
||||||
|
|
||||||
|
def export_to_dir(self, backupdir):
|
||||||
|
"""return after all delta chat state is exported to a new file in
|
||||||
|
the specified directory.
|
||||||
|
"""
|
||||||
|
l = os.listdir(backupdir)
|
||||||
|
self._imex_completed.clear()
|
||||||
|
lib.dc_imex(self._dc_context, 11, as_dc_charpointer(backupdir), ffi.NULL)
|
||||||
|
if not self._threads.is_started():
|
||||||
|
lib.dc_perform_imap_jobs(self._dc_context)
|
||||||
|
self._imex_completed.wait()
|
||||||
|
for x in os.listdir(backupdir):
|
||||||
|
if x not in l:
|
||||||
|
return os.path.join(backupdir, x)
|
||||||
|
|
||||||
|
def import_from_file(self, path):
|
||||||
|
"""import delta chat state from the specified backup file.
|
||||||
|
|
||||||
|
The account must be in unconfigured state for import to attempted.
|
||||||
|
"""
|
||||||
|
assert not self.is_configured(), "cannot import into configured account"
|
||||||
|
self._imex_completed.clear()
|
||||||
|
lib.dc_imex(self._dc_context, 12, as_dc_charpointer(path), ffi.NULL)
|
||||||
|
if not self._threads.is_started():
|
||||||
|
lib.dc_perform_imap_jobs(self._dc_context)
|
||||||
|
self._imex_completed.wait()
|
||||||
|
|
||||||
def start_threads(self):
|
def start_threads(self):
|
||||||
""" start IMAP/SMTP threads (and configure account if it hasn't happened).
|
""" start IMAP/SMTP threads (and configure account if it hasn't happened).
|
||||||
|
|
||||||
@@ -291,9 +319,19 @@ class Account(object):
|
|||||||
self._evlogger(evt_name, data1, data2)
|
self._evlogger(evt_name, data1, data2)
|
||||||
method = getattr(self._evhandler, evt_name.lower(), None)
|
method = getattr(self._evhandler, evt_name.lower(), None)
|
||||||
if method is not None:
|
if method is not None:
|
||||||
|
# handle sync methods
|
||||||
return method(data1, data2) or 0
|
return method(data1, data2) or 0
|
||||||
|
else:
|
||||||
|
# handle async methods
|
||||||
|
method = getattr(self, "on_" + evt_name.lower(), None)
|
||||||
|
if method is not None:
|
||||||
|
method(data1, data2)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def on_dc_event_imex_progress(self, data1, data2):
|
||||||
|
if data1 == 1000:
|
||||||
|
self._imex_completed.set()
|
||||||
|
|
||||||
|
|
||||||
class IOThreads:
|
class IOThreads:
|
||||||
def __init__(self, dc_context):
|
def __init__(self, dc_context):
|
||||||
@@ -301,8 +339,11 @@ class IOThreads:
|
|||||||
self._thread_quitflag = False
|
self._thread_quitflag = False
|
||||||
self._name2thread = {}
|
self._name2thread = {}
|
||||||
|
|
||||||
|
def is_started(self):
|
||||||
|
return len(self._name2thread) > 0
|
||||||
|
|
||||||
def start(self, imap=True, smtp=True):
|
def start(self, imap=True, smtp=True):
|
||||||
assert not self._name2thread
|
assert not self.is_started()
|
||||||
if imap:
|
if imap:
|
||||||
self._start_one_thread("imap", self.imap_thread_run)
|
self._start_one_thread("imap", self.imap_thread_run)
|
||||||
if smtp:
|
if smtp:
|
||||||
|
|||||||
@@ -202,6 +202,25 @@ class TestOfflineAccount:
|
|||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
ac1.configure(addr="123@example.org")
|
ac1.configure(addr="123@example.org")
|
||||||
|
|
||||||
|
def test_import_export_one_contact(self, acfactory, tmpdir):
|
||||||
|
backupdir = tmpdir.mkdir("backup")
|
||||||
|
ac1 = acfactory.get_configured_offline_account()
|
||||||
|
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
||||||
|
chat = ac1.create_chat_by_contact(contact1)
|
||||||
|
msg = chat.send_text("msg1")
|
||||||
|
contact = msg.get_sender_contact()
|
||||||
|
assert contact == ac1.get_self_contact()
|
||||||
|
assert not backupdir.listdir()
|
||||||
|
|
||||||
|
path = ac1.export_to_dir(backupdir.strpath)
|
||||||
|
assert os.path.exists(path)
|
||||||
|
ac2 = acfactory.get_unconfigured_account()
|
||||||
|
ac2.import_from_file(path)
|
||||||
|
l = ac2.get_contacts(query="some1")
|
||||||
|
assert len(l) == 1
|
||||||
|
contact2 = l[0]
|
||||||
|
assert contact2.addr == "some1@hello.com"
|
||||||
|
|
||||||
|
|
||||||
class TestOnlineAccount:
|
class TestOnlineAccount:
|
||||||
def test_one_account_init(self, acfactory):
|
def test_one_account_init(self, acfactory):
|
||||||
|
|||||||
Reference in New Issue
Block a user