Skip to content

Instantly share code, notes, and snippets.

@mattknox
Last active November 23, 2017 00:51
Show Gist options
  • Save mattknox/56b90335d675b6e6b970e4d3937517bd to your computer and use it in GitHub Desktop.
Save mattknox/56b90335d675b6e6b970e4d3937517bd to your computer and use it in GitHub Desktop.
require "socket"
class Memcached
attr_accessor :client
def initialize(store = {})
@client = client
@store = store
end
def get(key)
if value = @store[key]
"VALUE #{key} #{value.length}\n#{value}\nEND\n"
else
"END\n"
end
end
def set(key, data)
@store[key] = data
"STORED"
end
def serve(client)
while !client.eof? do
execute_command(client)
end
rescue Exception => e
puts e.class
puts e.message
puts e.backtrace
end
def parse(line)
verb, *rest = line.split
if "get" == verb && rest.size == 1 && rest.first.match(/^[a-zA-Z_]+$/)
[:get, rest]
elsif "get" == verb && rest.size > 1 && rest.all? {|s| s.match(/^[a-zA-Z_]+$/) }
[:get_multi, rest]
elsif "set" == verb && rest.size == 2 && rest.first.match(/^[a-zA-Z_]+$/) && rest.last.match(/^[1-9]\d*$/)
[:set, [rest.first], rest.last.to_i]
else
raise ArgumentError.new("invalid command #{line}")
end
end
def execute_command(client)
verb, keys, data_len = parse(client.gets)
if :get == verb
client.puts get(keys.first)
elsif :get_multi == verb
keys.map { |key| client.puts(get(key)) }
elsif :set == verb
data = client.read(data_len.succ).chomp
raise ArgumentError.new("bad data_len #{data_len} for data '#{data}'") unless data_len == data.length
client.puts set(keys.first, data)
end
end
end
class Runner
def self.run(port)
server = TCPServer.new port
server.setsockopt(:SOCKET, :REUSEADDR, 1)
memcache = Memcached.new
loop do
Thread.start(server.accept) do |client|
puts "server.accept"
memcache.serve client #BufferedSocketClient.new(client)
end
end
end
end
class FakeClient
def eof?
false
end
def gets
Kernel.gets
end
def puts(s)
Kernel.puts s
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment