make eventlogger module a global plugin

This commit is contained in:
holger krekel
2020-02-23 17:43:29 +01:00
parent 0d4b6f5627
commit 79f5e736b0
6 changed files with 74 additions and 54 deletions

View File

@@ -1,6 +1,7 @@
from . import capi, const, hookspec from . import capi, const, hookspec
from .capi import ffi from .capi import ffi
from .account import Account # noqa from .account import Account # noqa
from . import eventlogger
from pkg_resources import get_distribution, DistributionNotFound from pkg_resources import get_distribution, DistributionNotFound
try: try:
@@ -79,3 +80,7 @@ def get_dc_event_name(integer, _DC_EVENTNAME_MAP={}):
def register_global_plugin(plugin): def register_global_plugin(plugin):
gm = hookspec.Global._get_plugin_manager() gm = hookspec.Global._get_plugin_manager()
gm.register(plugin) gm.register(plugin)
gm.check_pending()
register_global_plugin(eventlogger)

View File

@@ -45,20 +45,10 @@ class Account(object):
) )
hook = hookspec.Global._get_plugin_manager().hook hook = hookspec.Global._get_plugin_manager().hook
hook.at_account_init(account=self, db_path=db_path) hook.account_init(account=self, db_path=db_path)
self._shutdown_event = Event()
self._threads = iothreads.IOThreads(self) self._threads = iothreads.IOThreads(self)
# send all FFI events for this account to a plugin hook
def _ll_event(ctx, evt_name, data1, data2):
assert ctx == self._dc_context
ffi_event = FFIEvent(name=evt_name, data1=data1, data2=data2)
self._pm.hook.process_ffi_event(
account=self, ffi_event=ffi_event
)
deltachat.set_context_callback(self._dc_context, _ll_event)
# open database # open database
if hasattr(db_path, "encode"): if hasattr(db_path, "encode"):
db_path = db_path.encode("utf8") db_path = db_path.encode("utf8")
@@ -66,6 +56,8 @@ class Account(object):
raise ValueError("Could not dc_open: {}".format(db_path)) raise ValueError("Could not dc_open: {}".format(db_path))
self._configkeys = self.get_config("sys.config_keys").split() self._configkeys = self.get_config("sys.config_keys").split()
atexit.register(self.shutdown) atexit.register(self.shutdown)
self._shutdown_event = Event()
@hookspec.account_hookimpl @hookspec.account_hookimpl
def process_ffi_event(self, ffi_event): def process_ffi_event(self, ffi_event):
@@ -549,20 +541,19 @@ class Account(object):
If this account is not configured, an internal configuration If this account is not configured, an internal configuration
job will be scheduled if config values are sufficiently specified. job will be scheduled if config values are sufficiently specified.
You may call :method:`wait_shutdown` or `shutdown` after the
account is in started mode.
:raises MissingCredentials: if `addr` and `mail_pw` values are not set. :raises MissingCredentials: if `addr` and `mail_pw` values are not set.
:returns: None :returns: None
""" """
if not self.is_configured(): if not self.is_configured():
if not self.get_config("addr") or not self.get_config("mail_pwd"): if not self.get_config("addr") or not self.get_config("mail_pw"):
raise MissingCredentials("addr or mail_pwd not set in config") raise MissingCredentials("addr or mail_pwd not set in config")
lib.dc_configure(self._dc_context) lib.dc_configure(self._dc_context)
self._threads.start() self._threads.start()
@hookspec.account_hookimpl
def after_shutdown(self):
self._shutdown_event.set()
def wait_shutdown(self): def wait_shutdown(self):
""" wait until shutdown of this account has completed. """ """ wait until shutdown of this account has completed. """
self._shutdown_event.wait() self._shutdown_event.wait()
@@ -570,16 +561,20 @@ class Account(object):
def shutdown(self, wait=True): def shutdown(self, wait=True):
""" shutdown account, stop threads and close and remove """ shutdown account, stop threads and close and remove
underlying dc_context and callbacks. """ underlying dc_context and callbacks. """
if hasattr(self, "_dc_context") and hasattr(self, "_threads"): dc_context = self._dc_context
if self._threads.is_started(): if dc_context is None:
self.stop_ongoing() return
self._threads.stop(wait=False)
lib.dc_close(self._dc_context) if self._threads.is_started():
self._threads.stop(wait=wait) # to wait for threads self.stop_ongoing()
deltachat.clear_context_callback(self._dc_context) self._threads.stop(wait=False)
del self._dc_context lib.dc_close(dc_context)
atexit.unregister(self.shutdown) self._threads.stop(wait=wait) # to wait for threads
self._pm.hook.after_shutdown() self._dc_context = None
atexit.unregister(self.shutdown)
hook = hookspec.Global._get_plugin_manager().hook
hook.account_after_shutdown(account=self, dc_context=dc_context)
self._shutdown_event.set()
def _destroy_dc_context(dc_context, dc_context_unref=lib.dc_context_unref): def _destroy_dc_context(dc_context, dc_context_unref=lib.dc_context_unref):
@@ -593,16 +588,6 @@ def _destroy_dc_context(dc_context, dc_context_unref=lib.dc_context_unref):
pass pass
class FFIEvent:
def __init__(self, name, data1, data2):
self.name = name
self.data1 = data1
self.data2 = data2
def __str__(self):
return "{name} data1={data1} data2={data2}".format(**self.__dict__)
class ScannedQRCode: class ScannedQRCode:
def __init__(self, dc_lot): def __init__(self, dc_lot):
self._dc_lot = dc_lot self._dc_lot = dc_lot

View File

@@ -1,6 +1,34 @@
import deltachat
import threading import threading
import time import time
from .hookspec import account_hookimpl from .hookspec import account_hookimpl, global_hookimpl
@global_hookimpl
def account_init(account):
# send all FFI events for this account to a plugin hook
def _ll_event(ctx, evt_name, data1, data2):
assert ctx == account._dc_context
ffi_event = FFIEvent(name=evt_name, data1=data1, data2=data2)
account._pm.hook.process_ffi_event(
account=account, ffi_event=ffi_event
)
deltachat.set_context_callback(account._dc_context, _ll_event)
@global_hookimpl
def account_after_shutdown(dc_context):
deltachat.clear_context_callback(dc_context)
class FFIEvent:
def __init__(self, name, data1, data2):
self.name = name
self.data1 = data1
self.data2 = data2
def __str__(self):
return "{name} data1={data1} data2={data2}".format(**self.__dict__)
class FFIEventLogger: class FFIEventLogger:

View File

@@ -47,10 +47,6 @@ class PerAccount:
def process_message_delivered(self, message): def process_message_delivered(self, message):
""" Called when an outgoing message has been delivered to SMTP. """ """ Called when an outgoing message has been delivered to SMTP. """
@account_hookspec
def after_shutdown(self):
""" Called after the account has been shutdown. """
class Global: class Global:
""" global hook specifications using a per-process singleton plugin manager instance. """ global hook specifications using a per-process singleton plugin manager instance.
@@ -66,5 +62,10 @@ class Global:
return cls._plugin_manager return cls._plugin_manager
@global_hookspec @global_hookspec
def at_account_init(self, account): def account_init(self, account):
""" called when `Account::__init__()` function starts executing. """ """ called when `Account::__init__()` function starts executing. """
@global_hookspec
def account_after_shutdown(self, account, dc_context):
""" Called after the account has been shutdown. """

View File

@@ -230,8 +230,8 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig, datadir):
configdict.update(config) configdict.update(config)
configdict["mvbox_watch"] = str(int(mvbox)) configdict["mvbox_watch"] = str(int(mvbox))
configdict["mvbox_move"] = "1" configdict["mvbox_move"] = "1"
ac.configure(**configdict) ac.update_config(configdict)
ac.start_threads() ac.start()
return ac return ac
def get_one_online_account(self, pre_generated_key=True): def get_one_online_account(self, pre_generated_key=True):
@@ -257,14 +257,14 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig, datadir):
self._preconfigure_key(ac, account.get_config("addr")) self._preconfigure_key(ac, account.get_config("addr"))
ac._evtracker.init_time = self.init_time ac._evtracker.init_time = self.init_time
ac._evtracker.set_timeout(30) ac._evtracker.set_timeout(30)
ac.configure( ac.update_config(dict(
addr=account.get_config("addr"), addr=account.get_config("addr"),
mail_pw=account.get_config("mail_pw"), mail_pw=account.get_config("mail_pw"),
mvbox_watch=account.get_config("mvbox_watch"), mvbox_watch=account.get_config("mvbox_watch"),
mvbox_move=account.get_config("mvbox_move"), mvbox_move=account.get_config("mvbox_move"),
sentbox_watch=account.get_config("sentbox_watch"), sentbox_watch=account.get_config("sentbox_watch"),
) ))
ac.start_threads() ac.start()
return ac return ac
am = AccountMaker() am = AccountMaker()

View File

@@ -1,6 +1,7 @@
from __future__ import print_function from __future__ import print_function
from deltachat import capi, cutil, const, set_context_callback, clear_context_callback from deltachat import capi, cutil, const, set_context_callback, clear_context_callback
from deltachat.hookspec import account_hookimpl from deltachat import register_global_plugin
from deltachat.hookspec import account_hookimpl, global_hookimpl
from deltachat.capi import ffi from deltachat.capi import ffi
from deltachat.capi import lib from deltachat.capi import lib
@@ -24,14 +25,14 @@ def test_dc_close_events(tmpdir, acfactory):
shutdowns = [] shutdowns = []
class ShutdownPlugin: class ShutdownPlugin:
@account_hookimpl @global_hookimpl
def after_shutdown(self): def account_after_shutdown(self, account):
assert not hasattr(ac1, "_dc_context") assert account._dc_context is None
shutdowns.append(1) shutdowns.append(account)
ac1.add_account_plugin(ShutdownPlugin()) register_global_plugin(ShutdownPlugin())
assert hasattr(ac1, "_dc_context") assert hasattr(ac1, "_dc_context")
ac1.shutdown() ac1.shutdown()
assert shutdowns == [1] assert shutdowns == [ac1]
def find(info_string): def find(info_string):
evlog = ac1._evtracker evlog = ac1._evtracker