comparison src/memory/memory.py @ 2144:1d3f73e065e1

core, jp: component handling + client handling refactoring: - SàT can now handle components - plugin have now a "modes" key in PLUGIN_INFO where they declare if they can be used with clients and or components. They default to be client only. - components are really similar to clients, but with some changes in behaviour: * component has "entry point", which is a special plugin with a componentStart method, which is called just after component is connected * trigger end with a different suffixes (e.g. profileConnected vs profileConnectedComponent), so a plugin which manage both clients and components can have different workflow * for clients, only triggers of plugins handling client mode are launched * for components, only triggers of plugins needed in dependencies are launched. They all must handle component mode. * component have a sendHistory attribute (False by default) which can be set to True to allow saving sent messages into history * for convenience, "client" is still used in method even if it can now be a component * a new "component" boolean attribute tells if we have a component or a client * components have to add themselve Message protocol * roster and presence protocols are not added for components * component default port is 5347 (which is Prosody's default port) - asyncCreateProfile has been renamed for profileCreate, both to follow new naming convention and to prepare the transition to fully asynchronous bridge - createProfile has a new "component" attribute. When used to create a component, it must be set to a component entry point - jp: added --component argument to profile/create - disconnect bridge method is now asynchronous, this way frontends can know when disconnection is finished - new PI_* constants for PLUGIN_INFO values (not used everywhere yet) - client/component connection workflow has been moved to their classes instead of being a host methods - host.messageSend is now client.sendMessage, and former client.sendMessage is now client.sendMessageData. - identities are now handled in client.identities list, so it can be updated dynamically by plugins (in the future, frontends should be able to update them too through bridge) - profileConnecting* profileConnected* profileDisconnected* and getHandler now all use client instead of profile
author Goffi <goffi@goffi.org>
date Sun, 12 Feb 2017 17:55:43 +0100
parents d44efd32bc2f
children 1bb9bf1b4150
comparison
equal deleted inserted replaced
2143:c3cac21157d4 2144:1d3f73e065e1
451 # we want to be sure that the profile exists 451 # we want to be sure that the profile exists
452 profile = self.getProfileName(profile) 452 profile = self.getProfileName(profile)
453 453
454 self.memory_data['Profile_default'] = profile 454 self.memory_data['Profile_default'] = profile
455 455
456 def asyncCreateProfile(self, name, password): 456 def createProfile(self, name, password, component=None):
457 """Create a new profile 457 """Create a new profile
458 @param name (unicode): profile name 458
459 @param password (unicode): profile password 459 @param name(unicode): profile name
460 @param password(unicode): profile password
460 Can be empty to disable password 461 Can be empty to disable password
462 @param component(None, unicode): set to entry point if this is a component
461 @return: Deferred 463 @return: Deferred
464 @raise exceptions.NotFound: component is not a known plugin import name
462 """ 465 """
463 if not name: 466 if not name:
464 raise ValueError(u"Empty profile name") 467 raise ValueError(u"Empty profile name")
465 if name[0] == '@': 468 if name[0] == '@':
466 raise ValueError(u"A profile name can't start with a '@'") 469 raise ValueError(u"A profile name can't start with a '@'")
468 raise ValueError(u"A profile name can't contain line feed ('\\n')") 471 raise ValueError(u"A profile name can't contain line feed ('\\n')")
469 472
470 if name in self._entities_cache: 473 if name in self._entities_cache:
471 raise exceptions.ConflictError(u"A session for this profile exists") 474 raise exceptions.ConflictError(u"A session for this profile exists")
472 475
473 d = self.params.asyncCreateProfile(name) 476 if component:
477 if not component in self.host.plugins:
478 raise exceptions.NotFound(_(u"Can't find component {component} entry point".format(
479 component = component)))
480 # FIXME: PLUGIN_INFO is not currently accessible after import, but type shoul be tested here
481 # if self.host.plugins[component].PLUGIN_INFO[u"type"] != C.PLUG_TYPE_ENTRY_POINT:
482 #  raise ValueError(_(u"Plugin {component} is not an entry point !".format(
483 #  component = component)))
484
485 d = self.params.createProfile(name, component)
474 486
475 def initPersonalKey(dummy): 487 def initPersonalKey(dummy):
476 # be sure to call this after checking that the profile doesn't exist yet 488 # be sure to call this after checking that the profile doesn't exist yet
477 personal_key = BlockCipher.getRandomKey(base64=True) # generated once for all and saved in a PersistentDict 489 personal_key = BlockCipher.getRandomKey(base64=True) # generated once for all and saved in a PersistentDict
478 self.auth_sessions.newSession({C.MEMORY_CRYPTO_KEY: personal_key}, profile=name) # will be encrypted by setParam 490 self.auth_sessions.newSession({C.MEMORY_CRYPTO_KEY: personal_key}, profile=name) # will be encrypted by setParam
493 d.addCallback(lambda dummy: self.auth_sessions.profileDelUnique(name)) 505 d.addCallback(lambda dummy: self.auth_sessions.profileDelUnique(name))
494 return d 506 return d
495 507
496 def asyncDeleteProfile(self, name, force=False): 508 def asyncDeleteProfile(self, name, force=False):
497 """Delete an existing profile 509 """Delete an existing profile
510
498 @param name: Name of the profile 511 @param name: Name of the profile
499 @param force: force the deletion even if the profile is connected. 512 @param force: force the deletion even if the profile is connected.
500 To be used for direct calls only (not through the bridge). 513 To be used for direct calls only (not through the bridge).
501 @return: a Deferred instance 514 @return: a Deferred instance
502 """ 515 """
507 except KeyError: 520 except KeyError:
508 pass 521 pass
509 d = self.params.asyncDeleteProfile(name, force) 522 d = self.params.asyncDeleteProfile(name, force)
510 d.addCallback(cleanMemory) 523 d.addCallback(cleanMemory)
511 return d 524 return d
525
526 def isComponent(self, profile_name):
527 """Tell if a profile is a component
528
529 @param profile_name(unicode): name of the profile
530 @return (bool): True if profile is a component
531 @raise exceptions.NotFound: profile doesn't exist
532 """
533 return self.storage.profileIsComponent(profile_name)
534
535 def getEntryPoint(self, profile_name):
536 """Get a component entry point
537
538 @param profile_name(unicode): name of the profile
539 @return (bool): True if profile is a component
540 @raise exceptions.NotFound: profile doesn't exist
541 """
542 return self.storage.getEntryPoint(profile_name)
512 543
513 ## History ## 544 ## History ##
514 545
515 def addToHistory(self, client, data): 546 def addToHistory(self, client, data):
516 return self.storage.addToHistory(data, client.profile) 547 return self.storage.addToHistory(data, client.profile)