Mercurial > libervia-backend
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: |