diff --git a/README.md b/README.md new file mode 100644 index 0000000..49be645 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# WECHAT NOTIFY + +Many scripts today may take a long time to run, such as deep learning tasks. We wonder to check the results immediately after its accomplishment but keeping an eye on the process is not desirable. + +This project is aimed to notify you through WeChat when certain command is completed. + +## requirements + +This package rely on `requests`. + +```bash +pip3 install requests +``` + +### SERVER CHAN + +This project rely on [SERVER CHAN](http://sc.ftqq.com/3.version) to push notifications to WeChat. Please follow the instructions on the website and **set your SCKEY to environment variable** as `SERVER_CHAN_TOKEN`. + +Your command's output and error will be write to file `stdout` and `stderr` regardless of whether notification will be push or not. + +## usage + +```bash +notify [bash command] +``` + +Note that special chars of bash, such as `>`, need to be escaped so that the script can capture the corrent bash command. For example: + +```bash +notify python train.py \> trail.log +``` + +## example + +WECHAT_NOTIFY will push three kinds of notifications. + +* [Success]: inform you [what command, start time, how long the command takes, last three lines of output(if exists)] + +* [Failed]: inform you [what command, start time, how long the command takes, last three lines of stderr(if exists)] + + +* [Keyboard Interrupt]: inform you [what command, start time, 'Keyboard Interrupt'] + + + +## TODO + +- [ ] unit test +- [ ] Email support +- [ ] test on WeChat Work diff --git a/imgs/failed.png b/imgs/failed.png new file mode 100644 index 0000000..54a3923 Binary files /dev/null and b/imgs/failed.png differ diff --git a/imgs/kayboard.png b/imgs/kayboard.png new file mode 100644 index 0000000..7cb5e58 Binary files /dev/null and b/imgs/kayboard.png differ diff --git a/imgs/success.png b/imgs/success.png new file mode 100644 index 0000000..82a4cea Binary files /dev/null and b/imgs/success.png differ diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..a0d3147 --- /dev/null +++ b/setup.py @@ -0,0 +1,16 @@ +from setuptools import setup + +setup(name="wechat-notify", + description="notify you on Wechat when certain task is completed", + version="1.0", + author="Tab_version", + author_email="tabvision@bupt.edu.cn", + packages=['wechat_notify'], + install_requires=[ + 'requests', + ], + entry_points = { + 'console_scripts': ['notify=wechat_notify.notify:main'], + }, + include_package_data=True, +) diff --git a/wechat_notify/__init__.py b/wechat_notify/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wechat_notify/notify.py b/wechat_notify/notify.py new file mode 100644 index 0000000..55f1d7c --- /dev/null +++ b/wechat_notify/notify.py @@ -0,0 +1,70 @@ +import sys +import os +import subprocess +import requests +import time + +def build_parser(): + if len(sys.argv) == 1: + raise ValueError('please input command') + return sys.argv[1:] + + +def send_request(output, err, process, token, command, start, duration, is_win): + if output is not None: + output = output.decode('utf-8').split('\r\n') if is_win else output.decode('utf-8').split('\n') + with open('stdout', 'w') as f: + f.write('\n'.join(output)) + if err is not None: + err = err.decode('utf-8').split('\r\n') if is_win else err.decode('utf-8').split('\n') + with open('stderr', 'w') as f: + f.write('\n'.join(err)) + temp = None + # import ipdb; ipdb.set_trace() + if process.poll() == 0: + if output is not None: + output = [''] * 3 + output + temp = 'the following are last three lines of stdout:\n' + '\n'.join(output[-3:]) + post_str = r'https://sc.ftqq.com/' + token + '.send?' + f'text=[Scuucess] command: ' + ' '.join(command) + f'&desp=start at {time.ctime(int(start))}\ttake time: {duration}\t' + (temp if temp is not None else '') + requests.post(post_str) + else: + if err is not None: + err = [''] * 3 + err + temp = 'the following are last three lines of stderr:\n' + '\n'.join(err[-3:]) + # import ipdb; ipdb.set_trace() + post_str = r'https://sc.ftqq.com/' + token + '.send?' + f'text=[Failed] command: ' + ' '.join(command) + f'&desp=start at {time.ctime(int(start))}\ttake time: {duration}\terror code: {process.poll()}'+ (temp if temp is not None else '') + print(post_str) + requests.post(post_str) + + + +def init(): + try: + token = os.environ['SERVER_CHAN_TOKEN'] + except KeyError: + print('environment variable `SERVER_CHAN_TOKEN` unfound') + exit(1) + return token + +def main(): + token = init() + start = time.time() + try: + command = build_parser() + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, err = process.communicate() + + except KeyboardInterrupt: + print('keyboard') + process.kill() + requests.post(r'https://sc.ftqq.com/' + token + '.send?' + f'text=[Failed] command: ' + ' '.join(command) + f'&desp=start at {time.ctime(int(start))}\nbecause of Keyboard Interrupt') + exit(0) + + duration = time.time() - start + is_win = (sys.platform == 'win32') + send_request(output=output, err=err, duration=duration, is_win=is_win,start=start, token=token, command=command, process=process) + + + +if __name__ == "__main__": + main()