comparison libervia/backend/memory/memory.py @ 4333:e94799a0908f

core (main): Let plugins have several handlers + various improvements: `get_handler` can now return several handlers, which is notably useful for component with several included services. Various improvements such move to `async` method, docstring/type hints update, and slight improvment of SatXMPPComponent. rel 453
author Goffi <goffi@goffi.org>
date Tue, 03 Dec 2024 00:11:00 +0100
parents 0d7bb4df2343
children
comparison
equal deleted inserted replaced
4332:71c939e34ca6 4333:e94799a0908f
1651 files.remove(file_data) 1651 files.remove(file_data)
1652 return files 1652 return files
1653 1653
1654 async def set_file( 1654 async def set_file(
1655 self, 1655 self,
1656 client, 1656 client: SatXMPPEntity,
1657 name, 1657 name: str,
1658 file_id=None, 1658 file_id: str | None = None,
1659 version="", 1659 version: str = "",
1660 parent=None, 1660 parent: str | None = None,
1661 path=None, 1661 path: str | None = None,
1662 type_=C.FILE_TYPE_FILE, 1662 type_: str = C.FILE_TYPE_FILE,
1663 file_hash=None, 1663 file_hash: str | None = None,
1664 hash_algo=None, 1664 hash_algo: str | None = None,
1665 size=None, 1665 size: int | None = None,
1666 namespace=None, 1666 namespace: str | None = None,
1667 mime_type=None, 1667 mime_type: str | None = None,
1668 public_id=None, 1668 public_id: str | None = None,
1669 created=None, 1669 created: float | None = None,
1670 modified=None, 1670 modified: int | None = None,
1671 owner=None, 1671 owner: jid.JID | None = None,
1672 access=None, 1672 access: dict | None = None,
1673 extra=None, 1673 extra: dict | None = None,
1674 peer_jid=None, 1674 peer_jid: Any | None = None,
1675 perms_to_check=(C.ACCESS_PERM_WRITE,), 1675 perms_to_check: tuple[str]|None = (C.ACCESS_PERM_WRITE,),
1676 ): 1676 ) -> None:
1677 """Set a file metadata 1677 """Set a file metadata.
1678 1678
1679 @param name(unicode): basename of the file 1679 @param name: basename of the file
1680 @param file_id(unicode): unique id of the file 1680 @param file_id: unique id of the file
1681 @param version(unicode): version of this file 1681 @param version: version of this file, empty string for current version or when
1682 empty string for current version or when there is no versioning 1682 there is no versioning
1683 @param parent(unicode, None): id of the directory containing the files 1683 @param parent: id of the directory containing the files
1684 @param path(unicode, None): virtual path of the file in the namespace 1684 @param path: virtual path of the file in the namespace, if set, parent must be
1685 if set, parent must be None. All intermediate directories will be created 1685 None. All intermediate directories will be created if needed, using current
1686 if needed, using current access. 1686 access.
1687 @param type_(str, None): type of file filter, can be one of C.FILE_TYPE_* 1687 @param type_: type of file filter, can be one of C.FILE_TYPE_*
1688 @param file_hash(unicode): unique hash of the payload 1688 @param file_hash: unique hash of the payload
1689 @param hash_algo(unicode): algorithm used for hashing the file (usually sha-256) 1689 @param hash_algo: algorithm used for hashing the file (usually sha-256)
1690 @param size(int): size in bytes 1690 @param size: size in bytes
1691 @param namespace(unicode, None): identifier (human readable is better) to group 1691 @param namespace: identifier (human readable is better) to group files. For
1692 files 1692 instance, namespace could be used to group files in a specific photo album.
1693 For instance, namespace could be used to group files in a specific photo album 1693 @param mime_type: MIME type of the file, or None if not known/guessed
1694 @param mime_type(unicode): MIME type of the file, or None if not known/guessed 1694 @param public_id: id used to share publicly the file via HTTP
1695 @param public_id(unicode): id used to share publicly the file via HTTP 1695 @param created: UNIX time of creation
1696 @param created(int): UNIX time of creation 1696 @param modified: UNIX time of last modification, or None to use created date
1697 @param modified(int,None): UNIX time of last modification, or None to use 1697 @param owner: jid of the owner of the file (mainly useful for component). will be
1698 created date 1698 used to check permission (only bare jid is used, don't use with MUC). Use None
1699 @param owner(jid.JID, None): jid of the owner of the file (mainly useful for 1699 to ignore permission (perms_to_check must be None too)
1700 component) 1700 @param access: serialisable dictionary with access rules.
1701 will be used to check permission (only bare jid is used, don't use with MUC).
1702 Use None to ignore permission (perms_to_check must be None too)
1703 @param access(dict, None): serialisable dictionary with access rules.
1704 None (or empty dict) to use private access, i.e. allow only profile's jid to 1701 None (or empty dict) to use private access, i.e. allow only profile's jid to
1705 access the file 1702 access the file.
1706 key can be on on C.ACCESS_PERM_*, 1703 Key can be on on C.ACCESS_PERM_*, then a sub dictionary with a type key is
1707 then a sub dictionary with a type key is used (one of C.ACCESS_TYPE_*). 1704 used (one of C.ACCESS_TYPE_*).
1708 According to type, extra keys can be used: 1705 According to type, extra keys can be used:
1709 - C.ACCESS_TYPE_PUBLIC: the permission is granted for everybody 1706 - C.ACCESS_TYPE_PUBLIC: the permission is granted for everybody
1710 - C.ACCESS_TYPE_WHITELIST: the permission is granted for jids (as unicode) 1707 - C.ACCESS_TYPE_WHITELIST: the permission is granted for jids (as unicode)
1711 in the 'jids' key 1708 in the 'jids' key. will be encoded to json in database
1712 will be encoded to json in database 1709 @param extra: serialisable dictionary of any extra data. will be encoded to json
1713 @param extra(dict, None): serialisable dictionary of any extra data 1710 in database
1714 will be encoded to json in database 1711 @param perms_to_check: permission to check. must be a tuple of C.ACCESS_PERM_* or
1715 @param perms_to_check(tuple[unicode],None): permission to check 1712 None. if None, permission will not be checked (peer_jid must be None too in
1716 must be a tuple of C.ACCESS_PERM_* or None 1713 this case)
1717 if None, permission will not be checked (peer_jid must be None too in this
1718 case)
1719 @param profile(unicode): profile owning the file
1720 """ 1714 """
1721 if "/" in name: 1715 if "/" in name:
1722 raise ValueError('name must not contain a slash ("/")') 1716 raise ValueError('name must not contain a slash ("/")')
1723 if file_id is None: 1717 if file_id is None:
1724 file_id = shortuuid.uuid() 1718 file_id = shortuuid.uuid()
1766 file_id=new_dir_id, 1760 file_id=new_dir_id,
1767 version="", 1761 version="",
1768 parent=parent, 1762 parent=parent,
1769 type_=C.FILE_TYPE_DIRECTORY, 1763 type_=C.FILE_TYPE_DIRECTORY,
1770 namespace=namespace, 1764 namespace=namespace,
1771 created=time.time(), 1765 created=created,
1772 owner=owner, 1766 owner=owner,
1773 access=access, 1767 access=access,
1774 extra={}, 1768 extra={},
1775 ) 1769 )
1776 parent = new_dir_id 1770 parent = new_dir_id
1825 the method will take older value as argument, and must update it in place 1819 the method will take older value as argument, and must update it in place
1826 Note that the callable must be thread-safe 1820 Note that the callable must be thread-safe
1827 """ 1821 """
1828 return self.storage.file_update(file_id, column, update_cb) 1822 return self.storage.file_update(file_id, column, update_cb)
1829 1823
1830 @defer.inlineCallbacks 1824 async def _delete_file(
1831 def _delete_file(
1832 self, 1825 self,
1833 client, 1826 client: SatXMPPEntity,
1834 peer_jid: jid.JID, 1827 peer_jid: jid.JID,
1835 recursive: bool, 1828 recursive: bool,
1836 files_path: Path, 1829 files_path: Path,
1837 file_data: dict, 1830 file_data: dict,
1838 ): 1831 ):
1839 """Internal method to delete files/directories recursively 1832 """Internal method to delete files/directories recursively
1840 1833
1841 @param peer_jid(jid.JID): entity requesting the deletion (must be owner of files 1834 @param peer_jid: entity requesting the deletion (must be owner of files
1842 to delete) 1835 to delete)
1843 @param recursive(boolean): True if recursive deletion is needed 1836 @param recursive: True if recursive deletion is needed
1844 @param files_path(unicode): path of the directory containing the actual files 1837 @param files_path: path of the directory containing the actual files
1845 @param file_data(dict): data of the file to delete 1838 @param file_data: data of the file to delete
1846 """ 1839 """
1847 if file_data["owner"] != peer_jid: 1840 if file_data["owner"] != peer_jid:
1848 raise exceptions.PermissionError( 1841 raise exceptions.PermissionError(
1849 "file {file_name} can't be deleted, {peer_jid} is not the owner".format( 1842 "file {file_name} can't be deleted, {peer_jid} is not the owner".format(
1850 file_name=file_data["name"], peer_jid=peer_jid.full() 1843 file_name=file_data["name"], peer_jid=peer_jid.full()
1851 ) 1844 )
1852 ) 1845 )
1853 if file_data["type"] == C.FILE_TYPE_DIRECTORY: 1846 if file_data["type"] == C.FILE_TYPE_DIRECTORY:
1854 sub_files = yield self.get_files(client, peer_jid, parent=file_data["id"]) 1847 sub_files = await self.get_files(client, peer_jid, parent=file_data["id"])
1855 if sub_files and not recursive: 1848 if sub_files and not recursive:
1856 raise exceptions.DataError(_("Can't delete directory, it is not empty")) 1849 raise exceptions.DataError(_("Can't delete directory, it is not empty"))
1857 # we first delete the sub-files 1850 # we first delete the sub-files
1858 for sub_file_data in sub_files: 1851 for sub_file_data in sub_files:
1859 if sub_file_data["type"] == C.FILE_TYPE_DIRECTORY: 1852 if sub_file_data["type"] == C.FILE_TYPE_DIRECTORY:
1860 sub_file_path = files_path / sub_file_data["name"] 1853 sub_file_path = files_path / sub_file_data["name"]
1861 else: 1854 else:
1862 sub_file_path = files_path 1855 sub_file_path = files_path
1863 yield self._delete_file( 1856 await self._delete_file(
1864 client, peer_jid, recursive, sub_file_path, sub_file_data 1857 client, peer_jid, recursive, sub_file_path, sub_file_data
1865 ) 1858 )
1866 # then the directory itself 1859 # then the directory itself
1867 yield self.storage.file_delete(file_data["id"]) 1860 await self.storage.file_delete(file_data["id"])
1868 elif file_data["type"] == C.FILE_TYPE_FILE: 1861 elif file_data["type"] == C.FILE_TYPE_FILE:
1869 log.info( 1862 log.info(
1870 _("deleting file {name} with hash {file_hash}").format( 1863 _("deleting file {name} with hash {file_hash}").format(
1871 name=file_data["name"], file_hash=file_data["file_hash"] 1864 name=file_data["name"], file_hash=file_data["file_hash"]
1872 ) 1865 )
1873 ) 1866 )
1874 yield self.storage.file_delete(file_data["id"]) 1867 await self.storage.file_delete(file_data["id"])
1875 references = yield self.get_files( 1868 references = await self.get_files(
1876 client, peer_jid, file_hash=file_data["file_hash"] 1869 client, peer_jid, file_hash=file_data["file_hash"]
1877 ) 1870 )
1878 if references: 1871 if references:
1879 log.debug("there are still references to the file, we keep it") 1872 log.debug("there are still references to the file, we keep it")
1880 else: 1873 else: