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
This commit is contained in:
parent
1ec2b29854
commit
1f3c6f0329
4 changed files with 82 additions and 78 deletions
|
|
@ -37,6 +37,12 @@ class SatXMPPEntity:
|
|||
identities: list[disco.DiscoIdentity]
|
||||
|
||||
|
||||
class SatXMPPComponent(SatXMPPEntity):
|
||||
|
||||
def is_local(self, jid_: t_jid.JID) -> bool:
|
||||
...
|
||||
|
||||
|
||||
EncryptionPlugin = namedtuple(
|
||||
"EncryptionPlugin", ("instance", "name", "namespace", "priority", "directed")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -516,9 +516,9 @@ class LiberviaBackend(service.Service):
|
|||
return
|
||||
raise ImportError("Error during initiation")
|
||||
if C.bool(plugin_info.get(C.PI_HANDLER, C.BOOL_FALSE)):
|
||||
self.plugins[import_name].is_handler = True
|
||||
self.plugins[import_name].has_handlers = True
|
||||
else:
|
||||
self.plugins[import_name].is_handler = False
|
||||
self.plugins[import_name].has_handlers = False
|
||||
# we keep metadata as a Class attribute
|
||||
self.plugins[import_name]._info = plugin_info
|
||||
# TODO: test xmppclient presence and register handler parent
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import asyncio
|
||||
import calendar
|
||||
from collections.abc import Iterable
|
||||
import copy
|
||||
from functools import partial
|
||||
import mimetypes
|
||||
|
|
@ -146,8 +147,12 @@ class SatXMPPEntity(core_types.SatXMPPEntity):
|
|||
self.plugins = plugins = self._get_plugins_list()
|
||||
for plugin in plugins:
|
||||
# we check if plugin handle client mode
|
||||
if plugin.is_handler:
|
||||
plugin.get_handler(self).setHandlerParent(self)
|
||||
if plugin.has_handlers:
|
||||
handlers = plugin.get_handler(self)
|
||||
if not isinstance(handlers, Iterable):
|
||||
handlers = [handlers]
|
||||
for handler in handlers:
|
||||
handler.setHandlerParent(self)
|
||||
|
||||
# profile_connecting/profile_connected methods handling
|
||||
|
||||
|
|
@ -1085,7 +1090,7 @@ class SatXMPPClient(SatXMPPEntity, wokkel_client.XMPPClient):
|
|||
|
||||
|
||||
@implementer(iwokkel.IDisco)
|
||||
class SatXMPPComponent(SatXMPPEntity, component.Component):
|
||||
class SatXMPPComponent(SatXMPPEntity, core_types.SatXMPPComponent, component.Component):
|
||||
"""XMPP component
|
||||
|
||||
This component are similar but not identical to clients.
|
||||
|
|
|
|||
|
|
@ -1653,70 +1653,64 @@ class Memory:
|
|||
|
||||
async def set_file(
|
||||
self,
|
||||
client,
|
||||
name,
|
||||
file_id=None,
|
||||
version="",
|
||||
parent=None,
|
||||
path=None,
|
||||
type_=C.FILE_TYPE_FILE,
|
||||
file_hash=None,
|
||||
hash_algo=None,
|
||||
size=None,
|
||||
namespace=None,
|
||||
mime_type=None,
|
||||
public_id=None,
|
||||
created=None,
|
||||
modified=None,
|
||||
owner=None,
|
||||
access=None,
|
||||
extra=None,
|
||||
peer_jid=None,
|
||||
perms_to_check=(C.ACCESS_PERM_WRITE,),
|
||||
):
|
||||
"""Set a file metadata
|
||||
client: SatXMPPEntity,
|
||||
name: str,
|
||||
file_id: str | None = None,
|
||||
version: str = "",
|
||||
parent: str | None = None,
|
||||
path: str | None = None,
|
||||
type_: str = C.FILE_TYPE_FILE,
|
||||
file_hash: str | None = None,
|
||||
hash_algo: str | None = None,
|
||||
size: int | None = None,
|
||||
namespace: str | None = None,
|
||||
mime_type: str | None = None,
|
||||
public_id: str | None = None,
|
||||
created: float | None = None,
|
||||
modified: int | None = None,
|
||||
owner: jid.JID | None = None,
|
||||
access: dict | None = None,
|
||||
extra: dict | None = None,
|
||||
peer_jid: Any | None = None,
|
||||
perms_to_check: tuple[str]|None = (C.ACCESS_PERM_WRITE,),
|
||||
) -> None:
|
||||
"""Set a file metadata.
|
||||
|
||||
@param name(unicode): basename of the file
|
||||
@param file_id(unicode): unique id of the file
|
||||
@param version(unicode): version of this file
|
||||
empty string for current version or when there is no versioning
|
||||
@param parent(unicode, None): id of the directory containing the files
|
||||
@param path(unicode, None): virtual path of the file in the namespace
|
||||
if set, parent must be None. All intermediate directories will be created
|
||||
if needed, using current access.
|
||||
@param type_(str, None): type of file filter, can be one of C.FILE_TYPE_*
|
||||
@param file_hash(unicode): unique hash of the payload
|
||||
@param hash_algo(unicode): algorithm used for hashing the file (usually sha-256)
|
||||
@param size(int): size in bytes
|
||||
@param namespace(unicode, None): identifier (human readable is better) to group
|
||||
files
|
||||
For instance, namespace could be used to group files in a specific photo album
|
||||
@param mime_type(unicode): MIME type of the file, or None if not known/guessed
|
||||
@param public_id(unicode): id used to share publicly the file via HTTP
|
||||
@param created(int): UNIX time of creation
|
||||
@param modified(int,None): UNIX time of last modification, or None to use
|
||||
created date
|
||||
@param owner(jid.JID, None): jid of the owner of the file (mainly useful for
|
||||
component)
|
||||
will be used to check permission (only bare jid is used, don't use with MUC).
|
||||
Use None to ignore permission (perms_to_check must be None too)
|
||||
@param access(dict, None): serialisable dictionary with access rules.
|
||||
@param name: basename of the file
|
||||
@param file_id: unique id of the file
|
||||
@param version: version of this file, empty string for current version or when
|
||||
there is no versioning
|
||||
@param parent: id of the directory containing the files
|
||||
@param path: virtual path of the file in the namespace, if set, parent must be
|
||||
None. All intermediate directories will be created if needed, using current
|
||||
access.
|
||||
@param type_: type of file filter, can be one of C.FILE_TYPE_*
|
||||
@param file_hash: unique hash of the payload
|
||||
@param hash_algo: algorithm used for hashing the file (usually sha-256)
|
||||
@param size: size in bytes
|
||||
@param namespace: identifier (human readable is better) to group files. For
|
||||
instance, namespace could be used to group files in a specific photo album.
|
||||
@param mime_type: MIME type of the file, or None if not known/guessed
|
||||
@param public_id: id used to share publicly the file via HTTP
|
||||
@param created: UNIX time of creation
|
||||
@param modified: UNIX time of last modification, or None to use created date
|
||||
@param owner: jid of the owner of the file (mainly useful for component). will be
|
||||
used to check permission (only bare jid is used, don't use with MUC). Use None
|
||||
to ignore permission (perms_to_check must be None too)
|
||||
@param access: serialisable dictionary with access rules.
|
||||
None (or empty dict) to use private access, i.e. allow only profile's jid to
|
||||
access the file
|
||||
key can be on on C.ACCESS_PERM_*,
|
||||
then a sub dictionary with a type key is used (one of C.ACCESS_TYPE_*).
|
||||
access the file.
|
||||
Key can be on on C.ACCESS_PERM_*, then a sub dictionary with a type key is
|
||||
used (one of C.ACCESS_TYPE_*).
|
||||
According to type, extra keys can be used:
|
||||
- C.ACCESS_TYPE_PUBLIC: the permission is granted for everybody
|
||||
- C.ACCESS_TYPE_WHITELIST: the permission is granted for jids (as unicode)
|
||||
in the 'jids' key
|
||||
will be encoded to json in database
|
||||
@param extra(dict, None): serialisable dictionary of any extra data
|
||||
will be encoded to json in database
|
||||
@param perms_to_check(tuple[unicode],None): permission to check
|
||||
must be a tuple of C.ACCESS_PERM_* or None
|
||||
if None, permission will not be checked (peer_jid must be None too in this
|
||||
case)
|
||||
@param profile(unicode): profile owning the file
|
||||
in the 'jids' key. will be encoded to json in database
|
||||
@param extra: serialisable dictionary of any extra data. will be encoded to json
|
||||
in database
|
||||
@param perms_to_check: permission to check. must be a tuple of C.ACCESS_PERM_* or
|
||||
None. if None, permission will not be checked (peer_jid must be None too in
|
||||
this case)
|
||||
"""
|
||||
if "/" in name:
|
||||
raise ValueError('name must not contain a slash ("/")')
|
||||
|
|
@ -1768,7 +1762,7 @@ class Memory:
|
|||
parent=parent,
|
||||
type_=C.FILE_TYPE_DIRECTORY,
|
||||
namespace=namespace,
|
||||
created=time.time(),
|
||||
created=created,
|
||||
owner=owner,
|
||||
access=access,
|
||||
extra={},
|
||||
|
|
@ -1827,10 +1821,9 @@ class Memory:
|
|||
"""
|
||||
return self.storage.file_update(file_id, column, update_cb)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _delete_file(
|
||||
async def _delete_file(
|
||||
self,
|
||||
client,
|
||||
client: SatXMPPEntity,
|
||||
peer_jid: jid.JID,
|
||||
recursive: bool,
|
||||
files_path: Path,
|
||||
|
|
@ -1838,11 +1831,11 @@ class Memory:
|
|||
):
|
||||
"""Internal method to delete files/directories recursively
|
||||
|
||||
@param peer_jid(jid.JID): entity requesting the deletion (must be owner of files
|
||||
@param peer_jid: entity requesting the deletion (must be owner of files
|
||||
to delete)
|
||||
@param recursive(boolean): True if recursive deletion is needed
|
||||
@param files_path(unicode): path of the directory containing the actual files
|
||||
@param file_data(dict): data of the file to delete
|
||||
@param recursive: True if recursive deletion is needed
|
||||
@param files_path: path of the directory containing the actual files
|
||||
@param file_data: data of the file to delete
|
||||
"""
|
||||
if file_data["owner"] != peer_jid:
|
||||
raise exceptions.PermissionError(
|
||||
|
|
@ -1851,7 +1844,7 @@ class Memory:
|
|||
)
|
||||
)
|
||||
if file_data["type"] == C.FILE_TYPE_DIRECTORY:
|
||||
sub_files = yield self.get_files(client, peer_jid, parent=file_data["id"])
|
||||
sub_files = await self.get_files(client, peer_jid, parent=file_data["id"])
|
||||
if sub_files and not recursive:
|
||||
raise exceptions.DataError(_("Can't delete directory, it is not empty"))
|
||||
# we first delete the sub-files
|
||||
|
|
@ -1860,19 +1853,19 @@ class Memory:
|
|||
sub_file_path = files_path / sub_file_data["name"]
|
||||
else:
|
||||
sub_file_path = files_path
|
||||
yield self._delete_file(
|
||||
await self._delete_file(
|
||||
client, peer_jid, recursive, sub_file_path, sub_file_data
|
||||
)
|
||||
# then the directory itself
|
||||
yield self.storage.file_delete(file_data["id"])
|
||||
await self.storage.file_delete(file_data["id"])
|
||||
elif file_data["type"] == C.FILE_TYPE_FILE:
|
||||
log.info(
|
||||
_("deleting file {name} with hash {file_hash}").format(
|
||||
name=file_data["name"], file_hash=file_data["file_hash"]
|
||||
)
|
||||
)
|
||||
yield self.storage.file_delete(file_data["id"])
|
||||
references = yield self.get_files(
|
||||
await self.storage.file_delete(file_data["id"])
|
||||
references = await self.get_files(
|
||||
client, peer_jid, file_hash=file_data["file_hash"]
|
||||
)
|
||||
if references:
|
||||
|
|
|
|||
Loading…
Reference in a new issue