diff --git a/validate_email/domainlist_check.py b/validate_email/domainlist_check.py index 29ac667..374c8d6 100644 --- a/validate_email/domainlist_check.py +++ b/validate_email/domainlist_check.py @@ -1,9 +1,11 @@ from logging import getLogger from typing import Optional +from filelock import FileLock + from .exceptions import DomainBlacklistedError from .updater import ( - BLACKLIST_FILEPATH_INSTALLED, BLACKLIST_FILEPATH_TMP, + BLACKLIST_FILEPATH_INSTALLED, BLACKLIST_FILEPATH_TMP, LOCK_PATH, update_builtin_blacklist) SetOrNone = Optional[set] @@ -30,8 +32,8 @@ class DomainListValidator(object): def _blacklist_path(self) -> str: 'Return the path of the `blacklist.txt` that should be loaded.' try: - # Zero size, file is touched to indicate the - # preinstalled file is still fresh enough + # Zero size: file is touched to indicate the preinstalled + # file is still fresh enough return BLACKLIST_FILEPATH_INSTALLED \ if BLACKLIST_FILEPATH_TMP.stat().st_size == 0 \ else BLACKLIST_FILEPATH_TMP @@ -42,13 +44,14 @@ class DomainListValidator(object): '(Re)load our built-in blacklist.' if not self._is_builtin_bl_used: return - bl_path = self._blacklist_path - LOGGER.debug(msg=f'(Re)loading blacklist: {bl_path}') - try: - with open(bl_path) as fd: - lines = fd.readlines() - except FileNotFoundError: - return + with FileLock(lock_file=LOCK_PATH): + bl_path = self._blacklist_path + LOGGER.debug(msg=f'(Re)loading blacklist from {bl_path}') + try: + with open(bl_path) as fd: + lines = fd.readlines() + except FileNotFoundError: + return self.domain_blacklist = set( x.strip().lower() for x in lines if x.strip()) diff --git a/validate_email/updater.py b/validate_email/updater.py index d0bf06c..7fd79df 100644 --- a/validate_email/updater.py +++ b/validate_email/updater.py @@ -35,7 +35,6 @@ class BlacklistUpdater(object): """ _refresh_when_older_than: int = 5 * 24 * 60 * 60 # 5 days - _on_update_callback: Callable = None _is_install_time: bool = False @property @@ -122,16 +121,18 @@ class BlacklistUpdater(object): BLACKLIST_FILEPATH_TMP.touch() return raise - if self._on_update_callback: - self._on_update_callback() def process( self, force: bool = False, callback: Optional[Callable] = None): 'Start optionally updating the blacklist.txt file.' # Locking to avoid multi-process update on multi-process startup - self._on_update_callback = callback with FileLock(lock_file=LOCK_PATH): self._process(force=force) + # Always execute callback because multiple processes can have + # different versions of blacklists (one before, one after + # updating) + if callback: + callback() def update_builtin_blacklist(