Пример #1
0
 def __init__(self, dbdir):
     """
     Init function
     """
     super(Database, self).__init__()
     # internal db dir, it contains the real
     self.directory = dbdir
     self.medialist = MediaList()
     # create or open db
     self._db = db.Database(self.directory + '/db')
Пример #2
0
 def __init__(self, dbdir):
     """
     Init function
     """
     super(Database, self).__init__()
     # internal db dir, it contains the real
     self.directory = dbdir
     self.medialist = MediaList()
     # create or open db
     self._db = db.Database(self.directory + '/db')
Пример #3
0
Файл: db.py Проект: clones/kaa
    def __init__(self, dbdir):
        """
        Init function
        """
        super(Database, self).__init__()
        # internal db dir, it contains the real db and the
        # overlay dir for the beacon
        self.directory = dbdir
        self.medialist = MediaList()

        # create or open db
        overlay = os.path.join(self.directory, 'overlays')
        if not os.path.isdir(overlay):
            os.makedirs(overlay)
        self._db = db.Database(self.directory + '/db')
Пример #4
0
class Database(kaa.Object):
    """
    Database API for the client side, providing read-only access to the
    beacon database.

    This class is subclassed by the server for the read/write database.
    """
    def __init__(self, dbdir):
        """
        Init function
        """
        super(Database, self).__init__()
        # internal db dir, it contains the real
        self.directory = dbdir
        self.medialist = MediaList()
        # create or open db
        self._db = db.Database(self.directory + '/db')

    def commit():
        """
        Stub on the client side: implemented in the server db
        """
        pass

    def add_object(*args, **kwargs):
        """
        Stub on the client side: implemented in the server db
        """
        pass

    def delete_object(*args, **kwargs):
        """
        Stub on the client side: implemented in the server db
        """
        pass

    def acquire_read_lock(self):
        """
        Stub on the client side: implemented in the server db
        """
        return kaa.InProgress().finish(None)

    def md5url(self, url, subdir):
        """
        Convert url into md5 sum
        """
        if url.startswith('http://'):
            subdir += '/%s/' % url[7:url[7:].find('/')+7]
        fname = hashlib.md5(url).hexdigest() + os.path.splitext(url)[1]
        return os.path.join(self.directory, subdir, fname)

    def get_db_info(self):
        """
        Returns information about the database.  Look at
        kaa.db.Database.get_db_info() for more details.
        """
        info = self._db.get_db_info()
        info['directory'] = self.directory
        return info

    # -------------------------------------------------------------------------
    # Query functions
    #
    # The query functions can modify the database when in server mode. E.g.
    # a directory query could detect deleted files and will delete them in
    # the database. In client mode, the query functions will use the database
    # read only.
    # -------------------------------------------------------------------------

    def query(self, **query):
        """
        Main query function. This function will call one of the specific
        query functions in this class depending on the query. This function
        returns an InProgress.
        """
        # Remove non-true recursive attribute from query (non-recursive is default).
        if not query.get('recursive', True):
            del query['recursive']
        # Passed by caller to collect list of deleted items for directory query.
        garbage = query.pop('garbage', None)
        # do query based on type
        if query.keys() == ['filename']:
            fname = os.path.realpath(query['filename'])
            return kaa.InProgress().execute(self.query_filename, fname)
        if query.keys() == ['id']:
            return kaa.InProgress().execute(self._db_query_id, query['id'])
        if sorted(query.keys()) == ['parent', 'recursive']:
            if not query['parent']._beacon_isdir:
                raise AttributeError('parent is no directory')
            return self._db_query_dir_recursive(query['parent'], garbage)
        if 'parent' in query:
            if len(query) == 1:
                if query['parent']._beacon_isdir:
                    return self._db_query_dir(query['parent'], garbage)
            query['parent'] = query['parent']._beacon_id
        if 'media' not in query and query.get('type') != 'media':
            # query only media we have right now
            query['media'] = db.QExpr('in', self.medialist.get_all_beacon_ids())
        elif query.get('media') == 'all':
            del query['media']
        if 'attr' in query:
            return kaa.InProgress().execute(self._db_query_attr, query)
        if query.get('type') == 'media':
            return kaa.InProgress().execute(self._db.query, **query)
        return self._db_query_raw(query)

    def query_media(self, media):
        """
        Get media information.
        """
        if hasattr(media, 'id'):
            # object is a media object
            id = media.id
        else:
            # object is only an id
            id = media
            media = None
        result = self._db.query(type="media", name=id)
        if not result:
            return None
        result = result[0]
        if not media:
            return result
        # TODO: it's a bit ugly to set url here, but we have no other choice
        media.url = result['content'] + '://' + media.mountpoint
        dbid = ('media', result['id'])
        media._beacon_id = dbid
        root = self._db.query(parent=dbid)[0]
        if root['type'] == 'dir':
            media.root = create_directory(root, media)
        else:
            media.root = create_item(root, media)
        return result

    @kaa.coroutine()
    def _db_query_dir(self, parent, garbage):
        """
        A query to get all files in a directory. The parameter parent is a
        directort object.
        """
        if parent._beacon_islink:
            # WARNING: parent is a link, we need to follow it
            dirname = os.path.realpath(parent.filename)
            parent = self.query_filename(dirname)
            if not parent._beacon_isdir:
                # oops, this is not directory anymore, return nothing
                yield []
        else:
            dirname = parent.filename[:-1]
        listing = parent._beacon_listdir()
        items = []
        if parent._beacon_id:
            items = [ create_by_type(i, parent, i['type'] == 'dir') \
                      for i in self._db.query(parent = parent._beacon_id) ]
        # sort items based on name. The listdir is also sorted by name,
        # that makes checking much faster
        items.sort(lambda x,y: cmp(x._beacon_name, y._beacon_name))
        # TODO: use parent mtime to check if an update is needed. Maybe call
        # it scan time or something like that. Also make it an option so the
        # user can turn the feature off.
        yield self.acquire_read_lock()
        pos = -1
        for f, fullname, stat_res in listing[0]:
            pos += 1
            isdir = stat.S_ISDIR(stat_res[stat.ST_MODE])
            if pos == len(items):
                # new file at the end
                if isdir:
                    items.append(create_directory(f, parent))
                    continue
                items.append(create_file(f, parent))
                continue
            while pos < len(items) and f > items[pos]._beacon_name:
                # file deleted
                i = items[pos]
                if not i.isdir and not i.isfile:
                    # A remote URL in the directory
                    pos += 1
                    continue
                items.remove(i)
                # Server only: delete from database by adding it to the
                # internal changes list. It will be deleted right before the
                # next commit.
                self.delete_object(i)
                if garbage is not None:
                    garbage.append(i)
            if pos < len(items) and f == items[pos]._beacon_name:
                # same file
                continue
            # new file
            if isdir:
                items.insert(pos, create_directory(f, parent))
                continue
            items.insert(pos, create_file(f, parent))
        if pos + 1 < len(items):
            # deleted files at the end
            for i in items[pos+1-len(items):]:
                if not i.isdir and not i.isfile:
                    # A remote URL in the directory
                    continue
                items.remove(i)
                # Server only: delete from database by adding it to the
                # internal changes list. It will be deleted right before the
                # next commit.
                self.delete_object(i)
                if garbage is not None:
                    garbage.append(i)
        # no need to sort the items again, they are already sorted based
        # on name, let us keep it that way. And name is unique in a directory.
        # items.sort(lambda x,y: cmp(x.url, y.url))
        yield items

    @kaa.coroutine()
    def _db_query_dir_recursive(self, parent, garbage):
        """
        Return all files in the directory 'parent' including files in
        subdirectories (and so on). The directories itself will not be
        returned. If a subdir is a softlink, it will be skipped. This
        query does not check if the files are still there and if the
        database list is up to date.
        """
        if parent._beacon_islink:
            # WARNING: parent is a link, we need to follow it
            dirname = os.path.realpath(parent.filename)
            parent = self.query_filename(dirname)
            if not parent._beacon_isdir:
                # oops, this is not directory anymore, return nothing
                yield []
        else:
            dirname = parent.filename[:-1]
        timer = time.time()
        items = []
        # A list of all directories we will look at. If a link is in the
        # directory it will be ignored.
        directories = [ parent ]
        while directories:
            parent = directories.pop(0)
            for i in (yield self._db_query_dir(parent, garbage)):
                if i.isdir and not i._beacon_islink:
                    directories.append(child)
                items.append(i)
            if time.time() > timer + 0.1:
                # we used too much time. Call yield NotFinished at
                # this point to continue later.
                timer = time.time()
                yield kaa.NotFinished
        # sort items based on name. The listdir is also sorted by name,
        # that makes checking much faster
        items.sort(lambda x,y: cmp(x._beacon_name, y._beacon_name))
        yield items

    def _db_query_id(self, (type, id), cache=None):
Пример #5
0
class Database(kaa.Object):
    """
    Database API for the client side, providing read-only access to the
    beacon database.

    This class is subclassed by the server for the read/write database.
    """
    def __init__(self, dbdir):
        """
        Init function
        """
        super(Database, self).__init__()
        # internal db dir, it contains the real
        self.directory = dbdir
        self.medialist = MediaList()
        # create or open db
        self._db = db.Database(self.directory + '/db')

    def commit():
        """
        Stub on the client side: implemented in the server db
        """
        pass

    def add_object(*args, **kwargs):
        """
        Stub on the client side: implemented in the server db
        """
        pass

    def delete_object(*args, **kwargs):
        """
        Stub on the client side: implemented in the server db
        """
        pass

    def acquire_read_lock(self):
        """
        Stub on the client side: implemented in the server db
        """
        return kaa.InProgress().finish(None)

    def md5url(self, url, subdir):
        """
        Convert url into md5 sum
        """
        if url.startswith('http://'):
            subdir += '/%s/' % url[7:url[7:].find('/')+7]
        fname = hashlib.md5(url).hexdigest() + os.path.splitext(url)[1]
        return os.path.join(self.directory, subdir, fname)

    def get_db_info(self):
        """
        Returns information about the database.  Look at
        kaa.db.Database.get_db_info() for more details.
        """
        info = self._db.get_db_info()
        info['directory'] = self.directory
        return info

    # -------------------------------------------------------------------------
    # Query functions
    #
    # The query functions can modify the database when in server mode. E.g.
    # a directory query could detect deleted files and will delete them in
    # the database. In client mode, the query functions will use the database
    # read only.
    # -------------------------------------------------------------------------

    def query(self, **query):
        """
        Main query function. This function will call one of the specific
        query functions in this class depending on the query. This function
        returns an InProgress.
        """
        # Remove non-true recursive attribute from query (non-recursive is default).
        if not query.get('recursive', True):
            del query['recursive']
        # Passed by caller to collect list of deleted items for directory query.
        garbage = query.pop('garbage', None)
        # do query based on type
        if query.keys() == ['filename']:
            fname = os.path.realpath(query['filename'])
            return kaa.InProgress().execute(self.query_filename, fname)
        if query.keys() == ['id']:
            return kaa.InProgress().execute(self._db_query_id, query['id'])
        if sorted(query.keys()) == ['parent', 'recursive']:
            if not query['parent']._beacon_isdir:
                raise AttributeError('parent is no directory')
            return self._db_query_dir_recursive(query['parent'], garbage)
        if 'parent' in query:
            if len(query) == 1:
                if query['parent']._beacon_isdir:
                    return self._db_query_dir(query['parent'], garbage)
            query['parent'] = query['parent']._beacon_id
        if 'media' not in query and query.get('type') != 'media':
            # query only media we have right now
            query['media'] = db.QExpr('in', self.medialist.get_all_beacon_ids())
        elif query.get('media') == 'all':
            del query['media']
        if 'attr' in query:
            return kaa.InProgress().execute(self._db_query_attr, query)
        if query.get('type') == 'media':
            return kaa.InProgress().execute(self._db.query, **query)
        return self._db_query_raw(query)

    def query_media(self, media):
        """
        Get media information.
        """
        if hasattr(media, 'id'):
            # object is a media object
            id = media.id
        else:
            # object is only an id
            id = media
            media = None
        result = self._db.query(type="media", name=id)
        if not result:
            return None
        result = result[0]
        if not media:
            return result
        # TODO: it's a bit ugly to set url here, but we have no other choice
        media.url = result['content'] + '://' + media.mountpoint
        dbid = ('media', result['id'])
        media._beacon_id = dbid
        root = self._db.query(parent=dbid)[0]
        if root['type'] == 'dir':
            media.root = create_directory(root, media)
        else:
            media.root = create_item(root, media)
        return result

    @kaa.coroutine()
    def _db_query_dir(self, parent, garbage):
        """
        A query to get all files in a directory. The parameter parent is a
        directort object.
        """
        if parent._beacon_islink:
            # WARNING: parent is a link, we need to follow it
            dirname = os.path.realpath(parent.filename)
            parent = self.query_filename(dirname)
            if not parent._beacon_isdir:
                # oops, this is not directory anymore, return nothing
                yield []
        else:
            dirname = parent.filename[:-1]
        listing = parent._beacon_listdir()
        items = []
        if parent._beacon_id:
            items = [ create_by_type(i, parent, i['type'] == 'dir') \
                      for i in self._db.query(parent = parent._beacon_id) ]
        # sort items based on name. The listdir is also sorted by name,
        # that makes checking much faster
        items.sort(lambda x,y: cmp(x._beacon_name, y._beacon_name))
        # TODO: use parent mtime to check if an update is needed. Maybe call
        # it scan time or something like that. Also make it an option so the
        # user can turn the feature off.
        yield self.acquire_read_lock()
        pos = -1
        for f, fullname, stat_res in listing[0]:
            pos += 1
            isdir = stat.S_ISDIR(stat_res[stat.ST_MODE])
            if pos == len(items):
                # new file at the end
                if isdir:
                    items.append(create_directory(f, parent))
                    continue
                items.append(create_file(f, parent))
                continue
            while pos < len(items) and f > items[pos]._beacon_name:
                # file deleted
                i = items[pos]
                if not i.isdir and not i.isfile:
                    # A remote URL in the directory
                    pos += 1
                    continue
                items.remove(i)
                # Server only: delete from database by adding it to the
                # internal changes list. It will be deleted right before the
                # next commit.
                self.delete_object(i)
                if garbage is not None:
                    garbage.append(i)
            if pos < len(items) and f == items[pos]._beacon_name:
                # same file
                continue
            # new file
            if isdir:
                items.insert(pos, create_directory(f, parent))
                continue
            items.insert(pos, create_file(f, parent))
        if pos + 1 < len(items):
            # deleted files at the end
            for i in items[pos+1-len(items):]:
                if not i.isdir and not i.isfile:
                    # A remote URL in the directory
                    continue
                items.remove(i)
                # Server only: delete from database by adding it to the
                # internal changes list. It will be deleted right before the
                # next commit.
                self.delete_object(i)
                if garbage is not None:
                    garbage.append(i)
        # no need to sort the items again, they are already sorted based
        # on name, let us keep it that way. And name is unique in a directory.
        # items.sort(lambda x,y: cmp(x.url, y.url))
        yield items

    @kaa.coroutine()
    def _db_query_dir_recursive(self, parent, garbage):
        """
        Return all files in the directory 'parent' including files in
        subdirectories (and so on). The directories itself will not be
        returned. If a subdir is a softlink, it will be skipped. This
        query does not check if the files are still there and if the
        database list is up to date.
        """
        if parent._beacon_islink:
            # WARNING: parent is a link, we need to follow it
            dirname = os.path.realpath(parent.filename)
            parent = self.query_filename(dirname)
            if not parent._beacon_isdir:
                # oops, this is not directory anymore, return nothing
                yield []
        else:
            dirname = parent.filename[:-1]
        timer = time.time()
        items = []
        # A list of all directories we will look at. If a link is in the
        # directory it will be ignored.
        directories = [ parent ]
        while directories:
            parent = directories.pop(0)
            for i in (yield self._db_query_dir(parent, garbage)):
                if i.isdir and not i._beacon_islink:
                    directories.append(child)
                items.append(i)
            if time.time() > timer + 0.1:
                # we used too much time. Call yield NotFinished at
                # this point to continue later.
                timer = time.time()
                yield kaa.NotFinished
        # sort items based on name. The listdir is also sorted by name,
        # that makes checking much faster
        items.sort(lambda x,y: cmp(x._beacon_name, y._beacon_name))
        yield items

    def _db_query_id(self, (type, id), cache=None):