{"action":"closed","number":9,"pull_request":{"url":"https://api.github.com/repos/Rapptz/discord.py/pulls/9","id":47021344,"html_url":"https://github.com/Rapptz/discord.py/pull/9","diff_url":"https://github.com/Rapptz/discord.py/pull/9.diff","patch_url":"https://github.com/Rapptz/discord.py/pull/9.patch","issue_url":"https://api.github.com/repos/Rapptz/discord.py/issues/9","number":9,"state":"closed","locked":false,"title":"Client Refactor","user":{"login":"Hornwitser","id":14362102,"avatar_url":"https://avatars.githubusercontent.com/u/14362102?v=3","gravatar_id":"","url":"https://api.github.com/users/Hornwitser","html_url":"https://github.com/Hornwitser","followers_url":"https://api.github.com/users/Hornwitser/followers","following_url":"https://api.github.com/users/Hornwitser/following{/other_user}","gists_url":"https://api.github.com/users/Hornwitser/gists{/gist_id}","starred_url":"https://api.github.com/users/Hornwitser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Hornwitser/subscriptions","organizations_url":"https://api.github.com/users/Hornwitser/orgs","repos_url":"https://api.github.com/users/Hornwitser/repos","events_url":"https://api.github.com/users/Hornwitser/events{/privacy}","received_events_url":"https://api.github.com/users/Hornwitser/received_events","type":"User","site_admin":false},"body":"This is the fork I've been working on, it pulls out WebSocketClient and ConnectionState from the Client class.  Mainly to separate the concerns of the Client class, and to make the code that handles the connection, it's state, and the client separated, and closer together.\r\n\r\nWebSocketClient handles a single WebSocket connection to Discord.  This run method of this class will listen on the socket and dispatch events using the event dispatches passed in the initializer in response to messages received.\r\n\r\nConnectionState holds the state of servers, messages, users, etc received from the WebSocket.  While this would logically be a part of the WebSocketClient, it not as simple to put in there, as when the connection for WebSocketClient dies, the object has to replaced by a new one in order to connect up again, but in the event of a gateway switch, or a fast reconnect the state should be kept. (note that this is currently not implemented).\r\n\r\nIn order to facilitate the split, the event system is overhauled to better be able to accept events from sub-objects of the Client class, with the added benefit of being able to define event handles as methods of a sub class of Client.  The main change being the introduction of a dispatch method, for invoking events.  I find the sub-classing method leads to cleaner and more elegant code, however the ``@client.event`` decorator is still fully supported.\r\n\r\nThe most significant change is the removal of the threading in the WebSocketClient.  This fixes a lot of race conditions and synchronization issues, see my comment on #8 for a few of them.  In the end, this means that ``client.run()`` has to be called, and the thread that calls it, will be the thread that executes the events and and listens on the WebSocket.  Additionally, exceptions raised by Client or on_error will be properly propagated out of the call to run, and the client will have properly terminated the WebSocket connection before executions leaves run.\r\n\r\nAlso added is a register method to create a new account, and some improvements in the examples with regard to the minimum recommended setup and error checking.\r\n\r\nNotably missing is the documentation of the new event system and new events available, in particular the dispatch method. Documentation of the sub classing method of creating a bot. And documentation of the reconnect behavior of the Client.","created_at":"2015-10-07T12:36:12Z","updated_at":"2015-10-11T09:36:35Z","closed_at":"2015-10-11T09:36:35Z","merged_at":"2015-10-11T09:36:35Z","merge_commit_sha":"98f816a0b8b58f821a4f7e7bac226fa7bd02b062","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Rapptz/discord.py/pulls/9/commits","review_comments_url":"https://api.github.com/repos/Rapptz/discord.py/pulls/9/comments","review_comment_url":"https://api.github.com/repos/Rapptz/discord.py/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Rapptz/discord.py/issues/9/comments","statuses_url":"https://api.github.com/repos/Rapptz/discord.py/statuses/e258c9b893b9540159d3c2e9d333059b2dc9ba2f","head":{"label":"Hornwitser:client-refactor","ref":"client-refactor","sha":"e258c9b893b9540159d3c2e9d333059b2dc9ba2f","user":{"login":"Hornwitser","id":14362102,"avatar_url":"https://avatars.githubusercontent.com/u/14362102?v=3","gravatar_id":"","url":"https://api.github.com/users/Hornwitser","html_url":"https://github.com/Hornwitser","followers_url":"https://api.github.com/users/Hornwitser/followers","following_url":"https://api.github.com/users/Hornwitser/following{/other_user}","gists_url":"https://api.github.com/users/Hornwitser/gists{/gist_id}","starred_url":"https://api.github.com/users/Hornwitser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Hornwitser/subscriptions","organizations_url":"https://api.github.com/users/Hornwitser/orgs","repos_url":"https://api.github.com/users/Hornwitser/repos","events_url":"https://api.github.com/users/Hornwitser/events{/privacy}","received_events_url":"https://api.github.com/users/Hornwitser/received_events","type":"User","site_admin":false},"repo":{"id":42778978,"name":"discord.py","full_name":"Hornwitser/discord.py","owner":{"login":"Hornwitser","id":14362102,"avatar_url":"https://avatars.githubusercontent.com/u/14362102?v=3","gravatar_id":"","url":"https://api.github.com/users/Hornwitser","html_url":"https://github.com/Hornwitser","followers_url":"https://api.github.com/users/Hornwitser/followers","following_url":"https://api.github.com/users/Hornwitser/following{/other_user}","gists_url":"https://api.github.com/users/Hornwitser/gists{/gist_id}","starred_url":"https://api.github.com/users/Hornwitser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Hornwitser/subscriptions","organizations_url":"https://api.github.com/users/Hornwitser/orgs","repos_url":"https://api.github.com/users/Hornwitser/repos","events_url":"https://api.github.com/users/Hornwitser/events{/privacy}","received_events_url":"https://api.github.com/users/Hornwitser/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Hornwitser/discord.py","description":"An API wrapper for Discord written in Python.","fork":true,"url":"https://api.github.com/repos/Hornwitser/discord.py","forks_url":"https://api.github.com/repos/Hornwitser/discord.py/forks","keys_url":"https://api.github.com/repos/Hornwitser/discord.py/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Hornwitser/discord.py/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Hornwitser/discord.py/teams","hooks_url":"https://api.github.com/repos/Hornwitser/discord.py/hooks","issue_events_url":"https://api.github.com/repos/Hornwitser/discord.py/issues/events{/number}","events_url":"https://api.github.com/repos/Hornwitser/discord.py/events","assignees_url":"https://api.github.com/repos/Hornwitser/discord.py/assignees{/user}","branches_url":"https://api.github.com/repos/Hornwitser/discord.py/branches{/branch}","tags_url":"https://api.github.com/repos/Hornwitser/discord.py/tags","blobs_url":"https://api.github.com/repos/Hornwitser/discord.py/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Hornwitser/discord.py/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Hornwitser/discord.py/git/refs{/sha}","trees_url":"https://api.github.com/repos/Hornwitser/discord.py/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Hornwitser/discord.py/statuses/{sha}","languages_url":"https://api.github.com/repos/Hornwitser/discord.py/languages","stargazers_url":"https://api.github.com/repos/Hornwitser/discord.py/stargazers","contributors_url":"https://api.github.com/repos/Hornwitser/discord.py/contributors","subscribers_url":"https://api.github.com/repos/Hornwitser/discord.py/subscribers","subscription_url":"https://api.github.com/repos/Hornwitser/discord.py/subscription","commits_url":"https://api.github.com/repos/Hornwitser/discord.py/commits{/sha}","git_commits_url":"https://api.github.com/repos/Hornwitser/discord.py/git/commits{/sha}","comments_url":"https://api.github.com/repos/Hornwitser/discord.py/comments{/number}","issue_comment_url":"https://api.github.com/repos/Hornwitser/discord.py/issues/comments{/number}","contents_url":"https://api.github.com/repos/Hornwitser/discord.py/contents/{+path}","compare_url":"https://api.github.com/repos/Hornwitser/discord.py/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Hornwitser/discord.py/merges","archive_url":"https://api.github.com/repos/Hornwitser/discord.py/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Hornwitser/discord.py/downloads","issues_url":"https://api.github.com/repos/Hornwitser/discord.py/issues{/number}","pulls_url":"https://api.github.com/repos/Hornwitser/discord.py/pulls{/number}","milestones_url":"https://api.github.com/repos/Hornwitser/discord.py/milestones{/number}","notifications_url":"https://api.github.com/repos/Hornwitser/discord.py/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Hornwitser/discord.py/labels{/name}","releases_url":"https://api.github.com/repos/Hornwitser/discord.py/releases{/id}","created_at":"2015-09-19T15:48:43Z","updated_at":"2015-09-19T15:49:57Z","pushed_at":"2015-10-06T19:51:24Z","git_url":"git://github.com/Hornwitser/discord.py.git","ssh_url":"git@github.com:Hornwitser/discord.py.git","clone_url":"https://github.com/Hornwitser/discord.py.git","svn_url":"https://github.com/Hornwitser/discord.py","homepage":"http://rapptz.github.io/discord.py/","size":468,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Rapptz:master","ref":"master","sha":"7b3f31f25c27efcee2aa3dfb2c521874d8706892","user":{"login":"Rapptz","id":1695103,"avatar_url":"https://avatars.githubusercontent.com/u/1695103?v=3","gravatar_id":"","url":"https://api.github.com/users/Rapptz","html_url":"https://github.com/Rapptz","followers_url":"https://api.github.com/users/Rapptz/followers","following_url":"https://api.github.com/users/Rapptz/following{/other_user}","gists_url":"https://api.github.com/users/Rapptz/gists{/gist_id}","starred_url":"https://api.github.com/users/Rapptz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rapptz/subscriptions","organizations_url":"https://api.github.com/users/Rapptz/orgs","repos_url":"https://api.github.com/users/Rapptz/repos","events_url":"https://api.github.com/users/Rapptz/events{/privacy}","received_events_url":"https://api.github.com/users/Rapptz/received_events","type":"User","site_admin":false},"repo":{"id":41179827,"name":"discord.py","full_name":"Rapptz/discord.py","owner":{"login":"Rapptz","id":1695103,"avatar_url":"https://avatars.githubusercontent.com/u/1695103?v=3","gravatar_id":"","url":"https://api.github.com/users/Rapptz","html_url":"https://github.com/Rapptz","followers_url":"https://api.github.com/users/Rapptz/followers","following_url":"https://api.github.com/users/Rapptz/following{/other_user}","gists_url":"https://api.github.com/users/Rapptz/gists{/gist_id}","starred_url":"https://api.github.com/users/Rapptz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rapptz/subscriptions","organizations_url":"https://api.github.com/users/Rapptz/orgs","repos_url":"https://api.github.com/users/Rapptz/repos","events_url":"https://api.github.com/users/Rapptz/events{/privacy}","received_events_url":"https://api.github.com/users/Rapptz/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Rapptz/discord.py","description":"An API wrapper for Discord written in Python.","fork":false,"url":"https://api.github.com/repos/Rapptz/discord.py","forks_url":"https://api.github.com/repos/Rapptz/discord.py/forks","keys_url":"https://api.github.com/repos/Rapptz/discord.py/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Rapptz/discord.py/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Rapptz/discord.py/teams","hooks_url":"https://api.github.com/repos/Rapptz/discord.py/hooks","issue_events_url":"https://api.github.com/repos/Rapptz/discord.py/issues/events{/number}","events_url":"https://api.github.com/repos/Rapptz/discord.py/events","assignees_url":"https://api.github.com/repos/Rapptz/discord.py/assignees{/user}","branches_url":"https://api.github.com/repos/Rapptz/discord.py/branches{/branch}","tags_url":"https://api.github.com/repos/Rapptz/discord.py/tags","blobs_url":"https://api.github.com/repos/Rapptz/discord.py/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Rapptz/discord.py/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Rapptz/discord.py/git/refs{/sha}","trees_url":"https://api.github.com/repos/Rapptz/discord.py/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Rapptz/discord.py/statuses/{sha}","languages_url":"https://api.github.com/repos/Rapptz/discord.py/languages","stargazers_url":"https://api.github.com/repos/Rapptz/discord.py/stargazers","contributors_url":"https://api.github.com/repos/Rapptz/discord.py/contributors","subscribers_url":"https://api.github.com/repos/Rapptz/discord.py/subscribers","subscription_url":"https://api.github.com/repos/Rapptz/discord.py/subscription","commits_url":"https://api.github.com/repos/Rapptz/discord.py/commits{/sha}","git_commits_url":"https://api.github.com/repos/Rapptz/discord.py/git/commits{/sha}","comments_url":"https://api.github.com/repos/Rapptz/discord.py/comments{/number}","issue_comment_url":"https://api.github.com/repos/Rapptz/discord.py/issues/comments{/number}","contents_url":"https://api.github.com/repos/Rapptz/discord.py/contents/{+path}","compare_url":"https://api.github.com/repos/Rapptz/discord.py/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Rapptz/discord.py/merges","archive_url":"https://api.github.com/repos/Rapptz/discord.py/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Rapptz/discord.py/downloads","issues_url":"https://api.github.com/repos/Rapptz/discord.py/issues{/number}","pulls_url":"https://api.github.com/repos/Rapptz/discord.py/pulls{/number}","milestones_url":"https://api.github.com/repos/Rapptz/discord.py/milestones{/number}","notifications_url":"https://api.github.com/repos/Rapptz/discord.py/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Rapptz/discord.py/labels{/name}","releases_url":"https://api.github.com/repos/Rapptz/discord.py/releases{/id}","created_at":"2015-08-21T22:19:08Z","updated_at":"2015-10-09T05:09:22Z","pushed_at":"2015-10-11T09:36:35Z","git_url":"git://github.com/Rapptz/discord.py.git","ssh_url":"git@github.com:Rapptz/discord.py.git","clone_url":"https://github.com/Rapptz/discord.py.git","svn_url":"https://github.com/Rapptz/discord.py","homepage":"http://rapptz.github.io/discord.py/","size":820,"stargazers_count":20,"watchers_count":20,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":8,"mirror_url":null,"open_issues_count":3,"forks":8,"open_issues":3,"watchers":20,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Rapptz/discord.py/pulls/9"},"html":{"href":"https://github.com/Rapptz/discord.py/pull/9"},"issue":{"href":"https://api.github.com/repos/Rapptz/discord.py/issues/9"},"comments":{"href":"https://api.github.com/repos/Rapptz/discord.py/issues/9/comments"},"review_comments":{"href":"https://api.github.com/repos/Rapptz/discord.py/pulls/9/comments"},"review_comment":{"href":"https://api.github.com/repos/Rapptz/discord.py/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Rapptz/discord.py/pulls/9/commits"},"statuses":{"href":"https://api.github.com/repos/Rapptz/discord.py/statuses/e258c9b893b9540159d3c2e9d333059b2dc9ba2f"}},"merged":true,"mergeable":null,"mergeable_state":"unknown","merged_by":{"login":"Rapptz","id":1695103,"avatar_url":"https://avatars.githubusercontent.com/u/1695103?v=3","gravatar_id":"","url":"https://api.github.com/users/Rapptz","html_url":"https://github.com/Rapptz","followers_url":"https://api.github.com/users/Rapptz/followers","following_url":"https://api.github.com/users/Rapptz/following{/other_user}","gists_url":"https://api.github.com/users/Rapptz/gists{/gist_id}","starred_url":"https://api.github.com/users/Rapptz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rapptz/subscriptions","organizations_url":"https://api.github.com/users/Rapptz/orgs","repos_url":"https://api.github.com/users/Rapptz/repos","events_url":"https://api.github.com/users/Rapptz/events{/privacy}","received_events_url":"https://api.github.com/users/Rapptz/received_events","type":"User","site_admin":false},"comments":0,"review_comments":0,"commits":10,"additions":419,"deletions":244,"changed_files":8}}