Skip to content

Instantly share code, notes, and snippets.

@glejeune glejeune/README.md
Created Nov 6, 2011

Embed
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
You can’t perform that action at this time.