Browse Source

Handle new lockfile versions in nsmd 1.6.0. Will still work in older versions

master
Nils 7 months ago
parent
commit
87a7d0f93b
  1. 38
      engine/nsmservercontrol.py
  2. 5
      engine/watcher.py
  3. 19
      qtgui/sessiontreecontroller.py

38
engine/nsmservercontrol.py

@ -41,6 +41,7 @@ from uuid import uuid4
from datetime import datetime
from sys import exit as sysexit
from time import sleep
from ctypes import c_ulong
#Our files
from .comparedirectories import md5_dir
@ -316,7 +317,7 @@ class NsmServerControl(object):
#Deactivate hooks for now. During init no hooks may be called,
#but some functions want to do that already. We setup the true hooks at the end of init
self.sessionOpenReadyHook= self.sessionOpenLoadingHook= self.sessionClosedHook= self.clientStatusHook= self.singleInstanceActivateWindowHook= self.dataClientNamesHook= self.dataClientDescriptionHook= nothing
self.lockfile_directory = getenv("XDG_RUNTIME_DIR")
self._queue = list() #Incoming OSC messages are buffered here.
#Status variables that are set by our callbacks
@ -1413,10 +1414,39 @@ class NsmServerControl(object):
return True
return False
def _simple_hash(self, s:str) -> int:
"""This is a translation from the nsm/file.c function of the same name.
We use it to find the lock file on our system.
It is a djb2 hash modulo 65521
"""
hashAddress = 5381
for i, char in enumerate(s):
hashAddress = ((hashAddress << 5) + hashAddress ) + ord(char)
hashAddress = c_ulong(hashAddress).value #wrap around for whatever number of bits unsinged long is on this system. 2**64 most likely
return hashAddress % 65521
def _get_lock_file_name(self, session_name:str, full_absolute_session_path:str) -> pathlib.Path:
"""This is a translation from the nsm/nsmd.c function of the same name.
We use it to find the lock file on our system.
To avoid collisions of two simple session names under either different subdirs or even
different session roots."""
#session_name in Agordejo includes subdirs. We want only the basename, like in nsmd. Luckily they are paths.
session_name = pathlib.Path(session_name).name #basename
session_hash:int = self._simple_hash(full_absolute_session_path)
session_lock = pathlib.Path(self.lockfile_directory, "nsm", session_name + str(session_hash))
return session_lock
def _checkIfLocked(self, nsmSessionName:str)->bool:
basePath = pathlib.Path(self.sessionRoot, nsmSessionName)
assert basePath.exists()
lockFile = pathlib.Path(basePath, ".lock")
#basePath = pathlib.Path(self.sessionRoot, nsmSessionName)
#assert basePath.exists()
#lockFile = pathlib.Path(basePath, ".lock")
lockFile = self._get_lock_file_name(nsmSessionName, str(pathlib.Path(self.sessionRoot, nsmSessionName)))
return lockFile.exists()
def getSessionFiles(self, nsmSessionName:str)->list:

5
engine/watcher.py

@ -155,7 +155,7 @@ class Watcher(object):
#Lockfiles
if self.lockFileHook:
lockfileState = entry["lockFile"].is_file()
lockfileState = self._nsmServerControl._checkIfLocked(nsmSessionName)
if not self._lastLockfile[nsmSessionName] == lockfileState:
self._lastLockfile[nsmSessionName] = lockfileState
self.lockFileHook(nsmSessionName, lockfileState)
@ -168,6 +168,3 @@ class Watcher(object):
logger.warning(f"File not found error for {entry}")
self._lastExport.remove(entry) #avoid stumbling upon this again
self._update()

19
qtgui/sessiontreecontroller.py

@ -98,16 +98,12 @@ class SessionItem(QtWidgets.QTreeWidgetItem):
def setLocked(self, state:bool):
"""Number of clients, symlinks and size change frequently while a session is open/locked.
We deactivate the display of these values while locked"""
return
if not state == self.isDisabled():
self.setDisabled(state)
if state:
self.setText(2, "") #number of clients
self.setText(3, "") #Symlinks
self.setText(4, "") #Size
else:
self.updateData()
We deactivate the display of these values while locked
This is also used for nsmd lockfiles and locked sessions, aka session open by another nsmd.
"""
self.updateData()
self.setDisabled(state)
def updateTimestamp(self, timestamp:str):
#Column 1 "Last Save"
@ -282,7 +278,7 @@ class SessionTreeController(object):
listOfLabelsAndFunctions = [
(QtCore.QCoreApplication.translate("SessionTree", "Copy Session"), lambda: self._askForCopyAndCopy(item.sessionDict["nsmSessionName"]))
]
if not item.isDisabled():
if not item.isDisabled() and not item.sessionDict["locked"]:
listOfLabelsAndFunctions.append((QtCore.QCoreApplication.translate("SessionTree", "Rename Session"), lambda: self._askForNameAndRenameSession(item.sessionDict["nsmSessionName"])))
#Delete should be the bottom item.
listOfLabelsAndFunctions.append((QtCore.QCoreApplication.translate("SessionTree", "Delete Session"), lambda: self.deleteSessionItem(item)))
@ -310,7 +306,6 @@ class SessionTreeController(object):
def _reactSelectionChanged(self, item, previous):
"""User clicks on an entry in the session chooser, or in the empty space.
in any case, the selection changes and we can decide if we activate/deactivate certain buttons"""
if not item or not type(item) is SessionItem or item.sessionDict["locked"] == True:
sessionSelectedState = False
else:

Loading…
Cancel
Save