1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 17:06:17 +00:00

Splitting daemon stuff

This commit is contained in:
spl0k 2019-04-22 12:46:38 +02:00
parent 9850cae241
commit 7f8369cac4
5 changed files with 123 additions and 96 deletions

View File

@ -16,7 +16,8 @@ import time
from pony.orm import db_session from pony.orm import db_session
from pony.orm import ObjectNotFound from pony.orm import ObjectNotFound
from .daemon import DaemonClient, DaemonUnavailableError, ScannerAlreadyRunningError from .daemon.client import DaemonClient
from .daemon.exceptions import DaemonUnavailableError, ScannerAlreadyRunningError
from .db import Folder, User from .db import Folder, User
from .managers.folder import FolderManager from .managers.folder import FolderManager
from .managers.user import UserManager from .managers.user import UserManager

View File

@ -0,0 +1,99 @@
# coding: utf-8
#
# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2019 Alban 'spl0k' Féron
#
# Distributed under terms of the GNU AGPLv3 license.
import logging
from multiprocessing.connection import Listener
from pony.orm import db_session
from threading import Thread
from .client import DaemonCommand
from .exceptions import ScannerAlreadyRunningError
from ..db import Folder
from ..scanner import Scanner
from ..utils import get_secret_key
from ..watcher import SupysonicWatcher
__all__ = [ 'Daemon' ]
logger = logging.getLogger(__name__)
class Daemon(object):
def __init__(self, config):
self.__config = config
self.__listener = None
self.__watcher = None
self.__scanner = None
watcher = property(lambda self: self.__watcher)
scanner = property(lambda self: self.__scanner)
def __handle_connection(self, connection):
cmd = connection.recv()
logger.debug('Received %s', cmd)
if isinstance(cmd, DaemonCommand):
cmd.apply(connection, self)
else:
logger.warn('Received unknown command %s', cmd)
def run(self):
self.__listener = Listener(address = self.__config.DAEMON['socket'], authkey = get_secret_key('daemon_key'))
logger.info("Listening to %s", self.__listener.address)
if self.__config.DAEMON['run_watcher']:
self.__watcher = SupysonicWatcher(self.__config)
self.__watcher.start()
while True:
conn = self.__listener.accept()
self.__handle_connection(conn)
def start_scan(self, folders = [], force = False):
if self.__scanner is not None and self.__scanner.is_alive():
raise ScannerAlreadyRunningError()
extensions = self.__config.BASE['scanner_extensions']
if extensions:
extensions = extensions.split(' ')
self.__scanner = ScannerThread(args = folders, kwargs = { 'force': force, 'extensions': extensions })
self.__scanner.start()
def terminate(self):
self.__listener.close()
if self.__watcher is not None:
self.__watcher.stop()
class ScannerThread(Thread):
def __init__(self, *args, **kwargs):
super(ScannerThread, self).__init__(*args, **kwargs)
self.__scanned = {}
def run(self):
force = self._kwargs.get('force', False)
extensions = self._kwargs.get('extensions')
s = Scanner(force = force, extensions = extensions)
with db_session:
if self._args:
folders = Folder.select(lambda f: f.root and f.name in self._args)
else:
folders = Folder.select(lambda f: f.root)
for f in folders:
name = f.name
logger.info('Scanning %s', name)
s.scan(f, lambda x: self.__scanned.update({ name: x }))
s.finish()
@property
def scanned(self):
# This isn't quite thread-safe but locking each time a file is scanned could affect performance
return sum(self.__scanned.values())

View File

@ -7,28 +7,14 @@
# #
# Distributed under terms of the GNU AGPLv3 license. # Distributed under terms of the GNU AGPLv3 license.
import logging from multiprocessing.connection import Client
from multiprocessing.connection import Client, Listener from .exceptions import DaemonUnavailableError, ScannerAlreadyRunningError
from pony.orm import db_session from ..config import get_current_config
from threading import Thread from ..py23 import strtype
from ..utils import get_secret_key
from .db import Folder __all__ = [ 'DaemonClient' ]
from .config import get_current_config
from .py23 import strtype
from .scanner import Scanner
from .utils import get_secret_key
from .watcher import SupysonicWatcher
__all__ = [ 'Daemon', 'DaemonClient', 'DaemonUnavailableError' ]
logger = logging.getLogger(__name__)
class DaemonUnavailableError(Exception):
pass
class ScannerAlreadyRunningError(Exception):
pass
class DaemonCommand(object): class DaemonCommand(object):
def apply(self, connection, daemon): def apply(self, connection, daemon):
@ -122,77 +108,3 @@ class DaemonClient(object):
rv = c.recv() rv = c.recv()
if rv.exception is not None: if rv.exception is not None:
raise rv.exception raise rv.exception
class Daemon(object):
def __init__(self, config):
self.__config = config
self.__listener = None
self.__watcher = None
self.__scanner = None
watcher = property(lambda self: self.__watcher)
scanner = property(lambda self: self.__scanner)
def __handle_connection(self, connection):
cmd = connection.recv()
logger.debug('Received %s', cmd)
if isinstance(cmd, DaemonCommand):
cmd.apply(connection, self)
else:
logger.warn('Received unknown command %s', cmd)
def run(self):
self.__listener = Listener(address = self.__config.DAEMON['socket'], authkey = get_secret_key('daemon_key'))
logger.info("Listening to %s", self.__listener.address)
if self.__config.DAEMON['run_watcher']:
self.__watcher = SupysonicWatcher(self.__config)
self.__watcher.start()
while True:
conn = self.__listener.accept()
self.__handle_connection(conn)
def start_scan(self, folders = [], force = False):
if self.__scanner is not None and self.__scanner.is_alive():
raise ScannerAlreadyRunningError()
extensions = self.__config.BASE['scanner_extensions']
if extensions:
extensions = extensions.split(' ')
self.__scanner = ScannerThread(args = folders, kwargs = { 'force': force, 'extensions': extensions })
self.__scanner.start()
def terminate(self):
self.__listener.close()
if self.__watcher is not None:
self.__watcher.stop()
class ScannerThread(Thread):
def __init__(self, *args, **kwargs):
super(ScannerThread, self).__init__(*args, **kwargs)
self.__scanned = {}
def run(self):
force = self._kwargs.get('force', False)
extensions = self._kwargs.get('extensions')
s = Scanner(force = force, extensions = extensions)
with db_session:
if self._args:
folders = Folder.select(lambda f: f.root and f.name in self._args)
else:
folders = Folder.select(lambda f: f.root)
for f in folders:
name = f.name
logger.info('Scanning %s', name)
s.scan(f, lambda x: self.__scanned.update({ name: x }))
s.finish()
@property
def scanned(self):
# This isn't quite thread-safe but locking each time a file is scanned could affect performance
return sum(self.__scanned.values())

View File

@ -0,0 +1,14 @@
# coding: utf-8
#
# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2019 Alban 'spl0k' Féron
#
# Distributed under terms of the GNU AGPLv3 license.
class DaemonUnavailableError(Exception):
pass
class ScannerAlreadyRunningError(Exception):
pass

View File

@ -13,7 +13,8 @@ import uuid
from pony.orm import select from pony.orm import select
from pony.orm import ObjectNotFound from pony.orm import ObjectNotFound
from ..daemon import DaemonClient, DaemonUnavailableError from ..daemon.client import DaemonClient
from ..daemon.exceptions import DaemonUnavailableError
from ..db import Folder, Track, Artist, Album, User, RatingTrack, StarredTrack from ..db import Folder, Track, Artist, Album, User, RatingTrack, StarredTrack
from ..py23 import strtype from ..py23 import strtype