Example #1
0
    def main():
        @RTMClient.run_on(event='message')
        def handle(web_client=None, data=None, **kwargs):
            print(f'Message data: {data}')

            if __should_handle(user=data.get('user'), text=data.get('text')):
                handle_message(data, web_client)

        global __web_client

        __web_client = WebClient(token=__slack_token)
        __rtm_client = RTMClient(token=__slack_token)
        __rtm_future = None

        while True:
            try:
                __rtm_future = __rtm_client.start()
                print("Learning bot is connected!")
                break
            except Exception:
                print(
                    "Failed to connect to Slack; retrying in 5 seconds\n\n\n\n\n"
                )
                time.sleep(5)

        asyncio.gather(__rtm_future, schedule_monitor())
Example #2
0
 def __init__(self):
     logging.basicConfig(
         level=os.environ.get("LOGLEVEL", "DEBUG"),
         format=
         '%(asctime)s - %(name)s:%(lineno)d - %(levelname)s - %(message)s',
     )
     self.__log = logging.getLogger(type(self).__name__)
     self.__log.info("Starting Moonbeam")
     self.__config = self.__load_config(prefix="Moonbeam")
     if 'BOT_TOKEN' not in self.__config:
         raise RuntimeError("BOT_TOKEN not found in config")
     self.__web_client = WebClient(self.__config['BOT_TOKEN'])
     self.__rtm_client = RTMClient(
         token=self.__config.get("BOT_TOKEN"),
         ping_interval=30,
         auto_reconnect=True,
     )
     self.__trigger_words = []
     self.__plugins = []
     self.__load_plugins()
     self.__rtm_client.run_on(event='message')(self.__process_message)
     self.__rtm_client.run_on(event='user_typing')(self.__process_typing)
     self.__rtm_client.run_on(event='reaction_added')(
         self.__process_reaction_added)
     self.__rtm_client.run_on(event='reaction_removed')(
         self.__process_reaction_removed)
     self.__rtm_client.start()
Example #3
0
    def serve_forever(self):
        self.sc = RTMClient(token=self.token, proxy=self.proxies)

        @RTMClient.run_on(event="open")
        def get_bot_identity(**payload):
            self.bot_identifier = SlackPerson(payload["web_client"],
                                              payload["data"]["self"]["id"])
            # only hook up the message callback once we have our identity set.
            self._setup_slack_callbacks()

        # log.info('Verifying authentication token')
        # self.auth = self.api_call("auth.test", raise_errors=False)
        # if not self.auth['ok']:
        #     raise SlackAPIResponseError(error=f"Couldn't authenticate with Slack. Server said: {self.auth['error']}")
        # log.debug("Token accepted")

        log.info("Connecting to Slack real-time-messaging API")
        self.sc.start()
        # Inject bot identity to alternative prefixes
        self.update_alternate_prefixes()

        try:
            while True:
                sleep(1)
        except KeyboardInterrupt:
            log.info("Interrupt received, shutting down..")
            return True
        except Exception:
            log.exception("Error reading from RTM stream:")
        finally:
            log.debug("Triggering disconnect callback")
            self.disconnect_callback()
Example #4
0
 def _register_plugin_actions(self, plugin_class, metadata, cls_instance,
                              fn_name, fn, class_help):
     fq_fn_name = "{}.{}".format(plugin_class, fn_name)
     if fn.__doc__:
         self._help['human'][class_help][
             fq_fn_name] = self._parse_human_help(fn.__doc__)
     for action, config in metadata['plugin_actions'].items():
         if action == 'process':
             event_type = config['event_type']
             RTMClient.on(event=event_type,
                          callback=callable_with_sanitized_event(fn))
         if action == 'respond_to' or action == 'listen_to':
             for regex in config['regex']:
                 event_handler = {
                     'class': cls_instance,
                     'class_name': plugin_class,
                     'function': fn,
                     'regex': regex
                 }
                 key = "{}-{}".format(fq_fn_name, regex.pattern)
                 self._plugin_actions[action][key] = event_handler
                 self._help['robot'][class_help].append(
                     self._parse_robot_help(regex, action))
         if action == 'schedule':
             Scheduler.get_instance().add_job(fq_fn_name,
                                              trigger='cron',
                                              args=[cls_instance],
                                              id=fq_fn_name,
                                              replace_existing=True,
                                              **config)
         if action == 'route':
             for route_config in config:
                 bottle.route(**route_config)(fn)
Example #5
0
    def test_02(self):
        logger = FoxylibLogger.func_level2logger(self.test_02, logging.DEBUG)

        loop = asyncio.get_event_loop()
        rtm_client = RTMClient(token=FoxylibSlack.xoxb_token(),
                               run_async=True,
                               loop=loop)

        async def inf_loop():
            logger = logging.getLogger()
            while 1:
                try:
                    logger.info("Ping Pong! I'm alive")
                    await asyncio.sleep(900)
                except asyncio.CancelledError:
                    break

        tasks = asyncio.gather(rtm_client.start(), inf_loop())

        def callback(signum, frame):
            tasks.cancel()
            logger.warning("Cancelling tasks...")

        # loop.add_signal_handler(signal.SIGINT, callback)
        signal.signal(signal.SIGINT, callback)
        signal.signal(signal.SIGTERM, callback)

        try:
            loop.run_until_complete(tasks)
        except asyncio.CancelledError as e:
            logger.error(e)
        finally:
            logger.info("Quitting... Bye!")
Example #6
0
 def connect(self):
     ssl_context = ssl.create_default_context()
     ssl_context.check_hostname = False
     ssl_context.verify_mode = ssl.CERT_NONE
     self.client  = RTMClient(token=self.token, ssl=ssl_context)
     self.client.run_on(event='message')(self.GetMessage)
     self.client.start()
Example #7
0
def run():
    import asyncio

    rtm_client = RTMClient(token=os.environ["SLACK_API_TOKEN"], run_async=True)
    loop = asyncio.get_event_loop()
    loop.set_debug(True)
    loop.run_until_complete(rtm_client.start())
Example #8
0
class RTMClient(Singleton):
    @wraps(SlackRTMClient.__init__)
    def __init__(self, token, *args, **kwargs):
        super().__init__()
        self._client = SlackRTMClient(token=token,
                                      run_async=True,
                                      loop=asyncio.get_running_loop(),
                                      *args,
                                      **kwargs)
        old_os_name = os.name
        os.name = 'nt'
        self._client.start()
        os.name = old_os_name

    @classmethod
    @wraps(SlackRTMClient.__init__)
    def start(cls, token, *args, **kwargs):
        return cls.instantiate(token, *args, **kwargs)._client

    @classmethod
    async def stop(cls):
        await cls.instance()._client.async_stop()

    @classmethod
    def on(cls, event):
        def decorator(callback):
            @SlackRTMClient.run_on(event=event)
            @wraps(callback)
            async def wrapper(**payload):
                await callback(**payload)

            return wrapper

        return decorator
Example #9
0
 def __init__(self):
     # this is the same environment variable that postgres uses, so you only
     # need to pass it once to compose
     self.db = db.PGDriver(password=os.environ["POSTGRES_PASSWORD"])
     self.userid = None
     slack_token = os.environ["SLACK_BOT_USER_TOKEN"]
     self.rtm_client = RTMClient(token=slack_token)
Example #10
0
    def __init__(self):
        slack_token = os.environ["SLACK_BDD_API_TOKEN"]
        self.rtm_client = RTMClient(token=slack_token)

        self.rtm_client.on(event="message", callback=self.listen)
        self.rtm_thread = threading.Thread(name="rtm_client",
                                           target=self.rtm_client.start)
        self.rtm_thread.start()
    async def test_issue_611(self):
        channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_issue_611)"

        self.message_count, self.reaction_count = 0, 0

        async def process_messages(**payload):
            self.logger.info(payload)
            if "subtype" in payload["data"] and payload["data"][
                    "subtype"] == "message_replied":
                return  # skip

            self.message_count += 1
            raise Exception("something is wrong!"
                            )  # This causes the termination of the process

        async def process_reactions(**payload):
            self.logger.info(payload)
            self.reaction_count += 1

        rtm = RTMClient(token=self.bot_token, run_async=True)
        RTMClient.on(event='message', callback=process_messages)
        RTMClient.on(event='reaction_added', callback=process_reactions)

        web_client = WebClient(token=self.bot_token, run_async=True)
        message = await web_client.chat_postMessage(channel=channel_id,
                                                    text=text)
        ts = message["ts"]

        await asyncio.sleep(3)

        # intentionally not waiting here
        rtm.start()

        try:
            await asyncio.sleep(3)

            first_reaction = await web_client.reactions_add(channel=channel_id,
                                                            timestamp=ts,
                                                            name="eyes")
            self.assertFalse("error" in first_reaction)
            await asyncio.sleep(2)

            should_be_ignored = await web_client.chat_postMessage(
                channel=channel_id, text="Hello?", thread_ts=ts)
            self.assertFalse("error" in should_be_ignored)
            await asyncio.sleep(2)

            second_reaction = await web_client.reactions_add(
                channel=channel_id, timestamp=ts, name="tada")
            self.assertFalse("error" in second_reaction)
            await asyncio.sleep(2)

            self.assertEqual(self.message_count, 1)
            self.assertEqual(self.reaction_count, 2)
        finally:
            if not rtm._stopped:
                rtm.stop()
def main():
  flags.mark_flag_as_required('customer')

  CUSTOMER_NAME = FLAGS.customer
  customer_codes ,msg_queue = cfg.read_config()

  rtm_client = RTMClient(token=customer_codes['customer1'])
  print(f'logging {FLAGS.customer}:{customer_codes["customer1"]}')  
  rtm_client.start()
Example #13
0
        async def slack_main():
            loop = asyncio.get_event_loop()
            rtm_client = RTMClient(token=FoxylibSlack.xoxb_token(), run_async=True, loop=loop)

            executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
            await asyncio.gather(
                loop.run_in_executor(executor, partial(sync_loop, rtm_client)),
                rtm_client.start()
            )
Example #14
0
    def setUp(self):
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)
        task = asyncio.ensure_future(self.mock_server(), loop=self.loop)
        self.loop.run_until_complete(asyncio.wait_for(task, 0.1))

        self.client = RTMClient(token=FoxylibSlack.xoxb_token(),
                                loop=self.loop,
                                auto_reconnect=False)
Example #15
0
    def __init__(self, token):
        self._slack_reader = RTMClient(token=token)
        self._slack_reader.start()
        self.client = WebClient(token=token)

        self._username_cache = {}
        self._channel_name_cache = {}
        self._logger = logging.getLogger('Transport')
        self.events = []
Example #16
0
 def run(self):
     self._running = True
     asyncio.set_event_loop(self._loop)
     rtm_client = RTMClient(token=SLACK_TOKEN)
     # rtm_client.start() does not like being run in a thread,
     # so just do the parts of it that work in a thread manually....
     future = asyncio.ensure_future(rtm_client._connect_and_read(),
                                    loop=self._loop)
     self._loop.run_until_complete(future)
     return
Example #17
0
    def main():
        @RTMClient.run_on(event='message')
        def handle(**kwargs):
            data = kwargs['data']   
            text = data['text'] 
            if data['user'] != __self_user_id and len(text) is not 0 and text.startswith('!'):
                command.runCommand(kwargs)

        rtm_client = RTMClient(token=__slack_token)
        rtm_client.start()
Example #18
0
 def slack_bot(self):
     print('\033[0;32m' + "[!] Starting slack bot!\033[0m")
     try:
         self.slack_data['text'] = 'Ready for action!'
         requests.post(url='https://slack.com/api/chat.postMessage',
                       data=self.slack_data)
         rtm_client = RTMClient(token=os.environ.get('SLACK_BOT_TOKEN'))
         rtm_client.start()
     except:
         pass
Example #19
0
    def connect(self, loop):
        asyncio.set_event_loop(loop)
        ssl_context = ssl_lib.create_default_context(cafile=certifi.where())

        self._slack_rtm = RTMClient(token=self._token,
                                    ssl=ssl_context,
                                    run_async=True,
                                    loop=loop)
        self._slack_rtm.run_on(event="message")(self.get_message)
        loop.run_until_complete(self._slack_rtm.start())
Example #20
0
    def __init__(self, name: str, pattern: str, remarks_location: str,
                 **kwargs):
        self.name = name
        self.pattern = pattern
        self.remarks_location = remarks_location

        self.slack_id = None
        self._rtm_client = RTMClient(**kwargs)
        self.slack_client = WebClient(**kwargs)

        self.remarks = self.get_file_contents()
Example #21
0
def start_work(retries=0):
    try:
        rtm_client = RTMClient(token=os.environ["SLACKBOT_API_TOKEN"],
                               auto_reconnect=True)
        rtm_client.start()
    except Exception as e:
        print(f'main loop crash {e}, try to restart, attempt {retries}')
        if retries == 3:
            raise e
        time.sleep(retries * 15)
        start_work(retries + 1)
Example #22
0
    def add_listener2rtm_client(cls, rtm_client, *, event: str, callback: Callable):
        # reference: RTMClient.on

        if isinstance(callback, list):
            for cb in callback:
                RTMClient._validate_callback(cb)
            previous_callbacks = rtm_client._callbacks[event]
            RTMClient._callbacks[event] = list(set(previous_callbacks + callback))
        else:
            RTMClient._validate_callback(callback)
            rtm_client._callbacks[event].append(callback)
Example #23
0
 async def test_issue_530_async(self):
     try:
         rtm_client = RTMClient(token="I am not a token", run_async=True)
         await rtm_client.start()
         self.fail("Raising an error here was expected")
     except Exception as e:
         self.assertEqual(
             "The request to the Slack API failed.\n"
             "The server responded with: {'ok': False, 'error': 'invalid_auth'}", str(e))
     finally:
         if not rtm_client._stopped:
             rtm_client.stop()
Example #24
0
    def __init__(self, token, external_functions=None):
        self.token = token
        self.external_functions = external_functions or self.DEFAULT_EXT_FUNCS

        self.web_client = WebClient(token=self.token)
        self.rtm_client = RTMClient(token=self.token)

        self.bot_id = self._connect()
        self.bot_id_text = f'<@{self.bot_id}>'

        # Decorate the message handler
        self.rtm_client.run_on(event='message')(self._message_handler)
Example #25
0
    def __init__(self, token, channel, cache):
        """
    Constructor
    :param token: Authentification token for bot
    :param channel: Name of the channel where the bot is hosted
    :param cache:   Location where to cache data
    """
        #  Bot mention detection
        self._self_mention = None
        self._channel = channel
        self._bot_id = None

        # Commands
        self._keywords = []
        self._authors = []
        self._known_cmd = {
            'help': (self._help_callback, ''),
            'list_keywords': (self._list_keyords_callback, ''),
            'add_keywords':
            (self._add_keyords_callback, 'List of space separated keywords '
             'to add'),
            'run_daily_arxiv_search': (self._run_daily_arxiv_search, '')
        }

        # Arxiv wrapper
        self._cache_folder = cache
        self._arxiv_cfg = _join(self._cache_folder, 'arxiv.cfg')
        if not _exists(self._arxiv_cfg):
            # cs.CV: Compute Vision
            # cs.AI: Artificial Inteligence
            # cs.LG: Machine learning
            # stat.ML: Machine learning
            # cs.GR: Graphics
            self._arxiv = ArxivParser(
                category=['cs.CV', 'cs.AI', 'cs.LG', 'stat.ML', 'cs.GR'])
            self._arxiv.save_config(self._arxiv_cfg)
        else:
            self._arxiv = ArxivParser.from_config(self._arxiv_cfg)
        # Reload authors/keywords
        self._load_config(self._cache_folder)
        #  Create client, define message callback + start service
        # run aynchronously
        # https://github.com/slackapi/python-slackclient/blob/master/tutorial/PythOnBoardingBot/async_app.py
        # https://stackoverflow.com/questions/56539228
        # Start Slack client + scheduler for daily research
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        self.client = RTMClient(token=token, run_async=True, loop=loop)
        self.client.on(event='open', callback=self.open_callback)
        self.client.on(event='message', callback=self.message_callback)
        loop.run_until_complete(
            asyncio.gather(self._daily_scheduler(token), self.client.start()))
        loop.close()
Example #26
0
    async def test_issue_558(self):
        channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_issue_558)"

        self.message_count, self.reaction_count = 0, 0

        async def process_messages(**payload):
            self.logger.debug(payload)
            self.message_count += 1
            await asyncio.sleep(10)  # this used to block all other handlers

        async def process_reactions(**payload):
            self.logger.debug(payload)
            self.reaction_count += 1

        rtm = RTMClient(token=self.bot_token, run_async=True)
        RTMClient.on(event='message', callback=process_messages)
        RTMClient.on(event='reaction_added', callback=process_reactions)

        web_client = WebClient(token=self.bot_token, run_async=True)
        message = await web_client.chat_postMessage(channel=channel_id,
                                                    text=text)
        self.assertFalse("error" in message)
        ts = message["ts"]
        await asyncio.sleep(3)

        # intentionally not waiting here
        rtm.start()
        await asyncio.sleep(3)

        try:
            first_reaction = await web_client.reactions_add(channel=channel_id,
                                                            timestamp=ts,
                                                            name="eyes")
            self.assertFalse("error" in first_reaction)
            await asyncio.sleep(2)

            message = await web_client.chat_postMessage(channel=channel_id,
                                                        text=text)
            self.assertFalse("error" in message)
            # used to start blocking here

            # This reaction_add event won't be handled due to a bug
            second_reaction = await web_client.reactions_add(
                channel=channel_id, timestamp=ts, name="tada")
            self.assertFalse("error" in second_reaction)
            await asyncio.sleep(2)

            self.assertEqual(self.message_count, 1)
            self.assertEqual(self.reaction_count, 2)  # used to fail
        finally:
            if not rtm._stopped:
                rtm.stop()
Example #27
0
 def __init__(
     self,
     *,
     token: str,
 ) -> None:
     self._webclient = WebClient(
         token=token,
         run_async=True,
     )
     self._rtm_client = RTMClient(
         token=token,
         run_async=True,
     )
Example #28
0
def run_bot():
    token = os.environ.get('SLACKBOT_TOKEN')
    report_url = os.environ.get('SLACKBOT_REPORT_URL')

    rtm_client = RTMClient(token=token)
    web_client = WebClient(token=token)

    global metrics
    metrics = None
    global channels
    channels = {
        u['id']: u['name']
        for u in web_client.channels_list()['channels']
    }
    global users
    users = {u['id']: u['name'] for u in web_client.users_list()['members']}

    if report_url:
        # Reports are enabled, so start reporting thread
        global last_run
        last_run = None
        metrics = defaultdict(int)

        class ReportingThread(threading.Thread):
            def run(self):
                while True:
                    curr_min = datetime.utcnow().minute
                    global last_run
                    global metrics
                    if last_run == curr_min:
                        sleep(5)
                        continue
                    last_run = curr_min
                    if not metrics:
                        continue
                    try:
                        metrics = json.dumps(metrics)
                        resp = post(url=report_url, json=dict(text=metrics))
                        resp.raise_for_status()
                    except Exception as exc:
                        print(exc)
                    metrics = defaultdict(int)

        reporting = ReportingThread(name='Reporting Thread')
        reporting.start()

    while True:
        try:
            rtm_client.start()
        except Exception as exc:
            logging.error('Exception during rtm_client.start', exc)
Example #29
0
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slackclient/issues/605
    """
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]
        self.channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
        self.rtm_client = RTMClient(token=self.bot_token, run_async=False)

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)

    @pytest.mark.skipif(condition=is_not_specified(), reason="still unfixed")
    def test_issue_605(self):
        self.text = "This message was sent to verify issue #605"
        self.called = False

        @RTMClient.run_on(event="message")
        def process_messages(**payload):
            self.logger.info(payload)
            self.called = True

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        t = threading.Thread(target=connect)
        t.setDaemon(True)
        try:
            t.start()
            self.assertFalse(self.called)

            time.sleep(3)

            self.web_client = WebClient(
                token=self.bot_token,
                run_async=False,
                loop=asyncio.new_event_loop(
                ),  # TODO: this doesn't work without this
            )
            new_message = self.web_client.chat_postMessage(
                channel=self.channel_id, text=self.text)
            self.assertFalse("error" in new_message)

            time.sleep(5)
            self.assertTrue(self.called)
        finally:
            t.join(.3)
    def __init__(self, bot_user_token, bot_id=None):
        self.name = BOT_NAME
        self.bot_id = bot_id
        if not self.bot_id:
            # Read the bot's id by calling auth.test
            response = WebClient(token=bot_user_token).api_call('auth.test')
            self.bot_id = response['user_id']
            logger.info(f'My bot_id is {self.bot_id}')

        # Create an instance of the RTM client
        self.sc = RTMClient(token=bot_user_token, run_async=True)

        # Connect our callback events to the RTM client
        RTMClient.run_on(event="hello")(self.on_hello)
        RTMClient.run_on(event="message")(self.on_message)
        RTMClient.run_on(event="goodbye")(self.on_goodbye)

        # startup our client event loop
        self.future = self.sc.start()
        self.bot_start = dt.now()
        self.msg_lock = Lock()
        self.at_bot = f'<@{self.bot_id}>'
        self.comic_history = []
        logger.info("Created new SlackClient Instance")
        self.xkcd = XkcdApi()