{"action":"created","comment":{"url":"https://api.github.com/repos/apache/incubator-pulsar/pulls/comments/126274730","pull_request_review_id":48749353,"id":126274730,"diff_hunk":"@@ -0,0 +1,181 @@\n+/**\n+ * Licensed to the Apache Software Foundation (ASF) under one\n+ * or more contributor license agreements.  See the NOTICE file\n+ * distributed with this work for additional information\n+ * regarding copyright ownership.  The ASF licenses this file\n+ * to you under the Apache License, Version 2.0 (the\n+ * \"License\"); you may not use this file except in compliance\n+ * with the License.  You may obtain a copy of the License at\n+ *\n+ *   http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing,\n+ * software distributed under the License is distributed on an\n+ * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n+ * KIND, either express or implied.  See the License for the\n+ * specific language governing permissions and limitations\n+ * under the License.\n+ */\n+\n+package org.apache.pulsar.proxy.server;\n+\n+import java.net.URI;\n+import java.net.URISyntaxException;\n+\n+import org.apache.pulsar.client.api.Authentication;\n+import org.apache.pulsar.common.api.Commands;\n+import org.apache.pulsar.common.api.PulsarDecoder;\n+import org.apache.pulsar.common.api.PulsarLengthFieldFrameDecoder;\n+import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnected;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+import io.netty.bootstrap.Bootstrap;\n+import io.netty.buffer.PooledByteBufAllocator;\n+import io.netty.channel.Channel;\n+import io.netty.channel.ChannelFuture;\n+import io.netty.channel.ChannelHandlerContext;\n+import io.netty.channel.ChannelInitializer;\n+import io.netty.channel.ChannelOption;\n+import io.netty.channel.socket.SocketChannel;\n+import io.netty.util.concurrent.Future;\n+import io.netty.util.concurrent.FutureListener;\n+\n+public class DirectProxyHandler {\n+\n+    private Channel inboundChannel;\n+    Channel outboundChannel;\n+\n+    private final Authentication authentication;\n+\n+    public DirectProxyHandler(ProxyService service, ProxyConnection proxyConnection, String targetBrokerUrl) {\n+        this.authentication = service.getClientAuthentication();\n+        this.inboundChannel = proxyConnection.ctx().channel();\n+\n+        // Start the connection attempt.\n+        Bootstrap b = new Bootstrap();\n+        // Tie the backend connection on the same thread to avoid context switches when passing data between the 2\n+        // connections\n+        b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);\n+        b.group(inboundChannel.eventLoop()).channel(inboundChannel.getClass()).option(ChannelOption.AUTO_READ, false);\n+        b.handler(new ChannelInitializer<SocketChannel>() {\n+            @Override\n+            protected void initChannel(SocketChannel ch) throws Exception {\n+                ch.pipeline().addLast(\"frameDecoder\",\n+                        new PulsarLengthFieldFrameDecoder(PulsarDecoder.MaxFrameSize, 0, 4, 0, 4));\n+                ch.pipeline().addLast(new ProxyBackendHandler());\n+            }\n+        });\n+\n+        URI targetBroker;\n+        try {\n+            // targetBrokerUrl is coming in the \"hostname:6650\" form, so we need to extract host and port\n+            targetBroker = new URI(\"pulsar://\" + targetBrokerUrl);\n+        } catch (URISyntaxException e) {\n+            log.warn(\"[{}] Failed to parse broker url '{}'\", inboundChannel, targetBrokerUrl, e);\n+            inboundChannel.close();\n+            return;\n+        }\n+\n+        ChannelFuture f = b.connect(targetBroker.getHost(), targetBroker.getPort());\n+        outboundChannel = f.channel();\n+        f.addListener(future -> {\n+            if (!future.isSuccess()) {\n+                // Close the connection if the connection attempt has failed.\n+                inboundChannel.close();\n+            }\n+        });\n+    }\n+\n+    enum BackendState {\n+        Init, HandshakeCompleted\n+    }\n+\n+    public class ProxyBackendHandler extends PulsarDecoder implements FutureListener<Void> {\n+\n+        private BackendState state = BackendState.Init;\n+\n+        @Override\n+        public void channelActive(ChannelHandlerContext ctx) throws Exception {\n+            // Send the Connect command to broker\n+            String authData = \"\";\n+            if (authentication.getAuthData().hasDataFromCommand()) {\n+                authData = authentication.getAuthData().getCommandData();\n+            }\n+            outboundChannel\n+                    .writeAndFlush(Commands.newConnect(authentication.getAuthMethodName(), authData, \"Pulsar proxy\"));\n+            outboundChannel.read();\n+        }\n+\n+        @Override\n+        public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {\n+            switch (state) {\n+            case Init:\n+                if (log.isDebugEnabled()) {\n+                    log.debug(\"[{}] [{}] Received msg on broker connection: {}\", inboundChannel, outboundChannel,\n+                            msg.getClass());\n+                }\n+\n+                // Do the regular decoding for the Connected message\n+                super.channelRead(ctx, msg);\n+                break;\n+\n+            case HandshakeCompleted:\n+                inboundChannel.writeAndFlush(msg).addListener(this);\n+                break;\n+\n+            default:\n+                break;\n+            }\n+\n+        }\n+\n+        @Override\n+        public void operationComplete(Future<Void> future) throws Exception {\n+            // This is invoked when the write operation on the paired connection is completed\n+            if (future.isSuccess()) {\n+                outboundChannel.read();","path":"pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/DirectProxyHandler.java","position":137,"original_position":137,"commit_id":"bed33fde1841b366997441ccf1414bfca9103367","original_commit_id":"bed33fde1841b366997441ccf1414bfca9103367","user":{"login":"merlimat","id":62500,"avatar_url":"https://avatars1.githubusercontent.com/u/62500?v=3","gravatar_id":"","url":"https://api.github.com/users/merlimat","html_url":"https://github.com/merlimat","followers_url":"https://api.github.com/users/merlimat/followers","following_url":"https://api.github.com/users/merlimat/following{/other_user}","gists_url":"https://api.github.com/users/merlimat/gists{/gist_id}","starred_url":"https://api.github.com/users/merlimat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/merlimat/subscriptions","organizations_url":"https://api.github.com/users/merlimat/orgs","repos_url":"https://api.github.com/users/merlimat/repos","events_url":"https://api.github.com/users/merlimat/events{/privacy}","received_events_url":"https://api.github.com/users/merlimat/received_events","type":"User","site_admin":false},"body":"No, the auto-read on the channel is set to false. The reason is to adapt to the speed of the slowest connection. \r\n\r\nSo, we read 1 buffer from `c1`, write into `c2`. When the write is completed (meaning we were able to write on the socket because the TCP send window was open), then we read the next buffer.","created_at":"2017-07-08T04:56:44Z","updated_at":"2017-07-08T04:56:44Z","html_url":"https://github.com/apache/incubator-pulsar/pull/548#discussion_r126274730","pull_request_url":"https://api.github.com/repos/apache/incubator-pulsar/pulls/548","_links":{"self":{"href":"https://api.github.com/repos/apache/incubator-pulsar/pulls/comments/126274730"},"html":{"href":"https://github.com/apache/incubator-pulsar/pull/548#discussion_r126274730"},"pull_request":{"href":"https://api.github.com/repos/apache/incubator-pulsar/pulls/548"}}},"pull_request":{"url":"https://api.github.com/repos/apache/incubator-pulsar/pulls/548","id":129085608,"html_url":"https://github.com/apache/incubator-pulsar/pull/548","diff_url":"https://github.com/apache/incubator-pulsar/pull/548.diff","patch_url":"https://github.com/apache/incubator-pulsar/pull/548.patch","issue_url":"https://api.github.com/repos/apache/incubator-pulsar/issues/548","number":548,"state":"open","locked":false,"title":"PIP-1 - Introduce Pulsar proxy component","user":{"login":"merlimat","id":62500,"avatar_url":"https://avatars1.githubusercontent.com/u/62500?v=3","gravatar_id":"","url":"https://api.github.com/users/merlimat","html_url":"https://github.com/merlimat","followers_url":"https://api.github.com/users/merlimat/followers","following_url":"https://api.github.com/users/merlimat/following{/other_user}","gists_url":"https://api.github.com/users/merlimat/gists{/gist_id}","starred_url":"https://api.github.com/users/merlimat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/merlimat/subscriptions","organizations_url":"https://api.github.com/users/merlimat/orgs","repos_url":"https://api.github.com/users/merlimat/repos","events_url":"https://api.github.com/users/merlimat/events{/privacy}","received_events_url":"https://api.github.com/users/merlimat/received_events","type":"User","site_admin":false},"body":"### Motivation\r\n\r\nhttps://github.com/apache/incubator-pulsar/wiki/PIP-1\r\n\r\nAs described in the wiki page, added a proxy component that exposes a stateless service that talk Pulsar binary protocol.","created_at":"2017-07-06T01:16:47Z","updated_at":"2017-07-08T04:56:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3b48ebefda1f0b8e8609b74b0e4a210c5993c56d","assignee":{"login":"merlimat","id":62500,"avatar_url":"https://avatars1.githubusercontent.com/u/62500?v=3","gravatar_id":"","url":"https://api.github.com/users/merlimat","html_url":"https://github.com/merlimat","followers_url":"https://api.github.com/users/merlimat/followers","following_url":"https://api.github.com/users/merlimat/following{/other_user}","gists_url":"https://api.github.com/users/merlimat/gists{/gist_id}","starred_url":"https://api.github.com/users/merlimat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/merlimat/subscriptions","organizations_url":"https://api.github.com/users/merlimat/orgs","repos_url":"https://api.github.com/users/merlimat/repos","events_url":"https://api.github.com/users/merlimat/events{/privacy}","received_events_url":"https://api.github.com/users/merlimat/received_events","type":"User","site_admin":false},"assignees":[{"login":"merlimat","id":62500,"avatar_url":"https://avatars1.githubusercontent.com/u/62500?v=3","gravatar_id":"","url":"https://api.github.com/users/merlimat","html_url":"https://github.com/merlimat","followers_url":"https://api.github.com/users/merlimat/followers","following_url":"https://api.github.com/users/merlimat/following{/other_user}","gists_url":"https://api.github.com/users/merlimat/gists{/gist_id}","starred_url":"https://api.github.com/users/merlimat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/merlimat/subscriptions","organizations_url":"https://api.github.com/users/merlimat/orgs","repos_url":"https://api.github.com/users/merlimat/repos","events_url":"https://api.github.com/users/merlimat/events{/privacy}","received_events_url":"https://api.github.com/users/merlimat/received_events","type":"User","site_admin":false}],"requested_reviewers":[{"login":"saandrews","id":20527148,"avatar_url":"https://avatars0.githubusercontent.com/u/20527148?v=3","gravatar_id":"","url":"https://api.github.com/users/saandrews","html_url":"https://github.com/saandrews","followers_url":"https://api.github.com/users/saandrews/followers","following_url":"https://api.github.com/users/saandrews/following{/other_user}","gists_url":"https://api.github.com/users/saandrews/gists{/gist_id}","starred_url":"https://api.github.com/users/saandrews/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saandrews/subscriptions","organizations_url":"https://api.github.com/users/saandrews/orgs","repos_url":"https://api.github.com/users/saandrews/repos","events_url":"https://api.github.com/users/saandrews/events{/privacy}","received_events_url":"https://api.github.com/users/saandrews/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/apache/incubator-pulsar/milestones/8","html_url":"https://github.com/apache/incubator-pulsar/milestone/8","labels_url":"https://api.github.com/repos/apache/incubator-pulsar/milestones/8/labels","id":2437352,"number":8,"title":"1.19.0-incubating","description":"","creator":{"login":"merlimat","id":62500,"avatar_url":"https://avatars1.githubusercontent.com/u/62500?v=3","gravatar_id":"","url":"https://api.github.com/users/merlimat","html_url":"https://github.com/merlimat","followers_url":"https://api.github.com/users/merlimat/followers","following_url":"https://api.github.com/users/merlimat/following{/other_user}","gists_url":"https://api.github.com/users/merlimat/gists{/gist_id}","starred_url":"https://api.github.com/users/merlimat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/merlimat/subscriptions","organizations_url":"https://api.github.com/users/merlimat/orgs","repos_url":"https://api.github.com/users/merlimat/repos","events_url":"https://api.github.com/users/merlimat/events{/privacy}","received_events_url":"https://api.github.com/users/merlimat/received_events","type":"User","site_admin":false},"open_issues":25,"closed_issues":53,"state":"open","created_at":"2017-04-05T17:12:10Z","updated_at":"2017-07-08T01:15:36Z","due_on":"2017-07-31T07:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/apache/incubator-pulsar/pulls/548/commits","review_comments_url":"https://api.github.com/repos/apache/incubator-pulsar/pulls/548/comments","review_comment_url":"https://api.github.com/repos/apache/incubator-pulsar/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/incubator-pulsar/issues/548/comments","statuses_url":"https://api.github.com/repos/apache/incubator-pulsar/statuses/bed33fde1841b366997441ccf1414bfca9103367","head":{"label":"merlimat:proxy","ref":"proxy","sha":"bed33fde1841b366997441ccf1414bfca9103367","user":{"login":"merlimat","id":62500,"avatar_url":"https://avatars1.githubusercontent.com/u/62500?v=3","gravatar_id":"","url":"https://api.github.com/users/merlimat","html_url":"https://github.com/merlimat","followers_url":"https://api.github.com/users/merlimat/followers","following_url":"https://api.github.com/users/merlimat/following{/other_user}","gists_url":"https://api.github.com/users/merlimat/gists{/gist_id}","starred_url":"https://api.github.com/users/merlimat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/merlimat/subscriptions","organizations_url":"https://api.github.com/users/merlimat/orgs","repos_url":"https://api.github.com/users/merlimat/repos","events_url":"https://api.github.com/users/merlimat/events{/privacy}","received_events_url":"https://api.github.com/users/merlimat/received_events","type":"User","site_admin":false},"repo":{"id":67633583,"name":"pulsar","full_name":"merlimat/pulsar","owner":{"login":"merlimat","id":62500,"avatar_url":"https://avatars1.githubusercontent.com/u/62500?v=3","gravatar_id":"","url":"https://api.github.com/users/merlimat","html_url":"https://github.com/merlimat","followers_url":"https://api.github.com/users/merlimat/followers","following_url":"https://api.github.com/users/merlimat/following{/other_user}","gists_url":"https://api.github.com/users/merlimat/gists{/gist_id}","starred_url":"https://api.github.com/users/merlimat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/merlimat/subscriptions","organizations_url":"https://api.github.com/users/merlimat/orgs","repos_url":"https://api.github.com/users/merlimat/repos","events_url":"https://api.github.com/users/merlimat/events{/privacy}","received_events_url":"https://api.github.com/users/merlimat/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/merlimat/pulsar","description":"Pulsar - distributed pub-sub messaging system","fork":true,"url":"https://api.github.com/repos/merlimat/pulsar","forks_url":"https://api.github.com/repos/merlimat/pulsar/forks","keys_url":"https://api.github.com/repos/merlimat/pulsar/keys{/key_id}","collaborators_url":"https://api.github.com/repos/merlimat/pulsar/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/merlimat/pulsar/teams","hooks_url":"https://api.github.com/repos/merlimat/pulsar/hooks","issue_events_url":"https://api.github.com/repos/merlimat/pulsar/issues/events{/number}","events_url":"https://api.github.com/repos/merlimat/pulsar/events","assignees_url":"https://api.github.com/repos/merlimat/pulsar/assignees{/user}","branches_url":"https://api.github.com/repos/merlimat/pulsar/branches{/branch}","tags_url":"https://api.github.com/repos/merlimat/pulsar/tags","blobs_url":"https://api.github.com/repos/merlimat/pulsar/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/merlimat/pulsar/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/merlimat/pulsar/git/refs{/sha}","trees_url":"https://api.github.com/repos/merlimat/pulsar/git/trees{/sha}","statuses_url":"https://api.github.com/repos/merlimat/pulsar/statuses/{sha}","languages_url":"https://api.github.com/repos/merlimat/pulsar/languages","stargazers_url":"https://api.github.com/repos/merlimat/pulsar/stargazers","contributors_url":"https://api.github.com/repos/merlimat/pulsar/contributors","subscribers_url":"https://api.github.com/repos/merlimat/pulsar/subscribers","subscription_url":"https://api.github.com/repos/merlimat/pulsar/subscription","commits_url":"https://api.github.com/repos/merlimat/pulsar/commits{/sha}","git_commits_url":"https://api.github.com/repos/merlimat/pulsar/git/commits{/sha}","comments_url":"https://api.github.com/repos/merlimat/pulsar/comments{/number}","issue_comment_url":"https://api.github.com/repos/merlimat/pulsar/issues/comments{/number}","contents_url":"https://api.github.com/repos/merlimat/pulsar/contents/{+path}","compare_url":"https://api.github.com/repos/merlimat/pulsar/compare/{base}...{head}","merges_url":"https://api.github.com/repos/merlimat/pulsar/merges","archive_url":"https://api.github.com/repos/merlimat/pulsar/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/merlimat/pulsar/downloads","issues_url":"https://api.github.com/repos/merlimat/pulsar/issues{/number}","pulls_url":"https://api.github.com/repos/merlimat/pulsar/pulls{/number}","milestones_url":"https://api.github.com/repos/merlimat/pulsar/milestones{/number}","notifications_url":"https://api.github.com/repos/merlimat/pulsar/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/merlimat/pulsar/labels{/name}","releases_url":"https://api.github.com/repos/merlimat/pulsar/releases{/id}","deployments_url":"https://api.github.com/repos/merlimat/pulsar/deployments","created_at":"2016-09-07T18:37:15Z","updated_at":"2017-05-26T11:28:02Z","pushed_at":"2017-07-08T04:44:05Z","git_url":"git://github.com/merlimat/pulsar.git","ssh_url":"git@github.com:merlimat/pulsar.git","clone_url":"https://github.com/merlimat/pulsar.git","svn_url":"https://github.com/merlimat/pulsar","homepage":"","size":8223,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"b801eaa5551a2e53593125cf4adf84b35437bb80","user":{"login":"apache","id":47359,"avatar_url":"https://avatars3.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":62117812,"name":"incubator-pulsar","full_name":"apache/incubator-pulsar","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars3.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/incubator-pulsar","description":"Pulsar - distributed pub-sub messaging system","fork":false,"url":"https://api.github.com/repos/apache/incubator-pulsar","forks_url":"https://api.github.com/repos/apache/incubator-pulsar/forks","keys_url":"https://api.github.com/repos/apache/incubator-pulsar/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/incubator-pulsar/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/incubator-pulsar/teams","hooks_url":"https://api.github.com/repos/apache/incubator-pulsar/hooks","issue_events_url":"https://api.github.com/repos/apache/incubator-pulsar/issues/events{/number}","events_url":"https://api.github.com/repos/apache/incubator-pulsar/events","assignees_url":"https://api.github.com/repos/apache/incubator-pulsar/assignees{/user}","branches_url":"https://api.github.com/repos/apache/incubator-pulsar/branches{/branch}","tags_url":"https://api.github.com/repos/apache/incubator-pulsar/tags","blobs_url":"https://api.github.com/repos/apache/incubator-pulsar/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/incubator-pulsar/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/incubator-pulsar/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/incubator-pulsar/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/incubator-pulsar/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/incubator-pulsar/languages","stargazers_url":"https://api.github.com/repos/apache/incubator-pulsar/stargazers","contributors_url":"https://api.github.com/repos/apache/incubator-pulsar/contributors","subscribers_url":"https://api.github.com/repos/apache/incubator-pulsar/subscribers","subscription_url":"https://api.github.com/repos/apache/incubator-pulsar/subscription","commits_url":"https://api.github.com/repos/apache/incubator-pulsar/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/incubator-pulsar/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/incubator-pulsar/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/incubator-pulsar/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/incubator-pulsar/contents/{+path}","compare_url":"https://api.github.com/repos/apache/incubator-pulsar/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/incubator-pulsar/merges","archive_url":"https://api.github.com/repos/apache/incubator-pulsar/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/incubator-pulsar/downloads","issues_url":"https://api.github.com/repos/apache/incubator-pulsar/issues{/number}","pulls_url":"https://api.github.com/repos/apache/incubator-pulsar/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/incubator-pulsar/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/incubator-pulsar/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/incubator-pulsar/labels{/name}","releases_url":"https://api.github.com/repos/apache/incubator-pulsar/releases{/id}","deployments_url":"https://api.github.com/repos/apache/incubator-pulsar/deployments","created_at":"2016-06-28T07:00:03Z","updated_at":"2017-07-07T15:52:44Z","pushed_at":"2017-07-08T00:41:51Z","git_url":"git://github.com/apache/incubator-pulsar.git","ssh_url":"git@github.com:apache/incubator-pulsar.git","clone_url":"https://github.com/apache/incubator-pulsar.git","svn_url":"https://github.com/apache/incubator-pulsar","homepage":"https://pulsar.incubator.apache.org","size":5024,"stargazers_count":1235,"watchers_count":1235,"language":"Java","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":268,"mirror_url":null,"open_issues_count":62,"forks":268,"open_issues":62,"watchers":1235,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/incubator-pulsar/pulls/548"},"html":{"href":"https://github.com/apache/incubator-pulsar/pull/548"},"issue":{"href":"https://api.github.com/repos/apache/incubator-pulsar/issues/548"},"comments":{"href":"https://api.github.com/repos/apache/incubator-pulsar/issues/548/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/incubator-pulsar/pulls/548/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/incubator-pulsar/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/incubator-pulsar/pulls/548/commits"},"statuses":{"href":"https://api.github.com/repos/apache/incubator-pulsar/statuses/bed33fde1841b366997441ccf1414bfca9103367"}}}}
{"actor":{"display_login":"merlimat"}}