good bye global plugin manager ... we only do per-account object plugin_management for now

This commit is contained in:
holger krekel
2020-02-22 17:43:00 +01:00
parent e9967c32e6
commit ec67b3975c
3 changed files with 40 additions and 44 deletions

View File

@@ -3,6 +3,7 @@
from __future__ import print_function from __future__ import print_function
import atexit import atexit
import threading import threading
from contextlib import contextmanager
import os import os
import time import time
from array import array from array import array
@@ -16,7 +17,7 @@ from .chat import Chat
from .message import Message from .message import Message
from .contact import Contact from .contact import Contact
from .eventlogger import EventLogger from .eventlogger import EventLogger
from .hookspec import get_plugin_manager, hookimpl from .hookspec import AccountHookSpecs, account_hookimpl
class Account(object): class Account(object):
@@ -41,15 +42,15 @@ class Account(object):
self._evlogger = EventLogger(self, logid, debug) self._evlogger = EventLogger(self, logid, debug)
self._threads = IOThreads(self._dc_context, self._evlogger._log_event) self._threads = IOThreads(self._dc_context, self._evlogger._log_event)
# register event call back and initialize plugin system # register event call back and initialize per-account plugin system
def _ll_event(ctx, evt_name, data1, data2): def _ll_event(ctx, evt_name, data1, data2):
assert ctx == self._dc_context assert ctx == self._dc_context
self.pluggy.hook.process_low_level_event( self.plugin_manager.hook.process_low_level_event(
account=self, event_name=evt_name, data1=data1, data2=data2 account=self, event_name=evt_name, data1=data1, data2=data2
) )
self.pluggy = get_plugin_manager() self.plugin_manager = AccountHookSpecs._make_plugin_manager()
self.pluggy.register(self._evlogger) self.plugin_manager.register(self._evlogger)
deltachat.set_context_callback(self._dc_context, _ll_event) deltachat.set_context_callback(self._dc_context, _ll_event)
# open database # open database
@@ -382,7 +383,7 @@ class Account(object):
return export_files[0] return export_files[0]
def _export(self, path, imex_cmd): def _export(self, path, imex_cmd):
with ImexTracker(self) as imex_tracker: with temp_plugin(self.plugin_manager, ImexTracker()) as imex_tracker:
lib.dc_imex(self._dc_context, imex_cmd, as_dc_charpointer(path), ffi.NULL) lib.dc_imex(self._dc_context, imex_cmd, as_dc_charpointer(path), ffi.NULL)
if not self._threads.is_started(): if not self._threads.is_started():
lib.dc_perform_imap_jobs(self._dc_context) lib.dc_perform_imap_jobs(self._dc_context)
@@ -404,7 +405,7 @@ class Account(object):
self._import(path, imex_cmd=12) self._import(path, imex_cmd=12)
def _import(self, path, imex_cmd): def _import(self, path, imex_cmd):
with ImexTracker(self) as imex_tracker: with temp_plugin(self.plugin_manager, ImexTracker()) as imex_tracker:
lib.dc_imex(self._dc_context, imex_cmd, as_dc_charpointer(path), ffi.NULL) lib.dc_imex(self._dc_context, imex_cmd, as_dc_charpointer(path), ffi.NULL)
if not self._threads.is_started(): if not self._threads.is_started():
lib.dc_perform_imap_jobs(self._dc_context) lib.dc_perform_imap_jobs(self._dc_context)
@@ -511,7 +512,7 @@ class Account(object):
deltachat.clear_context_callback(self._dc_context) deltachat.clear_context_callback(self._dc_context)
del self._dc_context del self._dc_context
atexit.unregister(self.shutdown) atexit.unregister(self.shutdown)
self.pluggy.unregister(self._evlogger) self.plugin_manager.unregister(self._evlogger)
def set_location(self, latitude=0.0, longitude=0.0, accuracy=0.0): def set_location(self, latitude=0.0, longitude=0.0, accuracy=0.0):
"""set a new location. It effects all chats where we currently """set a new location. It effects all chats where we currently
@@ -528,23 +529,19 @@ class Account(object):
raise ValueError("no chat is streaming locations") raise ValueError("no chat is streaming locations")
@contextmanager
def temp_plugin(plugin_manager, plugin):
plugin_manager.register(plugin)
yield plugin
plugin_manager.unregister(plugin)
class ImexTracker: class ImexTracker:
def __init__(self, account): def __init__(self):
self._imex_events = Queue() self._imex_events = Queue()
self.account = account
def __enter__(self): @account_hookimpl
self.account.pluggy.register(self) def process_low_level_event(self, event_name, data1, data2):
return self
def __exit__(self, *args):
self.account.pluggy.unregister(self)
@hookimpl
def process_low_level_event(self, account, event_name, data1, data2):
# there could be multiple accounts instantiated
if self.account is not account:
return
if event_name == "DC_EVENT_IMEX_PROGRESS": if event_name == "DC_EVENT_IMEX_PROGRESS":
self._imex_events.put(data1) self._imex_events.put(data1)
elif event_name == "DC_EVENT_IMEX_FILE_WRITTEN": elif event_name == "DC_EVENT_IMEX_FILE_WRITTEN":

View File

@@ -2,7 +2,7 @@ import threading
import re import re
import time import time
from queue import Queue, Empty from queue import Queue, Empty
from .hookspec import hookimpl from .hookspec import account_hookimpl
class EventLogger: class EventLogger:
@@ -18,11 +18,10 @@ class EventLogger:
self._timeout = None self._timeout = None
self.init_time = time.time() self.init_time = time.time()
@hookimpl @account_hookimpl
def process_low_level_event(self, account, event_name, data1, data2): def process_low_level_event(self, event_name, data1, data2):
if self.account == account: self._log_event(event_name, data1, data2)
self._log_event(event_name, data1, data2) self._event_queue.put((event_name, data1, data2))
self._event_queue.put((event_name, data1, data2))
def set_timeout(self, timeout): def set_timeout(self, timeout):
self._timeout = timeout self._timeout = timeout

View File

@@ -1,25 +1,25 @@
""" Hooks for python bindings """ """ Hooks for Python bindings to Delta Chat Core Rust CFFI"""
import pluggy import pluggy
name = "deltachat" __all__ = ["account_hookspec", "account_hookimpl", "AccountHookSpecs"]
hookspec = pluggy.HookspecMarker(name) _account_name = "deltachat-account"
hookimpl = pluggy.HookimplMarker(name) account_hookspec = pluggy.HookspecMarker(_account_name)
_plugin_manager = None account_hookimpl = pluggy.HookimplMarker(_account_name)
def get_plugin_manager(): class AccountHookSpecs:
global _plugin_manager """ per-Account-instance hook specifications.
if _plugin_manager is None:
_plugin_manager = pluggy.PluginManager(name)
_plugin_manager.add_hookspecs(DeltaChatHookSpecs)
return _plugin_manager
Account hook implementations need to be registered with an Account instance.
"""
@classmethod
def _make_plugin_manager(cls):
pm = pluggy.PluginManager(_account_name)
pm.add_hookspecs(cls)
return pm
class DeltaChatHookSpecs: @account_hookspec
""" Plugin Hook specifications for Python bindings to Delta Chat CFFI. """ def process_low_level_event(self, event_name, data1, data2):
@hookspec
def process_low_level_event(self, account, event_name, data1, data2):
""" process a CFFI low level events for a given account. """ """ process a CFFI low level events for a given account. """