{"action":"created","issue":{"url":"https://api.github.com/repos/miguelgrinberg/python-socketio/issues/45","repository_url":"https://api.github.com/repos/miguelgrinberg/python-socketio","labels_url":"https://api.github.com/repos/miguelgrinberg/python-socketio/issues/45/labels{/name}","comments_url":"https://api.github.com/repos/miguelgrinberg/python-socketio/issues/45/comments","events_url":"https://api.github.com/repos/miguelgrinberg/python-socketio/issues/45/events","html_url":"https://github.com/miguelgrinberg/python-socketio/pull/45","id":172749845,"number":45,"title":"Event handler middlewares","user":{"login":"efficiosoft","id":15107268,"avatar_url":"https://avatars.githubusercontent.com/u/15107268?v=3","gravatar_id":"","url":"https://api.github.com/users/efficiosoft","html_url":"https://github.com/efficiosoft","followers_url":"https://api.github.com/users/efficiosoft/followers","following_url":"https://api.github.com/users/efficiosoft/following{/other_user}","gists_url":"https://api.github.com/users/efficiosoft/gists{/gist_id}","starred_url":"https://api.github.com/users/efficiosoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/efficiosoft/subscriptions","organizations_url":"https://api.github.com/users/efficiosoft/orgs","repos_url":"https://api.github.com/users/efficiosoft/repos","events_url":"https://api.github.com/users/efficiosoft/events{/privacy}","received_events_url":"https://api.github.com/users/efficiosoft/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":3,"created_at":"2016-08-23T16:47:33Z","updated_at":"2016-08-24T13:17:05Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/miguelgrinberg/python-socketio/pulls/45","html_url":"https://github.com/miguelgrinberg/python-socketio/pull/45","diff_url":"https://github.com/miguelgrinberg/python-socketio/pull/45.diff","patch_url":"https://github.com/miguelgrinberg/python-socketio/pull/45.patch"},"body":"This deals with the concept of event handler middlewares. I wrote a chapter in the docs about them. Basically it's a way to add before/after event handlers on three layers for fine-grained control: These layers can alter the arguments the event handler will get or its return value transparently or completely abort execution, returning something else.\r\n\r\n- at server layer for *every* event by adding the middleware to ``socketio.Server.middlewares``\r\n- at namespace layer by adding the middleware to ``socketio.Namespace.middlewares``\r\n- at the event handler layer by decorating an event handler with ``@util.apply_middleware(...)``\r\n\r\nFinally, when the event is triggered, the ``socketio.Server._trigger_event`` method collects middlewares for the used event handler from these three layers (from least to most specific one) and applies them on the handler before execution.\r\n\r\nI wrote a test for it that is commented and it works well."},"comment":{"url":"https://api.github.com/repos/miguelgrinberg/python-socketio/issues/comments/242059568","html_url":"https://github.com/miguelgrinberg/python-socketio/pull/45#issuecomment-242059568","issue_url":"https://api.github.com/repos/miguelgrinberg/python-socketio/issues/45","id":242059568,"user":{"login":"efficiosoft","id":15107268,"avatar_url":"https://avatars.githubusercontent.com/u/15107268?v=3","gravatar_id":"","url":"https://api.github.com/users/efficiosoft","html_url":"https://github.com/efficiosoft","followers_url":"https://api.github.com/users/efficiosoft/followers","following_url":"https://api.github.com/users/efficiosoft/following{/other_user}","gists_url":"https://api.github.com/users/efficiosoft/gists{/gist_id}","starred_url":"https://api.github.com/users/efficiosoft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/efficiosoft/subscriptions","organizations_url":"https://api.github.com/users/efficiosoft/orgs","repos_url":"https://api.github.com/users/efficiosoft/repos","events_url":"https://api.github.com/users/efficiosoft/events{/privacy}","received_events_url":"https://api.github.com/users/efficiosoft/received_events","type":"User","site_admin":false},"created_at":"2016-08-24T13:17:05Z","updated_at":"2016-08-24T13:17:05Z","body":"I think I found another way to describe the whole idea with my humble English skills.\r\n\r\nSummary of interceptors\r\n=======================\r\n\r\nInterceptors are the idea of splitting the event processing horizontally into slices where each slice is an interceptor.\r\n\r\nOne interceptor may only depend on other interceptors that are placed above it (above means added later).\r\n\r\nEvent processing is done as follows:\r\n- Arguments of an event handler are passed into each interceptors ``before_event`` method from bottom to top. Each of these interceptors may alter the arguments.\r\n- When the top is reached, the real event handler is called with the updated arguments.\r\n- The returned values are now passed to the topmost interceptor's ``after_event`` method and may be altered there. The arguments ripple down until the bottommost interceptor is reached. Afterwards, the updated value is used as the result of the event processing.\r\n\r\nThere are special cases that interrupt the process and continue it at another point:\r\n\r\n- When a ``before_event`` method returns something else than ``None``, the \"climbing\" of the interceptor hill is aborted and the ``after_event`` processing starts at the interceptor that caused the abortion, using the returned values of ``before_event``. The real event handler is never called in that case.\r\n- When an exception is raised *anywhere* in the whole process (including ``before_event`` and ``after_event`` calls as well as the real event handler), a ``handle_exception`` method is called with the raised exception as its argument in the interceptor we've currently climbed up to. If an exception occurs in the real event handler, this will be the topmost interceptor. From there on, we start to climb downwards. The method can:\r\n  - either handle the exception and return something that will be treated as the return value, which is then passed to the next lower ``after_event`` method\r\n  - or re-raise the exception, what causes the next lower interceptor to be considered to handle the exception.\r\n\r\nI hope this makes the procedure clearer. It might seem to be a bit complex at first, but it actually is simple to use."}}
{"actor":{"display_login":"efficiosoft"}}