socky 0.0.6
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/README +10 -0
- data/Rakefile +15 -0
- data/VERSION +1 -0
- data/bin/socky +5 -0
- data/lib/em-websocket_hacks.rb +11 -0
- data/lib/socky.rb +58 -0
- data/lib/socky/connection.rb +84 -0
- data/lib/socky/connection/authentication.rb +72 -0
- data/lib/socky/connection/finders.rb +50 -0
- data/lib/socky/message.rb +94 -0
- data/lib/socky/misc.rb +48 -0
- data/lib/socky/net_request.rb +50 -0
- data/lib/socky/options.rb +29 -0
- data/lib/socky/options/config.rb +39 -0
- data/lib/socky/options/parser.rb +60 -0
- data/lib/socky/runner.rb +45 -0
- data/lib/socky/server.rb +28 -0
- metadata +91 -0
data/README
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
socky_gem
|
2
|
+
===========
|
3
|
+
|
4
|
+
Socky is a WebSocket server and client for Ruby on Rails
|
5
|
+
|
6
|
+
Please do not use it right now - it's unstable version so please wait for more stable(at last 0.1)
|
7
|
+
|
8
|
+
=======
|
9
|
+
|
10
|
+
Copyright (c) 2010 Bernard Potocki, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.name = "socky"
|
5
|
+
gemspec.summary = "Socky is a WebSocket server and client for Ruby on Rails"
|
6
|
+
gemspec.description = "Socky is a WebSocket server and client for Ruby on Rails"
|
7
|
+
gemspec.email = "b.potocki@imanel.org"
|
8
|
+
gemspec.homepage = "http://github.com/imanel/socky_gem"
|
9
|
+
gemspec.authors = ["Bernard Potocki"]
|
10
|
+
gemspec.add_dependency('em-websocket', '>= 0.0.6')
|
11
|
+
gemspec.files.exclude ".gitignore"
|
12
|
+
end
|
13
|
+
rescue LoadError
|
14
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
15
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.6
|
data/bin/socky
ADDED
data/lib/socky.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'logger'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'em-websocket'
|
5
|
+
require 'em-websocket_hacks'
|
6
|
+
$:.unshift(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
module Socky
|
9
|
+
|
10
|
+
class SockyError < StandardError #:nodoc:
|
11
|
+
end
|
12
|
+
|
13
|
+
VERSION = File.read(File.dirname(__FILE__) + '/../VERSION').strip
|
14
|
+
|
15
|
+
@@options = {}
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def options
|
19
|
+
@@options
|
20
|
+
end
|
21
|
+
|
22
|
+
def options=(val)
|
23
|
+
@@options = val
|
24
|
+
end
|
25
|
+
|
26
|
+
def logger
|
27
|
+
return @@logger if defined?(@@logger) && !@@logger.nil?
|
28
|
+
FileUtils.mkdir_p(File.dirname(log_path))
|
29
|
+
@@logger = Logger.new(log_path)
|
30
|
+
@@logger.level = Logger::INFO unless options[:debug]
|
31
|
+
@@logger
|
32
|
+
rescue
|
33
|
+
@@logger = Logger.new(STDOUT)
|
34
|
+
@@logger.level = Logger::INFO unless options[:debug]
|
35
|
+
@@logger
|
36
|
+
end
|
37
|
+
|
38
|
+
def logger=(logger)
|
39
|
+
@@logger = logger
|
40
|
+
end
|
41
|
+
|
42
|
+
def log_path
|
43
|
+
options[:log_path] || File.join(%w( / var run socky.log ))
|
44
|
+
end
|
45
|
+
|
46
|
+
def config_path
|
47
|
+
options[:config_path] || File.join(%w( / var run socky.yml ))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
require 'socky/misc'
|
53
|
+
require 'socky/options'
|
54
|
+
require 'socky/runner'
|
55
|
+
require 'socky/connection'
|
56
|
+
require 'socky/net_request'
|
57
|
+
require 'socky/server'
|
58
|
+
require 'socky/message'
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'socky/connection/authentication'
|
2
|
+
require 'socky/connection/finders'
|
3
|
+
|
4
|
+
module Socky
|
5
|
+
class Connection
|
6
|
+
include Socky::Misc
|
7
|
+
include Socky::Connection::Authentication
|
8
|
+
include Socky::Connection::Finders
|
9
|
+
|
10
|
+
@@connections = []
|
11
|
+
|
12
|
+
attr_reader :socket
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def connections
|
16
|
+
@@connections
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(socket)
|
21
|
+
@socket = socket
|
22
|
+
end
|
23
|
+
|
24
|
+
def admin
|
25
|
+
socket.request["Query"]["admin"] == "1"
|
26
|
+
end
|
27
|
+
|
28
|
+
def client
|
29
|
+
socket.request["Query"]["client_id"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def secret
|
33
|
+
socket.request["Query"]["client_secret"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def channels
|
37
|
+
@channels ||= socket.request["Query"]["channels"].to_s.split(",").collect(&:strip).reject(&:empty?)
|
38
|
+
end
|
39
|
+
|
40
|
+
def subscribe
|
41
|
+
debug [self.name, "incoming"]
|
42
|
+
subscribe_request
|
43
|
+
end
|
44
|
+
|
45
|
+
def unsubscribe
|
46
|
+
debug [self.name, "terminated"]
|
47
|
+
unsubscribe_request
|
48
|
+
end
|
49
|
+
|
50
|
+
def process_message(msg)
|
51
|
+
if admin
|
52
|
+
Socky::Message.process(self, msg)
|
53
|
+
else
|
54
|
+
self.send_message "You are not authorized to post messages"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def send_message(msg)
|
59
|
+
debug [self.name, "sending message", msg.inspect]
|
60
|
+
socket.send msg
|
61
|
+
end
|
62
|
+
|
63
|
+
def disconnect
|
64
|
+
socket.close_connection_after_writing
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_to_pool
|
68
|
+
@@connections << self unless self.admin || @@connections.include?(self)
|
69
|
+
end
|
70
|
+
|
71
|
+
def remove_from_pool
|
72
|
+
@@connections.delete(self)
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_json
|
76
|
+
{
|
77
|
+
:id => self.object_id,
|
78
|
+
:client_id => self.client,
|
79
|
+
:channels => self.channels
|
80
|
+
}.to_json
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Socky
|
2
|
+
class Connection
|
3
|
+
module Authentication
|
4
|
+
|
5
|
+
def subscribe_request
|
6
|
+
if authenticated?
|
7
|
+
debug [self.name, "authentication successed"]
|
8
|
+
add_to_pool
|
9
|
+
else
|
10
|
+
debug [self.name, "authentication failed"]
|
11
|
+
disconnect
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def unsubscribe_request
|
16
|
+
if authenticated?
|
17
|
+
remove_from_pool
|
18
|
+
send_unsubscribe_request unless admin
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def authenticated?
|
23
|
+
if @authenticated.nil?
|
24
|
+
@authenticated = (admin ? authenticate_as_admin : authenticate_as_user)
|
25
|
+
else
|
26
|
+
@authenticated
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def authenticate_as_admin
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
def authenticate_as_user
|
35
|
+
authenticated_by_url?
|
36
|
+
end
|
37
|
+
|
38
|
+
def authenticated_by_url?
|
39
|
+
send_subscribe_request
|
40
|
+
end
|
41
|
+
|
42
|
+
def send_subscribe_request
|
43
|
+
subscribe_url = options[:subscribe_url]
|
44
|
+
if subscribe_url
|
45
|
+
debug [self.name, "sending subscribe request to", subscribe_url]
|
46
|
+
Socky::NetRequest.post(subscribe_url, params_for_request)
|
47
|
+
else
|
48
|
+
true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def send_unsubscribe_request
|
53
|
+
unsubscribe_url = options[:unsubscribe_url]
|
54
|
+
if unsubscribe_url
|
55
|
+
debug [self.name, "sending unsubscribe request to", unsubscribe_url]
|
56
|
+
Socky::NetRequest.post(unsubscribe_url, params_for_request)
|
57
|
+
else
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def params_for_request
|
63
|
+
params = {}
|
64
|
+
params.merge!(:client_id => self.client) unless self.client.nil?
|
65
|
+
params.merge!(:client_secret => self.secret) unless self.secret.nil?
|
66
|
+
params.merge!(:channels => self.channels) unless self.channels.empty?
|
67
|
+
params
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Socky
|
2
|
+
class Connection
|
3
|
+
module Finders
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def find_all
|
11
|
+
connections
|
12
|
+
end
|
13
|
+
|
14
|
+
def find(opts = {})
|
15
|
+
clients = opts[:clients].to_a
|
16
|
+
channels = opts[:channels].to_a
|
17
|
+
connections = find_all
|
18
|
+
connections = filter_by_clients(connections, clients) unless clients.empty?
|
19
|
+
connections = filter_by_channels(connections, channels) unless channels.empty?
|
20
|
+
|
21
|
+
connections
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_by_clients(clients)
|
25
|
+
find(:clients => clients)
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_by_channels(channels)
|
29
|
+
find(:channels => channels)
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_by_clients_and_channels(clients, channels)
|
33
|
+
find(:clients => clients, :channels => channels)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def filter_by_clients(connections, clients)
|
39
|
+
connections.collect{ |con| con if clients.include? con.client }.compact
|
40
|
+
end
|
41
|
+
|
42
|
+
def filter_by_channels(connections, channels)
|
43
|
+
connections.collect{ |con| con if channels.any?{ |chan| con.channels.include?(chan) } }.compact
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Socky
|
4
|
+
class Message
|
5
|
+
include Socky::Misc
|
6
|
+
|
7
|
+
class UnauthorisedQuery < Socky::SockyError #:nodoc:
|
8
|
+
end
|
9
|
+
|
10
|
+
class InvalidBroadcast < Socky::SockyError #:nodoc:
|
11
|
+
end
|
12
|
+
|
13
|
+
class InvalidQuery < Socky::SockyError #:nodoc:
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :params, :creator
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def process(connection, message)
|
20
|
+
m = new(connection, message)
|
21
|
+
m.process
|
22
|
+
rescue SockyError => e
|
23
|
+
error connection.name, e
|
24
|
+
m.respond e.message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(creator, message)
|
29
|
+
@params = symbolize_keys JSON.parse(message)
|
30
|
+
@creator = creator
|
31
|
+
end
|
32
|
+
|
33
|
+
def process
|
34
|
+
debug [self.name, "processing", params.inspect]
|
35
|
+
|
36
|
+
verify_secret!
|
37
|
+
|
38
|
+
case params[:command].to_sym
|
39
|
+
when :broadcast then broadcast
|
40
|
+
when :query then query
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def verify_secret!
|
45
|
+
raise(UnauthorisedQuery, "invalid secret") unless options[:secret].nil? || options[:secret] == params[:secret]
|
46
|
+
end
|
47
|
+
|
48
|
+
def broadcast
|
49
|
+
case params[:type].to_sym
|
50
|
+
when :to_clients then broadcast_to_clients
|
51
|
+
when :to_channels then broadcast_to_channels
|
52
|
+
when :to_clients_on_channels then broadcast_to_clients_on_channels
|
53
|
+
else raise InvalidQuery, "unknown broadcast type"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def broadcast_to_clients
|
58
|
+
verify :clients
|
59
|
+
Socky::Server.send_to_clients(params[:body], params[:clients])
|
60
|
+
end
|
61
|
+
|
62
|
+
def broadcast_to_channels
|
63
|
+
verify :channels
|
64
|
+
Socky::Server.send_to_channels(params[:body], params[:channels])
|
65
|
+
end
|
66
|
+
|
67
|
+
def broadcast_to_clients_on_channels
|
68
|
+
verify :clients
|
69
|
+
verify :channels
|
70
|
+
Socky::Server.send_to_clients_on_channels(params[:body], params[:clients], params[:channels])
|
71
|
+
end
|
72
|
+
|
73
|
+
def query
|
74
|
+
case params[:type].to_sym
|
75
|
+
when :show_connections then query_show_connections
|
76
|
+
else raise InvalidQuery, "unknown query type"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def query_show_connections
|
81
|
+
respond Socky::Connection.find_all
|
82
|
+
end
|
83
|
+
|
84
|
+
def verify(field)
|
85
|
+
params[field] = params[field].to_a unless params[field].is_a?(Array)
|
86
|
+
params[field] = params[field].collect(&:to_s)
|
87
|
+
end
|
88
|
+
|
89
|
+
def respond(message)
|
90
|
+
creator.send_message(message.to_json)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
data/lib/socky/misc.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Socky
|
2
|
+
module Misc
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend Socky::Misc
|
6
|
+
end
|
7
|
+
|
8
|
+
def options
|
9
|
+
Socky.options
|
10
|
+
end
|
11
|
+
|
12
|
+
def options=(ob)
|
13
|
+
Socky.options = ob
|
14
|
+
end
|
15
|
+
|
16
|
+
def name
|
17
|
+
"#{self.class.to_s.split("::").last}(#{self.object_id})"
|
18
|
+
end
|
19
|
+
|
20
|
+
def log_path
|
21
|
+
Socky.log_path
|
22
|
+
end
|
23
|
+
|
24
|
+
def config_path
|
25
|
+
Socky.config_path
|
26
|
+
end
|
27
|
+
|
28
|
+
def info(args)
|
29
|
+
Socky.logger.info args.join(" ")
|
30
|
+
end
|
31
|
+
|
32
|
+
def debug(args)
|
33
|
+
Socky.logger.debug args.join(" ")
|
34
|
+
end
|
35
|
+
|
36
|
+
def error(name, error)
|
37
|
+
debug [name, "raised:", error.class, error.message]
|
38
|
+
end
|
39
|
+
|
40
|
+
def symbolize_keys(hash)
|
41
|
+
return self unless hash.is_a?(Hash)
|
42
|
+
hash.inject({}) do |options, (key, value)|
|
43
|
+
options[(key.to_sym rescue key) || key] = value
|
44
|
+
options
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/https'
|
4
|
+
require 'uri'
|
5
|
+
require 'cgi'
|
6
|
+
|
7
|
+
module Socky
|
8
|
+
class NetRequest
|
9
|
+
include Socky::Misc
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
def post(url, params = { })
|
14
|
+
uri = URI.parse(url)
|
15
|
+
params = params_from_hash(params)
|
16
|
+
headers = {"User-Agent" => "Ruby/#{RUBY_VERSION}"}
|
17
|
+
begin
|
18
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
19
|
+
if uri.scheme == 'https'
|
20
|
+
http.use_ssl = true
|
21
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
22
|
+
end
|
23
|
+
http.read_timeout = options[:timeout] || 5
|
24
|
+
resp, data = http.post(uri.path, params, headers)
|
25
|
+
return resp.is_a?(Net::HTTPOK)
|
26
|
+
rescue => e
|
27
|
+
debug ["Bad request", url.to_s, e.class, e.message]
|
28
|
+
return false
|
29
|
+
rescue Timeout::Error
|
30
|
+
debug [url.to_s, "timeout"]
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def params_from_hash(params)
|
36
|
+
result = []
|
37
|
+
params.each do |key, value|
|
38
|
+
if value.is_a? Array
|
39
|
+
value.each{ |v| result << "#{key}[]=#{CGI::escape(v.to_s)}"}
|
40
|
+
else
|
41
|
+
result << "#{key}=#{CGI::escape(value.to_s)}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
result.join('&')
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'yaml'
|
3
|
+
require 'erb'
|
4
|
+
require 'socky/options/config'
|
5
|
+
require 'socky/options/parser'
|
6
|
+
|
7
|
+
module Socky
|
8
|
+
module Options
|
9
|
+
include Socky::Options::Config
|
10
|
+
include Socky::Options::Parser
|
11
|
+
|
12
|
+
def prepare_options(argv)
|
13
|
+
self.options = {
|
14
|
+
:config_path => config_path
|
15
|
+
}
|
16
|
+
|
17
|
+
parse_options(argv)
|
18
|
+
read_config_file
|
19
|
+
|
20
|
+
self.options = {
|
21
|
+
:port => 8080,
|
22
|
+
:debug => false,
|
23
|
+
:deep_debug => false,
|
24
|
+
:log_path => log_path
|
25
|
+
}.merge(self.options)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Socky
|
2
|
+
module Options
|
3
|
+
module Config
|
4
|
+
|
5
|
+
def read_config_file
|
6
|
+
if !File.exists?(config_path)
|
7
|
+
puts "You must generate a config file (socky -g filename.yml)"
|
8
|
+
exit
|
9
|
+
end
|
10
|
+
|
11
|
+
self.options = YAML::load(ERB.new(IO.read(config_path)).result).merge!(self.options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate_config_file
|
15
|
+
if File.exists?(config_path)
|
16
|
+
puts "Config file already exists. You must remove it before generating a new one."
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
puts "Generating config file...."
|
20
|
+
File.open(config_path, 'w+') do |file|
|
21
|
+
file.write DEFAULT_CONFIG_FILE
|
22
|
+
end
|
23
|
+
puts "Config file generated at #{config_path}"
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
27
|
+
DEFAULT_CONFIG_FILE= <<-EOF
|
28
|
+
:port: 8080
|
29
|
+
:debug: false
|
30
|
+
|
31
|
+
:subscribe_url: http://localhost:3000/socky/subscribe
|
32
|
+
:unsubscribe_url: http://localhost:3000/socky/unsubscribe
|
33
|
+
|
34
|
+
:secret: my_secret_key
|
35
|
+
EOF
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Socky
|
2
|
+
module Options
|
3
|
+
module Parser
|
4
|
+
|
5
|
+
def parse_options(argv)
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.summary_width = 25
|
8
|
+
opts.banner = "Usage: socky [options]\n"
|
9
|
+
|
10
|
+
opts.separator ""
|
11
|
+
opts.separator "Configuration:"
|
12
|
+
|
13
|
+
opts.on("-g", "--generate FILE", String, "Generate config file") do |v|
|
14
|
+
options[:config_path] = File.expand_path(v) if v
|
15
|
+
generate_config_file
|
16
|
+
end
|
17
|
+
|
18
|
+
opts.on("-c", "--config FILE", String, "Path to configuration file.", "(default: #{Socky.config_path})") do |v|
|
19
|
+
options[:config_path] = File.expand_path(v)
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.separator ""; opts.separator "Network:"
|
23
|
+
|
24
|
+
opts.on("-p", "--port PORT", Integer, "Specify port", "(default: 8080)") do |v|
|
25
|
+
options[:port] = v
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.separator ""; opts.separator "Logging:"
|
29
|
+
|
30
|
+
opts.on("-l", "--log FILE", String, "Path to print debugging information.", "(default: #{Socky.log_path})") do |v|
|
31
|
+
options[:log_path] = File.expand_path(v)
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("--debug", "Run in debug mode") do
|
35
|
+
options[:debug] = true
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on("--deep-debug", "Run in debug mode that is even more verbose") do
|
39
|
+
options[:debug] = true
|
40
|
+
options[:deep_debug] = true
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.separator ""; opts.separator "Miscellaneous:"
|
44
|
+
|
45
|
+
opts.on_tail("-?", "--help", "Display this usage information.") do
|
46
|
+
puts "#{opts}\n"
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on_tail("-v", "--version", "Display version") do |v|
|
51
|
+
puts "Socky #{VERSION}"
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
end.parse!(argv)
|
55
|
+
options
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/socky/runner.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Socky
|
2
|
+
class Runner
|
3
|
+
include Socky::Misc
|
4
|
+
include Socky::Options
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def run(argv = ARGV)
|
8
|
+
self.new(argv)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(argv = ARGV)
|
13
|
+
prepare_options(argv)
|
14
|
+
start
|
15
|
+
end
|
16
|
+
|
17
|
+
def start
|
18
|
+
EventMachine.epoll
|
19
|
+
|
20
|
+
EventMachine.run do
|
21
|
+
|
22
|
+
trap("TERM") { stop }
|
23
|
+
trap("INT") { stop }
|
24
|
+
|
25
|
+
EventMachine::start_server("0.0.0.0", options[:port],
|
26
|
+
EventMachine::WebSocket::Connection, :debug => options[:deep_debug]) do |ws|
|
27
|
+
|
28
|
+
connection = Socky::Connection.new(ws)
|
29
|
+
ws.onopen { connection.subscribe }
|
30
|
+
ws.onmessage { |msg| connection.process_message(msg) }
|
31
|
+
ws.onclose { connection.unsubscribe }
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
info ["Server started"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def stop
|
40
|
+
info ["Server stopping"]
|
41
|
+
EventMachine.stop
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/lib/socky/server.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Socky
|
2
|
+
class Server
|
3
|
+
include Socky::Misc
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def send_to_clients(message, clients)
|
8
|
+
connections = Socky::Connection.find_by_clients(clients)
|
9
|
+
send_data(message, connections)
|
10
|
+
end
|
11
|
+
|
12
|
+
def send_to_channels(message, channels)
|
13
|
+
connections = Socky::Connection.find_by_channels(channels)
|
14
|
+
send_data(message, connections)
|
15
|
+
end
|
16
|
+
|
17
|
+
def send_to_clients_on_channels(message, clients, channels)
|
18
|
+
connections = Socky::Connection.find_by_clients_and_channels(clients, channels)
|
19
|
+
send_data(message, connections)
|
20
|
+
end
|
21
|
+
|
22
|
+
def send_data(message, connections)
|
23
|
+
connections.each{|c| c.send_message message}
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: socky
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 6
|
9
|
+
version: 0.0.6
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Bernard Potocki
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-24 00:00:00 +02:00
|
18
|
+
default_executable: socky
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: em-websocket
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
- 0
|
30
|
+
- 6
|
31
|
+
version: 0.0.6
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: Socky is a WebSocket server and client for Ruby on Rails
|
35
|
+
email: b.potocki@imanel.org
|
36
|
+
executables:
|
37
|
+
- socky
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README
|
42
|
+
files:
|
43
|
+
- README
|
44
|
+
- Rakefile
|
45
|
+
- VERSION
|
46
|
+
- bin/socky
|
47
|
+
- lib/em-websocket_hacks.rb
|
48
|
+
- lib/socky.rb
|
49
|
+
- lib/socky/connection.rb
|
50
|
+
- lib/socky/connection/authentication.rb
|
51
|
+
- lib/socky/connection/finders.rb
|
52
|
+
- lib/socky/message.rb
|
53
|
+
- lib/socky/misc.rb
|
54
|
+
- lib/socky/net_request.rb
|
55
|
+
- lib/socky/options.rb
|
56
|
+
- lib/socky/options/config.rb
|
57
|
+
- lib/socky/options/parser.rb
|
58
|
+
- lib/socky/runner.rb
|
59
|
+
- lib/socky/server.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: http://github.com/imanel/socky_gem
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options:
|
66
|
+
- --charset=UTF-8
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.3.6
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Socky is a WebSocket server and client for Ruby on Rails
|
90
|
+
test_files: []
|
91
|
+
|