{"action":"created","comment":{"url":"https://api.github.com/repos/uber/tchannel-java/pulls/comments/42433352","id":42433352,"diff_hunk":"@@ -0,0 +1,227 @@\n+/*\n+ * Copyright (c) 2015 Uber Technologies, Inc.\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining a copy\n+ * of this software and associated documentation files (the \"Software\"), to deal\n+ * in the Software without restriction, including without limitation the rights\n+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+ * copies of the Software, and to permit persons to whom the Software is\n+ * furnished to do so, subject to the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be included in\n+ * all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n+ * THE SOFTWARE.\n+ */\n+\n+package com.uber.tchannel.hyperbahn.api;\n+\n+import java.io.FileReader;\n+import java.io.IOException;\n+import java.io.Reader;\n+import java.net.InetSocketAddress;\n+import java.util.LinkedList;\n+import java.util.List;\n+import java.util.Random;\n+import java.util.Timer;\n+import java.util.TimerTask;\n+import java.util.concurrent.Executor;\n+import java.util.concurrent.TimeUnit;\n+import java.util.concurrent.atomic.AtomicBoolean;\n+import java.util.regex.Pattern;\n+\n+import com.google.common.util.concurrent.ListenableFuture;\n+import com.google.gson.Gson;\n+import com.uber.tchannel.api.Request;\n+import com.uber.tchannel.api.Response;\n+import com.uber.tchannel.api.TChannel;\n+import com.uber.tchannel.api.errors.TChannelError;\n+import com.uber.tchannel.hyperbahn.messages.AdvertiseRequest;\n+import com.uber.tchannel.hyperbahn.messages.AdvertiseResponse;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+public final class HyperbahnClient {\n+    private static final String HYPERBAHN_SERVICE_NAME = \"hyperbahn\";\n+    private static final String HYPERBAHN_ADVERTISE_ENDPOINT = \"ad\";\n+    public AtomicBoolean destroyed = new AtomicBoolean(false);\n+    private final Logger logger = LoggerFactory.getLogger(HyperbahnClient.class);\n+\n+    private final String service;\n+    private final TChannel tchannel;\n+    private final List<InetSocketAddress> routers;\n+    private final long advertiseTimeout;\n+    private final long advertiseInterval;\n+\n+    private Timer advertiseTimer = new Timer(true);\n+\n+    private HyperbahnClient(Builder builder) {\n+        this.service = builder.service;\n+        this.tchannel = builder.channel;\n+        this.routers = builder.routers;\n+        this.advertiseTimeout = builder.advertiseTimeout;\n+        this.advertiseInterval = builder.advertiseInterval;\n+    }\n+\n+    public ListenableFuture<Response<AdvertiseResponse>> advertise()\n+        throws InterruptedException, TChannelError {\n+\n+        final AdvertiseRequest advertiseRequest = new AdvertiseRequest();\n+        advertiseRequest.addService(service, 0);\n+\n+        // TODO: options for timeout, hard fail, etc.\n+        final Request<AdvertiseRequest> request = new Request.Builder<>(\n+            advertiseRequest,\n+            HYPERBAHN_SERVICE_NAME,\n+            HYPERBAHN_ADVERTISE_ENDPOINT\n+        )\n+            .setTTL(advertiseTimeout, TimeUnit.SECONDS)\n+            .build();\n+\n+        // TODO: should be part of tchannel peer selection\n+        final InetSocketAddress router = this.routers.get(new Random().nextInt(this.routers.size()));\n+        ListenableFuture<Response<AdvertiseResponse>> responseFuture = null;\n+        try {\n+            responseFuture = this.tchannel.callJSON(\n+                    router.getAddress(),\n+                    router.getPort(),\n+                    request,\n+                    AdvertiseResponse.class\n+            );\n+        } catch (TChannelError ex) {\n+            // TODO: should be moved into tchanne as retry ...\n+            this.logger.error(\"Advertise failure: \" + ex.toString());\n+\n+            // re-throw for now\n+            // TODO: should really handle internally\n+            throw ex;\n+        }\n+\n+        responseFuture.addListener(new Runnable() {","path":"tchannel-hyperbahn/src/main/java/com/uber/tchannel/hyperbahn/api/HyperbahnClient.java","position":106,"original_position":106,"commit_id":"27125073fb2cadd2fa7f5217c59e7ae6e1ac67e2","original_commit_id":"27125073fb2cadd2fa7f5217c59e7ae6e1ac67e2","user":{"login":"ShanniLi","id":5845092,"avatar_url":"https://avatars.githubusercontent.com/u/5845092?v=3","gravatar_id":"","url":"https://api.github.com/users/ShanniLi","html_url":"https://github.com/ShanniLi","followers_url":"https://api.github.com/users/ShanniLi/followers","following_url":"https://api.github.com/users/ShanniLi/following{/other_user}","gists_url":"https://api.github.com/users/ShanniLi/gists{/gist_id}","starred_url":"https://api.github.com/users/ShanniLi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ShanniLi/subscriptions","organizations_url":"https://api.github.com/users/ShanniLi/orgs","repos_url":"https://api.github.com/users/ShanniLi/repos","events_url":"https://api.github.com/users/ShanniLi/events{/privacy}","received_events_url":"https://api.github.com/users/ShanniLi/received_events","type":"User","site_admin":false},"body":"The implementation where I picked up from @wjs doesn't have a daemon thread implementation. It is a blocking call waiting for advertisement to finish.  ","created_at":"2015-10-19T22:17:04Z","updated_at":"2015-10-19T22:17:04Z","html_url":"https://github.com/uber/tchannel-java/pull/87#discussion_r42433352","pull_request_url":"https://api.github.com/repos/uber/tchannel-java/pulls/87","_links":{"self":{"href":"https://api.github.com/repos/uber/tchannel-java/pulls/comments/42433352"},"html":{"href":"https://github.com/uber/tchannel-java/pull/87#discussion_r42433352"},"pull_request":{"href":"https://api.github.com/repos/uber/tchannel-java/pulls/87"}}},"pull_request":{"url":"https://api.github.com/repos/uber/tchannel-java/pulls/87","id":48127592,"html_url":"https://github.com/uber/tchannel-java/pull/87","diff_url":"https://github.com/uber/tchannel-java/pull/87.diff","patch_url":"https://github.com/uber/tchannel-java/pull/87.patch","issue_url":"https://api.github.com/repos/uber/tchannel-java/issues/87","number":87,"state":"open","locked":false,"title":"Hyperbahn client","user":{"login":"ShanniLi","id":5845092,"avatar_url":"https://avatars.githubusercontent.com/u/5845092?v=3","gravatar_id":"","url":"https://api.github.com/users/ShanniLi","html_url":"https://github.com/ShanniLi","followers_url":"https://api.github.com/users/ShanniLi/followers","following_url":"https://api.github.com/users/ShanniLi/following{/other_user}","gists_url":"https://api.github.com/users/ShanniLi/gists{/gist_id}","starred_url":"https://api.github.com/users/ShanniLi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ShanniLi/subscriptions","organizations_url":"https://api.github.com/users/ShanniLi/orgs","repos_url":"https://api.github.com/users/ShanniLi/repos","events_url":"https://api.github.com/users/ShanniLi/events{/privacy}","received_events_url":"https://api.github.com/users/ShanniLi/received_events","type":"User","site_admin":false},"body":"r @willsalz @truncs @anson627 @junchaowu \r\n\r\nIn this PR, tchannel-java can advertise to Hyperbahn and serve requests.\r\nNext steps:\r\n1. TChannel SubChannel: allow connection pooling for different services.\r\n2. Retries\r\n  ","created_at":"2015-10-19T21:16:47Z","updated_at":"2015-10-19T22:17:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f04e1429a6a49e22249c4bcf0aedf91c0059a70c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/uber/tchannel-java/pulls/87/commits","review_comments_url":"https://api.github.com/repos/uber/tchannel-java/pulls/87/comments","review_comment_url":"https://api.github.com/repos/uber/tchannel-java/pulls/comments{/number}","comments_url":"https://api.github.com/repos/uber/tchannel-java/issues/87/comments","statuses_url":"https://api.github.com/repos/uber/tchannel-java/statuses/27125073fb2cadd2fa7f5217c59e7ae6e1ac67e2","head":{"label":"uber:hyperbahn-client","ref":"hyperbahn-client","sha":"27125073fb2cadd2fa7f5217c59e7ae6e1ac67e2","user":{"login":"uber","id":538264,"avatar_url":"https://avatars.githubusercontent.com/u/538264?v=3","gravatar_id":"","url":"https://api.github.com/users/uber","html_url":"https://github.com/uber","followers_url":"https://api.github.com/users/uber/followers","following_url":"https://api.github.com/users/uber/following{/other_user}","gists_url":"https://api.github.com/users/uber/gists{/gist_id}","starred_url":"https://api.github.com/users/uber/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/uber/subscriptions","organizations_url":"https://api.github.com/users/uber/orgs","repos_url":"https://api.github.com/users/uber/repos","events_url":"https://api.github.com/users/uber/events{/privacy}","received_events_url":"https://api.github.com/users/uber/received_events","type":"Organization","site_admin":false},"repo":{"id":39764417,"name":"tchannel-java","full_name":"uber/tchannel-java","owner":{"login":"uber","id":538264,"avatar_url":"https://avatars.githubusercontent.com/u/538264?v=3","gravatar_id":"","url":"https://api.github.com/users/uber","html_url":"https://github.com/uber","followers_url":"https://api.github.com/users/uber/followers","following_url":"https://api.github.com/users/uber/following{/other_user}","gists_url":"https://api.github.com/users/uber/gists{/gist_id}","starred_url":"https://api.github.com/users/uber/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/uber/subscriptions","organizations_url":"https://api.github.com/users/uber/orgs","repos_url":"https://api.github.com/users/uber/repos","events_url":"https://api.github.com/users/uber/events{/privacy}","received_events_url":"https://api.github.com/users/uber/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/uber/tchannel-java","description":"A Java implementation of the TChannel protocol.","fork":false,"url":"https://api.github.com/repos/uber/tchannel-java","forks_url":"https://api.github.com/repos/uber/tchannel-java/forks","keys_url":"https://api.github.com/repos/uber/tchannel-java/keys{/key_id}","collaborators_url":"https://api.github.com/repos/uber/tchannel-java/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/uber/tchannel-java/teams","hooks_url":"https://api.github.com/repos/uber/tchannel-java/hooks","issue_events_url":"https://api.github.com/repos/uber/tchannel-java/issues/events{/number}","events_url":"https://api.github.com/repos/uber/tchannel-java/events","assignees_url":"https://api.github.com/repos/uber/tchannel-java/assignees{/user}","branches_url":"https://api.github.com/repos/uber/tchannel-java/branches{/branch}","tags_url":"https://api.github.com/repos/uber/tchannel-java/tags","blobs_url":"https://api.github.com/repos/uber/tchannel-java/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/uber/tchannel-java/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/uber/tchannel-java/git/refs{/sha}","trees_url":"https://api.github.com/repos/uber/tchannel-java/git/trees{/sha}","statuses_url":"https://api.github.com/repos/uber/tchannel-java/statuses/{sha}","languages_url":"https://api.github.com/repos/uber/tchannel-java/languages","stargazers_url":"https://api.github.com/repos/uber/tchannel-java/stargazers","contributors_url":"https://api.github.com/repos/uber/tchannel-java/contributors","subscribers_url":"https://api.github.com/repos/uber/tchannel-java/subscribers","subscription_url":"https://api.github.com/repos/uber/tchannel-java/subscription","commits_url":"https://api.github.com/repos/uber/tchannel-java/commits{/sha}","git_commits_url":"https://api.github.com/repos/uber/tchannel-java/git/commits{/sha}","comments_url":"https://api.github.com/repos/uber/tchannel-java/comments{/number}","issue_comment_url":"https://api.github.com/repos/uber/tchannel-java/issues/comments{/number}","contents_url":"https://api.github.com/repos/uber/tchannel-java/contents/{+path}","compare_url":"https://api.github.com/repos/uber/tchannel-java/compare/{base}...{head}","merges_url":"https://api.github.com/repos/uber/tchannel-java/merges","archive_url":"https://api.github.com/repos/uber/tchannel-java/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/uber/tchannel-java/downloads","issues_url":"https://api.github.com/repos/uber/tchannel-java/issues{/number}","pulls_url":"https://api.github.com/repos/uber/tchannel-java/pulls{/number}","milestones_url":"https://api.github.com/repos/uber/tchannel-java/milestones{/number}","notifications_url":"https://api.github.com/repos/uber/tchannel-java/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/uber/tchannel-java/labels{/name}","releases_url":"https://api.github.com/repos/uber/tchannel-java/releases{/id}","created_at":"2015-07-27T08:49:33Z","updated_at":"2015-10-15T09:01:39Z","pushed_at":"2015-10-19T21:16:47Z","git_url":"git://github.com/uber/tchannel-java.git","ssh_url":"git@github.com:uber/tchannel-java.git","clone_url":"https://github.com/uber/tchannel-java.git","svn_url":"https://github.com/uber/tchannel-java","homepage":"","size":1263,"stargazers_count":31,"watchers_count":31,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10,"mirror_url":null,"open_issues_count":20,"forks":10,"open_issues":20,"watchers":31,"default_branch":"master"}},"base":{"label":"uber:master","ref":"master","sha":"c9e5b3339234a12731d58acdb816a06b12cc42ce","user":{"login":"uber","id":538264,"avatar_url":"https://avatars.githubusercontent.com/u/538264?v=3","gravatar_id":"","url":"https://api.github.com/users/uber","html_url":"https://github.com/uber","followers_url":"https://api.github.com/users/uber/followers","following_url":"https://api.github.com/users/uber/following{/other_user}","gists_url":"https://api.github.com/users/uber/gists{/gist_id}","starred_url":"https://api.github.com/users/uber/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/uber/subscriptions","organizations_url":"https://api.github.com/users/uber/orgs","repos_url":"https://api.github.com/users/uber/repos","events_url":"https://api.github.com/users/uber/events{/privacy}","received_events_url":"https://api.github.com/users/uber/received_events","type":"Organization","site_admin":false},"repo":{"id":39764417,"name":"tchannel-java","full_name":"uber/tchannel-java","owner":{"login":"uber","id":538264,"avatar_url":"https://avatars.githubusercontent.com/u/538264?v=3","gravatar_id":"","url":"https://api.github.com/users/uber","html_url":"https://github.com/uber","followers_url":"https://api.github.com/users/uber/followers","following_url":"https://api.github.com/users/uber/following{/other_user}","gists_url":"https://api.github.com/users/uber/gists{/gist_id}","starred_url":"https://api.github.com/users/uber/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/uber/subscriptions","organizations_url":"https://api.github.com/users/uber/orgs","repos_url":"https://api.github.com/users/uber/repos","events_url":"https://api.github.com/users/uber/events{/privacy}","received_events_url":"https://api.github.com/users/uber/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/uber/tchannel-java","description":"A Java implementation of the TChannel protocol.","fork":false,"url":"https://api.github.com/repos/uber/tchannel-java","forks_url":"https://api.github.com/repos/uber/tchannel-java/forks","keys_url":"https://api.github.com/repos/uber/tchannel-java/keys{/key_id}","collaborators_url":"https://api.github.com/repos/uber/tchannel-java/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/uber/tchannel-java/teams","hooks_url":"https://api.github.com/repos/uber/tchannel-java/hooks","issue_events_url":"https://api.github.com/repos/uber/tchannel-java/issues/events{/number}","events_url":"https://api.github.com/repos/uber/tchannel-java/events","assignees_url":"https://api.github.com/repos/uber/tchannel-java/assignees{/user}","branches_url":"https://api.github.com/repos/uber/tchannel-java/branches{/branch}","tags_url":"https://api.github.com/repos/uber/tchannel-java/tags","blobs_url":"https://api.github.com/repos/uber/tchannel-java/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/uber/tchannel-java/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/uber/tchannel-java/git/refs{/sha}","trees_url":"https://api.github.com/repos/uber/tchannel-java/git/trees{/sha}","statuses_url":"https://api.github.com/repos/uber/tchannel-java/statuses/{sha}","languages_url":"https://api.github.com/repos/uber/tchannel-java/languages","stargazers_url":"https://api.github.com/repos/uber/tchannel-java/stargazers","contributors_url":"https://api.github.com/repos/uber/tchannel-java/contributors","subscribers_url":"https://api.github.com/repos/uber/tchannel-java/subscribers","subscription_url":"https://api.github.com/repos/uber/tchannel-java/subscription","commits_url":"https://api.github.com/repos/uber/tchannel-java/commits{/sha}","git_commits_url":"https://api.github.com/repos/uber/tchannel-java/git/commits{/sha}","comments_url":"https://api.github.com/repos/uber/tchannel-java/comments{/number}","issue_comment_url":"https://api.github.com/repos/uber/tchannel-java/issues/comments{/number}","contents_url":"https://api.github.com/repos/uber/tchannel-java/contents/{+path}","compare_url":"https://api.github.com/repos/uber/tchannel-java/compare/{base}...{head}","merges_url":"https://api.github.com/repos/uber/tchannel-java/merges","archive_url":"https://api.github.com/repos/uber/tchannel-java/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/uber/tchannel-java/downloads","issues_url":"https://api.github.com/repos/uber/tchannel-java/issues{/number}","pulls_url":"https://api.github.com/repos/uber/tchannel-java/pulls{/number}","milestones_url":"https://api.github.com/repos/uber/tchannel-java/milestones{/number}","notifications_url":"https://api.github.com/repos/uber/tchannel-java/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/uber/tchannel-java/labels{/name}","releases_url":"https://api.github.com/repos/uber/tchannel-java/releases{/id}","created_at":"2015-07-27T08:49:33Z","updated_at":"2015-10-15T09:01:39Z","pushed_at":"2015-10-19T21:16:47Z","git_url":"git://github.com/uber/tchannel-java.git","ssh_url":"git@github.com:uber/tchannel-java.git","clone_url":"https://github.com/uber/tchannel-java.git","svn_url":"https://github.com/uber/tchannel-java","homepage":"","size":1263,"stargazers_count":31,"watchers_count":31,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":10,"mirror_url":null,"open_issues_count":20,"forks":10,"open_issues":20,"watchers":31,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/uber/tchannel-java/pulls/87"},"html":{"href":"https://github.com/uber/tchannel-java/pull/87"},"issue":{"href":"https://api.github.com/repos/uber/tchannel-java/issues/87"},"comments":{"href":"https://api.github.com/repos/uber/tchannel-java/issues/87/comments"},"review_comments":{"href":"https://api.github.com/repos/uber/tchannel-java/pulls/87/comments"},"review_comment":{"href":"https://api.github.com/repos/uber/tchannel-java/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/uber/tchannel-java/pulls/87/commits"},"statuses":{"href":"https://api.github.com/repos/uber/tchannel-java/statuses/27125073fb2cadd2fa7f5217c59e7ae6e1ac67e2"}}}}