core (xmpp): properly clean profile data in case of startConnection failure:
- profile is now always removed from profiles_connecting - an exception is raised if client already exists only if client is connected. Otherwise, it's deleted (this allow to keep session open to e.g. modify settings in case of failure during connection)
This commit is contained in:
parent
81de80348b
commit
cf82140690
1 changed files with 86 additions and 80 deletions
166
sat/core/xmpp.py
166
sat/core/xmpp.py
|
|
@ -163,103 +163,109 @@ class SatXMPPEntity:
|
|||
raise exceptions.CancelError(f"{profile} is already being connected")
|
||||
cls.profiles_connecting.add(profile)
|
||||
try:
|
||||
port = int(
|
||||
host.memory.getParamA(
|
||||
C.FORCE_PORT_PARAM, "Connection", profile_key=profile
|
||||
)
|
||||
)
|
||||
except ValueError:
|
||||
log.debug(_("Can't parse port value, using default value"))
|
||||
port = (
|
||||
None
|
||||
) # will use default value 5222 or be retrieved from a DNS SRV record
|
||||
|
||||
password = await host.memory.asyncGetParamA(
|
||||
"Password", "Connection", profile_key=profile
|
||||
)
|
||||
|
||||
entity_jid_s = await host.memory.asyncGetParamA(
|
||||
"JabberID", "Connection", profile_key=profile)
|
||||
entity_jid = jid.JID(entity_jid_s)
|
||||
|
||||
if not entity_jid.resource and not cls.is_component and entity_jid.user:
|
||||
# if no resource is specified, we create our own instead of using
|
||||
# server returned one, as it will then stay stable in case of reconnection.
|
||||
# we only do that for client and if there is a user part, to let server
|
||||
# decide for anonymous login
|
||||
resource_dict = await host.memory.storage.getPrivates(
|
||||
"core:xmpp", ["resource"] , profile=profile)
|
||||
try:
|
||||
resource = resource_dict["resource"]
|
||||
except KeyError:
|
||||
resource = f"{C.APP_NAME_FILE}.{shortuuid.uuid()}"
|
||||
await host.memory.storage.setPrivateValue(
|
||||
"core:xmpp", "resource", resource, profile=profile)
|
||||
port = int(
|
||||
host.memory.getParamA(
|
||||
C.FORCE_PORT_PARAM, "Connection", profile_key=profile
|
||||
)
|
||||
)
|
||||
except ValueError:
|
||||
log.debug(_("Can't parse port value, using default value"))
|
||||
port = (
|
||||
None
|
||||
) # will use default value 5222 or be retrieved from a DNS SRV record
|
||||
|
||||
log.info(_("We'll use the stable resource {resource}").format(
|
||||
resource=resource))
|
||||
entity_jid.resource = resource
|
||||
|
||||
if profile in host.profiles:
|
||||
raise exceptions.InternalError(
|
||||
f"There is already a profile of name {profile} in host")
|
||||
entity = host.profiles[profile] = cls(
|
||||
host, profile, entity_jid, password,
|
||||
host.memory.getParamA(C.FORCE_SERVER_PARAM, "Connection",
|
||||
profile_key=profile) or None,
|
||||
port, max_retries,
|
||||
password = await host.memory.asyncGetParamA(
|
||||
"Password", "Connection", profile_key=profile
|
||||
)
|
||||
|
||||
await entity.encryption.loadSessions()
|
||||
entity_jid_s = await host.memory.asyncGetParamA(
|
||||
"JabberID", "Connection", profile_key=profile)
|
||||
entity_jid = jid.JID(entity_jid_s)
|
||||
|
||||
entity._createSubProtocols()
|
||||
if not entity_jid.resource and not cls.is_component and entity_jid.user:
|
||||
# if no resource is specified, we create our own instead of using
|
||||
# server returned one, as it will then stay stable in case of
|
||||
# reconnection. we only do that for client and if there is a user part, to
|
||||
# let server decide for anonymous login
|
||||
resource_dict = await host.memory.storage.getPrivates(
|
||||
"core:xmpp", ["resource"] , profile=profile)
|
||||
try:
|
||||
resource = resource_dict["resource"]
|
||||
except KeyError:
|
||||
resource = f"{C.APP_NAME_FILE}.{shortuuid.uuid()}"
|
||||
await host.memory.storage.setPrivateValue(
|
||||
"core:xmpp", "resource", resource, profile=profile)
|
||||
|
||||
entity.fallBack = SatFallbackHandler(host)
|
||||
entity.fallBack.setHandlerParent(entity)
|
||||
log.info(_("We'll use the stable resource {resource}").format(
|
||||
resource=resource))
|
||||
entity_jid.resource = resource
|
||||
|
||||
entity.versionHandler = SatVersionHandler(C.APP_NAME_FULL, host.full_version)
|
||||
entity.versionHandler.setHandlerParent(entity)
|
||||
if profile in host.profiles:
|
||||
if host.profiles[profile].isConnected():
|
||||
raise exceptions.InternalError(
|
||||
f"There is already a connected profile of name {profile!r} in "
|
||||
f"host")
|
||||
log.debug(
|
||||
"removing unconnected profile {profile!r}")
|
||||
del host.profiles[profile]
|
||||
entity = host.profiles[profile] = cls(
|
||||
host, profile, entity_jid, password,
|
||||
host.memory.getParamA(C.FORCE_SERVER_PARAM, "Connection",
|
||||
profile_key=profile) or None,
|
||||
port, max_retries,
|
||||
)
|
||||
|
||||
entity.identityHandler = SatIdentityHandler()
|
||||
entity.identityHandler.setHandlerParent(entity)
|
||||
await entity.encryption.loadSessions()
|
||||
|
||||
log.debug(_("setting plugins parents"))
|
||||
entity._createSubProtocols()
|
||||
|
||||
plugin_conn_cb = await entity._callConnectionTriggers()
|
||||
entity.fallBack = SatFallbackHandler(host)
|
||||
entity.fallBack.setHandlerParent(entity)
|
||||
|
||||
entity.startService()
|
||||
entity.versionHandler = SatVersionHandler(C.APP_NAME_FULL, host.full_version)
|
||||
entity.versionHandler.setHandlerParent(entity)
|
||||
|
||||
await entity.conn_deferred
|
||||
entity.identityHandler = SatIdentityHandler()
|
||||
entity.identityHandler.setHandlerParent(entity)
|
||||
|
||||
await defer.maybeDeferred(entity.entityConnected)
|
||||
log.debug(_("setting plugins parents"))
|
||||
|
||||
# Call profileConnected callback for all plugins,
|
||||
# and print error message if any of them fails
|
||||
conn_cb_list = []
|
||||
for __, callback in plugin_conn_cb:
|
||||
conn_cb_list.append(utils.asDeferred(callback, entity))
|
||||
list_d = defer.DeferredList(conn_cb_list)
|
||||
plugin_conn_cb = await entity._callConnectionTriggers()
|
||||
|
||||
def logPluginResults(results):
|
||||
all_succeed = all([success for success, result in results])
|
||||
if not all_succeed:
|
||||
log.error(_("Plugins initialisation error"))
|
||||
for idx, (success, result) in enumerate(results):
|
||||
if not success:
|
||||
log.error(
|
||||
"error (plugin %(name)s): %(failure)s"
|
||||
% {
|
||||
"name": plugin_conn_cb[idx][0]._info["import_name"],
|
||||
"failure": result,
|
||||
}
|
||||
)
|
||||
entity.startService()
|
||||
|
||||
await list_d.addCallback(
|
||||
logPluginResults
|
||||
) # FIXME: we should have a timeout here, and a way to know if a plugin freeze
|
||||
# TODO: mesure launch time of each plugin
|
||||
await entity.conn_deferred
|
||||
|
||||
cls.profiles_connecting.remove(profile)
|
||||
await defer.maybeDeferred(entity.entityConnected)
|
||||
|
||||
# Call profileConnected callback for all plugins,
|
||||
# and print error message if any of them fails
|
||||
conn_cb_list = []
|
||||
for __, callback in plugin_conn_cb:
|
||||
conn_cb_list.append(utils.asDeferred(callback, entity))
|
||||
list_d = defer.DeferredList(conn_cb_list)
|
||||
|
||||
def logPluginResults(results):
|
||||
all_succeed = all([success for success, result in results])
|
||||
if not all_succeed:
|
||||
log.error(_("Plugins initialisation error"))
|
||||
for idx, (success, result) in enumerate(results):
|
||||
if not success:
|
||||
log.error(
|
||||
"error (plugin %(name)s): %(failure)s"
|
||||
% {
|
||||
"name": plugin_conn_cb[idx][0]._info["import_name"],
|
||||
"failure": result,
|
||||
}
|
||||
)
|
||||
|
||||
await list_d.addCallback(
|
||||
logPluginResults
|
||||
) # FIXME: we should have a timeout here, and a way to know if a plugin freeze
|
||||
# TODO: mesure launch time of each plugin
|
||||
finally:
|
||||
cls.profiles_connecting.remove(profile)
|
||||
|
||||
def _disconnectionCb(self, __):
|
||||
self._connected_d = None
|
||||
|
|
|
|||
Loading…
Reference in a new issue