Created
March 20, 2012 00:44
-
-
Save evilbetty/2129169 to your computer and use it in GitHub Desktop.
Simple chat server with eventmachine
This file contains hidden or 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
#!/usr/bin/env ruby | |
# | |
# Chat server attempt with Ruby and EventMachine. | |
# | |
# TODO: | |
# | |
# - Prevent chat from acting on \n (pressing enters in chat) | |
# - Handle (unexpected) disconnects properly (with unbind event). | |
# - Implement proper leaving with /quit. | |
# - Force names to be unique. | |
# - Implements private messages (using the unique names) | |
# - Handle annoying escape codes and arrow keys etc on prompt better. | |
# | |
# - Improvements | |
# - Funn Stuff | |
# | |
# - Implement channels? | |
# - Make a version for the real IRC protocol? | |
# | |
# | |
# CHANGELOG: | |
# | |
# - 21 Mar 2012 | |
# - Name validation added using regex | |
# - Added /me for the purpose of testing regex $1 | |
# - Added error handling with rescues | |
# - Removed @name from sendpublic to have a more general use, and added it in the else case statement | |
# - Replaced if elsif elsif else with a case statement using regex when checking for known commands | |
# | |
# | |
# Created on: 20 Mar 2012 01:28 | |
# Updated on: 21 Mar 2012 21:25 | |
# | |
# | |
# EvilBetty | |
# | |
require 'eventmachine' | |
# Config | |
IP = '0.0.0.0' | |
PORT = 8081 | |
class EmChat < EventMachine::Connection | |
#Accessor for name attribute and initialise the connections array | |
attr_accessor :name | |
@@clients = [] | |
#Own functions here | |
#Send data provided to all clients except the sending client by looping though all connections in array | |
def sendpublic(data) | |
@@clients.each do |client| | |
begin | |
#A bit messy way to remove the > that was already printed before with 2 backspaces, and readd > again after | |
client.send_data "\b\b#{data.strip}\n> " unless client == self | |
rescue | |
#if we cannot send to a client anymore remove it from clients list | |
@@clients.delete client | |
end | |
end | |
end | |
#EventMachine built in events below | |
#When a new connection is made welcome the client and ask name for initialisation | |
def post_init | |
send_data("Welcome to this chat server.\nWhat is your name? ") | |
end | |
#When data is received from a client this event runs | |
def receive_data(data) | |
#If name is not yet set do this first,set @initiated to true, and only now add client to connections array | |
if !@initiated | |
#Make sure name is 3 to 15 chars, and only contains letters and numbers | |
if data.strip =~ /^[a-zA-Z0-9]{3,15}$/ | |
@name = data.strip | |
@@clients << self | |
send_data "Welcome #{@name}.\n" | |
@initiated = true | |
sendpublic "#{@name} has joined.\n > " | |
else | |
send_data "Invalid Name. Max 15 chars. Only letters or numbers.\nName : " | |
end | |
#After initialisation of a connection continue here | |
else | |
#Check for recognised commands and handle them | |
case (data.strip) | |
# /names | |
when /^\/names$/ then | |
send_data "Current Users: " + @@clients.find_all.collect{ |client| client.name }.sort.join(" ") + "\n > " | |
# /help | |
when /^\/help$/ then | |
send_data "Help not implemented yet\n > " | |
# /me text | |
when /^\/me (.*)$/ then | |
sendpublic "* #{@name} #{$1.strip}" | |
send_data "* #{@name} #{$1.strip}\n >" | |
#If data is not a recognised command assume its chat text and send to all clients | |
else | |
sendpublic "#{@name} > #{data}" | |
send_data " > " | |
end | |
end | |
end | |
end | |
EM::run do | |
begin | |
EM::start_server IP, PORT, EmChat | |
puts "Service started on #{IP}:#{PORT}." | |
rescue RuntimeError | |
puts "Failed to start service on #{IP}:#{PORT}" | |
exit 1 | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment