-
-
Save toretore/35eb74a2cac3f214fd4b to your computer and use it in GitHub Desktop.
Mongrel2 handlers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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