{"action":"created","issue":{"url":"https://api.github.com/repos/KeepSafe/aiohttp/issues/401","labels_url":"https://api.github.com/repos/KeepSafe/aiohttp/issues/401/labels{/name}","comments_url":"https://api.github.com/repos/KeepSafe/aiohttp/issues/401/comments","events_url":"https://api.github.com/repos/KeepSafe/aiohttp/issues/401/events","html_url":"https://github.com/KeepSafe/aiohttp/issues/401","id":85941872,"number":401,"title":"Signals","user":{"login":"alexsdutton","id":238690,"avatar_url":"https://avatars.githubusercontent.com/u/238690?v=3","gravatar_id":"","url":"https://api.github.com/users/alexsdutton","html_url":"https://github.com/alexsdutton","followers_url":"https://api.github.com/users/alexsdutton/followers","following_url":"https://api.github.com/users/alexsdutton/following{/other_user}","gists_url":"https://api.github.com/users/alexsdutton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexsdutton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexsdutton/subscriptions","organizations_url":"https://api.github.com/users/alexsdutton/orgs","repos_url":"https://api.github.com/users/alexsdutton/repos","events_url":"https://api.github.com/users/alexsdutton/events{/privacy}","received_events_url":"https://api.github.com/users/alexsdutton/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":17,"created_at":"2015-06-07T20:53:59Z","updated_at":"2015-06-08T23:03:01Z","closed_at":null,"body":"To support altering headers before responses are sent, among other things, there should be a signals framework so people can hook into the response process. This would be extensible for other uses too. This issue follows on from #393.\r\n\r\nThe proposal is:\r\n\r\nCreate a new `signals` module, containing a `Signal` class. Its constructor takes a single argument, `arguments`, saying which arguments must be passed when dispatching the signal. This class has a method for checking that potential callbacks have a compatible signature. The module also contains instances of this class for individual types of signal (e.g. `response_start = Signal({'request', 'response'})` — I can't yet think of what other signals might be useful).\r\n\r\n`Application` gets a new `_signals = defaultdict(list)` and a `@property` that exposes a view of it. It gets a `add_signal_callback(signal : Signal, callback : Callable)` method, which checks that the callback is compatible (see above) and coerces the calback to a coroutine, before appending the callback to `self._signals[signal]`.\r\n\r\nSignal dispatching is done by `Appllication.dispatch_signal(signal : Signal, kwargs : dict)`, which iterates through the registered signals, calling each in turn.\r\n\r\n`Response.start()` is modified to dispatch the `response_start` signal after [this line](https://github.com/KeepSafe/aiohttp/blob/7823f61b13e5cff59dabe5df97031e516cf3faaf/aiohttp/web_reqrep.py#L582).\r\n\r\nI don't think there's any need to create signals for the request creation phase, as the request can be modified safely with middleware.\r\n\r\nThe use-case of adding response headers from middleware becomes this slightly contrived example:\r\n\r\n    import asyncio\r\n    import time\r\n    \r\n    from aiohttp.signals import response_start\r\n    \r\n    @asyncio.coroutine\r\n    def add_header_middleware(app, handler):\r\n        @asyncio.coroutine\r\n        def middleware(request):\r\n            request.started = time.time()\r\n            return (yield from handler(request))\r\n        return middleware\r\n    \r\n    def add_request_started(*, request, response):\r\n        response.headers['X-Started'] = str(request.started)\r\n    \r\n    app = Application(middlewares=(add_header_middleware,))\r\n    app.add_signal_handler(response_start, add_request_started)\r\n"},"comment":{"url":"https://api.github.com/repos/KeepSafe/aiohttp/issues/comments/110167303","html_url":"https://github.com/KeepSafe/aiohttp/issues/401#issuecomment-110167303","issue_url":"https://api.github.com/repos/KeepSafe/aiohttp/issues/401","id":110167303,"user":{"login":"fafhrd91","id":598990,"avatar_url":"https://avatars.githubusercontent.com/u/598990?v=3","gravatar_id":"","url":"https://api.github.com/users/fafhrd91","html_url":"https://github.com/fafhrd91","followers_url":"https://api.github.com/users/fafhrd91/followers","following_url":"https://api.github.com/users/fafhrd91/following{/other_user}","gists_url":"https://api.github.com/users/fafhrd91/gists{/gist_id}","starred_url":"https://api.github.com/users/fafhrd91/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fafhrd91/subscriptions","organizations_url":"https://api.github.com/users/fafhrd91/orgs","repos_url":"https://api.github.com/users/fafhrd91/repos","events_url":"https://api.github.com/users/fafhrd91/events{/privacy}","received_events_url":"https://api.github.com/users/fafhrd91/received_events","type":"User","site_admin":false},"created_at":"2015-06-08T23:03:01Z","updated_at":"2015-06-08T23:03:01Z","body":"@asvetlov i'm fine with signals. but we can not change start() method, this will brake all production code."}}