marvin 0.8.0.0 → 0.8.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/marvin +3 -2
- data/lib/marvin.rb +1 -7
- data/lib/marvin/abstract_client.rb +1 -4
- data/lib/marvin/base.rb +4 -2
- data/lib/marvin/command_handler.rb +6 -1
- data/lib/marvin/distributed/client.rb +27 -40
- data/lib/marvin/distributed/handler.rb +0 -1
- data/lib/marvin/distributed/protocol.rb +61 -3
- data/lib/marvin/distributed/server.rb +16 -15
- data/lib/marvin/irc/client.rb +4 -2
- data/lib/marvin/logging_handler.rb +11 -8
- metadata +16 -10
data/bin/marvin
CHANGED
@@ -3,8 +3,9 @@ require 'rubygems'
|
|
3
3
|
require File.join(File.dirname(__FILE__), "..", "lib", "marvin")
|
4
4
|
|
5
5
|
Marvin::Application.processing(ARGV) do |a|
|
6
|
-
|
7
|
-
|
6
|
+
version = Marvin.version
|
7
|
+
version << "p#{Marvin::VERSION[3]}" if Marvin::VERSION[3] != 0
|
8
|
+
a.banner = "Marvin v#{version} - An IRC Library for Ruby"
|
8
9
|
|
9
10
|
a.generator!
|
10
11
|
|
data/lib/marvin.rb
CHANGED
@@ -5,19 +5,14 @@ require 'perennial'
|
|
5
5
|
module Marvin
|
6
6
|
include Perennial
|
7
7
|
|
8
|
-
VERSION = [0, 8, 0,
|
8
|
+
VERSION = [0, 8, 0, 1]
|
9
9
|
|
10
|
-
# Misc.
|
11
|
-
#autoload :Util, 'marvin/util'
|
12
10
|
# Client
|
13
|
-
#autoload :AbstractClient, 'marvin/abstract_client'
|
14
|
-
#autoload :IRC, 'marvin/irc'
|
15
11
|
autoload :TestClient, 'marvin/test_client'
|
16
12
|
# Console of DOOM.
|
17
13
|
autoload :Console, 'marvin/console'
|
18
14
|
# Distributed
|
19
15
|
autoload :Distributed, 'marvin/distributed'
|
20
|
-
autoload :Status, 'marvin/status'
|
21
16
|
# Handler
|
22
17
|
autoload :Base, 'marvin/base'
|
23
18
|
autoload :CommandHandler, 'marvin/command_handler'
|
@@ -25,7 +20,6 @@ module Marvin
|
|
25
20
|
autoload :CoreCommands, 'marvin/core_commands'
|
26
21
|
autoload :MiddleMan, 'marvin/middle_man'
|
27
22
|
# These should be namespaced under IRC
|
28
|
-
#autoload :AbstractParser, 'marvin/abstract_parser'
|
29
23
|
autoload :Parsers, 'marvin/parsers'
|
30
24
|
|
31
25
|
|
data/lib/marvin/base.rb
CHANGED
@@ -76,9 +76,11 @@ module Marvin
|
|
76
76
|
before = dispatcher.handlers
|
77
77
|
register!(dispatcher)
|
78
78
|
after = dispatcher.handlers
|
79
|
-
(after - before).each
|
79
|
+
(after - before).each do |h|
|
80
|
+
h.client = dispatcher
|
81
|
+
h.handle(:reloaded, {})
|
82
|
+
end
|
80
83
|
end
|
81
|
-
|
82
84
|
end
|
83
85
|
|
84
86
|
end
|
@@ -8,7 +8,6 @@ module Marvin
|
|
8
8
|
|
9
9
|
@@exposed_method_mapping = Hash.new { |h,k| h[k] = [] }
|
10
10
|
@@method_descriptions = Hash.new { |h,k| h[k] = {} }
|
11
|
-
@@registered_classes = Set.new
|
12
11
|
|
13
12
|
class << self
|
14
13
|
|
@@ -48,6 +47,12 @@ module Marvin
|
|
48
47
|
"#{command_prefix}#{method}"
|
49
48
|
end
|
50
49
|
|
50
|
+
def reloading!
|
51
|
+
super
|
52
|
+
@@exposed_method_mapping.delete(self)
|
53
|
+
@@method_descriptions.delete(self)
|
54
|
+
end
|
55
|
+
|
51
56
|
end
|
52
57
|
|
53
58
|
on_event :incoming_message, :check_for_commands
|
@@ -26,13 +26,22 @@ module Marvin
|
|
26
26
|
@host_with_port
|
27
27
|
end
|
28
28
|
|
29
|
-
def method_missing(name, *args)
|
29
|
+
def method_missing(name, *args, &blk)
|
30
30
|
logger.debug "Proxying #{name}(#{args.inspect[1..-2]}) to #{@host_with_port}"
|
31
|
+
cb = nil
|
32
|
+
if blk.present?
|
33
|
+
cb = proc do |_, options|
|
34
|
+
if options.is_a?(Hash)
|
35
|
+
value = options.delete("return-value")
|
36
|
+
blk.call(value)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
31
40
|
@connection.send_message(:action, {
|
32
41
|
"action" => name.to_s,
|
33
42
|
"arguments" => args,
|
34
43
|
"client-host" => @host_with_port
|
35
|
-
})
|
44
|
+
}, &cb)
|
36
45
|
end
|
37
46
|
|
38
47
|
end
|
@@ -43,6 +52,7 @@ module Marvin
|
|
43
52
|
register_handler_method :authentication_failed
|
44
53
|
register_handler_method :authenticated
|
45
54
|
register_handler_method :unauthorized
|
55
|
+
register_handler_method :welcome
|
46
56
|
|
47
57
|
cattr_accessor :stopping
|
48
58
|
self.stopping = false
|
@@ -60,20 +70,13 @@ module Marvin
|
|
60
70
|
def post_init
|
61
71
|
super
|
62
72
|
logger.info "Connected to distributed server"
|
63
|
-
if should_use_tls?
|
64
|
-
logger.info "Attempting to initialize tls"
|
65
|
-
start_tls
|
66
|
-
else
|
67
|
-
process_authentication
|
68
|
-
end
|
69
73
|
end
|
70
74
|
|
71
|
-
def
|
72
|
-
logger.info "
|
73
|
-
process_authentication
|
75
|
+
def post_connect
|
76
|
+
logger.info "Connection started; processing authentication"
|
77
|
+
process_authentication
|
74
78
|
end
|
75
79
|
|
76
|
-
|
77
80
|
def unbind
|
78
81
|
if self.stopping
|
79
82
|
logger.info "Stopping distributed client"
|
@@ -91,6 +94,15 @@ module Marvin
|
|
91
94
|
end
|
92
95
|
end
|
93
96
|
|
97
|
+
def handle_welcome(options = {})
|
98
|
+
if should_use_ssl? && !ssl_enabled?
|
99
|
+
request_ssl!
|
100
|
+
else
|
101
|
+
@connected = true
|
102
|
+
post_connect
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
94
106
|
def handle_event(options = {})
|
95
107
|
event = options["event-name"]
|
96
108
|
client_host = options["client-host"]
|
@@ -142,34 +154,9 @@ module Marvin
|
|
142
154
|
end
|
143
155
|
end
|
144
156
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
return {} if blk.blank?
|
149
|
-
cb_id = "callback-#{seld.object_id}-#{Time.now.to_f}"
|
150
|
-
count = 0
|
151
|
-
count += 1 while @callbacks.has_key?(Digest::SHA256.hexdigest("#{cb_id}-#{count}"))
|
152
|
-
final_id = Digest::SHA256.hexdigest("#{cb_id}-#{count}")
|
153
|
-
@callbacks[final_id] = blk
|
154
|
-
{"callback-id" => final_id}
|
155
|
-
end
|
156
|
-
|
157
|
-
def process_callback(hash)
|
158
|
-
if hash.is_a?(Hash) && hash.has_key?("callback-id")
|
159
|
-
callback = @callbacks.delete(hash["callback-id"])
|
160
|
-
callback.call(self, hash)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def host_with_port
|
165
|
-
@host_with_port ||= begin
|
166
|
-
port, ip = Socket.unpack_sockaddr_in(get_peername)
|
167
|
-
"#{ip}:#{port}"
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def should_use_tls?
|
172
|
-
@using_tls ||= configuration.encrypted?
|
157
|
+
def request_ssl!
|
158
|
+
logger.info "Requesting SSL for Distributed Client"
|
159
|
+
send_message(:enable_ssl) unless ssl_enabled?
|
173
160
|
end
|
174
161
|
|
175
162
|
end
|
@@ -32,11 +32,19 @@ module Marvin
|
|
32
32
|
send_data "#{payload}\n"
|
33
33
|
end
|
34
34
|
|
35
|
+
def send_message_reply(name, arguments = {})
|
36
|
+
arguments["callback-id"] = @callback_id if @callback_id.present?
|
37
|
+
send_message(name, arguments)
|
38
|
+
end
|
39
|
+
|
35
40
|
def handle_response(response)
|
36
|
-
logger.debug "Handling response in distributed protocol (response
|
41
|
+
logger.debug "Handling response in distributed protocol (response: #{response.inspect})"
|
37
42
|
return unless response.is_a?(Hash) && response.has_key?("message")
|
38
43
|
options = response["options"] || {}
|
44
|
+
@callback_id = response.delete("callback-id")
|
45
|
+
process_callback(options)
|
39
46
|
process_response_message(response["message"], options)
|
47
|
+
@callback_id = nil
|
40
48
|
end
|
41
49
|
|
42
50
|
def host_with_port
|
@@ -46,11 +54,52 @@ module Marvin
|
|
46
54
|
end
|
47
55
|
end
|
48
56
|
|
57
|
+
def handle_enable_ssl(opts = {})
|
58
|
+
send_message_reply(:enabled_ssl)
|
59
|
+
enable_ssl
|
60
|
+
end
|
61
|
+
|
62
|
+
def handle_enabled_ssl(opts = {})
|
63
|
+
enable_ssl
|
64
|
+
end
|
65
|
+
|
66
|
+
def handle_noop(opts = {})
|
67
|
+
# DO NOTHING.
|
68
|
+
logger.debug "no-op"
|
69
|
+
end
|
70
|
+
|
71
|
+
# After the connection is made and / or ssl is enabled.
|
72
|
+
def post_connect
|
73
|
+
end
|
74
|
+
|
75
|
+
def ssl_handshake_completed
|
76
|
+
logger.debug "SSL Handshake completed"
|
77
|
+
if !connected?
|
78
|
+
@connected = true
|
79
|
+
post_connect
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
49
83
|
protected
|
50
84
|
|
85
|
+
def should_use_ssl?
|
86
|
+
@should_use_ssl ||= configuration.ssl?
|
87
|
+
end
|
88
|
+
|
89
|
+
def ssl_enabled?
|
90
|
+
instance_variable_defined?(:@ssl_enabled) && @ssl_enabled
|
91
|
+
end
|
92
|
+
|
93
|
+
def enable_ssl
|
94
|
+
return if ssl_enabled?
|
95
|
+
logger.debug "Enabling SSL"
|
96
|
+
start_tls
|
97
|
+
@ssl_enabled = true
|
98
|
+
end
|
99
|
+
|
51
100
|
def options_for_callback(blk)
|
52
101
|
return {} if blk.blank?
|
53
|
-
cb_id = "callback-#{
|
102
|
+
cb_id = "callback-#{self.object_id}-#{Time.now.to_f}"
|
54
103
|
count = 0
|
55
104
|
count += 1 while @callbacks.has_key?(Digest::SHA256.hexdigest("#{cb_id}-#{count}"))
|
56
105
|
final_id = Digest::SHA256.hexdigest("#{cb_id}-#{count}")
|
@@ -63,7 +112,7 @@ module Marvin
|
|
63
112
|
@callbacks ||= {}
|
64
113
|
if hash.is_a?(Hash) && hash.has_key?("callback-id")
|
65
114
|
callback = @callbacks.delete(hash["callback-id"])
|
66
|
-
callback.call(self, hash)
|
115
|
+
callback.call(self, hash) if callback.present?
|
67
116
|
end
|
68
117
|
end
|
69
118
|
|
@@ -83,6 +132,15 @@ module Marvin
|
|
83
132
|
self.handler_methods[name] = method
|
84
133
|
end
|
85
134
|
|
135
|
+
# Default Handlers
|
136
|
+
register_handler_method :enable_ssl
|
137
|
+
register_handler_method :enabled_ssl
|
138
|
+
register_handler_method :noop
|
139
|
+
|
140
|
+
def connected?
|
141
|
+
instance_variable_defined?(:@connected) && @connected
|
142
|
+
end
|
143
|
+
|
86
144
|
end
|
87
145
|
end
|
88
146
|
end
|
@@ -16,7 +16,7 @@ module Marvin
|
|
16
16
|
self.free_connections = []
|
17
17
|
self.action_whitelist = [:nick, :pong, :action, :msg, :quit, :part, :join, :command]
|
18
18
|
|
19
|
-
attr_accessor :processing, :configuration
|
19
|
+
attr_accessor :processing, :configuration
|
20
20
|
|
21
21
|
def initialize(*args)
|
22
22
|
@configuration = args.last.is_a?(Marvin::Nash) ? args.pop : Marvin::nash.new
|
@@ -24,18 +24,20 @@ module Marvin
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def post_init
|
27
|
-
super
|
28
27
|
@callbacks = {}
|
29
28
|
logger.info "Got distributed client connection with #{self.host_with_port}"
|
30
|
-
if
|
31
|
-
|
29
|
+
if should_use_ssl?
|
30
|
+
handle_enable_ssl
|
32
31
|
else
|
33
|
-
|
32
|
+
@connected = true
|
33
|
+
post_connect
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
38
|
-
|
37
|
+
def post_connect
|
38
|
+
logger.debug "Remote client available, welcoming"
|
39
|
+
send_message(:welcome)
|
40
|
+
complete_processing
|
39
41
|
end
|
40
42
|
|
41
43
|
def unbind
|
@@ -84,14 +86,17 @@ module Marvin
|
|
84
86
|
def handle_action(options = {})
|
85
87
|
return if fails_auth!
|
86
88
|
logger.debug "Handling action from on #{self.host_with_port}"
|
87
|
-
|
89
|
+
target = lookup_client_for(options["client-host"])
|
88
90
|
action = options["action"]
|
89
91
|
arguments = [*options["arguments"]]
|
90
|
-
return if
|
92
|
+
return if target.blank? || action.blank?
|
91
93
|
begin
|
92
94
|
a = action.to_sym
|
93
|
-
if self.action_whitelist.include?(a)
|
94
|
-
|
95
|
+
if self.action_whitelist.include?(a) && target.respond_to?(a)
|
96
|
+
res = target.send(a, *arguments)
|
97
|
+
if @callback_id.present? && res.respond_to?(:to_json)
|
98
|
+
send_message_reply(:noop, {"return-value" => res.to_json})
|
99
|
+
end
|
95
100
|
else
|
96
101
|
logger.warn "Client attempted invalid action #{a.inspect}"
|
97
102
|
end
|
@@ -123,10 +128,6 @@ module Marvin
|
|
123
128
|
@authenticated ||= false
|
124
129
|
end
|
125
130
|
|
126
|
-
def should_use_tls?
|
127
|
-
@using_tls ||= configuration.encrypted?
|
128
|
-
end
|
129
|
-
|
130
131
|
def fails_auth!
|
131
132
|
if requires_auth?
|
132
133
|
logger.debug "Authentication missing for distributed client"
|
data/lib/marvin/irc/client.rb
CHANGED
@@ -103,8 +103,10 @@ module Marvin::IRC
|
|
103
103
|
EventMachine.kqueue
|
104
104
|
EventMachine.epoll
|
105
105
|
EventMachine.run do
|
106
|
-
connections.
|
107
|
-
|
106
|
+
unless connections.data == false
|
107
|
+
connections.each_pair do |server, configuration|
|
108
|
+
connect(configuration.merge(:server => server.to_s))
|
109
|
+
end
|
108
110
|
end
|
109
111
|
Marvin::Distributed::Server.start if Marvin::Distributed::Handler.registered?
|
110
112
|
@@stopped = false
|
@@ -21,20 +21,23 @@ module Marvin
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
on_event :client_connected
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
24
|
+
on_event :client_connected, :presetup_logging
|
25
|
+
on_event :client_connected, :setup_logging
|
26
|
+
on_event :reloaded, :presetup_logging
|
27
|
+
on_event :reloaded, :setup_logging
|
29
28
|
|
30
|
-
on_event :client_disconnected
|
31
|
-
|
32
|
-
end
|
29
|
+
on_event :client_disconnected, :teardown_logging
|
30
|
+
on_event :reloaded, :teardown_logging
|
33
31
|
|
34
32
|
on_event :outgoing_nick do
|
35
33
|
@nick = options.new_nick
|
36
34
|
end
|
37
35
|
|
36
|
+
def presetup_logging
|
37
|
+
@server = self.client.host_with_port
|
38
|
+
@nick = self.client.nickname
|
39
|
+
end
|
40
|
+
|
38
41
|
# Called when the client connects, over ride it to
|
39
42
|
# do any of your specific setup.
|
40
43
|
def setup_logging
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marvin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.0.
|
4
|
+
version: 0.8.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darcy Laycock
|
@@ -10,27 +10,27 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
|
12
12
|
date: 2009-09-25 00:00:00 +08:00
|
13
|
-
default_executable:
|
13
|
+
default_executable: marvin
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
16
|
+
name: perennial
|
17
17
|
type: :runtime
|
18
18
|
version_requirement:
|
19
19
|
version_requirements: !ruby/object:Gem::Requirement
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.
|
23
|
+
version: 1.0.0.0
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
|
-
name: eventmachine
|
26
|
+
name: eventmachine
|
27
27
|
type: :runtime
|
28
28
|
version_requirement:
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.12.
|
33
|
+
version: 0.12.8
|
34
34
|
version:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: json
|
@@ -42,10 +42,16 @@ dependencies:
|
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: "0"
|
44
44
|
version:
|
45
|
-
description:
|
45
|
+
description: |-
|
46
|
+
Marvin is a library (also usable in framework / application form) that
|
47
|
+
makes it simple and fast to build applications around IRC. With an emphasis
|
48
|
+
on making common tasks (e.g. replies, bots using method call style syntax
|
49
|
+
and the like) easy, whilst still making it possible to do more complex thing
|
50
|
+
(1 connection, N worker processes, Multiple servers, etc) it aims to make
|
51
|
+
working with IRC in an evented fashion fun and easy for all rubyists.
|
46
52
|
email: sutto@sutto.net
|
47
|
-
executables:
|
48
|
-
|
53
|
+
executables:
|
54
|
+
- marvin
|
49
55
|
extensions: []
|
50
56
|
|
51
57
|
extra_rdoc_files: []
|
@@ -131,6 +137,6 @@ rubyforge_project:
|
|
131
137
|
rubygems_version: 1.3.2
|
132
138
|
signing_key:
|
133
139
|
specification_version: 3
|
134
|
-
summary: Evented IRC Library
|
140
|
+
summary: Evented IRC Library for Ruby, built on EventMachine and Perennial.
|
135
141
|
test_files: []
|
136
142
|
|