* fully supporting json concurrently with protocol buffers. specify ?pb=true to web URI
This commit is contained in:
parent
5b44da8ef2
commit
e64f3a4d0c
|
|
@ -9,9 +9,17 @@ include JamWebsockets
|
|||
jamenv = ENV['JAMENV']
|
||||
jamenv ||= 'development'
|
||||
|
||||
config = YAML::load(File.open('config/application.yml'))[jamenv]
|
||||
db_config = YAML::load(File.open('config/database.yml'))[jamenv]
|
||||
bin_dir = File.expand_path(File.dirname(__FILE__))
|
||||
|
||||
app_config_file = File.join(bin_dir, '..', 'config', 'application.yml')
|
||||
db_config_file = File.join(bin_dir, '..', 'config', 'database.yml')
|
||||
|
||||
# limit execution in base dir of project
|
||||
#app_config_file = File.join('config', 'application.yml')
|
||||
#db_config_file = File.join('config', 'database.yml')
|
||||
|
||||
config = YAML::load(File.open(app_config_file))[jamenv]
|
||||
db_config = YAML::load(File.open(db_config_file))[jamenv]
|
||||
|
||||
if config["verbose"]
|
||||
Logging.logger.root.level = :debug
|
||||
|
|
|
|||
|
|
@ -5,7 +5,14 @@ require 'protocol_buffers/compiler'
|
|||
class ProtocolBuffers::Message
|
||||
|
||||
def to_json(*args)
|
||||
hash = {'json_class' => self.class.name}
|
||||
|
||||
json = to_json_ready_object()
|
||||
|
||||
json.to_json(*args)
|
||||
end
|
||||
|
||||
def to_json_ready_object()
|
||||
hash = {}
|
||||
|
||||
# simpler version, includes all fields in the output, using the default
|
||||
# values if unset. also includes empty repeated fields as empty arrays.
|
||||
|
|
@ -19,15 +26,26 @@ class ProtocolBuffers::Message
|
|||
value = value_for_tag(field.tag)
|
||||
hash[field.name] = value unless value.empty?
|
||||
else
|
||||
hash[field.name] = value_for_tag(field.tag) if value_for_tag?(field.tag)
|
||||
if value_for_tag?(field.tag)
|
||||
value = value_for_tag(field.tag)
|
||||
if field.instance_of? ProtocolBuffers::Field::EnumField # if value is enum, resolve string value as ruby const
|
||||
hash[field.name] = field.value_to_name[value]
|
||||
else
|
||||
proxy_class = field.instance_variable_get(:@proxy_class)
|
||||
if proxy_class.nil?
|
||||
hash[field.name] = value
|
||||
else
|
||||
hash[field.name] = value.to_json_ready_object
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
hash.to_json(*args)
|
||||
|
||||
return hash
|
||||
end
|
||||
|
||||
def self.json_create(hash)
|
||||
hash.delete('json_class')
|
||||
|
||||
# initialize takes a hash of { attribute_name => value } so you can just
|
||||
# pass the hash into the constructor. but we're supposed to be showing off
|
||||
# reflection, here. plus, that raises an exception if there is an unknown
|
||||
|
|
@ -37,7 +55,15 @@ class ProtocolBuffers::Message
|
|||
message = new
|
||||
fields.each do |tag, field|
|
||||
if value = hash[field.name.to_s]
|
||||
message.set_value_for_tag(field.tag, value)
|
||||
if value.instance_of? Hash # if the value is a Hash, descend down into PB hierachy
|
||||
inner_class = field.instance_variable_get(:@proxy_class)
|
||||
value = inner_class.json_create(value)
|
||||
message.set_value_for_tag(field.tag, value)
|
||||
elsif field.instance_of? ProtocolBuffers::Field::EnumField # if value is enum, resolve string value as ruby const
|
||||
message.set_value_for_tag(field.tag, field.instance_variable_get(:@proxy_enum).const_get(value))
|
||||
else
|
||||
message.set_value_for_tag(field.tag, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
message
|
||||
|
|
|
|||
|
|
@ -3,12 +3,24 @@ require 'set'
|
|||
require 'hot_bunnies'
|
||||
require 'thread'
|
||||
require 'json'
|
||||
require 'eventmachine'
|
||||
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
include Jampb
|
||||
|
||||
# add new field to client connection
|
||||
module EventMachine
|
||||
module WebSocket
|
||||
class Connection < EventMachine::Connection
|
||||
attr_accessor :encode_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module JamWebsockets
|
||||
|
||||
|
||||
class Router
|
||||
|
||||
attr_accessor :user_context_lookup, :session_context_lookup
|
||||
|
|
@ -130,6 +142,7 @@ module JamWebsockets
|
|||
|
||||
@log.debug "received user-directed message for session: #{user_id}"
|
||||
|
||||
msg = Jampb::ClientMessage.parse(msg)
|
||||
contexts.each do |context|
|
||||
EM.schedule do
|
||||
@log.debug "sending user message to #{context}"
|
||||
|
|
@ -162,6 +175,7 @@ module JamWebsockets
|
|||
|
||||
@log.debug "received session-directed message for session: #{session_id}"
|
||||
|
||||
msg = Jampb::ClientMessage.parse(msg)
|
||||
contexts.each do |context|
|
||||
EM.schedule do
|
||||
@log.debug "sending session message to #{context}"
|
||||
|
|
@ -178,8 +192,12 @@ module JamWebsockets
|
|||
end
|
||||
|
||||
def send_to_client(client, msg)
|
||||
# this is so odd that this is necessary. but searching through the source code... it's all I could find in em-websocket
|
||||
client.instance_variable_get(:@handler).send_frame(:binary, msg)
|
||||
if client.encode_json
|
||||
client.send(msg.to_json.to_s)
|
||||
else
|
||||
# this is so odd that this is necessary from an API perspective. but searching through the source code... it's all I could find in em-websocket for allowing a binary message to be sent
|
||||
client.instance_variable_get(:@handler).send_frame(:binary, msg.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup()
|
||||
|
|
@ -228,15 +246,21 @@ module JamWebsockets
|
|||
@pending_clients.add(client)
|
||||
end
|
||||
|
||||
is_json = false
|
||||
# default to using json instead of pb
|
||||
client.encode_json = true
|
||||
|
||||
client.onopen {
|
||||
#binding.pry
|
||||
@log.debug "client connected #{client}"
|
||||
|
||||
# check for '?pb' or '?pb=true' in url query parameters
|
||||
query_pb = client.request["query"]["pb"]
|
||||
|
||||
p client.request["query"]
|
||||
is_json = !!client.request["query"]["json"]
|
||||
}
|
||||
if !query_pb.nil? && (query_pb == "" || query_pb == "true")
|
||||
client.encode_json = false
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
client.onclose {
|
||||
@log.debug "Connection closed"
|
||||
|
|
@ -263,12 +287,11 @@ module JamWebsockets
|
|||
|
||||
|
||||
begin
|
||||
if is_json
|
||||
#{"type":100, "target":"server", "Login" : {"username":"hi"}}
|
||||
if client.encode_json
|
||||
#example: {"type":"LOGIN", "target":"server", "login" : {"username":"hi"}}
|
||||
parse = JSON.parse(msg)
|
||||
p parse
|
||||
pb_msg = Jampb::ClientMessage.json_create(parse)
|
||||
p pb_msg
|
||||
self.route(pb_msg, client)
|
||||
else
|
||||
pb_msg = Jampb::ClientMessage.parse(msg.to_s)
|
||||
self.route(pb_msg, client)
|
||||
|
|
@ -277,7 +300,7 @@ module JamWebsockets
|
|||
@log.info "ending client session deliberately due to malformed client behavior. reason=#{e}"
|
||||
begin
|
||||
# wrap the message up and send it down
|
||||
error_msg = @message_factory.server_rejection_error(e.to_s).to_s
|
||||
error_msg = @message_factory.server_rejection_error(e.to_s)
|
||||
send_to_client(client, error_msg)
|
||||
ensure
|
||||
client.close_websocket
|
||||
|
|
@ -289,7 +312,7 @@ module JamWebsockets
|
|||
|
||||
begin
|
||||
# wrap the message up and send it down
|
||||
error_msg = @message_factory.server_generic_error(e.to_s).to_s
|
||||
error_msg = @message_factory.server_generic_error(e.to_s)
|
||||
send_to_client(client, error_msg)
|
||||
ensure
|
||||
client.close_websocket
|
||||
|
|
@ -385,9 +408,10 @@ module JamWebsockets
|
|||
end
|
||||
|
||||
def handle_login(login, client)
|
||||
username = login.username
|
||||
token = login.token
|
||||
password = login.password
|
||||
|
||||
username = login.username if login.value_for_tag(1)
|
||||
password = login.password if login.value_for_tag(2)
|
||||
token = login.token if login.value_for_tag(3)
|
||||
|
||||
user = valid_login(username, password, token)
|
||||
|
||||
|
|
@ -398,7 +422,7 @@ module JamWebsockets
|
|||
# respond with LOGIN_ACK to let client know it was successful
|
||||
#binding.pry
|
||||
remote_port, remote_ip = Socket.unpack_sockaddr_in(client.get_peername)
|
||||
login_ack = @message_factory.login_ack(remote_ip).to_s
|
||||
login_ack = @message_factory.login_ack(remote_ip)
|
||||
send_to_client(client, login_ack)
|
||||
|
||||
# remove from pending_queue
|
||||
|
|
@ -440,13 +464,13 @@ module JamWebsockets
|
|||
rescue => e
|
||||
# send back a failure ack and bail
|
||||
@log.debug "client requested non-existent session. client:#{client.request['origin']} user:#{context.user.email}"
|
||||
login_jam_session = @message_factory.login_jam_session_ack(true, e.to_s).to_s
|
||||
login_jam_session = @message_factory.login_jam_session_ack(true, e.to_s)
|
||||
send_to_client(client, login_jam_session)
|
||||
return
|
||||
end
|
||||
|
||||
# respond with LOGIN_JAM_SESSION_ACK to let client know it was successful
|
||||
login_jam_session = @message_factory.login_jam_session_ack(false, nil).to_s
|
||||
login_jam_session = @message_factory.login_jam_session_ack(false, nil)
|
||||
send_to_client(client, login_jam_session)
|
||||
|
||||
# send 'new client' message to other members in the session
|
||||
|
|
@ -464,18 +488,8 @@ module JamWebsockets
|
|||
|
||||
def valid_login(username, password, token)
|
||||
|
||||
if !username.nil? and !password.nil?
|
||||
# attempt login with username and password
|
||||
user = User.find_by_email(username)
|
||||
|
||||
if !user.nil? && user.authenticate(password)
|
||||
@log.debug "#{username} login via password"
|
||||
return user
|
||||
else
|
||||
@log.debug "#{username} login failure"
|
||||
return nil
|
||||
end
|
||||
elsif !token.nil?
|
||||
if !token.nil? && token != ''
|
||||
@log.debug "logging in via token"
|
||||
# attempt login with token
|
||||
user = User.find_by_remember_token(token)
|
||||
|
||||
|
|
@ -483,10 +497,24 @@ module JamWebsockets
|
|||
@log.debug "no user found with token"
|
||||
return false
|
||||
else
|
||||
@log.debug "#{username} login via token"
|
||||
@log.debug "#{user} login via token"
|
||||
return user
|
||||
end
|
||||
|
||||
elsif !username.nil? and !password.nil?
|
||||
|
||||
@log.debug "logging in via user/pass '#{username}' '#{password}'"
|
||||
# attempt login with username and password
|
||||
user = User.find_by_email(username)
|
||||
|
||||
if !user.nil? && user.authenticate(password)
|
||||
@log.debug "#{user} login via password"
|
||||
return user
|
||||
else
|
||||
@log.debug "#{username} login failure"
|
||||
return nil
|
||||
end
|
||||
else
|
||||
else
|
||||
raise SessionError, 'no login data was found in Login message'
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ require 'spec_helper'
|
|||
require 'thread'
|
||||
|
||||
LoginClient = Class.new do
|
||||
attr_accessor :onmsgblock, :onopenblock
|
||||
attr_accessor :onmsgblock, :onopenblock, :encode_json
|
||||
|
||||
def initiaize()
|
||||
|
||||
|
|
@ -43,9 +43,10 @@ def login(router, user, password)
|
|||
|
||||
login_ack = message_factory.login_ack("127.0.0.1")
|
||||
|
||||
router.should_receive(:send_to_client).with(client, login_ack.to_s)
|
||||
router.should_receive(:send_to_client).with(client, login_ack)
|
||||
client.should_receive(:onclose)
|
||||
client.should_receive(:onerror)
|
||||
client.should_receive(:request).and_return({ "query" => { "pb" => "true" } })
|
||||
client.should_receive(:get_peername).and_return("\x00\x02\x93\v\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||
|
||||
@router.new_client(client)
|
||||
|
|
@ -65,7 +66,7 @@ def login_jam_session(router, client, jam_session)
|
|||
message_factory = MessageFactory.new
|
||||
login_jam_session = message_factory.login_jam_session(jam_session.id)
|
||||
login_ack = message_factory.login_jam_session_ack(false, nil);
|
||||
router.should_receive(:send_to_client).with(client, login_ack.to_s)
|
||||
router.should_receive(:send_to_client).with(client, login_ack)
|
||||
client.onmsgblock.call login_jam_session.to_s
|
||||
end
|
||||
|
||||
|
|
@ -98,6 +99,7 @@ describe Router do
|
|||
client.should_receive(:onclose)
|
||||
client.should_receive(:onerror)
|
||||
client.should_receive(:onmessage)
|
||||
client.should_receive(:encode_json=)
|
||||
|
||||
@router.new_client(client)
|
||||
|
||||
|
|
@ -128,7 +130,7 @@ describe Router do
|
|||
it "should not allow login of bogus user", :mq => true do
|
||||
TestClient = Class.new do
|
||||
|
||||
attr_accessor :onmsgblock, :onopenblock
|
||||
attr_accessor :onmsgblock, :onopenblock, :encode_json
|
||||
|
||||
def initiaize()
|
||||
|
||||
|
|
@ -153,10 +155,11 @@ describe Router do
|
|||
|
||||
error_msg = message_factory.server_rejection_error("invalid login")
|
||||
|
||||
@router.should_receive(:send_to_client).with(client, error_msg.to_s)
|
||||
@router.should_receive(:send_to_client).with(client, error_msg)
|
||||
client.should_receive(:close_websocket)
|
||||
client.should_receive(:onclose)
|
||||
client.should_receive(:onerror)
|
||||
client.should_receive(:request).and_return({ "query" => { "pb" => "true" } })
|
||||
|
||||
|
||||
@router.new_client(client)
|
||||
|
|
@ -184,7 +187,7 @@ describe Router do
|
|||
user2 = FactoryGirl.create(:user) # in the jam session
|
||||
user3 = FactoryGirl.create(:user) # not in the jam session
|
||||
|
||||
jam_session = FactoryGirl.create(:jam_session, :user => user1)
|
||||
jam_session = FactoryGirl.create(:jam_session, :creator => user1)
|
||||
|
||||
jam_session_member1 = FactoryGirl.create(:jam_session_member, :user => user1, :jam_session => jam_session)
|
||||
jam_session_member2 = FactoryGirl.create(:jam_session_member, :user => user2, :jam_session => jam_session)
|
||||
|
|
@ -202,7 +205,7 @@ describe Router do
|
|||
user1 = FactoryGirl.create(:user) # in the jam session
|
||||
user2 = FactoryGirl.create(:user) # in the jam session
|
||||
|
||||
jam_session = FactoryGirl.create(:jam_session, :user => user1)
|
||||
jam_session = FactoryGirl.create(:jam_session, :creator => user1)
|
||||
|
||||
jam_session_member1 = FactoryGirl.create(:jam_session_member, :user => user1, :jam_session => jam_session)
|
||||
jam_session_member2 = FactoryGirl.create(:jam_session_member, :user => user2, :jam_session => jam_session)
|
||||
|
|
|
|||
Loading…
Reference in New Issue