openwebrx-clone/owrx/bookmarks.py

146 lines
4.5 KiB
Python

from datetime import datetime, timezone
from owrx.config.core import CoreConfig
import json
import os
import logging
logger = logging.getLogger(__name__)
class Bookmark(object):
def __init__(self, j):
self.name = j["name"]
self.frequency = j["frequency"]
self.modulation = j["modulation"]
def getName(self):
return self.name
def getFrequency(self):
return self.frequency
def getModulation(self):
return self.modulation
def __dict__(self):
return {
"name": self.getName(),
"frequency": self.getFrequency(),
"modulation": self.getModulation(),
}
class BookmakrSubscription(object):
def __init__(self, subscriptee, range, subscriber: callable):
self.subscriptee = subscriptee
self.range = range
self.subscriber = subscriber
def inRange(self, bookmark: Bookmark):
low, high = self.range
return low <= bookmark.getFrequency() <= high
def call(self, *args, **kwargs):
self.subscriber(*args, **kwargs)
def cancel(self):
self.subscriptee.unsubscribe(self)
class Bookmarks(object):
sharedInstance = None
@staticmethod
def getSharedInstance():
if Bookmarks.sharedInstance is None:
Bookmarks.sharedInstance = Bookmarks()
return Bookmarks.sharedInstance
def __init__(self):
self.file_modified = None
self.bookmarks = []
self.subscriptions = []
self.fileList = [Bookmarks._getBookmarksFile(), "/etc/openwebrx/bookmarks.json", "bookmarks.json"]
def _refresh(self):
modified = self._getFileModifiedTimestamp()
if self.file_modified is None or modified > self.file_modified:
logger.debug("reloading bookmarks from disk due to file modification")
self.bookmarks = self._loadBookmarks()
self.file_modified = modified
def _getFileModifiedTimestamp(self):
timestamp = 0
for file in self.fileList:
try:
timestamp = os.path.getmtime(file)
break
except FileNotFoundError:
pass
return datetime.fromtimestamp(timestamp, timezone.utc)
def _loadBookmarks(self):
for file in self.fileList:
try:
with open(file, "r") as f:
content = f.read()
if content:
bookmarks_json = json.loads(content)
return [Bookmark(d) for d in bookmarks_json]
except FileNotFoundError:
pass
except json.JSONDecodeError:
logger.exception("error while parsing bookmarks file %s", file)
return []
except Exception:
logger.exception("error while processing bookmarks from %s", file)
return []
return []
def getBookmarks(self, range=None):
self._refresh()
if range is None:
return self.bookmarks
else:
(lo, hi) = range
return [b for b in self.bookmarks if lo <= b.getFrequency() <= hi]
@staticmethod
def _getBookmarksFile():
coreConfig = CoreConfig()
return "{data_directory}/bookmarks.json".format(data_directory=coreConfig.get_data_directory())
def store(self):
# don't write directly to file to avoid corruption on exceptions
jsonContent = json.dumps([b.__dict__() for b in self.bookmarks], indent=4)
with open(Bookmarks._getBookmarksFile(), "w") as file:
file.write(jsonContent)
self.file_modified = self._getFileModifiedTimestamp()
def addBookmark(self, bookmark: Bookmark):
self.bookmarks.append(bookmark)
self.notifySubscriptions(bookmark)
def removeBookmark(self, bookmark: Bookmark):
if bookmark not in self.bookmarks:
return
self.bookmarks.remove(bookmark)
self.notifySubscriptions(bookmark)
def notifySubscriptions(self, bookmark: Bookmark):
for sub in self.subscriptions:
if sub.inRange(bookmark):
try:
sub.call()
except Exception:
logger.exception("Error while calling bookmark subscriptions")
def subscribe(self, range, callback):
self.subscriptions.append(BookmakrSubscription(self, range, callback))
def unsubscribe(self, subscriptions: BookmakrSubscription):
if subscriptions not in self.subscriptions:
return
self.subscriptions.remove(subscriptions)