Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
A (very) simple chat service using AMQP

Run

  1. Install and run an AMQP server (RabbitMQ is a good choise)

  2. Install amqp and ncurses-ruby gems

    sudo gem install amqp ncurses-ruby

  3. Run the client

    ruby ./amqp-chat.rb

require "rubygems"
require "ncurses"
require "amqp"
class ChatGui
def read_line(y, x,
window = Ncurses.stdscr,
max_len = (window.getmaxx - x - 1),
string = "",
cursor_pos = 0)
loop do
window.mvaddstr(y,x,string)
window.move(y,x+cursor_pos)
ch = window.getch
case ch
when Ncurses::KEY_ENTER, ?\n.ord, ?\r.ord
return string
when Ncurses::KEY_BACKSPACE, 127
string = string[0...([0, cursor_pos-1].max)] + string[cursor_pos..-1]
cursor_pos = [0, cursor_pos-1].max
window.mvaddstr(y, x+string.length, " ")
when (" "[0].ord..255)
if (cursor_pos < max_len)
string[cursor_pos,0] = ch.chr
cursor_pos += 1
else
Ncurses.beep
end
else
Ncurses.beep
end
end
end
def add_message(message)
@messages += message.split("\n")
if @messages.size > @max_messages
@messages.shift
end
refresh_messages_window
end
def refresh_messages_window
@messages_window.clear
y = 0
@messages.each do |message|
@messages_window.mvaddstr(y, 0, message)
y = y + 1
end
@messages_window.refresh
end
def initialize(nick)
@messages = []
Ncurses.initscr
Ncurses.cbreak
Ncurses.noecho
Ncurses.keypad(Ncurses.stdscr, true)
@window = Ncurses.stdscr
@maxy = @window.getmaxy - 1
@maxx = @window.getmaxx - 1
@prompt_window = Ncurses.newwin(2, @maxx, @maxy - 2, 0)
@prompt = "#{nick} >"
@messages_window = Ncurses.newwin(@maxy - 2, @maxx, 0, 0)
@max_messages = @messages_window.getmaxy
end
def run(&b)
loop do
# refresh_messages_window
@prompt_window.mvaddstr(0, 0, "-"*@maxx)
@prompt_window.mvaddstr(1, 0, @prompt)
message = read_line(1, @prompt.length + 1, @prompt_window)
yield message
@prompt_window.clear
end
end
def quit
Ncurses.endwin
end
end
# -- main --
def help(gui)
gui.add_message <<EOH
/help : display this help
/me <message> : send an action message
/privmsg <nickname> <message> : send a private message
/quit : Quit AMQP chat
/who : ask who is here
EOH
end
nickname = ARGV[0]
raise "Usage : #{$0} <nickname>" if nickname.nil?
gui = ChatGui.new(nickname)
AMQP.start("amqp://localhost") do |connection|
channel = AMQP::Channel.new(connection)
exchange = channel.headers("amqp.chat.v3")
public_queue = channel.queue("public.#{nickname}", :auto_delete => true)
public_queue.bind(exchange, :arguments => { :type => 'public' }).subscribe do |headers, payload|
gui.add_message payload.to_s
end
private_queue = channel.queue("private.#{nickname}", :auto_delete => true)
private_queue.bind(exchange, :arguments => { :type => 'private', :nick => nickname }).subscribe do |headers, payload|
gui.add_message payload.to_s
end
system_queue = channel.queue("system.#{nickname}", :auto_delete => true)
system_queue.bind(exchange, :arguments => { :type => 'system' }).subscribe do |headers, payload|
exchange.publish "-- #{nickname} is here", :headers => {:type => 'private', :nick => payload.to_s}
end
exchange.publish "** #{nickname} enter", :headers => {:type => 'public'}
Thread.new do
gui.run do |message|
case message
when /^\/quit\s*(.*)/
exchange.publish "** #{nickname} has quit (#{$1})", :headers => {:type => 'public'}
connection.close {
EventMachine.stop
}
break
when /^\/me\s*(.*)/
exchange.publish "** #{nickname} #{$1}", :headers => {:type => "public"}
when /^\/privmsg\s*([^\s]*)\s*(.*)/
exchange.publish ">> [#{Time.now.strftime('%H:%M:%S')}] #{nickname} : #{$2}", :headers => {:type => 'private', :nick => $1}
exchange.publish ">> [#{Time.now.strftime('%H:%M:%S')}] #{nickname} : #{$2}", :headers => {:type => 'private', :nick => nickname}
when /^\/who/
exchange.publish nickname, :headers => {:type => "system"}
when /^\/help/
help gui
else
exchange.publish "[#{Time.now.strftime('%H:%M:%S')}] #{nickname} : #{message}", :headers => {:type => 'public'}
end
end
end
end
gui.quit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment