def __split_group_message(self, msg: ReliableMessage,
                           members: List[ID]) -> Optional[Content]:
     """ Split group message for each member """
     messages = msg.split(members=members)
     success_list = []
     failed_list = []
     for item in messages:
         if item.delegate is None:
             item.delegate = msg.delegate
         if self.__forward_group_message(msg=item):
             success_list.append(item.receiver)
         else:
             failed_list.append(item.receiver)
     response = ReceiptCommand(message='Group message delivering')
     if len(success_list) > 0:
         response['success'] = ID.revert(success_list)
     if len(failed_list) > 0:
         response['failed'] = ID.revert(failed_list)
         # failed to get keys for this members,
         # query from sender by invite members
         sender = msg.sender
         group = msg.receiver
         cmd = GroupCommand.invite(group=group, members=failed_list)
         self.send_content(sender=None, receiver=sender, content=cmd)
     return response
Example #2
0
 def execute(self, cmd: Command, msg: ReliableMessage) -> Optional[Content]:
     assert isinstance(cmd, InviteCommand) or isinstance(cmd, ResetCommand), 'group command error: %s' % cmd
     facebook = self.facebook
     from ..facebook import Facebook
     assert isinstance(facebook, Facebook), 'entity delegate error: %s' % facebook
     # 0. check group
     group = cmd.group
     owner = facebook.owner(identifier=group)
     members = facebook.members(identifier=group)
     if owner is None or members is None or len(members) == 0:
         # FIXME: group profile lost?
         # FIXME: how to avoid strangers impersonating group members?
         return self.__temporary_save(cmd=cmd, sender=msg.sender)
     # 1. check permission
     sender = msg.sender
     if sender != owner:
         # not the owner? check assistants
         assistants = facebook.assistants(identifier=group)
         if assistants is None or sender not in assistants:
             text = '%s is not the owner/assistant of group %s, cannot reset members' % (sender, group)
             raise AssertionError(text)
     # 2. resetting members
     new_members = self.members(cmd=cmd)
     if new_members is None or len(new_members) == 0:
         raise ValueError('group command error: %s' % cmd)
     # 2.1. check owner
     if owner not in new_members:
         raise AssertionError('cannot expel owner (%s) of group: %s' % (owner, group))
     # 2.2. build expelled-list
     remove_list = []
     for item in members:
         if item not in new_members:
             # removing member found
             remove_list.append(item)
     # 2.3. build invited-list
     add_list = []
     for item in new_members:
         if item not in members:
             # adding member found
             add_list.append(item)
     # 2.4. do reset
     if len(add_list) > 0 or len(remove_list) > 0:
         if facebook.save_members(members=new_members, identifier=group):
             if len(add_list) > 0:
                 cmd['added'] = ID.revert(add_list)
             if len(remove_list) > 0:
                 cmd['removed'] = ID.revert(remove_list)
     # 3. response (no need to response this group command)
     return None
Example #3
0
 def __broadcast_message(self, msg: ReliableMessage) -> Optional[Content]:
     """ Deliver message to everyone@everywhere, including all neighbours """
     self.debug('broadcasting message from: %s' % msg.sender)
     if self.__traced(msg=msg, station=self.station):
         self.error('ignore traced msg: %s in %s' % (self.station, msg.get('traces')))
         return None
     session_server = self.session_server
     # push to all neighbors connected th current station
     neighbors = self.__neighbors.copy()
     sent_neighbors = []
     success = 0
     for sid in neighbors:
         if sid == self.station:
             continue
         sessions = session_server.active_sessions(identifier=sid)
         if len(sessions) == 0:
             self.warning('remote station (%s) not connected, try later.' % sid)
             continue
         if self.__push_message(msg=msg, receiver=sid, sessions=sessions):
             sent_neighbors.append(sid)
             success += 1
     # push to the bridge (octopus) of current station
     sid = self.station
     sessions = session_server.active_sessions(identifier=sid)
     if len(sessions) > 0:
         # tell the bridge ignore this neighbor stations
         sent_neighbors.append(sid)
         msg['sent_neighbors'] = ID.revert(sent_neighbors)
         self.__push_message(msg=msg, receiver=sid, sessions=sessions)
     # FIXME: what about the failures
     # response
     text = 'Message broadcast to %d/%d stations' % (success, len(neighbors))
     res = TextContent(text=text)
     res.group = msg.group
     return res
Example #4
0
 def save_contacts(self, contacts: List[ID], user: ID) -> bool:
     assert contacts is not None, 'contacts cannot be empty'
     # store into memory cache
     self.__contacts[user] = contacts
     # store into local storage
     path = self.__contacts_path(identifier=user)
     self.info('Saving contacts into: %s' % path)
     contacts = ID.revert(members=contacts)
     text = '\n'.join(contacts)
     return self.write_text(text=text, path=path)
Example #5
0
 def save_members(self, members: List[ID], group: ID) -> bool:
     assert len(
         members) > 0, 'group members should not be empty: %s' % group
     # 1. store into memory cache
     self.__members[group] = members
     # 2. store into local storage
     path = self.__members_path(identifier=group)
     self.info('Saving members into: %s' % path)
     members = ID.revert(members=members)
     text = '\n'.join(members)
     return self.write_text(text=text, path=path)
Example #6
0
 def execute(self, cmd: Command, msg: ReliableMessage) -> Optional[Content]:
     assert isinstance(cmd, InviteCommand), 'group command error: %s' % cmd
     facebook = self.facebook
     from ..facebook import Facebook
     assert isinstance(facebook,
                       Facebook), 'entity delegate error: %s' % facebook
     # 0. check group
     group = cmd.group
     owner = facebook.owner(identifier=group)
     members = facebook.members(identifier=group)
     if owner is None or members is None or len(members) == 0:
         # NOTICE: group membership lost?
         #         reset group members
         return self.__reset(cmd=cmd, msg=msg)
     # 1. check permission
     sender = msg.sender
     if sender not in members:
         # not a member? check assistants
         assistants = facebook.assistants(identifier=group)
         if assistants is None or sender not in assistants:
             raise AssertionError('only member/assistant can invite: %s' %
                                  msg)
     # 2. inviting members
     invite_list = self.members(cmd=cmd)
     if invite_list is None or len(invite_list) == 0:
         raise ValueError('invite command error: %s' % cmd)
     # 2.1. check for reset
     if sender == owner and owner in invite_list:
         # NOTICE: owner invites owner?
         #         it means this should be a 'reset' command
         return self.__reset(cmd=cmd, msg=msg)
     # 2.2. build invited-list
     add_list = []
     for item in invite_list:
         if item in members:
             continue
         # new member found
         add_list.append(item)
         members.append(item)
     # 2.3. do invite
     if len(add_list) > 0:
         if facebook.save_members(members=members, identifier=group):
             cmd['added'] = ID.revert(add_list)
     # 3. response (no need to response this group command)
     return None
Example #7
0
 def execute(self, cmd: Command, msg: ReliableMessage) -> Optional[Content]:
     assert isinstance(cmd, ExpelCommand), 'group command error: %s' % cmd
     facebook = self.facebook
     from ..facebook import Facebook
     assert isinstance(facebook,
                       Facebook), 'entity delegate error: %s' % facebook
     # 0. check group
     group = cmd.group
     owner = facebook.owner(identifier=group)
     members = facebook.members(identifier=group)
     if owner is None or members is None or len(members) == 0:
         raise LookupError('Group not ready: %s' % group)
     # 1. check permission
     sender = msg.sender
     if sender != owner:
         # not the owner? check assistants
         assistants = facebook.assistants(identifier=group)
         if assistants is None or sender not in assistants:
             text = '%s is not the owner/assistant of group %s, cannot expel member' % (
                 sender, group)
             raise AssertionError(text)
     # 2. expelling members
     expel_list = self.members(cmd=cmd)
     if expel_list is None or len(expel_list) == 0:
         raise ValueError('expel command error: %s' % cmd)
     # 2.1. check owner
     if owner in expel_list:
         raise AssertionError('cannot expel owner %s of group %s' %
                              (owner, group))
     # 2.2. build removed-list
     remove_list = []
     for item in expel_list:
         if item not in members:
             continue
         # expelled member found
         remove_list.append(item)
         members.remove(item)
     # 2.3. do expel
     if len(remove_list) > 0:
         if facebook.save_members(members=members, identifier=group):
             cmd['removed'] = ID.revert(remove_list)
     # 3. response (no need to response this group command)
     return None
Example #8
0
 def __traced(self, msg: ReliableMessage, station: ID) -> bool:
     traces = msg.get('traces')
     if traces is None:
         # broadcast message starts from here
         traces = [station]
     else:
         for node in traces:
             if isinstance(node, str):
                 if station == node:
                     return True
             elif isinstance(node, dict):
                 if station == node.get('ID'):
                     return True
             else:
                 self.error('traces node error: %s' % node)
         # broadcast message go through here
         traces.append(station)
     msg['traces'] = ID.revert(members=traces)
     return False
Example #9
0
 def users(self, value: List[ID]):
     if value is None:
         self.pop('users', None)
     else:
         self['users'] = ID.revert(members=value)
     self.__users = value
Example #10
0
 def mute_list(self, value: List[ID]):
     if value is None:
         self.pop('list', None)
     else:
         self['list'] = ID.revert(members=value)