Skip to content

Latest commit

 

History

History
128 lines (126 loc) · 9.08 KB

File metadata and controls

128 lines (126 loc) · 9.08 KB

Exercise: OrganizingAProject-1

(Tricky) Before reading the next section, see if you can write the code to format the data into columns, like the sample output at the start of the chapter. This is probably the longest piece of Elixir code you'll have written. Try to do it without using if or cond.

Solution

See the issues directory for the mix project containing the solution.

So, it definitely isn't pretty but it works. I'm sure I could clean this up considerably but I'm going to be lazy since I want to move on to the fun stuff. Here it is in iex:

iex> issues = Issues.CLI.process({"spokesgp", "spokes", 3})
[#HashDict<[{"number", 5}, {"comments", 0},
  {"title", "Split Router into two services."},
  {"created_at", "2016-06-15T19:07:14Z"}, {"state", "open"}, {"locked", false},
  {"url", "https://api.github.com/repos/spokesgp/spokes/issues/5"},
  {"comments_url",
   "https://api.github.com/repos/spokesgp/spokes/issues/5/comments"},
  {"labels",
   [[{"url", "https://api.github.com/repos/spokesgp/spokes/labels/enhancement"},
     {"name", "enhancement"}, {"color", "84b6eb"}]]}, {"id", 160499554},
  {"labels_url",
   "https://api.github.com/repos/spokesgp/spokes/issues/5/labels{/name}"},
  {"events_url",
   "https://api.github.com/repos/spokesgp/spokes/issues/5/events"},
  {"html_url", "https://github.com/spokesgp/spokes/issues/5"},
  {"user",
   [{"login", "pcewing"}, {"id", 11671852},
    {"avatar_url", "https://avatars.githubusercontent.com/u/11671852?v=3"},
    {"gravatar_id", ""}, {"url", "https://api.github.com/users/pcewing"},
    {"html_url", "https://github.com/pcewing"},
    {"followers_url", "https://api.github.com/users/pcewing/followers"},
    {"following_url",
     "https://api.github.com/users/pcewing/following{/other_user}"},
    {"gists_url", "https://api.github.com/users/pcewing/gists{/gist_id}"},
    {"starred_url",
     "https://api.github.com/users/pcewing/starred{/owner}{/repo}"},
    {"subscriptions_url", "https://api.github.com/users/pcewing/subscriptions"},
    {"organizations_url", "https://api.github.com/users/pcewing/orgs"},
    {"repos_url", "https://api.github.com/users/pcewing/repos"},
    {"events_url", "https://api.github.com/users/pcewing/events{/privacy}"},
    {"received_events_url",
     "https://api.github.com/users/pcewing/received_events"}, {"type", "User"},
    {"site_admin", false}]},
  {"body",
   "The *Router* service is currently tightly coupled with *Auth* in order to manage client connections correctly. I would rather the *Router* be a \"dumb\" service that simply routes messages and thus, it should be separated into two different services.\r\n\r\nThe client connection management should be pulled out and placed into a *Bouncer* service. As the name implies, the *Bouncer* is in charge of managing clients. It will do the same thing as the router currently does.\r\n- Accept probationary client connections\r\n- Verify the first message is one of the three expected types. (Register/Login/Reconnect request)\r\n- Route the request to Auth\r\n- Upon receiving the response, verify or reject the client connection.\r\n\r\n### Additional functionality to add\r\n#### Anonymous Requests\r\nI would like to add anonymous requests. The *Route* message header should have a source option of *anonymous*. It will be up to services to decide whether or not anonymity is supported for specific requests.\r\n\r\n#### Client Keepalive\r\nI'm not sure if this is necessary as the websocket should be cut if the client disconnects; however, there may be value in sending an occasional keepalive to clients to verify they are responsive."},
  {"assignees", []}, {"assignee", :null}, {"closed_at", :null},
  {"repository_url", "https://api.github.com/repos/spokesgp/spokes"},
  {"milestone", :null}, {"updated_at", "2016-06-15T20:19:58Z"}]>,
 #HashDict<[{"number", 6}, {"comments", 0},
  {"title", "Gracefully Close Websockets"},
  {"created_at", "2016-06-15T19:12:56Z"}, {"state", "open"}, {"locked", false},
  {"url", "https://api.github.com/repos/spokesgp/spokes/issues/6"},
  {"comments_url",
   "https://api.github.com/repos/spokesgp/spokes/issues/6/comments"},
  {"labels",
   [[{"url", "https://api.github.com/repos/spokesgp/spokes/labels/bug"},
     {"name", "bug"}, {"color", "ee0701"}]]}, {"id", 160500714},
  {"labels_url",
   "https://api.github.com/repos/spokesgp/spokes/issues/6/labels{/name}"},
  {"events_url",
   "https://api.github.com/repos/spokesgp/spokes/issues/6/events"},
  {"html_url", "https://github.com/spokesgp/spokes/issues/6"},
  {"user",
   [{"login", "pcewing"}, {"id", 11671852},
    {"avatar_url", "https://avatars.githubusercontent.com/u/11671852?v=3"},
    {"gravatar_id", ""}, {"url", "https://api.github.com/users/pcewing"},
    {"html_url", "https://github.com/pcewing"},
    {"followers_url", "https://api.github.com/users/pcewing/followers"},
    {"following_url",
     "https://api.github.com/users/pcewing/following{/other_user}"},
    {"gists_url", "https://api.github.com/users/pcewing/gists{/gist_id}"},
    {"starred_url",
     "https://api.github.com/users/pcewing/starred{/owner}{/repo}"},
    {"subscriptions_url", "https://api.github.com/users/pcewing/subscriptions"},
    {"organizations_url", "https://api.github.com/users/pcewing/orgs"},
    {"repos_url", "https://api.github.com/users/pcewing/repos"},
    {"events_url", "https://api.github.com/users/pcewing/events{/privacy}"},
    {"received_events_url",
     "https://api.github.com/users/pcewing/received_events"}, {"type", "User"},
    {"site_admin", false}]},
  {"body",
   "Right now I'm not bothering to close websockets gracefully.\r\n\r\n### Close Requests\r\nThe utility method *SpokesUtilities.Websocket.receive_message* should handle closing the right way. When a close message is received, it should send an acknowledgment and close.\r\n\r\n### Close Initiations\r\nLikewise, when we initiate websocket closures, we should wait for a response from the client. Currently we just kill the connection process but this is not the best way to go about it. We should reimplement the *reject* mechanism and send a close with a *:normal* reason and then wait to receive a response. Once the response is received, we can terminate the connection process (The client should have closed the socket). In the case of a timeout, we can just terminate the process as we currently do."},
  {"assignees", []}, {"assignee", :null}, {"closed_at", :null},
  {"repository_url", "https://api.github.com/repos/spokesgp/spokes"},
  {"milestone", :null}, {"updated_at", "2016-06-15T20:19:48Z"}]>,
 #HashDict<[{"number", 7}, {"comments", 0},
  {"title", "Add Logstash logger backend and set up ELK via docker."},
  {"created_at", "2016-06-15T20:19:22Z"}, {"state", "open"}, {"locked", false},
  {"url", "https://api.github.com/repos/spokesgp/spokes/issues/7"},
  {"comments_url",
   "https://api.github.com/repos/spokesgp/spokes/issues/7/comments"},
  {"labels",
   [[{"url", "https://api.github.com/repos/spokesgp/spokes/labels/enhancement"},
     {"name", "enhancement"}, {"color", "84b6eb"}]]}, {"id", 160514127},
  {"labels_url",
   "https://api.github.com/repos/spokesgp/spokes/issues/7/labels{/name}"},
  {"events_url",
   "https://api.github.com/repos/spokesgp/spokes/issues/7/events"},
  {"html_url", "https://github.com/spokesgp/spokes/issues/7"},
  {"user",
   [{"login", "pcewing"}, {"id", 11671852},
    {"avatar_url", "https://avatars.githubusercontent.com/u/11671852?v=3"},
    {"gravatar_id", ""}, {"url", "https://api.github.com/users/pcewing"},
    {"html_url", "https://github.com/pcewing"},
    {"followers_url", "https://api.github.com/users/pcewing/followers"},
    {"following_url",
     "https://api.github.com/users/pcewing/following{/other_user}"},
    {"gists_url", "https://api.github.com/users/pcewing/gists{/gist_id}"},
    {"starred_url",
     "https://api.github.com/users/pcewing/starred{/owner}{/repo}"},
    {"subscriptions_url", "https://api.github.com/users/pcewing/subscriptions"},
    {"organizations_url", "https://api.github.com/users/pcewing/orgs"},
    {"repos_url", "https://api.github.com/users/pcewing/repos"},
    {"events_url", "https://api.github.com/users/pcewing/events{/privacy}"},
    {"received_events_url",
     "https://api.github.com/users/pcewing/received_events"}, {"type", "User"},
    {"site_admin", false}]},
  {"body",
   "Currently the Logger only logs to stdio. A backend should be added for Logstash; see:\r\nhttps://github.com/marcelog/logger_logstash_backend\r\n\r\nELK should be deployed locally for this backend to submit to; see:\r\nhttps://github.com/deviantony/docker-elk"},
  {"assignees", []}, {"assignee", :null}, {"closed_at", :null},
  {"repository_url", "https://api.github.com/repos/spokesgp/spokes"},
  {"milestone", :null}, {"updated_at", "2016-06-15T20:19:34Z"}]>]
iex> Issues.Formatter.format issues
 # | created_at           | title                                                  
---+----------------------+--------------------------------------------------------
 5 | 2016-06-15T19:07:14Z | Split Router into two services.                        
 6 | 2016-06-15T19:12:56Z | Gracefully Close Websockets                            
 7 | 2016-06-15T20:19:22Z | Add Logstash logger backend and set up ELK via docker.
:ok