{"action":"created","issue":{"url":"https://api.github.com/repos/boazsegev/iodine/issues/6","repository_url":"https://api.github.com/repos/boazsegev/iodine","labels_url":"https://api.github.com/repos/boazsegev/iodine/issues/6/labels{/name}","comments_url":"https://api.github.com/repos/boazsegev/iodine/issues/6/comments","events_url":"https://api.github.com/repos/boazsegev/iodine/issues/6/events","html_url":"https://github.com/boazsegev/iodine/issues/6","id":169564776,"number":6,"title":"Rack SPEC discussion: Upgrading using `env['upgrade.websocket']`","user":{"login":"boazsegev","id":870622,"avatar_url":"https://avatars.githubusercontent.com/u/870622?v=3","gravatar_id":"","url":"https://api.github.com/users/boazsegev","html_url":"https://github.com/boazsegev","followers_url":"https://api.github.com/users/boazsegev/followers","following_url":"https://api.github.com/users/boazsegev/following{/other_user}","gists_url":"https://api.github.com/users/boazsegev/gists{/gist_id}","starred_url":"https://api.github.com/users/boazsegev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/boazsegev/subscriptions","organizations_url":"https://api.github.com/users/boazsegev/orgs","repos_url":"https://api.github.com/users/boazsegev/repos","events_url":"https://api.github.com/users/boazsegev/events{/privacy}","received_events_url":"https://api.github.com/users/boazsegev/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/boazsegev/iodine/labels/discussion","name":"discussion","color":"bfdadc"}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":42,"created_at":"2016-08-05T09:17:42Z","updated_at":"2016-08-22T16:22:19Z","closed_at":null,"body":"This is a discussion for the proposed upgrade workflow for Rack.\r\n\r\nI will update this first post with the information about the outline for implementation. This first draft is based my experience implementing this feature (and using this feature) with Iodine.\r\n\r\n---\r\n\r\n\r\n## The Websocket Callback Object\r\n\r\nWeb socket connection upgrade and handling is performed using a Websocket Callback Object.\r\n\r\nThe Websocket Callback Object should be a class (or an instance of such class) who's instances implement any of the following callbacks:\r\n\r\n* `on_open` will be called once the upgrade had completed.\r\n\r\n* `on_close` will be called _after_ the connection was closed.\r\n\r\n* `on_message(data)` will be called when incoming Websocket data is received. `data` will be a String with an encoding of UTF-8 for text messages and `binary` for non-text messages (as specified by the Websocket Protocol).\r\n\r\n     The client must assume that the `data` String will be a recyclable buffer and that it's content will be corrupted the moment the `on_message` callback returns.\r\n\r\n* `on_shutdown` will be called during the server's graceful shutdown process, _before_ the connection is closed and in addition to the `on_close` function (which is called _after_ the connection is closed.\r\n\r\nThe following method names are reserved for the network implementation.\r\n\r\nThese are methods that will be added to the Websocket Callback Object by the server (Iodine uses a module mixing for this) and should be used for handling network communication:\r\n\r\n* `write(data)` will send the data through the websocket connection. `data` **must** be a String. If `data` is UTF-8 encoded, the data will be sent as text. If `data` is binary encoded it will be sent as non-text (as specified by the Websocket Protocol).\r\n\r\n* `close` closes the connection once all the data in the outgoing queue was sent.\r\n\r\nConnection `ping` / `pong`, timeouts and network considerations should be implemented by the server.\r\n\r\nSettings might (or might not) be provided to allow for customization and adaptation for different network environments or extension requirements. However, these should be (ideally) set as command line arguments. Application logic should be kept separate from network logic and details when possible.\r\n\r\n## Upgrading\r\n\r\n* **Server**: When an upgrade request is received, the server will set the `env['upgrade.websockets?']` flag to `true`, to indicate that: 1. this specific request is upgradable; and 2. that the server supports this type of upgrade.\r\n\r\n* **Client**: When a client decides to upgrade a request, they will place a Websocket Callback Object (either a class or an instance) in the `env['upgrade.websockets']` Hash key [????]\r\n  \r\n* OR:\r\n  \r\n* **Client**: When a client decides to upgrade a request, they will send a Websocket Callback Object (either a class or an instance) to the server using the Proc object placed in the `env['upgrade.websockets']` Hash key - i.e. using `env['upgrade.websockets'].call(MyWebsocket.new(env))`\r\n  \r\n* **Server**: The server will review the `env` Hash *before* sending the response. If the `env['upgrade.websockets']` was set (OR the `env['upgrade.websockets']` Proc was called), the server will perform the upgrade, sending the correct response status and sending any headers present in the response and performing any required housekeeping, such as closing the response body, if exists. The response status shall be ignored and the correct status shall be set by the server.\r\n\r\n* **Server**: Once the upgrade had completed, The server will add the required websocket/network functions (see further on) to the callback handler. If the callback handler is a Class object, the server will create a new instance of that class.\r\n\r\n    Using a module mixin to alter the Websocket Callback Object's class is both allowed and encouraged.\r\n\r\n* **Server**: The server will call the `on_open` callback.\r\n\r\n        No other callbacks shall be called until the `on_open` callback had returned.\r\n\r\n        [???] Web socket messages shall be handled by the `on_message` callback in the same order in which they arrived and they will NOT be executed concurrently for the same connection.\r\n\r\n        [???] The `on_close` callback will NOT run concurrently with other callback."},"comment":{"url":"https://api.github.com/repos/boazsegev/iodine/issues/comments/241467661","html_url":"https://github.com/boazsegev/iodine/issues/6#issuecomment-241467661","issue_url":"https://api.github.com/repos/boazsegev/iodine/issues/6","id":241467661,"user":{"login":"evanphx","id":7,"avatar_url":"https://avatars.githubusercontent.com/u/7?v=3","gravatar_id":"","url":"https://api.github.com/users/evanphx","html_url":"https://github.com/evanphx","followers_url":"https://api.github.com/users/evanphx/followers","following_url":"https://api.github.com/users/evanphx/following{/other_user}","gists_url":"https://api.github.com/users/evanphx/gists{/gist_id}","starred_url":"https://api.github.com/users/evanphx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/evanphx/subscriptions","organizations_url":"https://api.github.com/users/evanphx/orgs","repos_url":"https://api.github.com/users/evanphx/repos","events_url":"https://api.github.com/users/evanphx/events{/privacy}","received_events_url":"https://api.github.com/users/evanphx/received_events","type":"User","site_admin":false},"created_at":"2016-08-22T16:22:19Z","updated_at":"2016-08-22T16:22:19Z","body":"That's totally unfair because you have the respond_to? check in there. That would not be in the hot path, can you remove it and run the benchmark again?"}}
{"actor":{"display_login":"evanphx"}}