Esempio n. 1
0
    def __init__(self,
                 context=None,
                 prompt_name='vexbot',
                 publish_address=None,
                 subscribe_address=None,
                 **kwargs):

        super().__init__()
        self.messaging = ZmqMessaging('shell', publish_address,
                                      subscribe_address, 'shell')

        self.command_manager = CommandManager(self.messaging)
        # FIXME
        self.command_manager._commands.pop('commands')
        self.stdout.write('Vexbot {}\n'.format(__version__))
        if kwargs.get('already_running', False):
            self.stdout.write('vexbot already running\n')
        self.stdout.write("Type \"help\" for command line help or "
                          "\"commands\" for bot commands\n\n")

        self.command_manager.register_command('start_vexbot', _start_vexbot)

        self.messaging.start_messaging()

        self.prompt = prompt_name + ': '
        self.misc_header = "Commands"
        self._exit_loop = False
        self._set_readline_helper(kwargs.get('history_file'))
Esempio n. 2
0
    def __init__(self, streamer_name, namespace, website_url, publish_address,
                 subscribe_address, service_name):

        self.log = logging.getLogger(__name__)
        self.log.setLevel(0)
        if not _WEBSOCKET_INSTALLED:
            self.log.error('Must install `websocket`')
        if not _REQUESTS_INSTALLED:
            self.log.error('Must install `requests')

        self.messaging = ZmqMessaging(service_name, publish_address,
                                      subscribe_address, service_name)

        self.messaging.start_messaging()
        self._streamer_name = streamer_name
        self.namespace = namespace
        self._website_url = website_url
        self.log.info('Getting Socket IO key!')
        self.key, heartbeat = self._connect_to_server_helper()
        self.log.info('Socket IO key got!')
        self.command_manager = AdapterCommandManager(self.messaging)
        self._thread = Thread(target=self.handle_subscription)
        self._thread.daemon = True
        self._thread.start()

        # alters URL to be more websocket...ie
        self._website_socket = self._website_url.replace('http', 'ws')
        self._website_socket += 'websocket/'
        self.nick = None
        super().__init__(self._website_socket + self.key,
                         on_open=self.on_open,
                         on_close=self.on_close,
                         on_message=self.on_message,
                         on_error=self.on_error)
Esempio n. 3
0
def main(nick,
         password,
         host,
         channel,
         publish_address,
         subscribe_address,
         service_name):

    if not _IRC3_INSTALLED:
        logging.error('irc requires `irc3` to be installed. Please install '
                      'using `pip install irc3`')

    irc_client = create_irc_bot(nick,
                                password,
                                host,
                                channel=channel)

    try:
        messaging = ZmqMessaging(service_name,
                                 publish_address,
                                 subscribe_address,
                                 socket_filter=service_name)

        messaging.start_messaging()
    except ZMQError:
        return
    # Duck type messaging onto irc_client, FTW
    irc_client.messaging = messaging
    command_parser = AdapterCommandManager(messaging)
    irc_client.command_parser = command_parser

    """
    command_parser.register_command('server config', _default)
    command_parser.register_command('ip', _default)
    command_parser.register_command('join', _default)
    command_parser.register_command('kick', _default)
    command_parser.register_command('part', _default)
    command_parser.register_command('invite', _default)
    command_parser.register_command('topic', _default)
    command_parser.register_command('away', _default)
    """

    irc_client.create_connection()
    irc_client.add_signal_handlers()
    event_loop = asyncio.get_event_loop()
    asyncio.ensure_future(_check_subscription(irc_client))
    atexit.register(_send_disconnected(messaging))

    handle_close = _handle_close(messaging, event_loop)
    signal.signal(signal.SIGINT, handle_close)
    signal.signal(signal.SIGTERM, handle_close)
    try:
        event_loop.run_forever()
    except KeyboardInterrupt:
        pass
    event_loop.close()
    sys.exit()
Esempio n. 4
0
    def __init__(self,
                 context=None,
                 prompt_name='vexbot',
                 publish_address=None,
                 subscribe_address=None,
                 **kwargs):

        super().__init__()
        self.messaging = ZmqMessaging('shell',
                                      publish_address,
                                      subscribe_address,
                                      'shell')

        self.command_manager = CommandManager(self.messaging)
        # FIXME
        self.command_manager._commands.pop('commands')
        self.stdout.write('Vexbot {}\n'.format(__version__))
        if kwargs.get('already_running', False):
            self.stdout.write('vexbot already running\n')
        self.stdout.write("Type \"help\" for command line help or "
                          "\"commands\" for bot commands\n\n")

        self.command_manager.register_command('start_vexbot',
                                              _start_vexbot)

        self.messaging.start_messaging()

        self.prompt = prompt_name + ': '
        self.misc_header = "Commands"
        self._exit_loop = False
        self._set_readline_helper(kwargs.get('history_file'))
Esempio n. 5
0
def main(client_secret_filepath, publish_address, subscribe_address):
    if not _GOOGLE_API_INSTALLED:
        logging.error(
            '`google-api-python-client` required to use youtube. Install using `pip install google-api-python-client'
        )
        return

    # TODO: Determine if this try/except pattern has become outdated
    # with new `connect` methods being called rather than the old bind
    try:
        messaging = ZmqMessaging('youtube', publish_address, subscribe_address,
                                 'youtube')

        messaging.start_messaging()
    except ZMQError:
        return

    # signal.signal(signal.SIGINT, handle_close)
    # signal.signal(signal.SIGTERM, handle_close)
    # handle_close = _handle_close(messaging)

    scope = [
        'https://www.googleapis.com/auth/youtube',
        'https://www.googleapis.com/auth/youtube.force-ssl',
        'https://www.googleapis.com/auth/youtube.readonly'
    ]

    youtube_api = _youtube_authentication(client_secret_filepath, scope)
    parts = 'snippet'
    livestream_response = youtube_api.liveBroadcasts().list(
        mine=True, part=parts, maxResults=1).execute()

    live_chat_id = livestream_response.get('items')[0]['snippet']['liveChatId']

    livechat_response = youtube_api.liveChatMessages().list(
        liveChatId=live_chat_id, part='snippet').execute()

    next_token = livechat_response.get('nextPageToken')
    polling_interval = livechat_response.get('pollingIntervalMillis')
    polling_interval = _convert_to_seconds(polling_interval)
    messaging.send_status('CONNECTED')

    event_loop = asyncio.get_event_loop()
    asyncio.ensure_future(
        _recv_loop(messaging, youtube_api, live_chat_id, next_token,
                   polling_interval))

    asyncio.ensure_future(
        _run(messaging, youtube_api.liveChatMessages(), live_chat_id))

    atexit.register(_send_disconnect(messaging))
    event_loop.run_forever()

    messaging.send_status('DISCONNECTED')
Esempio n. 6
0
def main(client_secret_filepath, publish_address, subscribe_address):
    if not _GOOGLE_API_INSTALLED:
        logging.error('`google-api-python-client` required to use youtube. Install using `pip install google-api-python-client')
        return

    # TODO: Determine if this try/except pattern has become outdated
    # with new `connect` methods being called rather than the old bind
    try:
        messaging = ZmqMessaging('youtube',
                                 publish_address,
                                 subscribe_address,
                                 'youtube')

        messaging.start_messaging()
    except ZMQError:
        return

    # signal.signal(signal.SIGINT, handle_close)
    # signal.signal(signal.SIGTERM, handle_close)
    # handle_close = _handle_close(messaging)

    scope = ['https://www.googleapis.com/auth/youtube',
             'https://www.googleapis.com/auth/youtube.force-ssl',
             'https://www.googleapis.com/auth/youtube.readonly']

    youtube_api = _youtube_authentication(client_secret_filepath, scope)
    parts = 'snippet'
    livestream_response = youtube_api.liveBroadcasts().list(mine=True,
                                                            part=parts,
                                                            maxResults=1).execute()


    live_chat_id = livestream_response.get('items')[0]['snippet']['liveChatId']

    livechat_response = youtube_api.liveChatMessages().list(liveChatId=live_chat_id, part='snippet').execute()

    next_token = livechat_response.get('nextPageToken')
    polling_interval = livechat_response.get('pollingIntervalMillis')
    polling_interval = _convert_to_seconds(polling_interval)
    messaging.send_status('CONNECTED')

    event_loop = asyncio.get_event_loop()
    asyncio.ensure_future(_recv_loop(messaging,
                                     youtube_api,
                                     live_chat_id,
                                     next_token,
                                     polling_interval))

    asyncio.ensure_future(_run(messaging,
                               youtube_api.liveChatMessages(),
                               live_chat_id))

    atexit.register(_send_disconnect(messaging))
    event_loop.run_forever()


    messaging.send_status('DISCONNECTED')
    def __init__(self,
                 url=None,
                 comment_element_id=None,
                 author_class_name=None,
                 message_class_name=None,
                 publish_address='',
                 subscribe_address='',
                 service_name=''):

        """
        `comment_element_id` is the css element where all the comments are,
        i.e., 'all-comments' for youtube

        `author_class_name` is the css class which holds the comment author
        username i.e., 'yt-user-name' for youtube

        `message_class_name` is the css class which holds the comment test
        ie., 'comment-text' for youtube
        """
        self.messaging = ZmqMessaging(service_name,
                                      publish_address,
                                      subscribe_address,
                                      'javascriptwebscraper')

        self.messaging.start_messaging()
        self.log = logging.getLogger(__name__)
        self.log.setLevel(logging.NOTSET)

        self.url = url
        self._number_of_messages = 0

        self.comment_element_id = comment_element_id
        self.author_class_name = author_class_name
        self.message_class_name = message_class_name
        self._driver = None
        self._kill = False
        signal.signal(signal.SIGINT, self._exit_gracefully)
        signal.signal(signal.SIGTERM, self._exit_gracefully)
Esempio n. 8
0
    def __init__(self,
                 jid,
                 password,
                 room,
                 publish_address,
                 subscribe_address,
                 service_name,
                 bot_nick='EchoBot',
                 **kwargs):

        # Initialize the parent class
        if not _SLEEKXMPP_INSTALLED:
            logging.error('must install sleekxmpp')

        super().__init__(jid, password)
        self.messaging = ZmqMessaging(service_name,
                                      publish_address,
                                      subscribe_address,
                                      service_name)

        self.messaging.start_messaging()
        self.command_manager = AdapterCommandManager(self.messaging)

        self.room = room
        self.nick = bot_nick
        self.log = logging.getLogger(__file__)

        # One-shot helper method used to register all the plugins
        self._register_plugin_helper()

        self.add_event_handler("session_start", self.start)
        self.add_event_handler("groupchat_message", self.muc_message)
        self.add_event_handler('connected', self._connected)
        self.add_event_handler('disconnected', self._disconnected)
        self._thread = Thread(target=self.run)
        self._thread.daemon = True
        self._thread.start()
Esempio n. 9
0
    def __init__(self,
                 streamer_name,
                 namespace,
                 website_url,
                 publish_address,
                 subscribe_address,
                 service_name):

        self.log = logging.getLogger(__name__)
        self.log.setLevel(0)
        if not _WEBSOCKET_INSTALLED:
            self.log.error('Must install `websocket`')
        if not _REQUESTS_INSTALLED:
            self.log.error('Must install `requests')

        self.messaging = ZmqMessaging(service_name,
                                      publish_address,
                                      subscribe_address,
                                      service_name)

        self.messaging.start_messaging()
        self._streamer_name = streamer_name
        self.namespace = namespace
        self._website_url = website_url
        self.log.info('Getting Socket IO key!')
        self.key, heartbeat = self._connect_to_server_helper()
        self.log.info('Socket IO key got!')
        self.command_manager = AdapterCommandManager(self.messaging)
        self._thread = Thread(target=self.handle_subscription)
        self._thread.daemon = True
        self._thread.start()

        # alters URL to be more websocket...ie
        self._website_socket = self._website_url.replace('http', 'ws')
        self._website_socket += 'websocket/'
        self.nick = None
        super().__init__(self._website_socket + self.key,
                         on_open=self.on_open,
                         on_close=self.on_close,
                         on_message=self.on_message,
                         on_error=self.on_error)
Esempio n. 10
0
class Shell(cmd.Cmd):
    def __init__(self,
                 context=None,
                 prompt_name='vexbot',
                 publish_address=None,
                 subscribe_address=None,
                 **kwargs):

        super().__init__()
        self.messaging = ZmqMessaging('shell', publish_address,
                                      subscribe_address, 'shell')

        self.command_manager = CommandManager(self.messaging)
        # FIXME
        self.command_manager._commands.pop('commands')
        self.stdout.write('Vexbot {}\n'.format(__version__))
        if kwargs.get('already_running', False):
            self.stdout.write('vexbot already running\n')
        self.stdout.write("Type \"help\" for command line help or "
                          "\"commands\" for bot commands\n\n")

        self.command_manager.register_command('start_vexbot', _start_vexbot)

        self.messaging.start_messaging()

        self.prompt = prompt_name + ': '
        self.misc_header = "Commands"
        self._exit_loop = False
        self._set_readline_helper(kwargs.get('history_file'))

    def default(self, arg):
        if not self.command_manager.is_command(arg, call_command=True):
            command, argument, line = self.parseline(arg)

            self.messaging.send_command(command=command,
                                        args=argument,
                                        line=line)

    def _set_readline_helper(self, history_file=None):
        try:
            import readline
        except ImportError:
            return

        try:
            readline.read_history_file(history_file)
        except IOError:
            pass
        readline.set_history_length(1000)
        atexit.register(readline.write_history_file, history_file)

    def run(self):
        frame = None
        while True and not self._exit_loop:
            try:
                # NOTE: not blocking here to check the _exit_loop condition
                frame = self.messaging.sub_socket.recv_multipart(zmq.NOBLOCK)
            except zmq.error.ZMQError:
                pass

            sleep(.5)

            if frame:
                message = decode_vex_message(frame)
                if message.type == 'RSP':
                    self.stdout.write("\n{}\n".format(self.doc_leader))
                    header = message.contents.get('original', 'Response')
                    contents = message.contents.get('response', None)
                    # FIXME
                    if (isinstance(header, (tuple, list))
                            and isinstance(contents,
                                           (tuple, list)) and contents):

                        for head, content in zip(header, contents):
                            self.print_topics(head, (contents, ), 15, 70)
                    else:
                        if isinstance(contents, str):
                            contents = (contents, )
                        self.print_topics(header, contents, 15, 70)

                    self.stdout.write("vexbot: ")
                    self.stdout.flush()

                else:
                    # FIXME
                    print(message.type, message.contents,
                          'fix me in shell adapter, run function')
                frame = None

    def _create_command_function(self, command):
        def resulting_function(arg):
            self.default(' '.join((command, arg)))

        return resulting_function

    def do_EOF(self, arg):
        self.stdout.write('\n')
        # NOTE: This ensures we exit out of the `run` method on EOF
        self._exit_loop = True
        return True

    def get_names(self):
        return dir(self)

    def do_help(self, arg):
        if arg:
            if self.command_manager.is_command(arg):
                doc = self.command_manager._commands[arg].__doc__
                if doc:
                    self.stdout.write("{}\n".format(str(doc)))
            else:
                self.messaging.send_command(command='help', args=arg)

        else:
            self.stdout.write("{}\n".format(self.doc_leader))
            # TODO: get these from robot?
            self.print_topics(self.misc_header, [
                'start vexbot\nhelp [foo]',
            ], 15, 80)

    def add_completion(self, command):
        setattr(self, 'do_{}'.format(command),
                self._create_command_function(command))

    """
Esempio n. 11
0
class WebSocket(WebSocketApp):
    def __init__(self,
                 streamer_name,
                 namespace,
                 website_url,
                 publish_address,
                 subscribe_address,
                 service_name):

        self.log = logging.getLogger(__name__)
        self.log.setLevel(0)
        if not _WEBSOCKET_INSTALLED:
            self.log.error('Must install `websocket`')
        if not _REQUESTS_INSTALLED:
            self.log.error('Must install `requests')

        self.messaging = ZmqMessaging(service_name,
                                      publish_address,
                                      subscribe_address,
                                      service_name)

        self.messaging.start_messaging()
        self._streamer_name = streamer_name
        self.namespace = namespace
        self._website_url = website_url
        self.log.info('Getting Socket IO key!')
        self.key, heartbeat = self._connect_to_server_helper()
        self.log.info('Socket IO key got!')
        self.command_manager = AdapterCommandManager(self.messaging)
        self._thread = Thread(target=self.handle_subscription)
        self._thread.daemon = True
        self._thread.start()

        # alters URL to be more websocket...ie
        self._website_socket = self._website_url.replace('http', 'ws')
        self._website_socket += 'websocket/'
        self.nick = None
        super().__init__(self._website_socket + self.key,
                         on_open=self.on_open,
                         on_close=self.on_close,
                         on_message=self.on_message,
                         on_error=self.on_error)

    def handle_subscription(self):
        while True:
            frame = self.messaging.sub_socket.recv_multipart()
            message = decode_vex_message(frame)
            if message.type == 'CMD':
                self.command_manager.parse_commands(message)
            if message.type == 'RSP':
                data = {}
                data['name'] = 'message'
                data['args'] = [message.contents.get('response'),
                                self._streamer_name]

                self.send_packet_helper(5, data)

    def repeat_run_forever(self):
        while True:
            try:
                self.run_forever()
            except (KeyboardInterrupt, SystemExit):
                break
            except Exception as e:
                self.log.info('Socket IO errors: {}'.format(e))
            self.messaging.send_status('DISCONNECTED')
            sleep(3)
            key, _ = self._connect_to_server_helper()
            self.url = self._website_socket + key

    def _connect_to_server_helper(self):
        r = requests.post(self._website_url)
        params = r.text

        # unused variables are connection_timeout and supported_formats
        key, heartbeat_timeout, _, _ = params.split(':')
        heartbeat_timeout = int(heartbeat_timeout)
        return key, heartbeat_timeout

    def on_open(self, *args):
        logging.info('Websocket open!')

    def on_close(self, *args):
        logging.info('Websocket closed :(')

    def on_message(self, *args):
        message = args[1].split(':', 3)
        key = int(message[0])
        # namespace = message[2]

        if len(message) >= 4:
            data = message[3]
        else:
            data = ''
        if key == 1 and args[1] == '1::':
            self.send_packet_helper(1)
        elif key == 1 and args[1] == '1::{}'.format(self.namespace):
            self.send_packet_helper(5, data={'name': 'initialize'})
            data = {'name': 'join',
                    'args': ['{}'.format(self._streamer_name)]}

            self.send_packet_helper(5, data=data)
            self.log.info('Connected to channel with socket io!')
            self.messaging.send_status('CONNECTED')
        elif key == 2:
            self.send_packet_helper(2)
        elif key == 5:
            data = json.loads(data, )
            if data['name'] == 'message':
                message = data['args'][0]
                sender = html.unescape(message['sender'])
                message = html.unescape(message['text'])
                self.messaging.send_message(author=sender, message=message)
            elif data['name'] == 'join':
                self.nick = data['args'][1]

    def on_error(self, *args):
        logging.error(args[1])

    def disconnect(self):
        callback = ''
        data = ''
        # '1::namespace'
        self.send(':'.join([str(self.TYPE_KEYS['DISCONNECT']),
                           callback, self.namespace, data]))

    def send_packet_helper(self,
                           type_key,
                           data=None):

        if data is None:
            data = ''
        else:
            data = json.dumps(data)

        # NOTE: callbacks currently not implemented
        callback = ''
        message = ':'.join([str(type_key), callback, self.namespace, data])
        self.send(message)
Esempio n. 12
0
class JavascriptWebscraper:
    def __init__(self,
                 url=None,
                 comment_element_id=None,
                 author_class_name=None,
                 message_class_name=None,
                 publish_address='',
                 subscribe_address='',
                 service_name=''):

        """
        `comment_element_id` is the css element where all the comments are,
        i.e., 'all-comments' for youtube

        `author_class_name` is the css class which holds the comment author
        username i.e., 'yt-user-name' for youtube

        `message_class_name` is the css class which holds the comment test
        ie., 'comment-text' for youtube
        """
        self.messaging = ZmqMessaging(service_name,
                                      publish_address,
                                      subscribe_address,
                                      'javascriptwebscraper')

        self.messaging.start_messaging()
        self.log = logging.getLogger(__name__)
        self.log.setLevel(logging.NOTSET)

        self.url = url
        self._number_of_messages = 0

        self.comment_element_id = comment_element_id
        self.author_class_name = author_class_name
        self.message_class_name = message_class_name
        self._driver = None
        self._kill = False
        signal.signal(signal.SIGINT, self._exit_gracefully)
        signal.signal(signal.SIGTERM, self._exit_gracefully)

    def _exit_gracefully(self, *args, **kwargs):
        if self._driver is not None:
            self._driver.quit()
        self._kill = True

    def run_forever(self):
        while True:
            try:
                self.log.info('Starting javascript scraper!')
                self.run()
            except selenium.common.exceptions.NoSuchElementException:
                self.log.error('Youtube parameters wrong, shutting down :(')
                break
            except Exception as e:
                if self._kill:
                    break
                else:
                    self.log.exception('Javascript error!', e)

    def run(self):
        if self._driver:
            self._driver.quit()
            self._driver = None
        self.log.info('starting up phantom javascript!')
        self._driver = webdriver.PhantomJS()
        # TODO: see if this is needed or not
        self._driver.set_window_size(1000, 1000)
        self._driver.get(self.url)

        # NOTE: need some time for comments to load
        self.log.info('youtube sleeping for 5 seconds!')
        sleep(5)
        self.log.info('youtube done sleeping')

        all_comments = self._driver.find_element_by_id(self.comment_element_id)
        # TODO: add in a signal here that all is connected!

        # NOTE: make sure this is ok if using for anything other than youtube
        comments = all_comments.find_elements_by_tag_name('li')
        self._number_of_messages = len(comments)
        self.messaging.send_status('CONNECTED')

        while True:
            sleep(1)
            comments = all_comments.find_elements_by_tag_name('li')
            comments_length = len(comments)

            if comments_length > self._number_of_messages:
                # NOTE: this number is intentionally NEGATIVE
                msgs_not_parsed = self._number_of_messages - comments_length

                self._number_of_messages = len(comments)
                comments = comments[msgs_not_parsed:]
                for comment in comments:
                    find_elem = comment.find_element_by_class_name
                    author = find_elem(self.author_class_name).text

                    message = find_elem(self.message_class_name).text
                    self.messaging.send_message(author=author, message=message)

        self.messaging.send_status('DISCONNECTED')
Esempio n. 13
0
class XMPPBot(ClientXMPP):
    def __init__(self,
                 jid,
                 password,
                 room,
                 publish_address,
                 subscribe_address,
                 service_name,
                 bot_nick='EchoBot',
                 **kwargs):

        # Initialize the parent class
        if not _SLEEKXMPP_INSTALLED:
            logging.error('must install sleekxmpp')

        super().__init__(jid, password)
        self.messaging = ZmqMessaging(service_name,
                                      publish_address,
                                      subscribe_address,
                                      service_name)

        self.messaging.start_messaging()
        self.command_manager = AdapterCommandManager(self.messaging)

        self.room = room
        self.nick = bot_nick
        self.log = logging.getLogger(__file__)

        # One-shot helper method used to register all the plugins
        self._register_plugin_helper()

        self.add_event_handler("session_start", self.start)
        self.add_event_handler("groupchat_message", self.muc_message)
        self.add_event_handler('connected', self._connected)
        self.add_event_handler('disconnected', self._disconnected)
        self._thread = Thread(target=self.run)
        self._thread.daemon = True
        self._thread.start()

    def run(self):
        while True:
            frame = self.messaging.sub_socket.recv_multipart()
            message = decode_vex_message(frame)
            if message.type == 'CMD':
                self.command_manager.parse_commands(message)
            elif message.type == 'RSP':
                channel = message.contents.get('channel')
                contents = message.contents.get('response')
                self.send_message(channel, contents, mtype='groupchat')

    def _disconnected(self, *args):
        self.messaging.send_status('DISCONNECTED')

    def _connected(self, *args):
        self.messaging.send_status('CONNECTED')

    def _register_plugin_helper(self):
        """
        One-shot helper method used to register all the plugins
        """
        # Service Discovery
        self.register_plugin('xep_0030')
        # XMPP Ping
        self.register_plugin('xep_0199')
        # Multiple User Chatroom
        self.register_plugin('xep_0045')

    def start(self, event):
        self.log.info('starting xmpp')
        self.send_presence()
        self.plugin['xep_0045'].joinMUC(self.room,
                                        self.nick,
                                        wait=True)

        self.get_roster()

    def muc_message(self, msg):
        self.messaging.send_message(author=msg['mucnick'],
                                    message=msg['body'],
                                    channel=msg['from'].bare)
Esempio n. 14
0
class WebSocket(WebSocketApp):
    def __init__(self, streamer_name, namespace, website_url, publish_address,
                 subscribe_address, service_name):

        self.log = logging.getLogger(__name__)
        self.log.setLevel(0)
        if not _WEBSOCKET_INSTALLED:
            self.log.error('Must install `websocket`')
        if not _REQUESTS_INSTALLED:
            self.log.error('Must install `requests')

        self.messaging = ZmqMessaging(service_name, publish_address,
                                      subscribe_address, service_name)

        self.messaging.start_messaging()
        self._streamer_name = streamer_name
        self.namespace = namespace
        self._website_url = website_url
        self.log.info('Getting Socket IO key!')
        self.key, heartbeat = self._connect_to_server_helper()
        self.log.info('Socket IO key got!')
        self.command_manager = AdapterCommandManager(self.messaging)
        self._thread = Thread(target=self.handle_subscription)
        self._thread.daemon = True
        self._thread.start()

        # alters URL to be more websocket...ie
        self._website_socket = self._website_url.replace('http', 'ws')
        self._website_socket += 'websocket/'
        self.nick = None
        super().__init__(self._website_socket + self.key,
                         on_open=self.on_open,
                         on_close=self.on_close,
                         on_message=self.on_message,
                         on_error=self.on_error)

    def handle_subscription(self):
        while True:
            frame = self.messaging.sub_socket.recv_multipart()
            message = decode_vex_message(frame)
            if message.type == 'CMD':
                self.command_manager.parse_commands(message)
            if message.type == 'RSP':
                data = {}
                data['name'] = 'message'
                data['args'] = [
                    message.contents.get('response'), self._streamer_name
                ]

                self.send_packet_helper(5, data)

    def repeat_run_forever(self):
        while True:
            try:
                self.run_forever()
            except (KeyboardInterrupt, SystemExit):
                break
            except Exception as e:
                self.log.info('Socket IO errors: {}'.format(e))
            self.messaging.send_status('DISCONNECTED')
            sleep(3)
            key, _ = self._connect_to_server_helper()
            self.url = self._website_socket + key

    def _connect_to_server_helper(self):
        r = requests.post(self._website_url)
        params = r.text

        # unused variables are connection_timeout and supported_formats
        key, heartbeat_timeout, _, _ = params.split(':')
        heartbeat_timeout = int(heartbeat_timeout)
        return key, heartbeat_timeout

    def on_open(self, *args):
        logging.info('Websocket open!')

    def on_close(self, *args):
        logging.info('Websocket closed :(')

    def on_message(self, *args):
        message = args[1].split(':', 3)
        key = int(message[0])
        # namespace = message[2]

        if len(message) >= 4:
            data = message[3]
        else:
            data = ''
        if key == 1 and args[1] == '1::':
            self.send_packet_helper(1)
        elif key == 1 and args[1] == '1::{}'.format(self.namespace):
            self.send_packet_helper(5, data={'name': 'initialize'})
            data = {'name': 'join', 'args': ['{}'.format(self._streamer_name)]}

            self.send_packet_helper(5, data=data)
            self.log.info('Connected to channel with socket io!')
            self.messaging.send_status('CONNECTED')
        elif key == 2:
            self.send_packet_helper(2)
        elif key == 5:
            data = json.loads(data, )
            if data['name'] == 'message':
                message = data['args'][0]
                sender = html.unescape(message['sender'])
                message = html.unescape(message['text'])
                self.messaging.send_message(author=sender, message=message)
            elif data['name'] == 'join':
                self.nick = data['args'][1]

    def on_error(self, *args):
        logging.error(args[1])

    def disconnect(self):
        callback = ''
        data = ''
        # '1::namespace'
        self.send(':'.join([
            str(self.TYPE_KEYS['DISCONNECT']), callback, self.namespace, data
        ]))

    def send_packet_helper(self, type_key, data=None):

        if data is None:
            data = ''
        else:
            data = json.dumps(data)

        # NOTE: callbacks currently not implemented
        callback = ''
        message = ':'.join([str(type_key), callback, self.namespace, data])
        self.send(message)
Esempio n. 15
0
class Shell(cmd.Cmd):
    def __init__(self,
                 context=None,
                 prompt_name='vexbot',
                 publish_address=None,
                 subscribe_address=None,
                 **kwargs):

        super().__init__()
        self.messaging = ZmqMessaging('shell',
                                      publish_address,
                                      subscribe_address,
                                      'shell')

        self.command_manager = CommandManager(self.messaging)
        # FIXME
        self.command_manager._commands.pop('commands')
        self.stdout.write('Vexbot {}\n'.format(__version__))
        if kwargs.get('already_running', False):
            self.stdout.write('vexbot already running\n')
        self.stdout.write("Type \"help\" for command line help or "
                          "\"commands\" for bot commands\n\n")

        self.command_manager.register_command('start_vexbot',
                                              _start_vexbot)

        self.messaging.start_messaging()

        self.prompt = prompt_name + ': '
        self.misc_header = "Commands"
        self._exit_loop = False
        self._set_readline_helper(kwargs.get('history_file'))

    def default(self, arg):
        if not self.command_manager.is_command(arg, call_command=True):
            command, argument, line = self.parseline(arg)

            self.messaging.send_command(command=command,
                                        args=argument,
                                        line=line)

    def _set_readline_helper(self, history_file=None):
        try:
            import readline
        except ImportError:
            return

        try:
            readline.read_history_file(history_file)
        except IOError:
            pass
        readline.set_history_length(1000)
        atexit.register(readline.write_history_file, history_file)

    def run(self):
        frame = None
        while True and not self._exit_loop:
            try:
                # NOTE: not blocking here to check the _exit_loop condition
                frame = self.messaging.sub_socket.recv_multipart(zmq.NOBLOCK)
            except zmq.error.ZMQError:
                pass

            sleep(.5)

            if frame:
                message = decode_vex_message(frame)
                if message.type == 'RSP':
                    self.stdout.write("\n{}\n".format(self.doc_leader))
                    header = message.contents.get('original', 'Response')
                    contents = message.contents.get('response', None)
                    # FIXME
                    if (isinstance(header, (tuple, list))
                            and isinstance(contents, (tuple, list))
                            and contents):

                        for head, content in zip(header, contents):
                            self.print_topics(head, (contents,), 15, 70)
                    else:
                        if isinstance(contents, str):
                            contents = (contents,)
                        self.print_topics(header,
                                          contents,
                                          15,
                                          70)

                    self.stdout.write("vexbot: ")
                    self.stdout.flush()

                else:
                    # FIXME
                    print(message.type,
                          message.contents,
                          'fix me in shell adapter, run function')
                frame = None

    def _create_command_function(self, command):
        def resulting_function(arg):
            self.default(' '.join((command, arg)))
        return resulting_function

    def do_EOF(self, arg):
        self.stdout.write('\n')
        # NOTE: This ensures we exit out of the `run` method on EOF
        self._exit_loop = True
        return True

    def get_names(self):
        return dir(self)

    def do_help(self, arg):
        if arg:
            if self.command_manager.is_command(arg):
                doc = self.command_manager._commands[arg].__doc__
                if doc:
                    self.stdout.write("{}\n".format(str(doc)))
            else:
                self.messaging.send_command(command='help', args=arg)

        else:
            self.stdout.write("{}\n".format(self.doc_leader))
            # TODO: get these from robot?
            self.print_topics(self.misc_header,
                              ['start vexbot\nhelp [foo]', ],
                              15,
                              80)

    def add_completion(self, command):
        setattr(self,
                'do_{}'.format(command),
                self._create_command_function(command))

    """