Example #1
0
    def __init__(self):
        signal.signal(signal.SIGTERM,self._stop_signal_handling)
        signal.signal(signal.SIGQUIT,self._stop_signal_handling)
        signal.signal(signal.SIGINT,self._stop_signal_handling)
        signal.signal(signal.SIGCHLD,self._child_death)
            
        self._outputs_subscribers = []      # instances that want to receive output text from controller
        self._outputs_queue = Queue()       # queue for text to be output by instances to controller
        self._commands_queue = Queue()      # queue for commands to be output by instances to controller
        self._config()
        
        # Starting the thread that will receive text to process (display/save/send)
        self._receive_outputs_thread = mythreading.ReceiveQueueThread(self.output_text,self._outputs_queue)
        self._receive_outputs_thread.start()
        
        # Loading modules and starting instances configured for auto start
        self._modules = BotModules(self._MODULE_PATH)        

        self.translator = BotCommandTranslator(self._modules)  

        
        
        #TODO: add more controller commands
        self._commands = {}
        self.add_command(BotCommand(name='shutdown',command='self.shutdown()'))
        self.add_command(BotCommand(name='list',command='self.list_modules()'))
        command = BotCommand(name='start',command='self.start(arguments)')
        command.add_argument('module', '.+')
        self.add_command(command)
        command = BotCommand(name='stop',command='self.stop(arguments)')
        command.add_argument('module', '.+')
        self.add_command(command)
        command = BotCommand(name='reload',command='self.reload(arguments)')
        command.add_argument('module', '.+')
        self.add_command(command)
Example #2
0
class MyBot(object):
    
    name = "MyBot"
    _MODULE_PATH='modules/'
    _THREAD_TIMEOUT_SECS = 5.0
    
    def __init__(self):
        signal.signal(signal.SIGTERM,self._stop_signal_handling)
        signal.signal(signal.SIGQUIT,self._stop_signal_handling)
        signal.signal(signal.SIGINT,self._stop_signal_handling)
        signal.signal(signal.SIGCHLD,self._child_death)
            
        self._outputs_subscribers = []      # instances that want to receive output text from controller
        self._outputs_queue = Queue()       # queue for text to be output by instances to controller
        self._commands_queue = Queue()      # queue for commands to be output by instances to controller
        self._config()
        
        # Starting the thread that will receive text to process (display/save/send)
        self._receive_outputs_thread = mythreading.ReceiveQueueThread(self.output_text,self._outputs_queue)
        self._receive_outputs_thread.start()
        
        # Loading modules and starting instances configured for auto start
        self._modules = BotModules(self._MODULE_PATH)        

        self.translator = BotCommandTranslator(self._modules)  

        
        
        #TODO: add more controller commands
        self._commands = {}
        self.add_command(BotCommand(name='shutdown',command='self.shutdown()'))
        self.add_command(BotCommand(name='list',command='self.list_modules()'))
        command = BotCommand(name='start',command='self.start(arguments)')
        command.add_argument('module', '.+')
        self.add_command(command)
        command = BotCommand(name='stop',command='self.stop(arguments)')
        command.add_argument('module', '.+')
        self.add_command(command)
        command = BotCommand(name='reload',command='self.reload(arguments)')
        command.add_argument('module', '.+')
        self.add_command(command)

    
    def add_command(self,command):
        self._commands[command.name]=command

    def _config(self):
        config_parser = ConfigParser()
        config_file_path = 'MyBot.cfg' #TODO: set this elsewhere
        config_parser.read(config_file_path)
        configuration_values={'LogLevel': logging.DEBUG}         # set default values here
        if not config_parser.has_section('Initialization'):
            config_parser.add_section('Initialization')
            
        for default in configuration_values:
            if config_parser.has_option('Initialization', default):
                configuration_values[default] = config_parser.get('Initialization', default)
            else:
                config_parser.set('Initialization', default, configuration_values[default])
        
        config_parser.write(open(config_file_path,"w"))
        self.log = logging.getLogger(self.name)
        self.log.setLevel(int(configuration_values['LogLevel']))
        self.log.add_log_file('common.log')
        self.log.debug('Initializing MyBot with PID %d...' % os.getpid())
        
    def _child_death(self,signum,frame):
        (pid,exit_code) = os.wait()
        try:
            instance = self._modules.get_running_instance(pid)
            self._modules.remove_running_instance(pid)
        except ValueError:
            self.log.error('Not a running instance?')
            return
        if exit_code != 0:
            self.log.error('%s crashed with exit code %d' % (instance.name,exit_code))
            self.output_text('%s crashed with exit code %d' % (instance.name,exit_code))
            #TODO: actions? restart? notify?
        else:
            self.output_text('%s stopped.' % (instance.name))

    def _stop_signal_handling(self,signum,frame):
        self.shutdown()

    # COMMANDS
    def reload(self,arguments=None):
        if arguments:
            module_name=arguments[0]
            module = self._modules.get_modules()[module_name]
            instances = module.get_instances().values()
            for instance in instances:
                self.stop({'module':instance.name})
                self._modules.remove_instance(module, instance.name)
                #TODO: wait for instances to stop?
            self.list_modules()
            del self._modules.get_modules()[module_name]
            file_path = module.file_path
            module = None
            module = self._modules.load_module(file_path)
            self._modules.initialize_module(module)
            print('Final')
            self.list_modules()
                
    def start(self,arguments=None):
        if arguments:
            instance_name = arguments['module']
            instance = self._modules.get_instance(instance_name)
            if instance:
                self.output_text('Starting %s ' % instance.name)
                instance.set_output_queue(self._outputs_queue)
                instance.check_outputs_subscriber(self._outputs_subscribers)
                instance.set_output_commands_queue(self._commands_queue)
                if instance.start():
                    self._modules.add_running_instance(instance)
            else:
                self.output_text('Instance not known: %s' % instance_name)                              
                
    def stop(self,arguments=None):
        if arguments:
            instance = self._modules.get_instance(arguments['module'])
            if instance:
                if instance.running():
                    self.output_text('Stopping %s ' % instance.name)
                    instance.stop()
                    #TODO: check if instance really stopped
                    
    def shutdown(self,arguments=None):
        if self._shuttingdown:
            return
        self._shuttingdown = True
        self.output_text('Controller shutting down...')
        
        # Shutting down instances of modules
        instances = self._modules.get_instances()
        for instance_name in instances:
            instance = self._modules.get_instance(instance_name)
            if instance.running():
                instance.stop()
                        
        if self._receive_outputs_thread:
            self._receive_outputs_thread.stop()
        self._receive_outputs_thread.join(self._THREAD_TIMEOUT_SECS)
 
        #TODO: not sure if this is necessary
        if self._receive_outputs_thread.is_alive():
            self.log.error('Receive outputs thread is taking too long to close...')
        self.log.debug('Outputs thread closed.')   
        logging.shutdown()
        
    def _get_module(self,module_name):
        if self._modules.get_instances().has_key(module_name):
            return self._modules.get_instances()[module_name]
        return False

    def list_modules(self,arguments=None):
        modules = self._modules.get_modules().values()
        running_instances = self._modules.get_running_instances()
        text = ''
        for module in modules:
            text = text + "\nInstances of %s: \n" % module.name
            instances = module.get_instances()
            if not instances:
                text = text + '** No instances available! \n'
                continue
            for instance in instances.values():
                if running_instances.has_key(instance.pid()):
                    status = 'Running with PID %d' % instance.pid()
                else:
                    status = 'Stopped'
                text = text + "\t%s\t\t%s\n" % (instance.name,status)
        self.output_text("%s\n" % text)
 
    # EO COMMANDS /
    
                
    def output_text(self,text):
        ''' Handle the output of text directing it to the available outputs '''
        sys.stdout.write(str(text)+"\n")
        for o in self._outputs_subscribers:
            if o: #TODO: review this 'if'
                o.put(str(text)+"\n")
    
    def execute_command(self,command_line):
        try:
            # translate command line into a command
            command = self.translator.validate_command(command_line)
        except BotCommandException, e:
            self.output_text(e.message)
            return
        if command==True:
            # just started or ended a conversation
            try:
                self.output_text('%s is listening ...' % self.translator.get_current_destination().name)
            except AttributeError:
                self.output_text('Bye...')
            return
        
        if command:
            if not command.destination_name:
                # command sent to controller
                #TODO: remove this when controller has been migrated to a module
                try:
                    available_command = self._commands[command.name]
                    arguments = available_command.validate(command.arguments)
                    exec(available_command.command)
                    return
                except KeyError:
                    self.output_text('KeyError: Unknown command: %s\n' % command_line)
                    return
                except Exception,e:
                    self.output_text(str(e))
                    return
            self._modules.get_instance(command.destination_name).queue_command(command)