{"action":"created","comment":{"url":"https://api.github.com/repos/Workiva/w_transport/pulls/comments/43893623","id":43893623,"diff_hunk":"@@ -27,20 +32,71 @@ abstract class CommonWSocket extends Stream implements WSocket {\n   /// no close reason available this property will be `null`.\n   String closeReason;\n \n+  /// The error that was either added to the socket sink or received from the\n+  /// socket stream. This will only be populated if an error occurs.\n+  var error;\n+\n+  /// Incoming communication. Data from the web socket will be piped\n+  /// to this controller's sink. The stream will be exposed, allowing\n+  /// users to listen to the incoming data.\n+  StreamController incoming;\n+\n   /// Whether or not the web socket is in the process of closing (or already has\n   /// closed). This prevents duplicate behavior if [close] is called multiple\n   /// times.\n-  bool _closed = false;\n+  bool isClosed = false;\n+\n+  /// Whether or not the outgoing sink has been closed.\n+  bool isSinkClosed = false;\n+\n+  /// Whether or not the incoming socket stream connection has been closed.\n+  bool isSocketClosed = false;\n+\n+  /// The stack trace from the error that was either added to the socket sink or\n+  /// received from the socket stream. This will only be populated if an error\n+  /// occurs.\n+  StackTrace stackTrace;\n+\n+  /// Outgoing communication. Sink will be exposed, allowing users to\n+  /// add items to the outgoing stream.\n+  StreamController outgoing;\n+\n+  /// The close event with close code and reason from the socket connection.\n+  /// Will only be populated once the socket has actually closed.\n+  WSocketCloseEvent _closeEvent;\n+\n+  /// Completer that will complete when [_allClosed] has completed and the close\n+  /// code and reason have been set. If the socket closed due to an error, this\n+  /// will complete with an error. Otherwise, it will complete normally.\n+  Completer<Null> _done = new Completer();\n \n   CommonWSocket() {\n-    done.whenComplete(() {\n-      _closed = true;\n+    // Wait for both the sink and the socket to finish closing before exposing\n+    // the close code, close reason, and completing the [_done] completer.\n+    // If the socket closed due to an error, the [_done] completer will be\n+    // completed with that error.\n+    allClosed.future.then((_) {","path":"lib/src/web_socket/common/w_socket.dart","position":64,"original_position":64,"commit_id":"350f8781225211dee98f5590d1fa736c94970b88","original_commit_id":"350f8781225211dee98f5590d1fa736c94970b88","user":{"login":"trentgrover-wf","id":3778206,"avatar_url":"https://avatars.githubusercontent.com/u/3778206?v=3","gravatar_id":"","url":"https://api.github.com/users/trentgrover-wf","html_url":"https://github.com/trentgrover-wf","followers_url":"https://api.github.com/users/trentgrover-wf/followers","following_url":"https://api.github.com/users/trentgrover-wf/following{/other_user}","gists_url":"https://api.github.com/users/trentgrover-wf/gists{/gist_id}","starred_url":"https://api.github.com/users/trentgrover-wf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trentgrover-wf/subscriptions","organizations_url":"https://api.github.com/users/trentgrover-wf/orgs","repos_url":"https://api.github.com/users/trentgrover-wf/repos","events_url":"https://api.github.com/users/trentgrover-wf/events{/privacy}","received_events_url":"https://api.github.com/users/trentgrover-wf/received_events","type":"User","site_admin":false},"body":"is there a reason for `allClosed` to be public?  I would suspect that there could be async issues if a consumer waited for `allClosed` instead of `done` because there's a tiny risk that these `closeCode` / `closeReason` vals might not yet be valid","created_at":"2015-11-04T15:27:57Z","updated_at":"2015-11-04T15:27:57Z","html_url":"https://github.com/Workiva/w_transport/pull/71#discussion_r43893623","pull_request_url":"https://api.github.com/repos/Workiva/w_transport/pulls/71","_links":{"self":{"href":"https://api.github.com/repos/Workiva/w_transport/pulls/comments/43893623"},"html":{"href":"https://github.com/Workiva/w_transport/pull/71#discussion_r43893623"},"pull_request":{"href":"https://api.github.com/repos/Workiva/w_transport/pulls/71"}}},"pull_request":{"url":"https://api.github.com/repos/Workiva/w_transport/pulls/71","id":49631060,"html_url":"https://github.com/Workiva/w_transport/pull/71","diff_url":"https://github.com/Workiva/w_transport/pull/71.diff","patch_url":"https://github.com/Workiva/w_transport/pull/71.patch","issue_url":"https://api.github.com/repos/Workiva/w_transport/issues/71","number":71,"state":"open","locked":false,"title":"Cleanup WSocket, handle errors correctly, naming changes","user":{"login":"evanweible-wf","id":1738457,"avatar_url":"https://avatars.githubusercontent.com/u/1738457?v=3","gravatar_id":"","url":"https://api.github.com/users/evanweible-wf","html_url":"https://github.com/evanweible-wf","followers_url":"https://api.github.com/users/evanweible-wf/followers","following_url":"https://api.github.com/users/evanweible-wf/following{/other_user}","gists_url":"https://api.github.com/users/evanweible-wf/gists{/gist_id}","starred_url":"https://api.github.com/users/evanweible-wf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/evanweible-wf/subscriptions","organizations_url":"https://api.github.com/users/evanweible-wf/orgs","repos_url":"https://api.github.com/users/evanweible-wf/repos","events_url":"https://api.github.com/users/evanweible-wf/events{/privacy}","received_events_url":"https://api.github.com/users/evanweible-wf/received_events","type":"User","site_admin":false},"body":"## Issue\r\n- Need to conform to new naming conventions (Client --> Browser, Server --> VM)\r\n- `addError()` was not behaving correctly - could not catch the exception\r\n- Not confident in how we are monitoring the sink/socket status and reacting to them closing in correct order\r\n\r\n## Changes\r\n**No breaking changes!** All of this is an refactor to the internal code - no public API changes required.\r\n\r\n**Source:**\r\n- `Client` --> `Browser`\r\n- `Server` --> `VM`\r\n- `WSocket.addError()` now handles the error itself instead of passing it on to the underlying socket. Adding an error to the socket would just cause it to close, so we explicitly close it now instead. This allows us to control when the error is thrown, allowing consumers to catch it via the `WSocket.done` Future.\r\n- Quite a bit of the `WSocket` logic was moved up into the `CommonWSocket` class, reducing the platform-dependent code and DRYing up the code.\r\n- All implementations of `WSocket` now handle the outgoing sink and incoming socket connection in a much more clean manner. Centralized some logic into a `shutDown()` method that handles closing the sink and socket. We explicitly wait for both the sink and the socket to finish closing before finalizing some info and completing the `done` Future.\r\n- `MockWSocket` class updated to better align with the real implementations.\r\n\r\n**Tests:**\r\n- `addError()` integration test now passes!\r\n\r\n## Areas of Regression\r\n- WebSocket (`WSocket` class)\r\n\r\n## Testing\r\n- CI passes\r\n- Socket example passes\r\n\r\n## Code Review\r\n@trentgrover-wf\r\n@maxwellpeterson-wf \r\n@dustinlessard-wf\r\n@jayudey-wf ","created_at":"2015-11-04T00:03:30Z","updated_at":"2015-11-04T15:27:57Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e9438357b77f9e28dc34bb775a345e344509748f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Workiva/w_transport/pulls/71/commits","review_comments_url":"https://api.github.com/repos/Workiva/w_transport/pulls/71/comments","review_comment_url":"https://api.github.com/repos/Workiva/w_transport/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Workiva/w_transport/issues/71/comments","statuses_url":"https://api.github.com/repos/Workiva/w_transport/statuses/350f8781225211dee98f5590d1fa736c94970b88","head":{"label":"Workiva:socket","ref":"socket","sha":"350f8781225211dee98f5590d1fa736c94970b88","user":{"login":"Workiva","id":1087529,"avatar_url":"https://avatars.githubusercontent.com/u/1087529?v=3","gravatar_id":"","url":"https://api.github.com/users/Workiva","html_url":"https://github.com/Workiva","followers_url":"https://api.github.com/users/Workiva/followers","following_url":"https://api.github.com/users/Workiva/following{/other_user}","gists_url":"https://api.github.com/users/Workiva/gists{/gist_id}","starred_url":"https://api.github.com/users/Workiva/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Workiva/subscriptions","organizations_url":"https://api.github.com/users/Workiva/orgs","repos_url":"https://api.github.com/users/Workiva/repos","events_url":"https://api.github.com/users/Workiva/events{/privacy}","received_events_url":"https://api.github.com/users/Workiva/received_events","type":"Organization","site_admin":false},"repo":{"id":32808289,"name":"w_transport","full_name":"Workiva/w_transport","owner":{"login":"Workiva","id":1087529,"avatar_url":"https://avatars.githubusercontent.com/u/1087529?v=3","gravatar_id":"","url":"https://api.github.com/users/Workiva","html_url":"https://github.com/Workiva","followers_url":"https://api.github.com/users/Workiva/followers","following_url":"https://api.github.com/users/Workiva/following{/other_user}","gists_url":"https://api.github.com/users/Workiva/gists{/gist_id}","starred_url":"https://api.github.com/users/Workiva/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Workiva/subscriptions","organizations_url":"https://api.github.com/users/Workiva/orgs","repos_url":"https://api.github.com/users/Workiva/repos","events_url":"https://api.github.com/users/Workiva/events{/privacy}","received_events_url":"https://api.github.com/users/Workiva/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Workiva/w_transport","description":"","fork":false,"url":"https://api.github.com/repos/Workiva/w_transport","forks_url":"https://api.github.com/repos/Workiva/w_transport/forks","keys_url":"https://api.github.com/repos/Workiva/w_transport/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Workiva/w_transport/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Workiva/w_transport/teams","hooks_url":"https://api.github.com/repos/Workiva/w_transport/hooks","issue_events_url":"https://api.github.com/repos/Workiva/w_transport/issues/events{/number}","events_url":"https://api.github.com/repos/Workiva/w_transport/events","assignees_url":"https://api.github.com/repos/Workiva/w_transport/assignees{/user}","branches_url":"https://api.github.com/repos/Workiva/w_transport/branches{/branch}","tags_url":"https://api.github.com/repos/Workiva/w_transport/tags","blobs_url":"https://api.github.com/repos/Workiva/w_transport/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Workiva/w_transport/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Workiva/w_transport/git/refs{/sha}","trees_url":"https://api.github.com/repos/Workiva/w_transport/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Workiva/w_transport/statuses/{sha}","languages_url":"https://api.github.com/repos/Workiva/w_transport/languages","stargazers_url":"https://api.github.com/repos/Workiva/w_transport/stargazers","contributors_url":"https://api.github.com/repos/Workiva/w_transport/contributors","subscribers_url":"https://api.github.com/repos/Workiva/w_transport/subscribers","subscription_url":"https://api.github.com/repos/Workiva/w_transport/subscription","commits_url":"https://api.github.com/repos/Workiva/w_transport/commits{/sha}","git_commits_url":"https://api.github.com/repos/Workiva/w_transport/git/commits{/sha}","comments_url":"https://api.github.com/repos/Workiva/w_transport/comments{/number}","issue_comment_url":"https://api.github.com/repos/Workiva/w_transport/issues/comments{/number}","contents_url":"https://api.github.com/repos/Workiva/w_transport/contents/{+path}","compare_url":"https://api.github.com/repos/Workiva/w_transport/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Workiva/w_transport/merges","archive_url":"https://api.github.com/repos/Workiva/w_transport/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Workiva/w_transport/downloads","issues_url":"https://api.github.com/repos/Workiva/w_transport/issues{/number}","pulls_url":"https://api.github.com/repos/Workiva/w_transport/pulls{/number}","milestones_url":"https://api.github.com/repos/Workiva/w_transport/milestones{/number}","notifications_url":"https://api.github.com/repos/Workiva/w_transport/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Workiva/w_transport/labels{/name}","releases_url":"https://api.github.com/repos/Workiva/w_transport/releases{/id}","created_at":"2015-03-24T15:43:40Z","updated_at":"2015-09-10T12:24:41Z","pushed_at":"2015-11-04T00:03:30Z","git_url":"git://github.com/Workiva/w_transport.git","ssh_url":"git@github.com:Workiva/w_transport.git","clone_url":"https://github.com/Workiva/w_transport.git","svn_url":"https://github.com/Workiva/w_transport","homepage":null,"size":1020,"stargazers_count":3,"watchers_count":3,"language":"Dart","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":5,"forks":1,"open_issues":5,"watchers":3,"default_branch":"master"}},"base":{"label":"Workiva:master","ref":"master","sha":"98258d6a667314937dae2b580ebc2e8a80314a7b","user":{"login":"Workiva","id":1087529,"avatar_url":"https://avatars.githubusercontent.com/u/1087529?v=3","gravatar_id":"","url":"https://api.github.com/users/Workiva","html_url":"https://github.com/Workiva","followers_url":"https://api.github.com/users/Workiva/followers","following_url":"https://api.github.com/users/Workiva/following{/other_user}","gists_url":"https://api.github.com/users/Workiva/gists{/gist_id}","starred_url":"https://api.github.com/users/Workiva/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Workiva/subscriptions","organizations_url":"https://api.github.com/users/Workiva/orgs","repos_url":"https://api.github.com/users/Workiva/repos","events_url":"https://api.github.com/users/Workiva/events{/privacy}","received_events_url":"https://api.github.com/users/Workiva/received_events","type":"Organization","site_admin":false},"repo":{"id":32808289,"name":"w_transport","full_name":"Workiva/w_transport","owner":{"login":"Workiva","id":1087529,"avatar_url":"https://avatars.githubusercontent.com/u/1087529?v=3","gravatar_id":"","url":"https://api.github.com/users/Workiva","html_url":"https://github.com/Workiva","followers_url":"https://api.github.com/users/Workiva/followers","following_url":"https://api.github.com/users/Workiva/following{/other_user}","gists_url":"https://api.github.com/users/Workiva/gists{/gist_id}","starred_url":"https://api.github.com/users/Workiva/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Workiva/subscriptions","organizations_url":"https://api.github.com/users/Workiva/orgs","repos_url":"https://api.github.com/users/Workiva/repos","events_url":"https://api.github.com/users/Workiva/events{/privacy}","received_events_url":"https://api.github.com/users/Workiva/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Workiva/w_transport","description":"","fork":false,"url":"https://api.github.com/repos/Workiva/w_transport","forks_url":"https://api.github.com/repos/Workiva/w_transport/forks","keys_url":"https://api.github.com/repos/Workiva/w_transport/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Workiva/w_transport/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Workiva/w_transport/teams","hooks_url":"https://api.github.com/repos/Workiva/w_transport/hooks","issue_events_url":"https://api.github.com/repos/Workiva/w_transport/issues/events{/number}","events_url":"https://api.github.com/repos/Workiva/w_transport/events","assignees_url":"https://api.github.com/repos/Workiva/w_transport/assignees{/user}","branches_url":"https://api.github.com/repos/Workiva/w_transport/branches{/branch}","tags_url":"https://api.github.com/repos/Workiva/w_transport/tags","blobs_url":"https://api.github.com/repos/Workiva/w_transport/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Workiva/w_transport/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Workiva/w_transport/git/refs{/sha}","trees_url":"https://api.github.com/repos/Workiva/w_transport/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Workiva/w_transport/statuses/{sha}","languages_url":"https://api.github.com/repos/Workiva/w_transport/languages","stargazers_url":"https://api.github.com/repos/Workiva/w_transport/stargazers","contributors_url":"https://api.github.com/repos/Workiva/w_transport/contributors","subscribers_url":"https://api.github.com/repos/Workiva/w_transport/subscribers","subscription_url":"https://api.github.com/repos/Workiva/w_transport/subscription","commits_url":"https://api.github.com/repos/Workiva/w_transport/commits{/sha}","git_commits_url":"https://api.github.com/repos/Workiva/w_transport/git/commits{/sha}","comments_url":"https://api.github.com/repos/Workiva/w_transport/comments{/number}","issue_comment_url":"https://api.github.com/repos/Workiva/w_transport/issues/comments{/number}","contents_url":"https://api.github.com/repos/Workiva/w_transport/contents/{+path}","compare_url":"https://api.github.com/repos/Workiva/w_transport/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Workiva/w_transport/merges","archive_url":"https://api.github.com/repos/Workiva/w_transport/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Workiva/w_transport/downloads","issues_url":"https://api.github.com/repos/Workiva/w_transport/issues{/number}","pulls_url":"https://api.github.com/repos/Workiva/w_transport/pulls{/number}","milestones_url":"https://api.github.com/repos/Workiva/w_transport/milestones{/number}","notifications_url":"https://api.github.com/repos/Workiva/w_transport/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Workiva/w_transport/labels{/name}","releases_url":"https://api.github.com/repos/Workiva/w_transport/releases{/id}","created_at":"2015-03-24T15:43:40Z","updated_at":"2015-09-10T12:24:41Z","pushed_at":"2015-11-04T00:03:30Z","git_url":"git://github.com/Workiva/w_transport.git","ssh_url":"git@github.com:Workiva/w_transport.git","clone_url":"https://github.com/Workiva/w_transport.git","svn_url":"https://github.com/Workiva/w_transport","homepage":null,"size":1020,"stargazers_count":3,"watchers_count":3,"language":"Dart","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":5,"forks":1,"open_issues":5,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Workiva/w_transport/pulls/71"},"html":{"href":"https://github.com/Workiva/w_transport/pull/71"},"issue":{"href":"https://api.github.com/repos/Workiva/w_transport/issues/71"},"comments":{"href":"https://api.github.com/repos/Workiva/w_transport/issues/71/comments"},"review_comments":{"href":"https://api.github.com/repos/Workiva/w_transport/pulls/71/comments"},"review_comment":{"href":"https://api.github.com/repos/Workiva/w_transport/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Workiva/w_transport/pulls/71/commits"},"statuses":{"href":"https://api.github.com/repos/Workiva/w_transport/statuses/350f8781225211dee98f5590d1fa736c94970b88"}}}}