Mercurial > libervia-backend
comparison sat/memory/memory.py @ 3541:888109774673
core: various changes and fixes to work with new storage and D-Bus bridge:
- fixes coroutines handling in various places
- fixes types which are not serialised by Tx DBus
- XEP-0384: call storage methods in main thread in XEP: Python OMEMO's Promise use thread
which prevent the use of AsyncIO loop. To work around that, callLater is used to launch
storage method in main thread. This is a temporary workaround, as Python OMEMO should
get rid of Promise implementation and threads soon.
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 03 Jun 2021 15:21:43 +0200 |
parents | f9a5b810f14d |
children | 71516731d0aa |
comparison
equal
deleted
inserted
replaced
3540:aa58451b77ba | 3541:888109774673 |
---|---|
1129 return self.params._getParamsValuesFromCategory( | 1129 return self.params._getParamsValuesFromCategory( |
1130 category, security_limit, app, extra_s, profile_key | 1130 category, security_limit, app, extra_s, profile_key |
1131 ) | 1131 ) |
1132 | 1132 |
1133 def asyncGetStringParamA( | 1133 def asyncGetStringParamA( |
1134 self, name, category, attr="value", security_limit=C.NO_SECURITY_LIMIT, | 1134 self, name, category, attribute="value", security_limit=C.NO_SECURITY_LIMIT, |
1135 profile_key=C.PROF_KEY_NONE): | 1135 profile_key=C.PROF_KEY_NONE): |
1136 | 1136 |
1137 profile = self.getProfileName(profile_key) | 1137 profile = self.getProfileName(profile_key) |
1138 return defer.ensureDeferred(self.params.asyncGetStringParamA( | 1138 return defer.ensureDeferred(self.params.asyncGetStringParamA( |
1139 name, category, attr, security_limit, profile | 1139 name, category, attribute, security_limit, profile |
1140 )) | 1140 )) |
1141 | 1141 |
1142 def _getParamsUI(self, security_limit, app, extra_s, profile_key): | 1142 def _getParamsUI(self, security_limit, app, extra_s, profile_key): |
1143 return self.params._getParamsUI(security_limit, app, extra_s, profile_key) | 1143 return self.params._getParamsUI(security_limit, app, extra_s, profile_key) |
1144 | 1144 |
1168 | 1168 |
1169 def _privateDataSet(self, namespace, key, data_s, profile_key): | 1169 def _privateDataSet(self, namespace, key, data_s, profile_key): |
1170 client = self.host.getClient(profile_key) | 1170 client = self.host.getClient(profile_key) |
1171 # we accept any type | 1171 # we accept any type |
1172 data = data_format.deserialise(data_s, type_check=None) | 1172 data = data_format.deserialise(data_s, type_check=None) |
1173 return self.storage.setPrivateValue( | 1173 return defer.ensureDeferred(self.storage.setPrivateValue( |
1174 namespace, key, data, binary=True, profile=client.profile) | 1174 namespace, key, data, binary=True, profile=client.profile)) |
1175 | 1175 |
1176 def _privateDataGet(self, namespace, key, profile_key): | 1176 def _privateDataGet(self, namespace, key, profile_key): |
1177 client = self.host.getClient(profile_key) | 1177 client = self.host.getClient(profile_key) |
1178 d = self.storage.getPrivates( | 1178 d = defer.ensureDeferred( |
1179 namespace, [key], binary=True, profile=client.profile) | 1179 self.storage.getPrivates( |
1180 namespace, [key], binary=True, profile=client.profile) | |
1181 ) | |
1180 d.addCallback(lambda data_dict: data_format.serialise(data_dict.get(key))) | 1182 d.addCallback(lambda data_dict: data_format.serialise(data_dict.get(key))) |
1181 return d | 1183 return d |
1182 | 1184 |
1183 def _privateDataDelete(self, namespace, key, profile_key): | 1185 def _privateDataDelete(self, namespace, key, profile_key): |
1184 client = self.host.getClient(profile_key) | 1186 client = self.host.getClient(profile_key) |
1185 return self.storage.delPrivateValue( | 1187 return defer.ensureDeferred(self.storage.delPrivateValue( |
1186 namespace, key, binary=True, profile=client.profile) | 1188 namespace, key, binary=True, profile=client.profile)) |
1187 | 1189 |
1188 ## Files ## | 1190 ## Files ## |
1189 | 1191 |
1190 def checkFilePermission( | 1192 def checkFilePermission( |
1191 self, | 1193 self, |
1249 else: | 1251 else: |
1250 raise exceptions.InternalError( | 1252 raise exceptions.InternalError( |
1251 _("unknown access type: {type}").format(type=perm_type) | 1253 _("unknown access type: {type}").format(type=perm_type) |
1252 ) | 1254 ) |
1253 | 1255 |
1254 @defer.inlineCallbacks | 1256 async def checkPermissionToRoot(self, client, file_data, peer_jid, perms_to_check): |
1255 def checkPermissionToRoot(self, client, file_data, peer_jid, perms_to_check): | |
1256 """do checkFilePermission on file_data and all its parents until root""" | 1257 """do checkFilePermission on file_data and all its parents until root""" |
1257 current = file_data | 1258 current = file_data |
1258 while True: | 1259 while True: |
1259 self.checkFilePermission(current, peer_jid, perms_to_check) | 1260 self.checkFilePermission(current, peer_jid, perms_to_check) |
1260 parent = current["parent"] | 1261 parent = current["parent"] |
1261 if not parent: | 1262 if not parent: |
1262 break | 1263 break |
1263 files_data = yield self.getFiles( | 1264 files_data = await self.getFiles( |
1264 client, peer_jid=None, file_id=parent, perms_to_check=None | 1265 client, peer_jid=None, file_id=parent, perms_to_check=None |
1265 ) | 1266 ) |
1266 try: | 1267 try: |
1267 current = files_data[0] | 1268 current = files_data[0] |
1268 except IndexError: | 1269 except IndexError: |
1269 raise exceptions.DataError("Missing parent") | 1270 raise exceptions.DataError("Missing parent") |
1270 | 1271 |
1271 @defer.inlineCallbacks | 1272 async def _getParentDir( |
1272 def _getParentDir( | |
1273 self, client, path, parent, namespace, owner, peer_jid, perms_to_check | 1273 self, client, path, parent, namespace, owner, peer_jid, perms_to_check |
1274 ): | 1274 ): |
1275 """Retrieve parent node from a path, or last existing directory | 1275 """Retrieve parent node from a path, or last existing directory |
1276 | 1276 |
1277 each directory of the path will be retrieved, until the last existing one | 1277 each directory of the path will be retrieved, until the last existing one |
1291 | 1291 |
1292 # we retrieve all directories from path until we get the parent container | 1292 # we retrieve all directories from path until we get the parent container |
1293 # non existing directories will be created | 1293 # non existing directories will be created |
1294 parent = "" | 1294 parent = "" |
1295 for idx, path_elt in enumerate(path_elts): | 1295 for idx, path_elt in enumerate(path_elts): |
1296 directories = yield self.storage.getFiles( | 1296 directories = await self.storage.getFiles( |
1297 client, | 1297 client, |
1298 parent=parent, | 1298 parent=parent, |
1299 type_=C.FILE_TYPE_DIRECTORY, | 1299 type_=C.FILE_TYPE_DIRECTORY, |
1300 name=path_elt, | 1300 name=path_elt, |
1301 namespace=namespace, | 1301 namespace=namespace, |
1302 owner=owner, | 1302 owner=owner, |
1303 ) | 1303 ) |
1304 if not directories: | 1304 if not directories: |
1305 defer.returnValue((parent, path_elts[idx:])) | 1305 return (parent, path_elts[idx:]) |
1306 # from this point, directories don't exist anymore, we have to create them | 1306 # from this point, directories don't exist anymore, we have to create them |
1307 elif len(directories) > 1: | 1307 elif len(directories) > 1: |
1308 raise exceptions.InternalError( | 1308 raise exceptions.InternalError( |
1309 _("Several directories found, this should not happen") | 1309 _("Several directories found, this should not happen") |
1310 ) | 1310 ) |
1311 else: | 1311 else: |
1312 directory = directories[0] | 1312 directory = directories[0] |
1313 self.checkFilePermission(directory, peer_jid, perms_to_check) | 1313 self.checkFilePermission(directory, peer_jid, perms_to_check) |
1314 parent = directory["id"] | 1314 parent = directory["id"] |
1315 defer.returnValue((parent, [])) | 1315 return (parent, []) |
1316 | 1316 |
1317 def getFileAffiliations(self, file_data: dict) -> Dict[jid.JID, str]: | 1317 def getFileAffiliations(self, file_data: dict) -> Dict[jid.JID, str]: |
1318 """Convert file access to pubsub like affiliations""" | 1318 """Convert file access to pubsub like affiliations""" |
1319 affiliations = {} | 1319 affiliations = {} |
1320 access_data = file_data['access'] | 1320 access_data = file_data['access'] |
1482 raise exceptions.InternalError( | 1482 raise exceptions.InternalError( |
1483 "Owner must be set for component if peer_jid is None" | 1483 "Owner must be set for component if peer_jid is None" |
1484 ) | 1484 ) |
1485 return peer_jid.userhostJID() | 1485 return peer_jid.userhostJID() |
1486 | 1486 |
1487 @defer.inlineCallbacks | 1487 async def getFiles( |
1488 def getFiles( | |
1489 self, client, peer_jid, file_id=None, version=None, parent=None, path=None, | 1488 self, client, peer_jid, file_id=None, version=None, parent=None, path=None, |
1490 type_=None, file_hash=None, hash_algo=None, name=None, namespace=None, | 1489 type_=None, file_hash=None, hash_algo=None, name=None, namespace=None, |
1491 mime_type=None, public_id=None, owner=None, access=None, projection=None, | 1490 mime_type=None, public_id=None, owner=None, access=None, projection=None, |
1492 unique=False, perms_to_check=(C.ACCESS_PERM_READ,)): | 1491 unique=False, perms_to_check=(C.ACCESS_PERM_READ,)): |
1493 """Retrieve files with with given filters | 1492 """Retrieve files with with given filters |
1534 ) | 1533 ) |
1535 owner = self.getFilesOwner(client, owner, peer_jid, file_id, parent) | 1534 owner = self.getFilesOwner(client, owner, peer_jid, file_id, parent) |
1536 if path is not None: | 1535 if path is not None: |
1537 path = str(path) | 1536 path = str(path) |
1538 # permission are checked by _getParentDir | 1537 # permission are checked by _getParentDir |
1539 parent, remaining_path_elts = yield self._getParentDir( | 1538 parent, remaining_path_elts = await self._getParentDir( |
1540 client, path, parent, namespace, owner, peer_jid, perms_to_check | 1539 client, path, parent, namespace, owner, peer_jid, perms_to_check |
1541 ) | 1540 ) |
1542 if remaining_path_elts: | 1541 if remaining_path_elts: |
1543 # if we have remaining path elements, | 1542 # if we have remaining path elements, |
1544 # the parent directory is not found | 1543 # the parent directory is not found |
1545 raise failure.Failure(exceptions.NotFound()) | 1544 raise failure.Failure(exceptions.NotFound()) |
1546 if parent and peer_jid: | 1545 if parent and peer_jid: |
1547 # if parent is given directly and permission check is requested, | 1546 # if parent is given directly and permission check is requested, |
1548 # we need to check all the parents | 1547 # we need to check all the parents |
1549 parent_data = yield self.storage.getFiles(client, file_id=parent) | 1548 parent_data = await self.storage.getFiles(client, file_id=parent) |
1550 try: | 1549 try: |
1551 parent_data = parent_data[0] | 1550 parent_data = parent_data[0] |
1552 except IndexError: | 1551 except IndexError: |
1553 raise exceptions.DataError("mising parent") | 1552 raise exceptions.DataError("mising parent") |
1554 yield self.checkPermissionToRoot( | 1553 await self.checkPermissionToRoot( |
1555 client, parent_data, peer_jid, perms_to_check | 1554 client, parent_data, peer_jid, perms_to_check |
1556 ) | 1555 ) |
1557 | 1556 |
1558 files = yield self.storage.getFiles( | 1557 files = await self.storage.getFiles( |
1559 client, | 1558 client, |
1560 file_id=file_id, | 1559 file_id=file_id, |
1561 version=version, | 1560 version=version, |
1562 parent=parent, | 1561 parent=parent, |
1563 type_=type_, | 1562 type_=type_, |
1576 if peer_jid: | 1575 if peer_jid: |
1577 # if permission are checked, we must remove all file that user can't access | 1576 # if permission are checked, we must remove all file that user can't access |
1578 to_remove = [] | 1577 to_remove = [] |
1579 for file_data in files: | 1578 for file_data in files: |
1580 try: | 1579 try: |
1581 self.checkFilePermission(file_data, peer_jid, perms_to_check, set_affiliation=True) | 1580 self.checkFilePermission( |
1581 file_data, peer_jid, perms_to_check, set_affiliation=True | |
1582 ) | |
1582 except exceptions.PermissionError: | 1583 except exceptions.PermissionError: |
1583 to_remove.append(file_data) | 1584 to_remove.append(file_data) |
1584 for file_data in to_remove: | 1585 for file_data in to_remove: |
1585 files.remove(file_data) | 1586 files.remove(file_data) |
1586 defer.returnValue(files) | 1587 return files |
1587 | 1588 |
1588 @defer.inlineCallbacks | 1589 async def setFile( |
1589 def setFile( | |
1590 self, client, name, file_id=None, version="", parent=None, path=None, | 1590 self, client, name, file_id=None, version="", parent=None, path=None, |
1591 type_=C.FILE_TYPE_FILE, file_hash=None, hash_algo=None, size=None, | 1591 type_=C.FILE_TYPE_FILE, file_hash=None, hash_algo=None, size=None, |
1592 namespace=None, mime_type=None, public_id=None, created=None, modified=None, | 1592 namespace=None, mime_type=None, public_id=None, created=None, modified=None, |
1593 owner=None, access=None, extra=None, peer_jid=None, | 1593 owner=None, access=None, extra=None, peer_jid=None, |
1594 perms_to_check=(C.ACCESS_PERM_WRITE,) | 1594 perms_to_check=(C.ACCESS_PERM_WRITE,) |
1666 owner = self.getFilesOwner(client, owner, peer_jid, file_id, parent) | 1666 owner = self.getFilesOwner(client, owner, peer_jid, file_id, parent) |
1667 | 1667 |
1668 if path is not None: | 1668 if path is not None: |
1669 path = str(path) | 1669 path = str(path) |
1670 # _getParentDir will check permissions if peer_jid is set, so we use owner | 1670 # _getParentDir will check permissions if peer_jid is set, so we use owner |
1671 parent, remaining_path_elts = yield self._getParentDir( | 1671 parent, remaining_path_elts = await self._getParentDir( |
1672 client, path, parent, namespace, owner, owner, perms_to_check | 1672 client, path, parent, namespace, owner, owner, perms_to_check |
1673 ) | 1673 ) |
1674 # if remaining directories don't exist, we have to create them | 1674 # if remaining directories don't exist, we have to create them |
1675 for new_dir in remaining_path_elts: | 1675 for new_dir in remaining_path_elts: |
1676 new_dir_id = shortuuid.uuid() | 1676 new_dir_id = shortuuid.uuid() |
1677 yield self.storage.setFile( | 1677 await self.storage.setFile( |
1678 client, | 1678 client, |
1679 name=new_dir, | 1679 name=new_dir, |
1680 file_id=new_dir_id, | 1680 file_id=new_dir_id, |
1681 version="", | 1681 version="", |
1682 parent=parent, | 1682 parent=parent, |
1689 ) | 1689 ) |
1690 parent = new_dir_id | 1690 parent = new_dir_id |
1691 elif parent is None: | 1691 elif parent is None: |
1692 parent = "" | 1692 parent = "" |
1693 | 1693 |
1694 yield self.storage.setFile( | 1694 await self.storage.setFile( |
1695 client, | 1695 client, |
1696 file_id=file_id, | 1696 file_id=file_id, |
1697 version=version, | 1697 version=version, |
1698 parent=parent, | 1698 parent=parent, |
1699 type_=type_, | 1699 type_=type_, |