juggernaut 0.5.4 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/README +8 -0
- data/Rakefile +16 -17
- data/VERSION +1 -0
- data/examples/juggernaut_observer.js +22 -0
- data/examples/juggernaut_observer.rb +24 -0
- data/examples/roster.rb +10 -0
- data/juggernaut.gemspec +48 -0
- data/lib/juggernaut/rails/engine.rb +7 -0
- data/lib/juggernaut.rb +42 -145
- data/vendor/assets/javascripts/json.js +480 -0
- data/vendor/assets/javascripts/juggernaut.js +142 -0
- data/vendor/assets/javascripts/socket_io.js +3204 -0
- metadata +64 -80
- data/History.txt +0 -5
- data/Manifest.txt +0 -12
- data/README.txt +0 -48
- data/bin/juggernaut +0 -4
- data/lib/juggernaut/client.rb +0 -156
- data/lib/juggernaut/message.rb +0 -19
- data/lib/juggernaut/miscel.rb +0 -27
- data/lib/juggernaut/runner.rb +0 -208
- data/lib/juggernaut/server.rb +0 -370
- data/lib/juggernaut/utils.rb +0 -11
data/.document
ADDED
data/.gitignore
ADDED
data/README
ADDED
data/Rakefile
CHANGED
@@ -1,19 +1,18 @@
|
|
1
|
-
# -*- ruby -*-
|
2
|
-
|
3
1
|
require 'rubygems'
|
4
|
-
require '
|
5
|
-
require './lib/juggernaut.rb'
|
6
|
-
|
7
|
-
Hoe.new('juggernaut', Juggernaut::VERSION) do |p|
|
8
|
-
p.rubyforge_name = 'juggernaut'
|
9
|
-
p.author = 'Alex MacCaw'
|
10
|
-
p.email = 'info@eribium.org'
|
11
|
-
# p.summary = 'FIX'
|
12
|
-
# p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
13
|
-
p.url = 'http://juggernaut.rubyforge.org'
|
14
|
-
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
|
-
p.extra_deps << ['eventmachine', '>=0.10.0']
|
16
|
-
p.extra_deps << ['json', '>=1.1.2']
|
17
|
-
end
|
2
|
+
require 'rake'
|
18
3
|
|
19
|
-
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "juggernaut"
|
8
|
+
gem.summary = %Q{Simple realtime push}
|
9
|
+
gem.description = %Q{Use Juggernaut to easily implement realtime chat, collaboration, gaming and much more!}
|
10
|
+
gem.email = "info@eribium.org"
|
11
|
+
gem.homepage = "http://github.com/maccman/juggernaut"
|
12
|
+
gem.authors = ["Alex MacCaw"]
|
13
|
+
gem.add_dependency "redis", ">= 0"
|
14
|
+
end
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
18
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.1
|
@@ -0,0 +1,22 @@
|
|
1
|
+
// Assumes you're using SuperModel
|
2
|
+
// http://github.com/maccman/supermodel-js
|
3
|
+
|
4
|
+
jQuery(function($){
|
5
|
+
var jug = new Juggernaut;
|
6
|
+
jug.subscribe("/sync/your_user_id", function(sync){
|
7
|
+
var klass = eval(sync.klass);
|
8
|
+
switch(sync.type) {
|
9
|
+
case "create":
|
10
|
+
klass.create(sync.record);
|
11
|
+
break;
|
12
|
+
case "update":
|
13
|
+
klass.update(sync.id, sync.record);
|
14
|
+
break;
|
15
|
+
case "destroy":
|
16
|
+
klass.destroy(sync.id);
|
17
|
+
break;
|
18
|
+
default:
|
19
|
+
throw("Unknown type:" + type);
|
20
|
+
}
|
21
|
+
});
|
22
|
+
})
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class JuggernautObserver < ActiveRecord::Observer
|
2
|
+
observe :activity, :user
|
3
|
+
|
4
|
+
def after_create(rec)
|
5
|
+
publish(:create, rec)
|
6
|
+
end
|
7
|
+
|
8
|
+
def after_update(rec)
|
9
|
+
publish(:update, rec)
|
10
|
+
end
|
11
|
+
|
12
|
+
def after_destroy(rec)
|
13
|
+
publish(:destroy, rec)
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
def publish(type, rec)
|
18
|
+
Juggernaut.publish(
|
19
|
+
Array(rec.sync_clients).map {|c| "/sync/#{c}" },
|
20
|
+
{:type => type, :id => rec.id,
|
21
|
+
:klass => rec.class.name, :record => rec}
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
data/examples/roster.rb
ADDED
data/juggernaut.gemspec
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{juggernaut}
|
8
|
+
s.version = "2.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = [%q{Alex MacCaw}]
|
12
|
+
s.date = %q{2012-01-03}
|
13
|
+
s.description = %q{Use Juggernaut to easily implement realtime chat, collaboration, gaming and much more!}
|
14
|
+
s.email = %q{info@eribium.org}
|
15
|
+
s.files = [
|
16
|
+
".document",
|
17
|
+
".gitignore",
|
18
|
+
"README",
|
19
|
+
"Rakefile",
|
20
|
+
"VERSION",
|
21
|
+
"examples/juggernaut_observer.js",
|
22
|
+
"examples/juggernaut_observer.rb",
|
23
|
+
"examples/roster.rb",
|
24
|
+
"juggernaut.gemspec",
|
25
|
+
"lib/juggernaut.rb",
|
26
|
+
"lib/juggernaut/rails/engine.rb",
|
27
|
+
"vendor/assets/javascripts/json.js",
|
28
|
+
"vendor/assets/javascripts/juggernaut.js",
|
29
|
+
"vendor/assets/javascripts/socket_io.js"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/maccman/juggernaut}
|
32
|
+
s.require_paths = [%q{lib}]
|
33
|
+
s.rubygems_version = %q{1.8.6}
|
34
|
+
s.summary = %q{Simple realtime push}
|
35
|
+
|
36
|
+
if s.respond_to? :specification_version then
|
37
|
+
s.specification_version = 3
|
38
|
+
|
39
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
40
|
+
s.add_runtime_dependency(%q<redis>, [">= 0"])
|
41
|
+
else
|
42
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
43
|
+
end
|
44
|
+
else
|
45
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
data/lib/juggernaut.rb
CHANGED
@@ -1,152 +1,49 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require 'json'
|
4
|
-
$:.unshift(File.dirname(__FILE__))
|
1
|
+
require "redis"
|
2
|
+
require "json"
|
5
3
|
|
6
|
-
|
7
|
-
|
4
|
+
# Attempt to provide Engine to Rails
|
5
|
+
require "juggernaut/rails/engine"
|
8
6
|
|
9
|
-
|
7
|
+
module Juggernaut
|
8
|
+
EVENTS = [
|
9
|
+
"juggernaut:subscribe",
|
10
|
+
"juggernaut:unsubscribe",
|
11
|
+
"juggernaut:custom"
|
12
|
+
]
|
13
|
+
|
14
|
+
def options
|
15
|
+
@options ||= {}
|
10
16
|
end
|
11
|
-
|
12
|
-
@@options = {}
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# :subscription_url: http://localhost:3000/sessions/juggernaut_subscription
|
32
|
-
|
33
|
-
# === Broadcast and query authentication ===
|
34
|
-
# Leave all broadcast/query options uncommented to allow anyone to broadcast/query.
|
35
|
-
#
|
36
|
-
# Broadcast authentication in a production environment is very importantant since broadcasters
|
37
|
-
# can execute JavaScript on subscribed clients, leaving you vulnerable to cross site scripting
|
38
|
-
# attacks if broadcasters aren't authenticated.
|
39
|
-
|
40
|
-
# 1) Via IP address
|
41
|
-
#
|
42
|
-
# If specified, if a client has an ip that is specified in allowed_ips, than it is automatically
|
43
|
-
# authenticated, even if a secret_key isn't provided.
|
44
|
-
#
|
45
|
-
# This is the recommended method for broadcast authentication.
|
46
|
-
#
|
47
|
-
:allowed_ips:
|
48
|
-
- 127.0.0.1
|
49
|
-
# - 192.168.0.1
|
50
|
-
|
51
|
-
# 2) Via HTTP request
|
52
|
-
#
|
53
|
-
# If specified, if a client attempts a broadcast/query, without a secret_key or using an IP
|
54
|
-
# no included in allowed_ips, then broadcast_query_login_url will be called.
|
55
|
-
# Parameters passed, if given, are: session_id, client_id, channels and type.
|
56
|
-
#
|
57
|
-
# The server should check that the session_id matches up to the client id, and the client
|
58
|
-
# is allowed to perform that particular type of broadcast/query.
|
59
|
-
#
|
60
|
-
# If a status code other than 200 is encountered, the broadcast_query_login_url fails
|
61
|
-
# and the client is disconnected.
|
62
|
-
#
|
63
|
-
# :broadcast_query_login_url: http://localhost:3000/sessions/juggernaut_broadcast
|
64
|
-
|
65
|
-
# 3) Via shared secret key
|
66
|
-
#
|
67
|
-
# This secret key must be sent with any query/broadcast commands.
|
68
|
-
# It must be the same as the one in the Rails config file.
|
69
|
-
#
|
70
|
-
# You shouldn't authenticate broadcasts from subscribed clients using this method
|
71
|
-
# since the secret_key will be easily visible in the page (and not so secret any more)!
|
72
|
-
#
|
73
|
-
# :secret_key: your_secret_key_here
|
74
|
-
|
75
|
-
# == Subscription Logout ==
|
76
|
-
|
77
|
-
# If specified, logout_connection_url is called everytime a specific connection from a subscribed client disconnects.
|
78
|
-
# Parameters passed are session_id, client_id and an array of channels specific to that connection.
|
79
|
-
#
|
80
|
-
# :logout_connection_url: http://localhost:3000/sessions/juggernaut_connection_logout
|
81
|
-
|
82
|
-
# Logout url is called when all connections from a subscribed client are closed.
|
83
|
-
# Parameters passed are session_id and client_id.
|
84
|
-
#
|
85
|
-
# :logout_url: http://localhost:3000/sessions/juggernaut_logout
|
86
|
-
|
87
|
-
# === Miscellaneous ===
|
88
|
-
|
89
|
-
# timeout defaults to 10. A timeout is the time between when a client closes a connection
|
90
|
-
# and a logout_request or logout_connection_request is made. The reason for this is that a client
|
91
|
-
# may only temporarily be disconnected, and may attempt a reconnect very soon.
|
92
|
-
#
|
93
|
-
# :timeout: 10
|
94
|
-
|
95
|
-
# store_messages defaults to false. If this option is true, messages send to connections will be stored.
|
96
|
-
# This is useful since a client can then receive broadcasted message that it has missed (perhaps it was disconnected).
|
97
|
-
#
|
98
|
-
# :store_messages: false
|
99
|
-
|
100
|
-
# === Server ===
|
101
|
-
|
102
|
-
# Host defaults to "0.0.0.0". You shouldn't need to change this.
|
103
|
-
# :host: 0.0.0.0
|
104
|
-
|
105
|
-
# Port is mandatory
|
106
|
-
:port: 5001
|
107
|
-
|
108
|
-
# Defaults to value of :port. If you are doing port forwarding you'll need to configure this to the same
|
109
|
-
# value as :public_port in the juggernaut_hosts.yml file
|
110
|
-
# :public_port: 5001
|
111
|
-
|
112
|
-
EOF
|
113
|
-
|
114
|
-
class << self
|
115
|
-
def options
|
116
|
-
@@options
|
117
|
-
end
|
118
|
-
|
119
|
-
def options=(val)
|
120
|
-
@@options = val
|
121
|
-
end
|
122
|
-
|
123
|
-
def logger
|
124
|
-
return @@logger if defined?(@@loggger)
|
125
|
-
FileUtils.mkdir_p(File.dirname(log_path))
|
126
|
-
@@logger = Logger.new(log_path)
|
127
|
-
@@logger.level = Logger::INFO if options[:debug] == false
|
128
|
-
@@logger
|
129
|
-
rescue
|
130
|
-
@@logger = Logger.new(STDOUT)
|
131
|
-
end
|
132
|
-
|
133
|
-
def log_path
|
134
|
-
options[:log_path] || File.join(%w( / var run juggernaut.log ))
|
135
|
-
end
|
136
|
-
|
137
|
-
def pid_path
|
138
|
-
options[:pid_path] || File.join(%w( / var run ), "juggernaut.#{options[:port]}.pid" )
|
139
|
-
end
|
140
|
-
|
141
|
-
def config_path
|
142
|
-
options[:config_path] || File.join(%w( / var run juggernaut.yml ))
|
18
|
+
def options=(val)
|
19
|
+
@options = val
|
20
|
+
end
|
21
|
+
|
22
|
+
def url=(url)
|
23
|
+
options[:url] = url
|
24
|
+
end
|
25
|
+
|
26
|
+
def publish(channels, data, options = {})
|
27
|
+
message = ({:channels => Array(channels).uniq, :data => data}).merge(options)
|
28
|
+
redis.publish(key, message.to_json)
|
29
|
+
end
|
30
|
+
|
31
|
+
def subscribe
|
32
|
+
Redis.connect(options).subscribe(*EVENTS) do |on|
|
33
|
+
on.message do |type, msg|
|
34
|
+
yield(type.gsub(/^juggernaut:/, "").to_sym, JSON.parse(msg))
|
143
35
|
end
|
36
|
+
end
|
144
37
|
end
|
145
|
-
|
38
|
+
|
39
|
+
protected
|
40
|
+
def redis
|
41
|
+
@redis ||= Redis.connect(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def key(*args)
|
45
|
+
args.unshift(:juggernaut).join(":")
|
46
|
+
end
|
146
47
|
|
147
|
-
|
148
|
-
|
149
|
-
require 'juggernaut/message'
|
150
|
-
require 'juggernaut/client'
|
151
|
-
require 'juggernaut/server'
|
152
|
-
require 'juggernaut/runner'
|
48
|
+
extend self
|
49
|
+
end
|