marvin 0.8.0.0 → 0.8.0.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/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
- a.banner = "Marvin v#{Marvin::VERSION} - An IRC Library for Ruby"
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
 
@@ -5,19 +5,14 @@ require 'perennial'
5
5
  module Marvin
6
6
  include Perennial
7
7
 
8
- VERSION = [0, 8, 0, 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
 
@@ -57,10 +57,7 @@ module Marvin
57
57
  end
58
58
 
59
59
  def process_development
60
- if @@development
61
- Marvin::Reloading.reload!
62
- setup_handlers
63
- end
60
+ Marvin::Reloading.reload! if @@development
64
61
  end
65
62
 
66
63
  def dispatch(*args)
@@ -76,9 +76,11 @@ module Marvin
76
76
  before = dispatcher.handlers
77
77
  register!(dispatcher)
78
78
  after = dispatcher.handlers
79
- (after - before).each { |h| h.handle(:reloaded, {}) }
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 ssl_handshake_completed
72
- logger.info "tls handshake completed"
73
- process_authentication if should_use_tls?
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
- protected
146
-
147
- def options_for_callback(blk)
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
@@ -2,7 +2,6 @@ module Marvin
2
2
  module Distributed
3
3
  class Handler < Marvin::Base
4
4
 
5
-
6
5
  EVENT_WHITELIST = [:incoming_message, :incoming_action]
7
6
  QUEUE_PROCESSING_SPACING = 3
8
7
 
@@ -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 => #{response.inspect})"
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-#{seld.object_id}-#{Time.now.to_f}"
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, :using_tls
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 should_use_tls?
31
- start_tls
29
+ if should_use_ssl?
30
+ handle_enable_ssl
32
31
  else
33
- complete_processing
32
+ @connected = true
33
+ post_connect
34
34
  end
35
35
  end
36
36
 
37
- def ssl_handshake_completed
38
- complete_processing if should_use_tls?
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
- server = lookup_client_for(options["client-host"])
89
+ target = lookup_client_for(options["client-host"])
88
90
  action = options["action"]
89
91
  arguments = [*options["arguments"]]
90
- return if server.blank? || action.blank?
92
+ return if target.blank? || action.blank?
91
93
  begin
92
94
  a = action.to_sym
93
- if self.action_whitelist.include?(a)
94
- server.send(a, *arguments) if server.respond_to?(a)
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"
@@ -103,8 +103,10 @@ module Marvin::IRC
103
103
  EventMachine.kqueue
104
104
  EventMachine.epoll
105
105
  EventMachine.run do
106
- connections.each_pair do |server, configuration|
107
- connect(configuration.merge(:server => server.to_s))
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 do
25
- @server = self.client.host_with_port
26
- @nick = self.client.nickname
27
- setup_logging
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 do
31
- teardown_logging
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.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: Sutto-perennial
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.2.4.6
23
+ version: 1.0.0.0
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
- name: eventmachine-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.9
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 of Doom
140
+ summary: Evented IRC Library for Ruby, built on EventMachine and Perennial.
135
141
  test_files: []
136
142