Mongrel2 handlers
handler = Handler( | |
send_spec = "tcp://*:9999", | |
send_ident = "7B0A2BF9-0DB2-4FEB-AD90-75C649B859FC", | |
recv_spec = "tcp://*:9998", | |
recv_ident = "" | |
) | |
main = Server( | |
uuid="242DABD4-D5BE-4D16-A042-D4985C8095BD", | |
access_log="/logs/access.log", | |
error_log="/logs/error.log", | |
chroot="./", | |
default_host="localhost", | |
name="test", | |
pid_file="/run/mongrel2.pid", | |
port=6767, | |
hosts = [ | |
Host(name="localhost", routes={ | |
"/": handler | |
}) | |
] | |
) | |
servers = [main] |
require 'eventmachine' | |
require 'em-zeromq' | |
require 'json' | |
require 'securerandom' | |
EM.run do | |
context = EM::ZeroMQ::Context.new(1) | |
requests = context.socket(ZMQ::PULL) | |
requests.connect('tcp://127.0.0.1:9999') | |
responses = context.socket(ZMQ::PUB) | |
responses.connect('tcp://127.0.0.1:9998') | |
responses.setsockopt(ZMQ::IDENTITY, SecureRandom.uuid) | |
requests.on :message do |msg| | |
#SERVER_UUID CLIENT_ID PATH N:HEADERS_JSON, N:BODY, | |
#7B0A2BF9-0DB2-4FEB-AD90-75C649B859FC 3 / 29:{"Content-Type":"text/plain"}, 13:Hello handler | |
uuid, id, path, rest = msg.copy_out_string.split(' ', 4) | |
netstrings = [] | |
until rest.empty? #6:{JSON},15:hello my friend, | |
length = rest[/\A\d+/] #6 #15 | |
rest.slice!(0, length.length+1) #6: #15: | |
netstrings << rest.slice!(0, length.to_i) #{JSON} #hello my friend | |
rest.slice!(0) #, #, | |
end | |
headers, body = netstrings | |
headers = JSON.parse(headers) | |
p headers | |
p body | |
response_body = 'Hello, Mongrel2!' | |
response_body = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: #{response_body.bytesize}\r\n\r\n#{response_body}" | |
#Response format: SERVER_UUID N:CLIENT_IDS, BODY | |
#7B0A2BF9-0DB2-4FEB-AD90-75C649B859FC 1:3, Hello Mongrel2! | |
response = '%s %d:%s, %s' % [uuid, id.size, id, response_body] | |
responses.send_msg(response) | |
end | |
end#EM.run |
require 'eventmachine' | |
require 'em-zeromq' | |
require 'json' | |
require 'securerandom' | |
EM.run do | |
context = EM::ZeroMQ::Context.new(1) | |
requests = context.socket(ZMQ::PULL) | |
requests.connect('tcp://127.0.0.1:9999') | |
responses = context.socket(ZMQ::PUB) | |
responses.connect('tcp://127.0.0.1:9998') | |
responses.setsockopt(ZMQ::IDENTITY, SecureRandom.uuid) | |
clients = [] | |
requests.on :message do |msg| | |
uuid, id, path, rest = msg.copy_out_string.split(' ', 4) | |
netstrings = [] | |
until rest.empty? #6:{JSON},15:hello my friend, | |
length = rest[/\A\d+/] #6 #15 | |
rest.slice!(0, length.length+1) #6: #15: | |
netstrings << rest.slice!(0, length.to_i) #{JSON} #hello my friend | |
rest.slice!(0) #, #, | |
end | |
headers, body = netstrings | |
headers = JSON.parse(headers) | |
#When a client disconnects, a special METHOD header with value JSON is sent by Mongrel2 | |
#The body is a JSON document with "type":"disconnect" | |
if headers['METHOD'] == 'JSON' && JSON.parse(body)['type'] == 'disconnect' | |
clients.delete(id) #Remove client's id from list of connected clients | |
puts "Client #{id} disconnected (#{clients.size} clients left)" | |
else | |
clients << id #First contact, add client's id to list of connected clients | |
response_headers = {'Content-Type' => 'text/event-stream'} #SSE MIME type | |
response_body = "HTTP/1.1 200 OK\r\n#{response_headers.map{|k,v| "#{k}: #{v}" }.join("\r\n")}\r\n\r\n" | |
response = '%s %d:%s, %s' % [uuid, id.size, id, response_body] | |
responses.send_msg(response) | |
puts "Client #{id} connected (currently #{clients.size} clients)" | |
end | |
end | |
c = 0 | |
EM.add_periodic_timer 1 do | |
event = "event: counter\r\ndata: #{c+=1}\r\n\r\n" #SSE event | |
ids = clients.join(' ') | |
# UUID of server from config Send to all connected clients | |
responses.send_msg('%s %d:%s, %s' % ['7B0A2BF9-0DB2-4FEB-AD90-75C649B859FC', ids.size, ids, event]) | |
end | |
end#EM.run |
require 'eventmachine' | |
require 'em-zeromq' | |
require 'json' | |
require 'securerandom' | |
require 'base64' | |
EM.run do | |
context = EM::ZeroMQ::Context.new(1) | |
requests = context.socket(ZMQ::PULL) | |
requests.connect('tcp://127.0.0.1:9999') | |
responses = context.socket(ZMQ::PUB) | |
responses.connect('tcp://127.0.0.1:9998') | |
responses.setsockopt(ZMQ::IDENTITY, SecureRandom.uuid) | |
clients = {} | |
require 'em-websocket' | |
requests.on :message do |msg| | |
uuid, id, path, rest = msg.copy_out_string.split(' ', 4) | |
netstrings = [] | |
until rest.empty? #6:{JSON},15:hello my friend, | |
length = rest[/\A\d+/] #6 #15 | |
rest.slice!(0, length.length+1) #6: #15: | |
netstrings << rest.slice!(0, length.to_i) #{JSON} #hello my friend | |
rest.slice!(0) #, #, | |
end | |
headers, body = netstrings | |
headers = JSON.parse(headers) | |
if headers['METHOD'] == 'WEBSOCKET_HANDSHAKE' | |
clients[id] = {websocket: EM::WebSocket::Connection.new(id, {})} #One per client | |
#Override send_data to use responses ZMQ socket | |
(class << clients[id][:websocket];self;end).send(:define_method, :send_data){|d| responses.send_msg('%s %d:%s, %s' % [uuid, id.size, id, d]) } | |
headers.delete_if{|k,v| k =~ /\A[A-Z]+\Z/ }#Delete Mongrel2 custom headers | |
http = "GET / HTTP/1.1\r\n#{headers.map{|k,v| "#{k}: #{v}" }.join("\r\n")}\r\n\r\n#{body}" | |
clients[id][:websocket].receive_data(http)#Pass HTTP on to em-websocket connection instance | |
elsif headers['METHOD'] == 'WEBSOCKET' | |
data = JSON.parse(body) | |
if data['type'] == 'join' | |
clients[id][:name] = data['name'] | |
clients.each{|i,h| h[:websocket].send(JSON.generate(type: 'join', name:clients[id][:name])) } | |
puts "#{data['name']} joined" | |
elsif data['type'] == 'message' | |
clients.each{|i,h| h[:websocket].send(JSON.generate(type: 'message', name:clients[id][:name], message:data['message'])) } | |
puts "#{clients[id][:name]} said: #{data['message']}" | |
end | |
else | |
puts "Received HTTP request" | |
response_body = "HTTP/1.1 418 I'm a teapot\r\nContent-Length: 0\r\nConnection: close\r\n\r\nNot really, I'm a WebSocket" | |
responses.send_msg('%s %d:%s, %s' % [uuid, id.size, id, response_body]) | |
end | |
end | |
end#EM.run |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment