|
|
|
|
|
""" |
|
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 |