| | |
| | |
| | """ |
| | slack_bot.py |
| | Created on May 02 2020 11:02 |
| | a bot to send message/image during program run |
| | @author: Tu Bui tu@surrey.ac.uk |
| | """ |
| |
|
| | from __future__ import absolute_import |
| | from __future__ import division |
| | from __future__ import print_function |
| | import os |
| | import sys |
| | import requests |
| | import socket |
| | from slack import WebClient |
| | from slack.errors import SlackApiError |
| | import threading |
| |
|
| |
|
| | SLACK_MAX_PRINT_ERROR = 3 |
| | SLACK_ERROR_CODE = {'not_active': 1, |
| | 'API': 2} |
| |
|
| |
|
| | def welcome_message(): |
| | hostname = socket.gethostname() |
| | all_args = ' '.join(sys.argv) |
| | out_text = 'On server {}: {}\n'.format(hostname, all_args) |
| | return out_text |
| |
|
| |
|
| | class Notifier(object): |
| | """ |
| | A slack bot to send text/image to a given workspace channel. |
| | This class initializes with a text file as input, the text file should contain 2 lines: |
| | slack token |
| | slack channel |
| | |
| | Usage: |
| | msg = Notifier(token_file) |
| | msg.send_initial_text(' '.join(sys.argv)) |
| | msg.send_text('hi, this text is inside slack thread') |
| | msg.send_file(your_file, 'file title') |
| | """ |
| | def __init__(self, token_file): |
| | """ |
| | setup slack |
| | :param token_file: path to slack token file |
| | """ |
| | self.active = True |
| | self.thread_id = None |
| | self.counter = 0 |
| | if not os.path.exists(token_file): |
| | print('[SLACK] token file not found. You will not be notified.') |
| | self.active = False |
| | else: |
| | try: |
| | with open(token_file, 'r') as f: |
| | lines = f.readlines() |
| | self.token = lines[0].strip() |
| | self.channel = lines[1].strip() |
| | except Exception as e: |
| | print(e) |
| | print('[SLACK] fail to read token file. You will not be notified.') |
| | self.active = False |
| |
|
| | def _handel_error(self, e): |
| | assert e.response["ok"] is False |
| | assert e.response["error"] |
| | self.counter += 1 |
| | if self.counter <= SLACK_MAX_PRINT_ERROR: |
| | print(f"Got the following error, you will not be notified: {e.response['error']}") |
| |
|
| | def send_init_text(self, text=None): |
| | """ |
| | start a new thread with a main message and register the thread id |
| | :param text: initial message for this thread |
| | :return: |
| | """ |
| | if not self.active: |
| | return SLACK_ERROR_CODE['not_active'] |
| | try: |
| | if text is None: |
| | text = welcome_message() |
| | sc = WebClient(self.token) |
| | response = sc.chat_postMessage(channel=self.channel, text=text) |
| | self.thread_id = response['ts'] |
| | except SlackApiError as e: |
| | self._handel_error(e) |
| | return SLACK_ERROR_CODE['API'] |
| | print('[SLACK] sent initial text. Chat ID %s. Message %s' % (self.thread_id, text)) |
| | return 0 |
| |
|
| | def send_init_file(self, file_path, title=''): |
| | """ |
| | start a new thread with a file and register thread id |
| | :param file_path: path to file |
| | :param title: title of this file |
| | :return: 0 if success otherwise error code |
| | """ |
| | if not self.active: |
| | return SLACK_ERROR_CODE['not_active'] |
| | try: |
| | response = sc.files_upload(title=title, channels=self.channel, file=file_path) |
| | self.thread_id = response['ts'] |
| | except SlackApiError as e: |
| | self._handel_error(e) |
| | return SLACK_ERROR_CODE['API'] |
| | print('[SLACK] sent initial file. Chat ID %s.' % self.thread_id) |
| | return 0 |
| |
|
| | def send_text(self, text, reply_broadcast=False): |
| | """ |
| | send text as a thread if one is registered in self.thread_id. |
| | Otherwise send as a new message |
| | :param text: message to send. |
| | :return: 0 if success, error code otherwise |
| | """ |
| | print(text) |
| | if not self.active: |
| | return SLACK_ERROR_CODE['not_active'] |
| | if self.thread_id is None: |
| | self.send_init_text(text) |
| | else: |
| | try: |
| | sc = WebClient(self.token) |
| | response = sc.chat_postMessage(channel=self.channel, text=text, |
| | thread_ts=self.thread_id, as_user=True, |
| | reply_broadcast=reply_broadcast) |
| | except SlackApiError as e: |
| | self._handel_error(e) |
| | return SLACK_ERROR_CODE['API'] |
| | return 0 |
| |
|
| | def _send_file(self, file_path, title='', reply_broadcast=False): |
| | """can be multithread target""" |
| | try: |
| | sc = WebClient(self.token) |
| | sc.files_upload(title=title, channels=self.channel, |
| | thread_ts=self.thread_id, file=file_path, |
| | reply_broadcast=reply_broadcast) |
| | except SlackApiError as e: |
| | self._handel_error(e) |
| | return SLACK_ERROR_CODE['API'] |
| | return 0 |
| |
|
| | def send_file(self, file_path, title='', reply_broadcast=False): |
| | if not self.active: |
| | return SLACK_ERROR_CODE['not_active'] |
| | if self.thread_id is None: |
| | return self.send_init_file(file_path, title) |
| | else: |
| | os_thread = threading.Thread(target=self._send_file, args=(file_path, title, reply_broadcast)) |
| | os_thread.start() |
| | return 0 |