Skip to content
This repository has been archived by the owner on Oct 2, 2019. It is now read-only.

Commit

Permalink
feature: Use channels do deal with memory concurrency
Browse files Browse the repository at this point in the history
By using a Channel is expected that the memory get no concurrent access,
the Fibers should send all the requests over the Channel. The same will
receive and perform in the received order.

Additional changes:
  - Add a 'request' abstraction, to deal with parsing the received
  message and handling commands
  • Loading branch information
marceloboeira committed Sep 2, 2016
1 parent 80eedd8 commit 5b721d1
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 36 deletions.
39 changes: 39 additions & 0 deletions src/bojack/request.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require "socket"
require "logger"
require "./logger"
require "./command"
require "./memory"

module BoJack
class Request
@logger : ::Logger = BoJack::Logger.instance
def initialize(@body : String, @socket : TCPSocket, @memory : BoJack::Memory(String, Array(String))); end

def perform
@logger.info("#{@socket.remote_address} requested: #{@body.strip}")
params = parse(@body)
command = BoJack::Command.from(params[:command])

response = command.run(@socket, @memory, params)

@socket.puts(response)
rescue e
message = "error: #{e.message}"
@logger.error(message)
@socket.puts(message)
end

private def parse(body) : Hash(Symbol, String | Array(String))
body = body.split(" ").map { |item| item.strip }

command = body[0]
result = Hash(Symbol, String | Array(String)).new
result[:command] = command

result[:key] = body[1] if body[1]?
result[:value] = body[2].split(",") if body[2]?

result
end
end
end
49 changes: 13 additions & 36 deletions src/bojack/server.cr
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
require "socket"
require "logger"
require "./logger"
require "./request"
require "./memory"
require "./command"
require "./logo"

module BoJack
class Server
@hostname : String
@port : Int8 | Int16 | Int32 | Int64
@logger : ::Logger = BoJack::Logger.instance
@channel : Channel::Unbuffered(BoJack::Request) = Channel(BoJack::Request).new
@memory = BoJack::Memory(String, Array(String)).new

def initialize(@hostname = "127.0.0.1", @port = 5000); end

def start
server = TCPServer.new(@hostname, @port)
server.tcp_nodelay = true
server.recv_buffer_size = 4096
memory = BoJack::Memory(String, Array(String)).new

BoJack::Logo.render

Expand All @@ -29,51 +30,27 @@ module BoJack
exit
end

spawn do
loop do
if request = @channel.receive
request.perform
end
end
end

loop do
if socket = server.accept
@logger.info("#{socket.remote_address} connected")

spawn do
loop do
request = socket.gets
break unless request

@logger.info("#{socket.remote_address} requested: #{request.strip}")

begin
params = parse_request(request)
command = BoJack::Command.from(params[:command])

response = command.run(socket, memory, params)

if command.is_a?(BoJack::Commands::Close)
break
end

socket.puts(response)
rescue e
message = "error: #{e.message}"
@logger.error(message)
socket.puts(message)
if message = socket.gets
@channel.send(BoJack::Request.new(message, socket, @memory))
end
end
end
end
end
end

private def parse_request(request) : Hash(Symbol, String | Array(String))
request = request.split(" ").map { |item| item.strip }

command = request[0]
result = Hash(Symbol, String | Array(String)).new
result[:command] = command

result[:key] = request[1] if request[1]?
result[:value] = request[2].split(",") if request[2]?

result
end
end

end

3 comments on commit 5b721d1

@mauricioabreu
Copy link
Collaborator

Choose a reason for hiding this comment

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

πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘

@mauricioabreu
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry :P

@marceloboeira
Copy link
Owner Author

Choose a reason for hiding this comment

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

@mauricioabreu thanks ahahah

Please sign in to comment.