mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 08:56:17 +00:00
Splitting daemon stuff
This commit is contained in:
parent
9850cae241
commit
7f8369cac4
@ -16,7 +16,8 @@ import time
|
||||
from pony.orm import db_session
|
||||
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 .managers.folder import FolderManager
|
||||
from .managers.user import UserManager
|
||||
|
99
supysonic/daemon/__init__.py
Normal file
99
supysonic/daemon/__init__.py
Normal 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())
|
@ -7,28 +7,14 @@
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
import logging
|
||||
from multiprocessing.connection import Client
|
||||
|
||||
from multiprocessing.connection import Client, Listener
|
||||
from pony.orm import db_session
|
||||
from threading import Thread
|
||||
from .exceptions import DaemonUnavailableError, ScannerAlreadyRunningError
|
||||
from ..config import get_current_config
|
||||
from ..py23 import strtype
|
||||
from ..utils import get_secret_key
|
||||
|
||||
from .db import Folder
|
||||
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
|
||||
__all__ = [ 'DaemonClient' ]
|
||||
|
||||
class DaemonCommand(object):
|
||||
def apply(self, connection, daemon):
|
||||
@ -122,77 +108,3 @@ class DaemonClient(object):
|
||||
rv = c.recv()
|
||||
if rv.exception is not None:
|
||||
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())
|
14
supysonic/daemon/exceptions.py
Normal file
14
supysonic/daemon/exceptions.py
Normal 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
|
@ -13,7 +13,8 @@ import uuid
|
||||
from pony.orm import select
|
||||
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 ..py23 import strtype
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user