From dbc56e29a5d57c025204d64b47367c807c34c1c6 Mon Sep 17 00:00:00 2001 From: vaibhav Date: Sun, 21 May 2017 13:18:09 +0530 Subject: [PATCH] bots: Add simple flask server for running contrib bots. --- api/flask_bot_server.py | 70 ++++++++++++++++++++++++++++++++++ zerver/lib/outgoing_webhook.py | 1 + 2 files changed, 71 insertions(+) create mode 100644 api/flask_bot_server.py diff --git a/api/flask_bot_server.py b/api/flask_bot_server.py new file mode 100644 index 0000000000..580fe6d07e --- /dev/null +++ b/api/flask_bot_server.py @@ -0,0 +1,70 @@ +from __future__ import absolute_import +from flask import Flask, request, jsonify +import os +import sys +import json +from typing import Any, Dict, Mapping, Union, List +from werkzeug.exceptions import BadRequest +from six.moves.configparser import SafeConfigParser + +our_dir = os.path.dirname(os.path.abspath(__file__)) + +# For dev setups, we can find the API in the repo itself. +if os.path.exists(os.path.join(our_dir, '../api/zulip')): + sys.path.insert(0, '../api') + +from zulip import Client +from bots_api.run import get_lib_module +from bots_api.bot_lib import BotHandlerApi, StateHandler + +bots_config = {} # type: Dict[str, Mapping[str, str]] +available_bots = [] # type: List[str] +bots_lib_module = {} # type: Dict[str, Any] + +def read_config_file(config_file_path): + # type: (str) -> None + parser = SafeConfigParser() + parser.read(config_file_path) + + for section in parser.sections(): + bots_config[section] = { + "email": parser.get(section, 'email'), + "key": parser.get(section, 'key'), + "site": parser.get(section, 'site'), + } + +def load_lib_modules(): + # type: () -> None + for bot in available_bots: + path = "bots/" + str(bot) + "/" + str(bot) + ".py" + bots_lib_module[bot] = get_lib_module(path) + +app = Flask(__name__) + +@app.route('/bots/', methods=['POST']) +def handle_bot(bot): + # type: (str) -> Union[str, BadRequest] + if bot not in available_bots: + return BadRequest("requested bot service {} not supported".format(bot)) + + client = Client(email=bots_config[bot]["email"], + api_key=bots_config[bot]["key"], + site=bots_config[bot]["site"]) + restricted_client = BotHandlerApi(client) + message_handler = bots_lib_module[bot].handler_class() + + # TODO: Handle stateful bots properly. + state_handler = StateHandler() + + event = json.loads(request.data) + message_handler.handle_message(message=event["message"], + client=restricted_client, + state_handler=state_handler) + return "Success!" + +if __name__ == "__main__": + read_config_file(sys.argv[1]) + available_bots = list(bots_config.keys()) + load_lib_modules() + + app.run(host="127.0.0.1", port=5002, debug=True) diff --git a/zerver/lib/outgoing_webhook.py b/zerver/lib/outgoing_webhook.py index 787e9ba063..b5cb656c8b 100644 --- a/zerver/lib/outgoing_webhook.py +++ b/zerver/lib/outgoing_webhook.py @@ -76,6 +76,7 @@ def do_rest_call(rest_operation, event, timeout=None): request_kwargs['timeout'] = timeout try: + # TODO: Add comment describing structure of data being sent to third party URL. response = requests.request(http_method, final_url, data=json.dumps(event), **request_kwargs) if str(response.status_code).startswith('2'): succeed_with_message(event, "received response: `" + str(response.content) + "`.")