Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 2 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,9 @@ event loops, the Redis protocol and more.
**Note**: If you're viewing this repo on GitHub, head over to
[codecrafters.io](https://codecrafters.io) to try the challenge.

# Passing the first stage
# Timeline

The entry point for your Redis implementation is in `lib/server.ex`. Study and
uncomment the relevant code, and push your changes to pass the first stage:

```sh
git add .
git commit -m "pass 1st stage" # any msg
git push origin master
```

That's all!
- PR: Improving connection handling (https://github.com/girorme/my-redis/pull/1)

# Stage 2 & beyond

Expand Down
29 changes: 29 additions & 0 deletions lib/handler.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule Handler do
@moduledoc """
This genserver handle incoming requests from the client as messages
"""

use GenServer
require Logger

@impl true
def init(initial_state \\ %{socket: nil}) do
state = Map.put(initial_state, :client_id, :rand.uniform(9999))
Logger.info("[id: #{state.client_id}] Redis connection received... Waiting data")
{:ok, state}
end

@impl true
def handle_info({:tcp, socket, data}, %{client_id: client_id} = state) do
Logger.info("[id: #{client_id}] Received: #{data}")
:gen_tcp.send(socket, "+PONG\r\n")
{:noreply, state}
end

@impl true
def handle_info({:tcp_closed, socket}, %{client_id: client_id} = state) do
Logger.info("[id: #{client_id}] Closing connection...")
:gen_tcp.send(socket, "+PONG\r\n")
{:noreply, state}
end
end
32 changes: 18 additions & 14 deletions lib/server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,31 @@ defmodule Server do

use Application

def start(_type, _args) do
Supervisor.start_link([{Task, fn -> Server.listen() end}], strategy: :one_for_one)
end
require Logger

@doc """
Listen for incoming connections
"""
def listen(port \\ 6379) do
def start(_type, _args) do
port = 6379
IO.puts("Starting redis server on port: #{port}")

# # Since the tester restarts your program quite often, setting SO_REUSEADDR
# # ensures that we don't run into 'Address already in use' errors
{:ok, socket} = :gen_tcp.listen(port, [:binary, active: false, reuseaddr: true])
{:ok, client} = :gen_tcp.accept(socket)

IO.puts("Redis connection received... Waiting data")
{:ok, socket} = :gen_tcp.listen(port, [:binary, active: true, reuseaddr: true])
Supervisor.start_link([{Task, fn -> Server.accept(socket) end}], strategy: :one_for_one)
end

{:ok, data} = :gen_tcp.recv(client, 0)
@doc """
Listen for incoming connections
"""
def accept(socket) do
case :gen_tcp.accept(socket) do
{:ok, client_socket} ->
{:ok, pid} = GenServer.start(Handler, %{socket: client_socket})
:gen_tcp.controlling_process(client_socket, pid)

IO.puts("Received: #{data}")
err ->
Logger.error(err)
end

:gen_tcp.send(client, "+PONG\r\n")
accept(socket)
end
end