Created
June 8, 2012 10:56
-
-
Save Shinpeim/2894978 to your computer and use it in GitHub Desktop.
メッセージングサーバの習作
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
# -*- coding: utf-8 -*- | |
require 'eventmachine' | |
require 'json' | |
require 'hashie' | |
#ログイン済みのコネクションハンドラーのコンテナ | |
class LoginedConnectionContainer | |
@@users = {} | |
def self.add(user_id,connection) | |
@@users[user_id] = connection | |
end | |
def self.fetch(user_id) | |
@@users[user_id] | |
end | |
def self.remove(user_id) | |
@@users.delete(user_id) | |
end | |
def self.list | |
@@users.keys | |
end | |
end | |
class ConnectionHandler < EM::Connection | |
def post_init | |
@state = ConnectionState::Connected.new(self) | |
@buffer = '' | |
end | |
#クライアントからデータ送られて来たときに呼ばれる | |
#Stateに委譲 | |
def receive_data(chunk) | |
@buffer += chunk | |
return unless @buffer =~ /\r\n$/ | |
line = @buffer.gsub(/[[:cntrl:]]/,"").encode("UTF-8") rescue raise("invalid utf-8 string") | |
@buffer = '' | |
data = Hashie::Mash.new(JSON.parse(line)) rescue raise("invalid JSON") | |
next_state = @state.process(data) | |
@state = next_state | |
rescue => e | |
send_error(e.message) | |
end | |
#接続切れたときに呼ばれる | |
#Stateに委譲 | |
def unbind | |
@state.unbind | |
end | |
def send_line(data) | |
send_data(data + "\r\n") | |
end | |
private | |
def to_valid_utf8(line) | |
return | |
end | |
def send_error(msg) | |
error = JSON.generate({"event" => "error","message" => msg}) | |
send_line(error) | |
close_connection_after_writing | |
end | |
end | |
#State | |
module ConnectionState | |
#接続後すぐの状態 | |
class Connected | |
def initialize(connection) | |
@connection = connection | |
end | |
def process(data) | |
raise "user_id is required in login request" unless data.user_id | |
LoginedConnectionContainer.add(data.user_id, @connection) | |
return Logined.new(data.user_id) | |
end | |
def unbind | |
# do nothing | |
end | |
end | |
#ログイン後の状態 | |
class Logined | |
def initialize(user_id) | |
@user_id = user_id | |
end | |
def process(data) | |
raise "'to' is required in message" unless data.to | |
raise "'message' is required in message" unless data.message | |
msg = JSON.generate({"event" => "message", "from" => @user_id, "message" => data.message}) | |
to = LoginedConnectionContainer.fetch(data.to) | |
return unless to | |
to.send_line(msg) | |
return self | |
end | |
def unbind | |
LoginedConnectionContainer.remove(@user_id) | |
end | |
end | |
end | |
EM::run do | |
host,port = "0.0.0.0", 6789 | |
EM.add_periodic_timer(1) do | |
p LoginedConnectionContainer.list | |
end | |
EM::start_server host, port, ConnectionHandler | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment