From 1ad86428c849f80df6adc233e65b14c5f6413929 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Fri, 17 May 2019 14:55:29 +0000 Subject: [PATCH] Added support for custom webhooks --- platypush/backend/http/app/routes/execute.py | 8 +++- platypush/backend/http/app/routes/hook.py | 49 ++++++++++++++++++++ platypush/message/event/http/hook.py | 28 +++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 platypush/backend/http/app/routes/hook.py create mode 100644 platypush/message/event/http/hook.py diff --git a/platypush/backend/http/app/routes/execute.py b/platypush/backend/http/app/routes/execute.py index ed15b1c1..4887dc01 100644 --- a/platypush/backend/http/app/routes/execute.py +++ b/platypush/backend/http/app/routes/execute.py @@ -21,7 +21,13 @@ def execute(): """ Endpoint to execute commands """ if not authentication_ok(request): return authenticate() - msg = json.loads(request.data.decode('utf-8')) + try: + msg = json.loads(request.data.decode('utf-8')) + except Exception as e: + logger().error('Unable to parse JSON from request {}: {}'.format( + request.data, str(e))) + abort(400, str(e)) + logger().info('Received message on the HTTP backend: {}'.format(msg)) try: diff --git a/platypush/backend/http/app/routes/hook.py b/platypush/backend/http/app/routes/hook.py new file mode 100644 index 00000000..c7e4e197 --- /dev/null +++ b/platypush/backend/http/app/routes/hook.py @@ -0,0 +1,49 @@ +import json + +from flask import Blueprint, abort, request, Response + +from platypush.backend.http.app import template_folder +from platypush.backend.http.app.utils import authenticate, authentication_ok, \ + logger, send_message + +from platypush.message.event.http.hook import WebhookEvent + + +hook = Blueprint('hook', __name__, template_folder=template_folder) + +# Declare routes list +__routes__ = [ + hook, +] + +@hook.route('/hook/', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS']) +def hook(hook_name): + """ Endpoint for custom webhooks """ + if not authentication_ok(request): return authenticate() + + event_args = { + 'hook': hook_name, + 'method': request.method, + 'args': dict(request.args or {}), + 'data': request.data.decode(), + } + + if event_args['data']: + try: + event_args['data'] = json.loads(event_args['data']) + except: + pass + + event = WebhookEvent(**event_args) + + try: + response = send_message(event) + return Response(json.dumps({'status': 'ok', **event_args}), + mimetype='application/json') + except Exception as e: + logger().error('Error while dispatching webhook event {}: {}'. + format(event, str(e))) + abort(500, str(e)) + + +# vim:sw=4:ts=4:et: diff --git a/platypush/message/event/http/hook.py b/platypush/message/event/http/hook.py new file mode 100644 index 00000000..645da843 --- /dev/null +++ b/platypush/message/event/http/hook.py @@ -0,0 +1,28 @@ +from platypush.message.event import Event + +class WebhookEvent(Event): + """ + Event triggered when a custom webhook is called. + """ + + def __init__(self, hook, method, data=None, args=None, *argv, **kwargs): + """ + :param hook: Name of the invoked web hook, from http://host:port/hook/ + :type hook: str + + :param method: HTTP method (in uppercase) + :type method: str + + :param data: Extra data passed over POST/PUT/DELETE + :type data: str or dict/list from JSON + + :param args: Extra query string arguments + :type args: dict + """ + + super().__init__(hook=hook, method=method, data=data, + args=args or {}, *argv, **kwargs) + + +# vim:sw=4:ts=4:et: +