Skip to content

Instantly share code, notes, and snippets.

@tmm1
Created March 11, 2010 21:31
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save tmm1/329682 to your computer and use it in GitHub Desktop.
Save tmm1/329682 to your computer and use it in GitHub Desktop.
EM Chat Server Demo
require 'rubygems'
require 'eventmachine'
require 'em-http' # gem install em-http-request
require 'yajl' # gem install yajl-ruby
class String
def bold
"\033[1m#{self}\033[0m"
end
end
module ChatClient
def post_init
@buf = ''
@name = "anonymous_#{ChatClient.client_num+=1}"
@sid = ChatClient.channel.subscribe do |msg|
send_msg(msg)
end
send_header
send_prompt
ChatClient.channel << "#{@name.bold} has joined.\n"
end
def unbind
ChatClient.channel.unsubscribe(@sid)
ChatClient.channel << "#{@name.bold} has left.\n"
end
def receive_data data
@buf << data
quit and return if @buf =~ /(\006|\004)/ # ctrl+c or ctrl+d
while line = @buf.slice!(/(.+)\r?\n/)
p [@name, line]
send_prompt
if line =~ %r|^/nick (.+)|
new_name = $1.strip[0..12]
ChatClient.channel << "#{@name.bold} is now known as #{new_name.bold}\n"
@name = new_name
send_prompt
elsif line =~ %r|^/me (.+)|
ChatClient.channel << "#{@name.bold} #{$1.strip}\n"
elsif line =~ %r|^/say (.+)|
send_msg "\033[37mAdding #{$1.strip.bold} to the say queue at position #{ChatClient.say_queue.size+1}\033[0m\n"
ChatClient.say_queue.push "#{@name} said #{$1.strip}"
elsif line =~ %r|^/quit|
quit
elsif line =~ /^\e/ # ignore escape sequences
send_prompt
elsif !line.strip.empty?
ChatClient.channel << "#{@name.bold}: #{line.gsub(/[^[:print:]]/,'')}\n"
end
end
end
private
def send_header
send_data "\033[2;23r"
send_data "\033[2J"
send_data "\033[1H"
header = "Welcome to the EventMachine Chat Demo (/nick, /me, /say, /quit)".center(80)
send_data "\033[32m#{header}\033[0m"
end
def send_msg msg
send_data "\0337"
send_data "\033M"
send_data "\033[23;1H"
send_data msg
send_data "\0338"
end
def send_prompt
send_data "\033[24H"
send_data "\033[2K"
send_data "\033[1m"
send_data @name
send_data "\033[0m: "
end
def quit
send_data "\033[2J"
send_data "\033[1;1H"
header = "Check out http://gist.github.com/329682 for the source to the EM chat server".center(80)
send_data "\033[32m#{header}\033[0m"
send_data "\033[r"
send_data "\033[3;1H"
close_connection_after_writing
end
@client_num = 0
class << self
attr_accessor :client_num
end
def ChatClient.channel
@channel ||= EM::Channel.new
end
def ChatClient.say_queue
@say_queue ||= begin
q = EM::Queue.new
# pop off items from the queue one at a time, and pass them to `say`
processor = proc{ |msg|
ChatClient.channel << "\033[37mSaying: #{msg.bold}\033[0m\n"
EM.system("say", msg) do |out, status|
p [:say, msg, status]
q.pop(&processor)
end
}
# pop off the first item
q.pop(&processor)
q
end
end
end
class TwitterStream
def initialize(user, pass, tags, &blk)
raise ArgumentError, 'block required' unless blk
http = EM::HttpRequest.new(
"http://stream.twitter.com/1/statuses/filter.json?track=#{tags.join(',')}"
).get(
:head => {'authorization' => [user, pass]}
)
parser = Yajl::Parser.new(:symbolize_keys => true)
parser.on_parse_complete = blk
http.stream do |data|
parser << data
end
end
end
EM.run{
EM.start_server '0.0.0.0', 1337, ChatClient
EM::PeriodicTimer.new(90) do
ChatClient.channel << "\033[31mThe time is now #{Time.now}\033[0m\n"
end
TwitterStream.new('USERNAME', 'PASSWORD', %w[ railsconf eventmachine ]) do |tweet|
name, msg = tweet[:user][:screen_name], tweet[:text]
p [:tweet, name, msg]
ChatClient.channel << "\033[34;1m@#{name}\033[0m: #{msg}\n"
end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment