mad_chatter 0.0.7 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +9 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +29 -0
- data/{LICENSE → LICENSE.txt} +0 -0
- data/README.md +76 -0
- data/Rakefile +55 -0
- data/bin/mad_chatter +33 -10
- data/lib/mad_chatter/action.rb +34 -0
- data/lib/mad_chatter/actions/join.rb +12 -15
- data/lib/mad_chatter/actions/rename.rb +13 -16
- data/lib/mad_chatter/config.rb +49 -0
- data/lib/mad_chatter/extensions.rb +13 -0
- data/lib/mad_chatter/message.rb +19 -19
- data/lib/mad_chatter/server.rb +52 -89
- data/lib/mad_chatter/servers/em_websocket.rb +38 -0
- data/lib/mad_chatter/servers/juggernaut.rb +9 -0
- data/lib/mad_chatter/servers/websocket_rack.rb +9 -0
- data/lib/mad_chatter/users.rb +1 -4
- data/lib/mad_chatter/version.rb +5 -0
- data/lib/mad_chatter.rb +21 -15
- data/templates/config.yml +6 -0
- data/templates/extensions.rb +13 -0
- data/templates/{index.html → web/index.html} +0 -0
- data/templates/{javascript.js → web/javascript.js} +1 -1
- data/templates/{stylesheets → web/stylesheets}/reset.css +0 -0
- data/templates/{stylesheets → web/stylesheets}/styles.css +9 -27
- data/test/helper.rb +18 -0
- data/test/test_mad_chatter.rb +7 -0
- metadata +98 -24
- data/README +0 -0
- data/lib/mad_chatter/actions/base.rb +0 -36
- data/lib/mad_chatter/actions.rb +0 -61
data/CHANGELOG.txt
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Mad Chatter
|
2
|
+
|
3
|
+
Version 0.1.0
|
4
|
+
- Refactored extension architecture. Much nicer syntax now.
|
5
|
+
- Moved some of the main configuration to a config.yml file (which is generated when you use the 'new' command)
|
6
|
+
- Created skeleton classes for alternative web socket server implementations and moved the default implementation into its own class
|
7
|
+
|
8
|
+
Versions < 0.1.0
|
9
|
+
- Some of the features were implemented, but there were many holes that needed to be filled
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
# Gem dependencies
|
4
|
+
gem 'thor'
|
5
|
+
gem 'eventmachine', '0.12.10'
|
6
|
+
gem 'em-websocket'
|
7
|
+
|
8
|
+
# Development dependencies
|
9
|
+
group :development do
|
10
|
+
gem "shoulda", ">= 0"
|
11
|
+
gem "bundler", "~> 1.0.0"
|
12
|
+
gem "jeweler", "~> 1.6.4"
|
13
|
+
gem "rcov", ">= 0"
|
14
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.2.6)
|
5
|
+
em-websocket (0.3.5)
|
6
|
+
addressable (>= 2.1.1)
|
7
|
+
eventmachine (>= 0.12.9)
|
8
|
+
eventmachine (0.12.10)
|
9
|
+
git (1.2.5)
|
10
|
+
jeweler (1.6.4)
|
11
|
+
bundler (~> 1.0)
|
12
|
+
git (>= 1.2.5)
|
13
|
+
rake
|
14
|
+
rake (0.9.2.2)
|
15
|
+
rcov (0.9.11)
|
16
|
+
shoulda (2.11.3)
|
17
|
+
thor (0.14.6)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
bundler (~> 1.0.0)
|
24
|
+
em-websocket
|
25
|
+
eventmachine (= 0.12.10)
|
26
|
+
jeweler (~> 1.6.4)
|
27
|
+
rcov
|
28
|
+
shoulda
|
29
|
+
thor
|
data/{LICENSE → LICENSE.txt}
RENAMED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
#Mad Chatter
|
2
|
+
|
3
|
+
Mad Chatter is a fun, easy to customize chat server. It's written in Ruby and utilizes HTML 5 Web Sockets for fast communication.
|
4
|
+
|
5
|
+
##Getting Started
|
6
|
+
|
7
|
+
To get started, first install the Mad Chatter gem:
|
8
|
+
|
9
|
+
gem install mad_chatter
|
10
|
+
|
11
|
+
Then generate the directory where your chat application will live:
|
12
|
+
|
13
|
+
mad_chatter new mychatroom
|
14
|
+
|
15
|
+
This command will generate the following structure:
|
16
|
+
|
17
|
+
mychatroom/
|
18
|
+
config.rb
|
19
|
+
extensions/
|
20
|
+
web/
|
21
|
+
index.html
|
22
|
+
javascript.js
|
23
|
+
stylesheets/
|
24
|
+
reset.css
|
25
|
+
styles.css
|
26
|
+
|
27
|
+
To start your chat server, navigate to the directory that was just created and run...
|
28
|
+
|
29
|
+
mad_chatter start
|
30
|
+
|
31
|
+
This will start the web socket server on a specific port. You can now open the index.html file in your browser and start playing. All the files necessary to serve to the client are in the web directory. Feel free to copy/move these files if you'd prefer them somewhere else.
|
32
|
+
|
33
|
+
The start command will launch the web socket server in the background. You can use this command in production to start your server and leave it running. If you need to stop the server, simply run...
|
34
|
+
|
35
|
+
mad_chatter stop
|
36
|
+
|
37
|
+
|
38
|
+
##Chat Actions
|
39
|
+
|
40
|
+
Hopefully, the default chatroom will be relatively intuitive to use. However, there are some extra features that Mad Chatter provides. Every chat message is parsed to see if it is a normal chat message, or if its a special action. These actions are much like IRC commands. For example, if I wanted to change my screen name from Andrew to Andy I could chat this message:
|
41
|
+
|
42
|
+
/nick andy
|
43
|
+
|
44
|
+
Mad Chatter will interpret this message as an action and change the user name to andy.
|
45
|
+
|
46
|
+
If I wanted to embed a YouTube video for all the members of the chatroom to enjoy, I could type:
|
47
|
+
|
48
|
+
/youtube http://youtu.be/n1NVfDlU6yQ
|
49
|
+
|
50
|
+
You can even create your own actions to do whatever you want.
|
51
|
+
|
52
|
+
|
53
|
+
##Customizing
|
54
|
+
|
55
|
+
The goal of Mad Chatter is to make it easy to create, host, and customize your own chat server. Let's take a look at the different ways you can customize your new chat server.
|
56
|
+
|
57
|
+
If you want to customize the html/css of your chatroom, you'll find them in the web directory.
|
58
|
+
|
59
|
+
There is an example config file that shows a few examples of things you can customize.
|
60
|
+
|
61
|
+
The extensions directory is for you to create your own chat actions. You can add your custom extensions by specifying them in the config file.
|
62
|
+
|
63
|
+
|
64
|
+
##Contributing
|
65
|
+
|
66
|
+
Please fork and send pull requests! Or submit issues if you have suggestions on how to improve.
|
67
|
+
|
68
|
+
##TODO
|
69
|
+
|
70
|
+
- Actually implement the server daemonization mentioned above
|
71
|
+
- Add support for alternative web socket servers like Juggernaut, Socket.io, or Cramp and web-socket-js for better cross-browser support
|
72
|
+
- Add tests!
|
73
|
+
|
74
|
+
##Copyright
|
75
|
+
|
76
|
+
Copyright (c) 2011 Andrew Havens. See LICENSE.txt for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
require './lib/mad_chatter/version.rb'
|
16
|
+
Jeweler::Tasks.new do |gem|
|
17
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
18
|
+
gem.name = "mad_chatter"
|
19
|
+
gem.version = MadChatter::VERSION
|
20
|
+
gem.homepage = "http://github.com/andrewhavens/mad_chatter"
|
21
|
+
gem.license = "MIT"
|
22
|
+
gem.summary = %Q{Mad Chatter is a fun, easy to customize chat server, utilizing HTML 5 Web Sockets}
|
23
|
+
gem.description = %Q{Mad Chatter is a fun, easy to customize chat server, utilizing HTML 5 Web Sockets}
|
24
|
+
gem.email = "email@andrewhavens.com"
|
25
|
+
gem.authors = ["Andrew Havens"]
|
26
|
+
# dependencies defined in Gemfile
|
27
|
+
end
|
28
|
+
Jeweler::RubygemsDotOrgTasks.new
|
29
|
+
|
30
|
+
require 'rake/testtask'
|
31
|
+
Rake::TestTask.new(:test) do |test|
|
32
|
+
test.libs << 'lib' << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
|
37
|
+
require 'rcov/rcovtask'
|
38
|
+
Rcov::RcovTask.new do |test|
|
39
|
+
test.libs << 'test'
|
40
|
+
test.pattern = 'test/**/test_*.rb'
|
41
|
+
test.verbose = true
|
42
|
+
test.rcov_opts << '--exclude "gems/*"'
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default => :test
|
46
|
+
|
47
|
+
require 'rake/rdoctask'
|
48
|
+
Rake::RDocTask.new do |rdoc|
|
49
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "mad_chatter #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
data/bin/mad_chatter
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'thor'
|
4
|
+
require File.expand_path('../../lib/mad_chatter', __FILE__)
|
4
5
|
|
5
6
|
module MadChatter
|
6
7
|
|
@@ -8,21 +9,43 @@ module MadChatter
|
|
8
9
|
include Thor::Actions
|
9
10
|
|
10
11
|
def self.source_root
|
11
|
-
File.expand_path(
|
12
|
+
File.expand_path('../../', __FILE__)
|
12
13
|
end
|
13
14
|
|
14
|
-
desc "new", "
|
15
|
+
desc "new [name]", "Generates a new Mad Chatter chatroom application"
|
15
16
|
def new(name)
|
17
|
+
copy_file "templates/config.yml", "#{name}/config.yml"
|
18
|
+
copy_file "templates/extensions.rb", "#{name}/extensions.rb"
|
16
19
|
empty_directory "#{name}/extensions"
|
17
|
-
copy_file "
|
18
|
-
copy_file "
|
19
|
-
copy_file "templates/
|
20
|
-
copy_file "templates/
|
21
|
-
|
22
|
-
|
20
|
+
copy_file "templates/web/index.html", "#{name}/web/index.html"
|
21
|
+
copy_file "templates/web/javascript.js", "#{name}/web/javascript.js"
|
22
|
+
copy_file "templates/web/stylesheets/reset.css", "#{name}/web/stylesheets/reset.css"
|
23
|
+
copy_file "templates/web/stylesheets/styles.css", "#{name}/web/stylesheets/styles.css"
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'start', 'Starts the chat server'
|
27
|
+
def start
|
28
|
+
MadChatter.start
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'stop', 'Stops the chat server'
|
32
|
+
def stop
|
33
|
+
# stop the currently running daemon
|
34
|
+
# not sure how to best implement this part yet
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'restart', 'Restarts the chat server'
|
38
|
+
def restart
|
39
|
+
# restarts the currently running daemon
|
40
|
+
# not sure how to best implement this part yet
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'version', 'Displays the current version number'
|
44
|
+
def version
|
45
|
+
puts MadChatter::VERSION
|
23
46
|
end
|
24
47
|
|
25
48
|
end
|
26
49
|
end
|
27
50
|
|
28
|
-
MadChatter::Cli.start
|
51
|
+
MadChatter::Cli.start(ARGV)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module MadChatter
|
2
|
+
class Action
|
3
|
+
|
4
|
+
def self.inherited(extension_class)
|
5
|
+
MadChatter.extension_classes << extension_class.new
|
6
|
+
end
|
7
|
+
|
8
|
+
# Helper methods
|
9
|
+
|
10
|
+
def stop_message_handling
|
11
|
+
raise 'Dont call anymore message listeners'
|
12
|
+
end
|
13
|
+
|
14
|
+
def send_json(json)
|
15
|
+
MadChatter::Server.send_json(json)
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_message(text)
|
19
|
+
message = MadChatter::Message.new('message', text)
|
20
|
+
send_json(message.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
def send_status_message(text)
|
24
|
+
message = MadChatter::Message.new('status', text)
|
25
|
+
send_json(message.to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
def send_users_list
|
29
|
+
message = MadChatter::Message.new('users', MadChatter::Users.current)
|
30
|
+
send_json(message.to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -1,26 +1,23 @@
|
|
1
1
|
module MadChatter
|
2
|
-
|
3
2
|
module Actions
|
4
|
-
|
5
|
-
class Join < MadChatter::Actions::Base
|
3
|
+
class Join < MadChatter::Action
|
6
4
|
|
7
|
-
@@
|
5
|
+
@@regex = /\/join (.+)/
|
8
6
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
def handle(message)
|
8
|
+
if message.text =~ @@regex
|
9
|
+
username = parse_username(message.text)
|
10
|
+
MadChatter::Users.update(message.token, username)
|
11
|
+
send_status_message "#{username} has joined the chatroom"
|
12
|
+
send_users_list
|
13
|
+
stop_message_handling
|
14
|
+
end
|
14
15
|
end
|
15
16
|
|
16
|
-
def
|
17
|
-
|
18
|
-
# the rest will be the new username
|
19
|
-
username = @message.sub("#{@@command} ", '')
|
17
|
+
def parse_username(text)
|
18
|
+
@@regex.match(text).captures[0]
|
20
19
|
end
|
21
20
|
|
22
21
|
end
|
23
|
-
|
24
22
|
end
|
25
|
-
|
26
23
|
end
|
@@ -1,27 +1,24 @@
|
|
1
1
|
module MadChatter
|
2
|
-
|
3
2
|
module Actions
|
4
|
-
|
5
|
-
class Rename < MadChatter::Actions::Base
|
3
|
+
class Rename < MadChatter::Action
|
6
4
|
|
7
|
-
@@
|
5
|
+
@@regex = /\/nick (.+)/
|
8
6
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
def handle(message)
|
8
|
+
if message.text =~ @@regex
|
9
|
+
old_username = message.username
|
10
|
+
username = parse_username(message.text)
|
11
|
+
MadChatter::Users.update(message.token, username)
|
12
|
+
send_status_message "#{old_username} is now known as #{username}"
|
13
|
+
send_users_list
|
14
|
+
stop_message_handling
|
15
|
+
end
|
15
16
|
end
|
16
17
|
|
17
|
-
def
|
18
|
-
|
19
|
-
# the rest will be the new username
|
20
|
-
username = @message.sub("#{@@command} ", '')
|
18
|
+
def parse_username(text)
|
19
|
+
@@regex.match(text).captures[0]
|
21
20
|
end
|
22
21
|
|
23
22
|
end
|
24
|
-
|
25
23
|
end
|
26
|
-
|
27
24
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module MadChatter
|
2
|
+
|
3
|
+
def self.simple_extensions
|
4
|
+
@@simple_extensions ||= []
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.extension_classes
|
8
|
+
@@extension_classes ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
module Config
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def init
|
15
|
+
config = MadChatter::Config.initialize_config
|
16
|
+
MadChatter::Config.initialize_extensions
|
17
|
+
return config
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize_config
|
21
|
+
config_file = File.join(Dir.pwd, 'config.yml')
|
22
|
+
|
23
|
+
unless File.exist?(config_file)
|
24
|
+
raise 'Could not find Mad Chatter config.yml file'
|
25
|
+
end
|
26
|
+
|
27
|
+
config = YAML::load(File.open(config_file))
|
28
|
+
defaults = {
|
29
|
+
'websocket_backend' => 'websocket-rack',
|
30
|
+
'websocket_port' => 8100,
|
31
|
+
}
|
32
|
+
@config = defaults.merge!(config)
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize_extensions
|
36
|
+
simple_extensions_file = File.join(Dir.pwd, 'extensions.rb')
|
37
|
+
if File.exist?(simple_extensions_file)
|
38
|
+
file_contents = File.read(simple_extensions_file)
|
39
|
+
MadChatter::Extensions.load_simple_extensions(file_contents)
|
40
|
+
end
|
41
|
+
|
42
|
+
Dir[Dir.pwd + '/extensions/*.rb'].each do |file|
|
43
|
+
require file
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module MadChatter
|
2
|
+
class Extensions
|
3
|
+
|
4
|
+
def self.load_simple_extensions(extensions)
|
5
|
+
instance_eval extensions, __FILE__, __LINE__
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.on_message(regex, &block)
|
9
|
+
MadChatter.simple_extensions << { regex: regex, block: block }
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
data/lib/mad_chatter/message.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
require 'mad_chatter/actions'
|
2
|
-
require 'mad_chatter/actions/base'
|
3
|
-
|
4
1
|
module MadChatter
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
2
|
+
class Message
|
3
|
+
|
4
|
+
attr_accessor :type, :text, :token, :username
|
5
|
+
|
6
|
+
def initialize(type, message_text, token = nil, username = nil)
|
7
|
+
@type = type
|
8
|
+
@text = message_text
|
9
|
+
@token = token
|
10
|
+
@username = username
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
JSON.generate({
|
15
|
+
type: @type,
|
16
|
+
message: @text,
|
17
|
+
username: @username,
|
18
|
+
})
|
19
|
+
end
|
20
|
+
|
20
21
|
end
|
21
|
-
|
22
22
|
end
|
data/lib/mad_chatter/server.rb
CHANGED
@@ -1,116 +1,79 @@
|
|
1
|
-
require 'digest/sha1'
|
2
|
-
require 'mad_chatter/users'
|
3
|
-
require 'mad_chatter/message'
|
4
|
-
|
5
1
|
module MadChatter
|
6
2
|
|
7
3
|
class Server
|
8
4
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
|
12
|
-
:port => 8100
|
13
|
-
}
|
14
|
-
@options = defaults.merge!(options)
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
@server = initialize_server
|
15
8
|
end
|
16
9
|
|
17
10
|
def self.main_channel
|
18
11
|
@main_channel ||= EventMachine::Channel.new
|
19
12
|
end
|
13
|
+
|
14
|
+
def initialize_server
|
15
|
+
# TODO: Figure out a better (more flexible/dynamic) way to initialize the server class
|
16
|
+
if @config['websocket_backend'] && @config['websocket_backend'] == 'MadChatter::Servers::EventMachineWebSocket'
|
17
|
+
return MadChatter::Servers::EventMachineWebSocket.new(self, @config['websocket_port'])
|
18
|
+
end
|
19
|
+
|
20
|
+
raise 'You did not specify a valid class name for websocket_backend'
|
21
|
+
end
|
20
22
|
|
21
23
|
def start
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
subscriber_id = MadChatter::Server.main_channel.subscribe { |msg| ws.send(msg) } #main send method, gets called when @main_channel.push gets called
|
27
|
-
token = generate_token()
|
28
|
-
send_client_token(ws, token)
|
29
|
-
|
30
|
-
ws.onclose do
|
31
|
-
username = MadChatter::Users.username(token)
|
32
|
-
if username
|
33
|
-
MadChatter::Server.send_status "#{username} has left the chatroom"
|
34
|
-
MadChatter::Users.remove(token)
|
35
|
-
end
|
36
|
-
MadChatter::Server.main_channel.unsubscribe(subscriber_id)
|
37
|
-
end
|
38
|
-
|
39
|
-
ws.onmessage do |msg_json|
|
40
|
-
msg = JSON.parse(msg_json)
|
41
|
-
if msg['token'].nil?
|
42
|
-
send_client_error(ws, 'Token is required')
|
43
|
-
else
|
44
|
-
message = MadChatter::MessageFactory.find(msg['message'], msg['token'])
|
45
|
-
message.process
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
24
|
+
EM.run do
|
25
|
+
puts "Starting Mad Chatter Web Socket server on port #{@config['websocket_port']}."
|
26
|
+
@server.start
|
50
27
|
end
|
51
28
|
end
|
52
29
|
|
53
|
-
def
|
54
|
-
|
30
|
+
def register_connection(&send_client_message_block)
|
31
|
+
subscriber_id = MadChatter::Server.main_channel.subscribe(send_client_message_block)
|
32
|
+
send_client_message_block.call(connection_token)
|
55
33
|
end
|
56
34
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
message: message
|
61
|
-
})
|
62
|
-
send_to_client(client, data)
|
63
|
-
end
|
64
|
-
|
65
|
-
def send_client_token(client, token)
|
66
|
-
data = JSON.generate({
|
67
|
-
type: 'token',
|
68
|
-
message: token
|
69
|
-
})
|
70
|
-
send_to_client(client, data)
|
35
|
+
def connection_token
|
36
|
+
token = Digest::SHA1.hexdigest Time.now.to_s
|
37
|
+
MadChatter::Message.new('token', token).to_s
|
71
38
|
end
|
72
39
|
|
73
|
-
def
|
74
|
-
|
40
|
+
def connection_closed(id)
|
41
|
+
MadChatter::Server.main_channel.unsubscribe(id)
|
75
42
|
end
|
76
43
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
44
|
+
def message_received(json)
|
45
|
+
msg = JSON.parse(json)
|
46
|
+
username = MadChatter::Users.find_username_by_token(msg['token'])
|
47
|
+
message = MadChatter::Message.new(msg['type'], msg['message'], msg['token'], username)
|
48
|
+
|
49
|
+
if message.token.nil?
|
50
|
+
return # Token is required to send messages
|
51
|
+
end
|
52
|
+
|
53
|
+
begin
|
54
|
+
MadChatter.simple_extensions.each do |extension|
|
55
|
+
if message.text =~ extension[:regex]
|
56
|
+
MadChatter::Action.instance_exec do
|
57
|
+
args = extension[:regex].match(message.text).captures
|
58
|
+
extension[:block].call(args)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
92
62
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
message
|
98
|
-
|
99
|
-
|
63
|
+
MadChatter.extension_classes.each do |extension|
|
64
|
+
extension.handle(message)
|
65
|
+
end
|
66
|
+
|
67
|
+
MadChatter::Server.send_json(message.to_s)
|
68
|
+
rescue RuntimeError
|
69
|
+
# dont need to do anything, just prevent any errors from stopping the server
|
70
|
+
end
|
100
71
|
end
|
101
72
|
|
102
|
-
def self.
|
103
|
-
|
104
|
-
type: 'action',
|
105
|
-
message: message
|
106
|
-
})
|
107
|
-
MadChatter::Server.push_to_all_connections(data)
|
73
|
+
def self.send_json(json)
|
74
|
+
MadChatter::Server.main_channel.push(json)
|
108
75
|
end
|
109
76
|
|
110
|
-
def Server.push_to_all_connections(data)
|
111
|
-
# puts 'sending to all clients: ' + data
|
112
|
-
MadChatter::Server.main_channel.push(data)
|
113
|
-
end
|
114
77
|
end
|
115
78
|
|
116
|
-
end
|
79
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'em-websocket'
|
2
|
+
|
3
|
+
module MadChatter
|
4
|
+
module Servers
|
5
|
+
class EventMachineWebSocket
|
6
|
+
|
7
|
+
def initialize(main_server, port)
|
8
|
+
@main_server = main_server
|
9
|
+
@config = {
|
10
|
+
:host => '0.0.0.0',
|
11
|
+
:port => port
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
EventMachine::WebSocket.start(@config) do |ws|
|
17
|
+
|
18
|
+
ws.onopen do
|
19
|
+
|
20
|
+
connection_id = @main_server.register_connection do |msg|
|
21
|
+
ws.send(msg)
|
22
|
+
end
|
23
|
+
|
24
|
+
ws.onclose do
|
25
|
+
@main_server.connection_closed(connection_id)
|
26
|
+
end
|
27
|
+
|
28
|
+
ws.onmessage do |msg|
|
29
|
+
@main_server.message_received(msg)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/mad_chatter/users.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
module MadChatter
|
2
|
-
|
3
2
|
class Users
|
4
3
|
|
5
|
-
# Singleton storage for all current users
|
6
4
|
class << self
|
7
5
|
|
8
6
|
def users
|
@@ -17,7 +15,7 @@ module MadChatter
|
|
17
15
|
MadChatter::Users.users.delete(token)
|
18
16
|
end
|
19
17
|
|
20
|
-
def
|
18
|
+
def find_username_by_token(token)
|
21
19
|
MadChatter::Users.users[token]
|
22
20
|
end
|
23
21
|
|
@@ -31,5 +29,4 @@ module MadChatter
|
|
31
29
|
end
|
32
30
|
|
33
31
|
end
|
34
|
-
|
35
32
|
end
|
data/lib/mad_chatter.rb
CHANGED
@@ -1,23 +1,29 @@
|
|
1
|
-
|
2
|
-
$:.unshift(
|
1
|
+
lib_dir = File.expand_path('..', __FILE__)
|
2
|
+
$:.unshift( lib_dir ) unless $:.include?( lib_dir )
|
3
3
|
|
4
|
-
require 'bundler'
|
5
|
-
|
6
|
-
require 'em-websocket'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'eventmachine'
|
7
6
|
require 'json'
|
7
|
+
require 'digest/sha1'
|
8
8
|
|
9
|
+
require 'mad_chatter/action'
|
10
|
+
require 'mad_chatter/config'
|
11
|
+
require 'mad_chatter/extensions'
|
12
|
+
require 'mad_chatter/message'
|
9
13
|
require 'mad_chatter/server'
|
10
|
-
require 'mad_chatter/
|
14
|
+
require 'mad_chatter/users'
|
11
15
|
|
12
|
-
|
16
|
+
require 'mad_chatter/actions/join'
|
17
|
+
require 'mad_chatter/actions/rename'
|
13
18
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
require 'mad_chatter/servers/em_websocket'
|
20
|
+
|
21
|
+
module MadChatter
|
22
|
+
|
23
|
+
def self.start
|
24
|
+
config = MadChatter::Config.init
|
25
|
+
server = MadChatter::Server.new(config)
|
26
|
+
server.start
|
27
|
+
end
|
22
28
|
|
23
29
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#
|
2
|
+
# Simple Mad Chatter Extensions
|
3
|
+
#
|
4
|
+
# You can add as many extensions as you want in this file using the
|
5
|
+
# simple extension syntax. For more complicated extensions, add your
|
6
|
+
# classes to the extensions directory.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# on_message /hey andrew: (.+)/ do |msg|
|
11
|
+
# send_status_message 'Someone sent andrew a chat message'
|
12
|
+
# end
|
13
|
+
#
|
File without changes
|
@@ -110,7 +110,7 @@ var MadChatter = {
|
|
110
110
|
},
|
111
111
|
|
112
112
|
display_message: function(username, message){
|
113
|
-
$("#messages").append("<p><
|
113
|
+
$("#messages").append("<p class='message'><span class='username'>" + username + ":</span> " + message + "<time>" + get_current_time() + "</time></p>");
|
114
114
|
},
|
115
115
|
|
116
116
|
scroll_to_bottom_of_chat: function(){
|
File without changes
|
@@ -20,28 +20,6 @@
|
|
20
20
|
font: 14px Verdana, Geneva, Arial, Helvetica, sans-serif;
|
21
21
|
padding: 5px;
|
22
22
|
}
|
23
|
-
/*
|
24
|
-
#chatroom {
|
25
|
-
text-align: left;
|
26
|
-
background: #fff;
|
27
|
-
padding: 5px 10px 10px;
|
28
|
-
}
|
29
|
-
|
30
|
-
#chatroom #sidebar {
|
31
|
-
float: left;
|
32
|
-
width: 200px;
|
33
|
-
color: #fff;
|
34
|
-
background-color: #000;
|
35
|
-
height: 100%;
|
36
|
-
}
|
37
|
-
|
38
|
-
#chatroom #body {
|
39
|
-
float: right;
|
40
|
-
margin-left: 200px;
|
41
|
-
width: 580px;
|
42
|
-
height: 100%;
|
43
|
-
}
|
44
|
-
*/
|
45
23
|
|
46
24
|
#chatroom{
|
47
25
|
margin:0;
|
@@ -77,18 +55,22 @@
|
|
77
55
|
padding: 0.25em;
|
78
56
|
}
|
79
57
|
|
80
|
-
#messages
|
58
|
+
#messages p.message .username {
|
59
|
+
font-weight: bold;
|
60
|
+
}
|
61
|
+
|
62
|
+
#messages p.message time, #messages p.status time {
|
81
63
|
float: right;
|
82
64
|
color: #999;
|
83
65
|
}
|
84
66
|
|
85
|
-
#messages .status {
|
67
|
+
#messages p.status {
|
86
68
|
text-align: center;
|
87
69
|
color: #999;
|
88
70
|
}
|
89
71
|
|
90
72
|
#keyboard{
|
91
|
-
position:absolute
|
73
|
+
/* position:absolute;*/
|
92
74
|
bottom:0;
|
93
75
|
left:220px;
|
94
76
|
width:400%;
|
@@ -103,10 +85,10 @@
|
|
103
85
|
}
|
104
86
|
|
105
87
|
@media screen{
|
106
|
-
#chatroom>div#sidebar{
|
88
|
+
#chatroom > div#sidebar{
|
107
89
|
position:fixed;
|
108
90
|
}
|
109
|
-
#chatroom>div#keyboard{
|
91
|
+
#chatroom > div#keyboard{
|
110
92
|
position:fixed;
|
111
93
|
}
|
112
94
|
}
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'mad_chatter'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mad_chatter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,55 +9,126 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-12-07 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
16
|
-
requirement: &
|
16
|
+
requirement: &2159049300 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0
|
21
|
+
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2159049300
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: eventmachine
|
27
|
+
requirement: &2159048600 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - =
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.12.10
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2159048600
|
25
36
|
- !ruby/object:Gem::Dependency
|
26
37
|
name: em-websocket
|
27
|
-
requirement: &
|
38
|
+
requirement: &2159031280 !ruby/object:Gem::Requirement
|
28
39
|
none: false
|
29
40
|
requirements:
|
30
|
-
- -
|
41
|
+
- - ! '>='
|
31
42
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0
|
43
|
+
version: '0'
|
33
44
|
type: :runtime
|
34
45
|
prerelease: false
|
35
|
-
version_requirements: *
|
36
|
-
|
37
|
-
|
46
|
+
version_requirements: *2159031280
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: shoulda
|
49
|
+
requirement: &2159030600 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2159030600
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: bundler
|
60
|
+
requirement: &2159029860 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.0.0
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2159029860
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jeweler
|
71
|
+
requirement: &2159028900 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.6.4
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *2159028900
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rcov
|
82
|
+
requirement: &2159027800 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *2159027800
|
91
|
+
description: Mad Chatter is a fun, easy to customize chat server, utilizing HTML 5
|
92
|
+
Web Sockets
|
38
93
|
email: email@andrewhavens.com
|
39
94
|
executables:
|
40
95
|
- mad_chatter
|
41
96
|
extensions: []
|
42
|
-
extra_rdoc_files:
|
97
|
+
extra_rdoc_files:
|
98
|
+
- LICENSE.txt
|
99
|
+
- README.md
|
43
100
|
files:
|
44
|
-
-
|
101
|
+
- CHANGELOG.txt
|
102
|
+
- Gemfile
|
103
|
+
- Gemfile.lock
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- bin/mad_chatter
|
108
|
+
- lib/mad_chatter.rb
|
109
|
+
- lib/mad_chatter/action.rb
|
45
110
|
- lib/mad_chatter/actions/join.rb
|
46
111
|
- lib/mad_chatter/actions/rename.rb
|
47
|
-
- lib/mad_chatter/
|
112
|
+
- lib/mad_chatter/config.rb
|
113
|
+
- lib/mad_chatter/extensions.rb
|
48
114
|
- lib/mad_chatter/message.rb
|
49
115
|
- lib/mad_chatter/server.rb
|
116
|
+
- lib/mad_chatter/servers/em_websocket.rb
|
117
|
+
- lib/mad_chatter/servers/juggernaut.rb
|
118
|
+
- lib/mad_chatter/servers/websocket_rack.rb
|
50
119
|
- lib/mad_chatter/users.rb
|
51
|
-
- lib/mad_chatter.rb
|
52
|
-
-
|
53
|
-
- templates/
|
54
|
-
- templates/
|
55
|
-
- templates/
|
56
|
-
- templates/stylesheets/
|
57
|
-
-
|
58
|
-
-
|
120
|
+
- lib/mad_chatter/version.rb
|
121
|
+
- templates/config.yml
|
122
|
+
- templates/extensions.rb
|
123
|
+
- templates/web/index.html
|
124
|
+
- templates/web/javascript.js
|
125
|
+
- templates/web/stylesheets/reset.css
|
126
|
+
- templates/web/stylesheets/styles.css
|
127
|
+
- test/helper.rb
|
128
|
+
- test/test_mad_chatter.rb
|
59
129
|
homepage: http://github.com/andrewhavens/mad_chatter
|
60
|
-
licenses:
|
130
|
+
licenses:
|
131
|
+
- MIT
|
61
132
|
post_install_message:
|
62
133
|
rdoc_options: []
|
63
134
|
require_paths:
|
@@ -68,6 +139,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
139
|
- - ! '>='
|
69
140
|
- !ruby/object:Gem::Version
|
70
141
|
version: '0'
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
hash: -79813361519807005
|
71
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
146
|
none: false
|
73
147
|
requirements:
|
data/README
DELETED
File without changes
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module MadChatter
|
2
|
-
|
3
|
-
module Actions
|
4
|
-
|
5
|
-
class Base
|
6
|
-
|
7
|
-
def initialize(message, user_token)
|
8
|
-
@message = message
|
9
|
-
@user_token = user_token
|
10
|
-
end
|
11
|
-
|
12
|
-
def process
|
13
|
-
send_message(@message)
|
14
|
-
end
|
15
|
-
|
16
|
-
def username
|
17
|
-
MadChatter::Users.username(@user_token)
|
18
|
-
end
|
19
|
-
|
20
|
-
def send_status(message)
|
21
|
-
MadChatter::Server.send_status(message)
|
22
|
-
end
|
23
|
-
|
24
|
-
def send_action(message)
|
25
|
-
MadChatter::Server.send_action(message)
|
26
|
-
end
|
27
|
-
|
28
|
-
def send_message(message)
|
29
|
-
MadChatter::Server.send_message(username, message)
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
data/lib/mad_chatter/actions.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
require 'mad_chatter/actions/base'
|
2
|
-
require 'mad_chatter/actions/join'
|
3
|
-
require 'mad_chatter/actions/rename'
|
4
|
-
|
5
|
-
module MadChatter
|
6
|
-
|
7
|
-
module Actions
|
8
|
-
|
9
|
-
class << self
|
10
|
-
|
11
|
-
def config(&block)
|
12
|
-
@config_block = block
|
13
|
-
end
|
14
|
-
|
15
|
-
def registered_actions
|
16
|
-
@registered_actions
|
17
|
-
end
|
18
|
-
|
19
|
-
def init
|
20
|
-
load_config_file
|
21
|
-
load_default_actions
|
22
|
-
load_action_extensions
|
23
|
-
end
|
24
|
-
|
25
|
-
def load_config_file
|
26
|
-
if File.exists?('config.rb')
|
27
|
-
load 'config.rb' # load up action extensions
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def load_default_actions
|
32
|
-
@registered_actions = {}
|
33
|
-
@registered_actions['/join'] = 'MadChatter::Actions::Join'
|
34
|
-
@registered_actions['/nick'] = 'MadChatter::Actions::Rename'
|
35
|
-
end
|
36
|
-
|
37
|
-
def load_action_extensions
|
38
|
-
config = MadChatter::Actions::Config.new
|
39
|
-
@config_block.call(config) if @config_block
|
40
|
-
config.actions.each do |command, action_class|
|
41
|
-
@registered_actions[command] = action_class
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class Config
|
47
|
-
|
48
|
-
attr_accessor :actions
|
49
|
-
|
50
|
-
def initialize
|
51
|
-
@actions = {}
|
52
|
-
end
|
53
|
-
|
54
|
-
def add(command, action_class)
|
55
|
-
@actions[command] = action_class
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|