1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-06-05 09:53:33 +03:00

Move journal locking code into new monitor.JournalLock class

This commit is contained in:
Athanasius 2021-03-05 12:03:54 +00:00
parent 872f380831
commit c0e7be98f8
2 changed files with 75 additions and 51 deletions

View File

@ -10,7 +10,6 @@ import sys
import webbrowser import webbrowser
from builtins import object, str from builtins import object, str
from os import chdir, environ from os import chdir, environ
from os import getpid as os_getpid
from os.path import dirname, isdir, join from os.path import dirname, isdir, join
from sys import platform from sys import platform
from time import localtime, strftime, time from time import localtime, strftime, time
@ -34,6 +33,7 @@ if __name__ == '__main__':
# After the redirect in case config does logging setup # After the redirect in case config does logging setup
from config import appversion, appversion_nobuild, config, copyright from config import appversion, appversion_nobuild, config, copyright
from EDMCLogging import edmclogger, logger, logging from EDMCLogging import edmclogger, logger, logging
from monitor import JournalLock
if __name__ == '__main__': # noqa: C901 if __name__ == '__main__': # noqa: C901
# Command-line arguments # Command-line arguments
@ -79,23 +79,11 @@ if __name__ == '__main__': # noqa: C901
""" """
logger.trace('Begin...') logger.trace('Begin...')
locked = journal_lock.journaldir_obtain_lock()
if platform == 'win32': if platform == 'win32':
logger.trace('win32, using msvcrt')
# win32 doesn't have fcntl, so we have to use msvcrt
import msvcrt
logger.trace(f'journal_dir_lockfile = {journal_dir_lockfile!r}') if not locked:
locked = False
try:
msvcrt.locking(journal_dir_lockfile.fileno(), msvcrt.LK_NBLCK, 4096)
except Exception as e:
logger.info(f"Exception: Couldn't lock journal directory \"{journal_dir}\""
f", assuming another process running: {e!r}")
locked = True
if locked:
# Need to do the check for this being an edmc:// auth callback # Need to do the check for this being an edmc:// auth callback
import ctypes import ctypes
from ctypes.wintypes import BOOL, HWND, INT, LPARAM, LPCWSTR, LPWSTR from ctypes.wintypes import BOOL, HWND, INT, LPARAM, LPCWSTR, LPWSTR
@ -177,28 +165,6 @@ if __name__ == '__main__': # noqa: C901
return False # Another instance is running return False # Another instance is running
else:
logger.trace('NOT win32, using fcntl')
try:
import fcntl
except ImportError:
logger.warning("Not on win32 and we have no fcntl, can't use a file lock!"
"Allowing multiple instances!")
return True # Lie about there being no other instances
try:
fcntl.flock(journal_dir_lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
except Exception as e:
logger.info(f"Exception: Couldn't lock journal directory \"{journal_dir}\","
f"assuming another process running: {e!r}")
return False
journal_dir_lockfile.write(f"Path: {journal_dir}\nPID: {os_getpid()}\n")
journal_dir_lockfile.flush()
logger.trace('Done')
return True return True
def already_running_popup(): def already_running_popup():
@ -224,20 +190,9 @@ if __name__ == '__main__': # noqa: C901
root.mainloop() root.mainloop()
journal_dir: str = config.get('journaldir') or config.default_journal_dir journal_lock = JournalLock()
# This must be at top level to guarantee the file handle doesn't go out
# of scope and get cleaned up, removing the lock with it.
journal_dir_lockfile_name = join(journal_dir, 'edmc-journal-lock.txt')
try:
journal_dir_lockfile = open(journal_dir_lockfile_name, mode='w+', encoding='utf-8')
# Linux CIFS read-only mount throws: OSError(30, 'Read-only file system') if journal_lock.journal_dir_lockfile:
# Linux no-write-perm directory throws: PermissionError(13, 'Permission denied')
except Exception as e: # For remote FS this could be any of a wide range of exceptions
logger.warning(f"Couldn't open \"{journal_dir_lockfile_name}\" for \"w+\""
f" Aborting duplicate process checks: {e!r}")
else:
if not no_other_instance_running(): if not no_other_instance_running():
# There's a copy already running. # There's a copy already running.

View File

@ -2,6 +2,7 @@ from collections import defaultdict, OrderedDict
import json import json
import re import re
import threading import threading
from os import getpid as os_getpid
from os import listdir, SEEK_SET, SEEK_END from os import listdir, SEEK_SET, SEEK_END
from os.path import basename, expanduser, isdir, join from os.path import basename, expanduser, isdir, join
from sys import platform from sys import platform
@ -1021,3 +1022,71 @@ class EDLogs(FileSystemEventHandler): # type: ignore # See below
# singleton # singleton
monitor = EDLogs() monitor = EDLogs()
class JournalLock:
"""Handle locking of journal directory."""
def __init__(self):
"""Initialise where the journal directory and lock file are."""
self.journal_dir: str = config.get('journaldir') or config.default_journal_dir
self.journal_dir_lock = None
self.journal_dir_lockfile_name: str = join(self.journal_dir, 'edmc-journal-lock.txt')
try:
self.journal_dir_lockfile = open(self.journal_dir_lockfile_name, mode='w+', encoding='utf-8')
# Linux CIFS read-only mount throws: OSError(30, 'Read-only file system')
# Linux no-write-perm directory throws: PermissionError(13, 'Permission denied')
except Exception as e: # For remote FS this could be any of a wide range of exceptions
logger.warning(f"Couldn't open \"{self.journal_dir_lockfile_name}\" for \"w+\""
f" Aborting duplicate process checks: {e!r}")
def journaldir_obtain_lock(self) -> bool:
"""
Attempt to obtain a lock on the journal directory.
:return: bool - True if we successfully obtained the lock
"""
logger.trace(f'journal_dir_lockfile = {self.journal_dir_lockfile!r}')
if platform == 'win32':
logger.trace('win32, using msvcrt')
# win32 doesn't have fcntl, so we have to use msvcrt
import msvcrt
try:
msvcrt.locking(self.journal_dir_lockfile.fileno(), msvcrt.LK_NBLCK, 4096)
except Exception as e:
logger.info(f"Exception: Couldn't lock journal directory \"{self.journal_dir}\""
f", assuming another process running: {e!r}")
return False
else:
logger.trace('NOT win32, using fcntl')
try:
import fcntl
except ImportError:
logger.warning("Not on win32 and we have no fcntl, can't use a file lock!"
"Allowing multiple instances!")
return True # Lie about being locked
try:
fcntl.flock(self.journal_dir_lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
except Exception as e:
logger.info(f"Exception: Couldn't lock journal directory \"{self.journal_dir}\","
f"assuming another process running: {e!r}")
return False
self.journal_dir_lockfile.write(f"Path: {self.journal_dir}\nPID: {os_getpid()}\n")
self.journal_dir_lockfile.flush()
logger.trace('Done')
return True
def journaldir_release_lock(self) -> bool:
"""Release lock on journal directory."""
pass