{"action":"created","comment":{"url":"https://api.github.com/repos/keybase/gregor/pulls/comments/59069281","id":59069281,"diff_hunk":"@@ -1,46 +1,135 @@\n package rpc\n \n import (\n+\t\"time\"\n+\n \t\"github.com/keybase/gregor/protocol/gregor1\"\n \t\"golang.org/x/net/context\"\n )\n \n // sessionCacher implements gregor1.AuthInterface with a cache of authenticated sessions.\n type sessionCacher struct {\n \ta          gregor1.AuthInterface\n+\ttimeout    time.Duration\n \tsessions   map[gregor1.SessionToken]gregor1.AuthResult\n \tsessionIDs map[gregor1.SessionID]gregor1.SessionToken\n+\treqCh      chan request\n }\n \n-func NewSessionCacher(a gregor1.AuthInterface) gregor1.AuthInterface {\n-\treturn &sessionCacher{\n+// NewSessionCacher creates a new AuthInterface that caches sessions for the given timeout.\n+func NewSessionCacher(a gregor1.AuthInterface, timeout time.Duration) gregor1.AuthInterface {\n+\tsc := &sessionCacher{\n \t\ta:          a,\n+\t\ttimeout:    timeout,\n \t\tsessions:   make(map[gregor1.SessionToken]gregor1.AuthResult),\n \t\tsessionIDs: make(map[gregor1.SessionID]gregor1.SessionToken),\n+\t\treqCh:      make(chan request),\n+\t}\n+\tgo sc.requestHandler()\n+\treturn sc\n+}\n+\n+type request interface{}\n+\n+type authResp struct {\n+\tres gregor1.AuthResult\n+\tok  bool\n+}\n+\n+type readTokReq struct {\n+\ttok  gregor1.SessionToken\n+\tresp chan authResp\n+}\n+\n+func (sc *sessionCacher) readTok(tok gregor1.SessionToken) (resp authResp) {\n+\tresp.res, resp.ok = sc.sessions[tok]\n+\treturn\n+}\n+\n+type setResReq struct {\n+\ttok gregor1.SessionToken\n+\tres gregor1.AuthResult\n+}\n+\n+func (sc *sessionCacher) setRes(tok gregor1.SessionToken, res gregor1.AuthResult) {\n+\tsc.sessions[tok] = res\n+\tsc.sessionIDs[res.Sid] = tok\n+}\n+\n+type deleteSIDReq struct {\n+\tsid gregor1.SessionID\n+}\n+\n+func (sc *sessionCacher) deleteSID(sid gregor1.SessionID) {\n+\tif tok, ok := sc.sessionIDs[sid]; ok {\n+\t\tif _, ok := sc.sessions[tok]; ok {\n+\t\t\tdelete(sc.sessions, sc.sessionIDs[sid])\n+\t\t}\n+\t\tdelete(sc.sessionIDs, sid)\n+\t}\n+}\n+\n+type expirySt struct {\n+\tsid    gregor1.SessionID\n+\texpiry time.Time\n+}\n+\n+func expireAtTime(expiryCh chan gregor1.SessionID, e expirySt) {\n+\ttime.Sleep(e.expiry.Sub(time.Now()))\n+\texpiryCh <- e.sid\n+}\n+\n+// requestHandler runs in a single goroutine, handling all access requests and\n+// periodic expiry of sessions.\n+func (sc *sessionCacher) requestHandler() {\n+\texpiryCh := make(chan gregor1.SessionID)\n+\tvar expiryQueue []expirySt\n+\tfor {\n+\t\tselect {\n+\t\tcase sid := <-expiryCh:\n+\t\t\tsc.deleteSID(sid)\n+\t\t\texpiryQueue = expiryQueue[1:]\n+\t\t\tif len(expiryQueue) > 0 {\n+\t\t\t\tgo expireAtTime(expiryCh, expiryQueue[0])\n+\t\t\t}\n+\t\tcase req := <-sc.reqCh:\n+\t\t\tswitch req := req.(type) {\n+\t\t\tcase readTokReq:\n+\t\t\t\treq.resp <- sc.readTok(req.tok)\n+\t\t\tcase setResReq:\n+\t\t\t\tsc.setRes(req.tok, req.res)\n+\t\t\t\te := expirySt{\n+\t\t\t\t\tsid:    req.res.Sid,\n+\t\t\t\t\texpiry: time.Now().Add(sc.timeout),\n+\t\t\t\t}\n+\t\t\t\tif len(expiryQueue) == 0 {\n+\t\t\t\t\tgo expireAtTime(expiryCh, e)\n+\t\t\t\t}\n+\t\t\t\texpiryQueue = append(expiryQueue, e)\n+\t\t\tcase deleteSIDReq:\n+\t\t\t\tsc.deleteSID(req.sid)\n+\t\t\t}\n+\t\t}\n \t}\n }\n \n func (sc *sessionCacher) AuthenticateSessionToken(ctx context.Context, tok gregor1.SessionToken) (res gregor1.AuthResult, err error) {\n-\tvar ok bool\n-\tif res, ok = sc.sessions[tok]; ok {\n+\trespCh := make(chan authResp)\n+\tsc.reqCh <- readTokReq{tok, respCh}\n+\tif resp := <-respCh; resp.ok {","path":"rpc/session.go","position":null,"original_position":123,"commit_id":"6dc6816ff54a343cb9d807e728909e34c487f9aa","original_commit_id":"6dc6816ff54a343cb9d807e728909e34c487f9aa","user":{"login":"strib","id":8516691,"avatar_url":"https://avatars.githubusercontent.com/u/8516691?v=3","gravatar_id":"","url":"https://api.github.com/users/strib","html_url":"https://github.com/strib","followers_url":"https://api.github.com/users/strib/followers","following_url":"https://api.github.com/users/strib/following{/other_user}","gists_url":"https://api.github.com/users/strib/gists{/gist_id}","starred_url":"https://api.github.com/users/strib/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/strib/subscriptions","organizations_url":"https://api.github.com/users/strib/orgs","repos_url":"https://api.github.com/users/strib/repos","events_url":"https://api.github.com/users/strib/events{/privacy}","received_events_url":"https://api.github.com/users/strib/received_events","type":"User","site_admin":false},"body":"If `ctx` can ever be canceled, you might want to select on `ctx.Done()` as well to avoid blocking forever.","created_at":"2016-04-08T18:28:51Z","updated_at":"2016-04-08T18:28:51Z","html_url":"https://github.com/keybase/gregor/pull/21#discussion_r59069281","pull_request_url":"https://api.github.com/repos/keybase/gregor/pulls/21","_links":{"self":{"href":"https://api.github.com/repos/keybase/gregor/pulls/comments/59069281"},"html":{"href":"https://github.com/keybase/gregor/pull/21#discussion_r59069281"},"pull_request":{"href":"https://api.github.com/repos/keybase/gregor/pulls/21"}}},"pull_request":{"url":"https://api.github.com/repos/keybase/gregor/pulls/21","id":65377274,"html_url":"https://github.com/keybase/gregor/pull/21","diff_url":"https://github.com/keybase/gregor/pull/21.diff","patch_url":"https://github.com/keybase/gregor/pull/21.patch","issue_url":"https://api.github.com/repos/keybase/gregor/issues/21","number":21,"state":"open","locked":false,"title":"RPC Integration with Session Server","user":{"login":"jacobhaven","id":95305,"avatar_url":"https://avatars.githubusercontent.com/u/95305?v=3","gravatar_id":"","url":"https://api.github.com/users/jacobhaven","html_url":"https://github.com/jacobhaven","followers_url":"https://api.github.com/users/jacobhaven/followers","following_url":"https://api.github.com/users/jacobhaven/following{/other_user}","gists_url":"https://api.github.com/users/jacobhaven/gists{/gist_id}","starred_url":"https://api.github.com/users/jacobhaven/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacobhaven/subscriptions","organizations_url":"https://api.github.com/users/jacobhaven/orgs","repos_url":"https://api.github.com/users/jacobhaven/repos","events_url":"https://api.github.com/users/jacobhaven/events{/privacy}","received_events_url":"https://api.github.com/users/jacobhaven/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-04-05T21:56:35Z","updated_at":"2016-04-08T18:28:51Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a1f65ae9e5ac051f792bafd0ed94205f1eafa694","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/keybase/gregor/pulls/21/commits","review_comments_url":"https://api.github.com/repos/keybase/gregor/pulls/21/comments","review_comment_url":"https://api.github.com/repos/keybase/gregor/pulls/comments{/number}","comments_url":"https://api.github.com/repos/keybase/gregor/issues/21/comments","statuses_url":"https://api.github.com/repos/keybase/gregor/statuses/6dc6816ff54a343cb9d807e728909e34c487f9aa","head":{"label":"keybase:jacob/CORE-2707","ref":"jacob/CORE-2707","sha":"6dc6816ff54a343cb9d807e728909e34c487f9aa","user":{"login":"keybase","id":5400834,"avatar_url":"https://avatars.githubusercontent.com/u/5400834?v=3","gravatar_id":"","url":"https://api.github.com/users/keybase","html_url":"https://github.com/keybase","followers_url":"https://api.github.com/users/keybase/followers","following_url":"https://api.github.com/users/keybase/following{/other_user}","gists_url":"https://api.github.com/users/keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/keybase/subscriptions","organizations_url":"https://api.github.com/users/keybase/orgs","repos_url":"https://api.github.com/users/keybase/repos","events_url":"https://api.github.com/users/keybase/events{/privacy}","received_events_url":"https://api.github.com/users/keybase/received_events","type":"Organization","site_admin":false},"repo":{"id":53508286,"name":"gregor","full_name":"keybase/gregor","owner":{"login":"keybase","id":5400834,"avatar_url":"https://avatars.githubusercontent.com/u/5400834?v=3","gravatar_id":"","url":"https://api.github.com/users/keybase","html_url":"https://github.com/keybase","followers_url":"https://api.github.com/users/keybase/followers","following_url":"https://api.github.com/users/keybase/following{/other_user}","gists_url":"https://api.github.com/users/keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/keybase/subscriptions","organizations_url":"https://api.github.com/users/keybase/orgs","repos_url":"https://api.github.com/users/keybase/repos","events_url":"https://api.github.com/users/keybase/events{/privacy}","received_events_url":"https://api.github.com/users/keybase/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/keybase/gregor","description":"A simple state-sync service for UX notifications","fork":false,"url":"https://api.github.com/repos/keybase/gregor","forks_url":"https://api.github.com/repos/keybase/gregor/forks","keys_url":"https://api.github.com/repos/keybase/gregor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/keybase/gregor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/keybase/gregor/teams","hooks_url":"https://api.github.com/repos/keybase/gregor/hooks","issue_events_url":"https://api.github.com/repos/keybase/gregor/issues/events{/number}","events_url":"https://api.github.com/repos/keybase/gregor/events","assignees_url":"https://api.github.com/repos/keybase/gregor/assignees{/user}","branches_url":"https://api.github.com/repos/keybase/gregor/branches{/branch}","tags_url":"https://api.github.com/repos/keybase/gregor/tags","blobs_url":"https://api.github.com/repos/keybase/gregor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/keybase/gregor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/keybase/gregor/git/refs{/sha}","trees_url":"https://api.github.com/repos/keybase/gregor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/keybase/gregor/statuses/{sha}","languages_url":"https://api.github.com/repos/keybase/gregor/languages","stargazers_url":"https://api.github.com/repos/keybase/gregor/stargazers","contributors_url":"https://api.github.com/repos/keybase/gregor/contributors","subscribers_url":"https://api.github.com/repos/keybase/gregor/subscribers","subscription_url":"https://api.github.com/repos/keybase/gregor/subscription","commits_url":"https://api.github.com/repos/keybase/gregor/commits{/sha}","git_commits_url":"https://api.github.com/repos/keybase/gregor/git/commits{/sha}","comments_url":"https://api.github.com/repos/keybase/gregor/comments{/number}","issue_comment_url":"https://api.github.com/repos/keybase/gregor/issues/comments{/number}","contents_url":"https://api.github.com/repos/keybase/gregor/contents/{+path}","compare_url":"https://api.github.com/repos/keybase/gregor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/keybase/gregor/merges","archive_url":"https://api.github.com/repos/keybase/gregor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/keybase/gregor/downloads","issues_url":"https://api.github.com/repos/keybase/gregor/issues{/number}","pulls_url":"https://api.github.com/repos/keybase/gregor/pulls{/number}","milestones_url":"https://api.github.com/repos/keybase/gregor/milestones{/number}","notifications_url":"https://api.github.com/repos/keybase/gregor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/keybase/gregor/labels{/name}","releases_url":"https://api.github.com/repos/keybase/gregor/releases{/id}","deployments_url":"https://api.github.com/repos/keybase/gregor/deployments","created_at":"2016-03-09T15:23:03Z","updated_at":"2016-04-05T21:33:00Z","pushed_at":"2016-04-08T18:28:31Z","git_url":"git://github.com/keybase/gregor.git","ssh_url":"git@github.com:keybase/gregor.git","clone_url":"https://github.com/keybase/gregor.git","svn_url":"https://github.com/keybase/gregor","homepage":null,"size":2057,"stargazers_count":1,"watchers_count":1,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":2,"forks":1,"open_issues":2,"watchers":1,"default_branch":"master"}},"base":{"label":"keybase:master","ref":"master","sha":"ccc84f28c12f1a5a30334a5353830e4925d3076f","user":{"login":"keybase","id":5400834,"avatar_url":"https://avatars.githubusercontent.com/u/5400834?v=3","gravatar_id":"","url":"https://api.github.com/users/keybase","html_url":"https://github.com/keybase","followers_url":"https://api.github.com/users/keybase/followers","following_url":"https://api.github.com/users/keybase/following{/other_user}","gists_url":"https://api.github.com/users/keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/keybase/subscriptions","organizations_url":"https://api.github.com/users/keybase/orgs","repos_url":"https://api.github.com/users/keybase/repos","events_url":"https://api.github.com/users/keybase/events{/privacy}","received_events_url":"https://api.github.com/users/keybase/received_events","type":"Organization","site_admin":false},"repo":{"id":53508286,"name":"gregor","full_name":"keybase/gregor","owner":{"login":"keybase","id":5400834,"avatar_url":"https://avatars.githubusercontent.com/u/5400834?v=3","gravatar_id":"","url":"https://api.github.com/users/keybase","html_url":"https://github.com/keybase","followers_url":"https://api.github.com/users/keybase/followers","following_url":"https://api.github.com/users/keybase/following{/other_user}","gists_url":"https://api.github.com/users/keybase/gists{/gist_id}","starred_url":"https://api.github.com/users/keybase/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/keybase/subscriptions","organizations_url":"https://api.github.com/users/keybase/orgs","repos_url":"https://api.github.com/users/keybase/repos","events_url":"https://api.github.com/users/keybase/events{/privacy}","received_events_url":"https://api.github.com/users/keybase/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/keybase/gregor","description":"A simple state-sync service for UX notifications","fork":false,"url":"https://api.github.com/repos/keybase/gregor","forks_url":"https://api.github.com/repos/keybase/gregor/forks","keys_url":"https://api.github.com/repos/keybase/gregor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/keybase/gregor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/keybase/gregor/teams","hooks_url":"https://api.github.com/repos/keybase/gregor/hooks","issue_events_url":"https://api.github.com/repos/keybase/gregor/issues/events{/number}","events_url":"https://api.github.com/repos/keybase/gregor/events","assignees_url":"https://api.github.com/repos/keybase/gregor/assignees{/user}","branches_url":"https://api.github.com/repos/keybase/gregor/branches{/branch}","tags_url":"https://api.github.com/repos/keybase/gregor/tags","blobs_url":"https://api.github.com/repos/keybase/gregor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/keybase/gregor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/keybase/gregor/git/refs{/sha}","trees_url":"https://api.github.com/repos/keybase/gregor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/keybase/gregor/statuses/{sha}","languages_url":"https://api.github.com/repos/keybase/gregor/languages","stargazers_url":"https://api.github.com/repos/keybase/gregor/stargazers","contributors_url":"https://api.github.com/repos/keybase/gregor/contributors","subscribers_url":"https://api.github.com/repos/keybase/gregor/subscribers","subscription_url":"https://api.github.com/repos/keybase/gregor/subscription","commits_url":"https://api.github.com/repos/keybase/gregor/commits{/sha}","git_commits_url":"https://api.github.com/repos/keybase/gregor/git/commits{/sha}","comments_url":"https://api.github.com/repos/keybase/gregor/comments{/number}","issue_comment_url":"https://api.github.com/repos/keybase/gregor/issues/comments{/number}","contents_url":"https://api.github.com/repos/keybase/gregor/contents/{+path}","compare_url":"https://api.github.com/repos/keybase/gregor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/keybase/gregor/merges","archive_url":"https://api.github.com/repos/keybase/gregor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/keybase/gregor/downloads","issues_url":"https://api.github.com/repos/keybase/gregor/issues{/number}","pulls_url":"https://api.github.com/repos/keybase/gregor/pulls{/number}","milestones_url":"https://api.github.com/repos/keybase/gregor/milestones{/number}","notifications_url":"https://api.github.com/repos/keybase/gregor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/keybase/gregor/labels{/name}","releases_url":"https://api.github.com/repos/keybase/gregor/releases{/id}","deployments_url":"https://api.github.com/repos/keybase/gregor/deployments","created_at":"2016-03-09T15:23:03Z","updated_at":"2016-04-05T21:33:00Z","pushed_at":"2016-04-08T18:28:31Z","git_url":"git://github.com/keybase/gregor.git","ssh_url":"git@github.com:keybase/gregor.git","clone_url":"https://github.com/keybase/gregor.git","svn_url":"https://github.com/keybase/gregor","homepage":null,"size":2057,"stargazers_count":1,"watchers_count":1,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":2,"forks":1,"open_issues":2,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/keybase/gregor/pulls/21"},"html":{"href":"https://github.com/keybase/gregor/pull/21"},"issue":{"href":"https://api.github.com/repos/keybase/gregor/issues/21"},"comments":{"href":"https://api.github.com/repos/keybase/gregor/issues/21/comments"},"review_comments":{"href":"https://api.github.com/repos/keybase/gregor/pulls/21/comments"},"review_comment":{"href":"https://api.github.com/repos/keybase/gregor/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/keybase/gregor/pulls/21/commits"},"statuses":{"href":"https://api.github.com/repos/keybase/gregor/statuses/6dc6816ff54a343cb9d807e728909e34c487f9aa"}}}}