Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth required #36

Merged
merged 13 commits into from
Apr 13, 2017
Merged

Auth required #36

merged 13 commits into from
Apr 13, 2017

Conversation

tallguy-hackett
Copy link
Collaborator

This fixes #27

I added functionality to pass connection information into the parser to generate the CONNECT command. This may not be the best way to do it so I'm very open to suggestions. I also added a Gnat.ping function that sends a PING command to the server to help verify an authenticated connection without a need for a subscription request.

There's also no error handling if the client tries to use a connection without authenticating.

@tallguy-hackett
Copy link
Collaborator Author

tallguy-hackett commented Mar 31, 2017

This probably fails the Travis CI checks because the test I wrote needs to a second server running that requires authentication.

@mmmries
Copy link
Collaborator

mmmries commented Mar 31, 2017

@tallguy-hackett you could get travis to pass by adding a before_script step that starts an additional gnats server on a different port

@mmmries
Copy link
Collaborator

mmmries commented Mar 31, 2017

Looks like you and @film42 have both been thinking about this problem: https://github.com/mmmries/gnat/compare/gt/parse_info_and_ok?expand=1

I like that both of you pushed the parsing into Gnat.Parser.

Copy link
Collaborator

@mmmries mmmries left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm digging the approach here. I like doing the full handshake before getting into the normal flow of a GenServer. The test with Travis is also 👍.

Just some concerns around developer burden to run two gnatsd servers and race conditions in the ping command.

:ok = Gnat.ping(gnat)
```
"""
def ping(pid) do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exposing this as usable behavior seems odd to me. What happens for instance if two different clients both send call Gnat.ping close to the same time? The state.pinger would end up holding the address of the second client and the first one would timeout waiting for a PONG.

I think it probably makes sense for the Gnat actor to send a PING every so often and expect a response, but I don't understand the purpose of making it a callable behavior. Maybe I'm missing something?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually pretty common on nats clients, but the method is called flush: https://github.com/nats-io/go-nats/blob/master/nats.go#L2464-L2468

}
{:ok, pid} = Gnat.start_link(connection_settings)
assert Process.alive?(pid)
:ok = Gnat.ping(pid)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, is this the reason you wanted expose ping as a public function? I guess it's a pretty good way to verify that the connection was successful... It's certainly simpler than doing a sub + pub + receive

:gen_tcp.close(socket)
{:error, reason} ->
Mix.raise "Cannot connect to gnatsd" <>
" (http://localhost:4223):" <>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the helpful error message here, but it seems like a pain to force all developers to run two gnatsd servers while developing. Maybe this is a good time to tag our tests and default the integration tests to be skipped

receive do
{:tcp, ^tcp, operation} ->
"INFO" = operation |> String.split |> List.first |> String.upcase
:gen_tcp.send(tcp, "CONNECT {\"verbose\": false}\r\n")
{_, [{:info, options}]} = Parser.parse(Parser.new, operation)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know, there's no guarantee that the entire INFO message will fit in this first TCP packet, so I think moving the message parsing into Parser is a good start, but I think it might be better to let the genserver receive packets until the parser finds the INFO message. And then maybe we wait for a message from the genserver in init to ensure the handshake completed successfully?

@@ -1,5 +1,6 @@
defmodule Gnat.Parser do
require Logger
require Poison
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to require poison to use the parser.

@tallguy-hackett
Copy link
Collaborator Author

I added some functionality for tagging tests as well as dynamically checking for a second server when including the multi_server tagged tests. I think it works out pretty well. So now by default running tests won't include the requirement for the 2nd server.

after 1000 ->
{:error, "timed out waiting for info"}
end
end

defp connect(tcp, %{auth_required: true}=_options, %{username: username, password: password}=_connection_settings) do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to assign unused variables _connection_settings and _options here. The pattern matching should be just fine and if someone wanted context about what is being matched, they can look and the other connect function

@mmmries mmmries mentioned this pull request Apr 3, 2017
@mmmries mmmries merged commit 5695d6a into master Apr 13, 2017
@mmmries mmmries deleted the auth-required branch April 13, 2017 02:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support auth_required option when receiving INFO
4 participants