Sutto-marvin 0.4.0 → 0.8.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/marvin +22 -156
- data/handlers/keiki_thwopper.rb +21 -0
- data/handlers/tweet_tweet.rb +1 -3
- data/lib/marvin/abstract_client.rb +75 -189
- data/lib/marvin/abstract_parser.rb +9 -11
- data/lib/marvin/base.rb +134 -101
- data/lib/marvin/client/actions.rb +104 -0
- data/lib/marvin/client/default_handlers.rb +97 -0
- data/lib/marvin/command_handler.rb +60 -49
- data/lib/marvin/console.rb +4 -31
- data/lib/marvin/core_commands.rb +30 -12
- data/lib/marvin/distributed/client.rb +225 -0
- data/lib/marvin/distributed/handler.rb +85 -0
- data/lib/marvin/distributed/protocol.rb +88 -0
- data/lib/marvin/distributed/server.rb +154 -0
- data/lib/marvin/distributed.rb +4 -10
- data/lib/marvin/dsl.rb +103 -0
- data/lib/marvin/exception_tracker.rb +7 -4
- data/lib/marvin/irc/client.rb +127 -99
- data/lib/marvin/irc/event.rb +14 -10
- data/lib/marvin/irc.rb +0 -1
- data/lib/marvin/middle_man.rb +1 -1
- data/lib/marvin/parsers/command.rb +10 -8
- data/lib/marvin/parsers/prefixes/host_mask.rb +12 -7
- data/lib/marvin/parsers/prefixes/server.rb +1 -1
- data/lib/marvin/parsers/ragel_parser.rb +59 -52
- data/lib/marvin/parsers/ragel_parser.rl +6 -7
- data/lib/marvin/parsers/simple_parser.rb +4 -9
- data/lib/marvin/parsers.rb +1 -2
- data/lib/marvin/settings.rb +29 -79
- data/lib/marvin/test_client.rb +20 -26
- data/lib/marvin/util.rb +10 -3
- data/lib/marvin.rb +42 -39
- data/templates/boot.erb +3 -0
- data/templates/connections.yml.erb +10 -0
- data/templates/debug_handler.erb +5 -0
- data/templates/hello_world.erb +10 -0
- data/templates/rakefile.erb +15 -0
- data/templates/settings.yml.erb +8 -0
- data/{config/setup.rb → templates/setup.erb} +8 -10
- data/templates/test_helper.erb +17 -0
- data/test/abstract_client_test.rb +63 -0
- data/test/parser_comparison.rb +2 -2
- data/test/parser_test.rb +3 -3
- data/test/test_helper.rb +58 -6
- metadata +51 -83
- data/README.textile +0 -105
- data/TUTORIAL.textile +0 -54
- data/VERSION.yml +0 -4
- data/config/boot.rb +0 -14
- data/config/connections.yml.sample +0 -5
- data/config/settings.yml.sample +0 -13
- data/handlers/logging_handler.rb +0 -89
- data/lib/marvin/core_ext.rb +0 -11
- data/lib/marvin/daemon.rb +0 -71
- data/lib/marvin/data_store.rb +0 -73
- data/lib/marvin/dispatchable.rb +0 -99
- data/lib/marvin/distributed/dispatch_handler.rb +0 -83
- data/lib/marvin/distributed/drb_client.rb +0 -78
- data/lib/marvin/distributed/ring_server.rb +0 -41
- data/lib/marvin/handler.rb +0 -12
- data/lib/marvin/irc/server/abstract_connection.rb +0 -84
- data/lib/marvin/irc/server/base_connection.rb +0 -66
- data/lib/marvin/irc/server/channel.rb +0 -115
- data/lib/marvin/irc/server/named_store.rb +0 -14
- data/lib/marvin/irc/server/remote_interface.rb +0 -77
- data/lib/marvin/irc/server/user/handle_mixin.rb +0 -140
- data/lib/marvin/irc/server/user.rb +0 -5
- data/lib/marvin/irc/server/user_connection.rb +0 -134
- data/lib/marvin/irc/server/virtual_user_connection.rb +0 -80
- data/lib/marvin/irc/server.rb +0 -71
- data/lib/marvin/loader.rb +0 -149
- data/lib/marvin/logger.rb +0 -86
- data/lib/marvin/options.rb +0 -42
- data/lib/marvin/parsers/regexp_parser.rb +0 -93
- data/lib/marvin/status.rb +0 -72
- data/script/client +0 -3
- data/script/console +0 -3
- data/script/distributed_client +0 -3
- data/script/install +0 -1
- data/script/ring_server +0 -4
- data/script/server +0 -4
- data/script/status +0 -3
- data/spec/marvin/abstract_client_test.rb +0 -38
- data/spec/spec_helper.rb +0 -14
data/handlers/logging_handler.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
# A Simple Channel Logger, built for the
|
2
|
-
# #offrails community. Please note that this
|
3
|
-
# relies on models etc. inside the Rails App.
|
4
|
-
# it's suited for modification of subclassing
|
5
|
-
# if you wish to write your own Channel Logger.
|
6
|
-
# I plan on open sourcing the app sometime in
|
7
|
-
# the near future.
|
8
|
-
class LoggingHandler < Marvin::CommandHandler
|
9
|
-
|
10
|
-
class_inheritable_accessor :connection, :setup
|
11
|
-
attr_accessor :listening, :users
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
super
|
15
|
-
logger.debug "Setting up LoggingHandler"
|
16
|
-
self.setup!
|
17
|
-
self.users = {}
|
18
|
-
end
|
19
|
-
|
20
|
-
# Control
|
21
|
-
|
22
|
-
exposes :listen, :earmuffs
|
23
|
-
|
24
|
-
desc "Makes me listen up and take not of what you're saying."
|
25
|
-
def listen(data)
|
26
|
-
unless listening?
|
27
|
-
@listening = true
|
28
|
-
reply "Busted! I heard _everything_ you said ;)"
|
29
|
-
else
|
30
|
-
reply "Uh, You never asked me to put my earmuffs on?"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
desc "Sends me off into a corner with my ear muffs so you can have your discussions in peace"
|
35
|
-
def earmuffs(data)
|
36
|
-
if listening?
|
37
|
-
@listening = false
|
38
|
-
reply "Oh hai, I'm not listening anymore."
|
39
|
-
else
|
40
|
-
reply "I've already put the earmuffs on!"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def listening?
|
45
|
-
@listening
|
46
|
-
end
|
47
|
-
|
48
|
-
# The actual logging
|
49
|
-
|
50
|
-
on_event :incoming_message do
|
51
|
-
log_message(options.nick, options.target, options.message)
|
52
|
-
end
|
53
|
-
|
54
|
-
on_event :outgoing_message do
|
55
|
-
log_message(client.nickname, options.target, options.message)
|
56
|
-
end
|
57
|
-
|
58
|
-
on_event :incoming_action do
|
59
|
-
log_message(options.nick, options.target, "ACTION \01#{options.message}\01")
|
60
|
-
end
|
61
|
-
|
62
|
-
def log_message(from, to, message)
|
63
|
-
return unless listening?
|
64
|
-
ensure_connection_is_alive # Before Logging, ensure that the connection is alive.
|
65
|
-
self.users[from.strip] ||= IrcHandle.find_or_create_by_name(from.strip)
|
66
|
-
self.users[from.strip].messages.create :message => message, :target => to
|
67
|
-
end
|
68
|
-
|
69
|
-
# Our General Tasks
|
70
|
-
|
71
|
-
def setup!
|
72
|
-
return true if self.setup
|
73
|
-
load_prerequisites
|
74
|
-
self.setup = true
|
75
|
-
self.listening = true
|
76
|
-
end
|
77
|
-
|
78
|
-
def load_prerequisites
|
79
|
-
require File.join(Marvin::Settings.rails_root, "config/environment")
|
80
|
-
end
|
81
|
-
|
82
|
-
def ensure_connection_is_alive
|
83
|
-
unless ActiveRecord::Base.connection.active?
|
84
|
-
ActiveRecord::Base.connection.reconnect!
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
|
89
|
-
end
|
data/lib/marvin/core_ext.rb
DELETED
data/lib/marvin/daemon.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
module Marvin
|
2
|
-
class Daemon
|
3
|
-
class << self
|
4
|
-
|
5
|
-
def alive?(pid)
|
6
|
-
return Process.getpgid(pid) != -1
|
7
|
-
rescue Errno::ESRCH
|
8
|
-
return false
|
9
|
-
end
|
10
|
-
|
11
|
-
def kill_all(type = :all)
|
12
|
-
if type == :all
|
13
|
-
files = Dir[Marvin::Settings.root / "tmp/pids/*.pid"]
|
14
|
-
files.each { |f| kill_all_from f }
|
15
|
-
elsif type.is_a?(Symbol)
|
16
|
-
kill_all_from(pid_file_for(type))
|
17
|
-
end
|
18
|
-
return nil
|
19
|
-
end
|
20
|
-
|
21
|
-
def daemonize!
|
22
|
-
exit if fork
|
23
|
-
Process.setsid
|
24
|
-
exit if fork
|
25
|
-
self.write_pid
|
26
|
-
File.umask 0000
|
27
|
-
STDIN.reopen "/dev/null"
|
28
|
-
STDOUT.reopen "/dev/null", "a"
|
29
|
-
STDERR.reopen STDOUT
|
30
|
-
Marvin::Settings.verbose = false
|
31
|
-
end
|
32
|
-
|
33
|
-
def cleanup!
|
34
|
-
f = pids_file_for(Marvin::Loader.type)
|
35
|
-
FileUtils.rm_f(f) if (pids_from(f) - Process.pid).blank?
|
36
|
-
end
|
37
|
-
|
38
|
-
def pids_for_type(type)
|
39
|
-
pids_from(pid_file_for(type))
|
40
|
-
end
|
41
|
-
|
42
|
-
protected
|
43
|
-
|
44
|
-
def kill_all_from(file)
|
45
|
-
pids = pids_from(file)
|
46
|
-
pids.each { |p| Process.kill("TERM", p) unless p == Process.pid }
|
47
|
-
FileUtils.rm_f(file)
|
48
|
-
rescue => e
|
49
|
-
STDOUT.puts e.inspect
|
50
|
-
end
|
51
|
-
|
52
|
-
def pid_file_for(type)
|
53
|
-
Marvin::Settings.root / "tmp" / "pids" / "marvin-#{type.to_s.underscore}.pid"
|
54
|
-
end
|
55
|
-
|
56
|
-
def pids_from(file)
|
57
|
-
return [] unless File.exist?(file)
|
58
|
-
pids = File.read(file)
|
59
|
-
pids = pids.split("\n").map { |l| l.strip.to_i(10) }.select { |p| alive?(p) }
|
60
|
-
end
|
61
|
-
|
62
|
-
def write_pid
|
63
|
-
f = pid_file_for(Marvin::Loader.type)
|
64
|
-
pids = pids_from(f)
|
65
|
-
pids << Process.pid unless pids.include?(Process.pid)
|
66
|
-
File.open(f, "w+") { |f| f.puts pids.join("\n") }
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
data/lib/marvin/data_store.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module Marvin
|
4
|
-
# Implements a simple datastore interface, designed to make
|
5
|
-
# it easy to develop handlers which have persistent data.
|
6
|
-
class DataStore
|
7
|
-
|
8
|
-
cattr_accessor :logger, :registered_stores
|
9
|
-
self.logger = Marvin::Logger.logger
|
10
|
-
self.registered_stores = {}
|
11
|
-
|
12
|
-
# Returns the path to the data store relative to this file.
|
13
|
-
# Used when loading / dumping the data.
|
14
|
-
def self.datastore_location
|
15
|
-
path = Marvin::Settings[:datastore_location] ? Marvin::Settings.datastore_location : "tmp/datastore.json"
|
16
|
-
return Marvin::Settings.root / path
|
17
|
-
end
|
18
|
-
|
19
|
-
# Dump the current data store contents to file.
|
20
|
-
def self.dump!
|
21
|
-
File.open(self.datastore_location, "w+") do |f|
|
22
|
-
f.write self.registered_stores.to_json
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# Load the current data store contents from file.
|
27
|
-
def self.load!
|
28
|
-
results = {}
|
29
|
-
if File.exists?(self.datastore_location)
|
30
|
-
begin
|
31
|
-
json = JSON.load(File.read(self.datastore_location))
|
32
|
-
results = json if json.is_a?(Hash)
|
33
|
-
rescue JSON::ParserError
|
34
|
-
end
|
35
|
-
end
|
36
|
-
self.registered_stores = results
|
37
|
-
end
|
38
|
-
|
39
|
-
|
40
|
-
# For each individual datastore.
|
41
|
-
|
42
|
-
attr_accessor :name
|
43
|
-
|
44
|
-
def initialize(name)
|
45
|
-
self.name = name.to_s
|
46
|
-
self.registered_stores ||= {}
|
47
|
-
self.registered_stores[self.name] ||= {}
|
48
|
-
end
|
49
|
-
|
50
|
-
def [](key)
|
51
|
-
((self.registered_stores||={})[self.name]||={})[key.to_s]
|
52
|
-
end
|
53
|
-
|
54
|
-
def []=(key,value)
|
55
|
-
self.registered_stores[self.name][key.to_s] = value
|
56
|
-
end
|
57
|
-
|
58
|
-
def method_missing(name, *args, &blk)
|
59
|
-
if name.to_s =~ /^(.*)=$/i
|
60
|
-
self[$1.to_s] = args.first
|
61
|
-
elsif self.registered_stores[self.name].has_key?(name.to_s)
|
62
|
-
return self.registered_stores[self.name][name.to_s]
|
63
|
-
else
|
64
|
-
super(name, *args, &blk)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def to_hash
|
69
|
-
self.registered_stores[self.name]
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
end
|
data/lib/marvin/dispatchable.rb
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
module Marvin
|
2
|
-
# = Marvin::Dispatchable
|
3
|
-
# A Generic mixin which lets you define an object
|
4
|
-
# Which accepts handlers which can have arbitrary
|
5
|
-
# events dispatched.
|
6
|
-
# == Usage
|
7
|
-
#
|
8
|
-
# class X
|
9
|
-
# include Marvin::Dispatchable
|
10
|
-
# self.handlers << SomeHandler.new
|
11
|
-
# end
|
12
|
-
# X.new.dispatch(:name, {:args => "Values"})
|
13
|
-
#
|
14
|
-
# Will first check if SomeHandler#handle_name exists,
|
15
|
-
# calling handle_name({:args => "Values"}) if it does,
|
16
|
-
# otherwise calling SomeHandler#handle(:name, {:args => "Values"})
|
17
|
-
module Dispatchable
|
18
|
-
|
19
|
-
def self.included(parent)
|
20
|
-
parent.class_eval do
|
21
|
-
include InstanceMethods
|
22
|
-
extend ClassMethods
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
module InstanceMethods
|
27
|
-
|
28
|
-
# Returns the handlers registered on this class,
|
29
|
-
# used inside +dispatch+. Note that it will call
|
30
|
-
# dup on each of the objects to get a new instance.
|
31
|
-
# please ensure your object acts accordingly.
|
32
|
-
def handlers
|
33
|
-
@handlers ||= self.class.handlers.map { |h| h.dup }
|
34
|
-
end
|
35
|
-
|
36
|
-
# Dispatch an 'event' with a given name to the handlers
|
37
|
-
# registered on the current class. Used as a nicer way of defining
|
38
|
-
# behaviours that should occur under a given set of circumstances.
|
39
|
-
# == Params
|
40
|
-
# +name+: The name of the current event
|
41
|
-
# +opts+: an optional hash of options to pass
|
42
|
-
def dispatch(name, opts = {})
|
43
|
-
# The full handler name is the method we call given it exists.
|
44
|
-
full_handler_name = :"handle_#{name.to_s.underscore}"
|
45
|
-
# First, dispatch locally if the method is defined.
|
46
|
-
if self.respond_to?(full_handler_name)
|
47
|
-
self.send(full_handler_name, opts)
|
48
|
-
end
|
49
|
-
# Iterate through all of the registered handlers,
|
50
|
-
# If there is a method named handle_<event_name>
|
51
|
-
# defined we sent that otherwise we call the handle
|
52
|
-
# method on the handler. Note that the handle method
|
53
|
-
# is the only required aspect of a handler. An improved
|
54
|
-
# version of this would likely cache the respond_to?
|
55
|
-
# call.
|
56
|
-
self.handlers.each do |handler|
|
57
|
-
if handler.respond_to?(full_handler_name)
|
58
|
-
handler.send(full_handler_name, opts)
|
59
|
-
else
|
60
|
-
handler.handle name, opts
|
61
|
-
end
|
62
|
-
end
|
63
|
-
# If we get the HaltHandlerProcessing exception, we
|
64
|
-
# catch it and continue on our way. In essence, we
|
65
|
-
# stop the dispatch of events to the next set of the
|
66
|
-
# handlers.
|
67
|
-
rescue HaltHandlerProcessing => e
|
68
|
-
Marvin::Logger.info "Halting processing chain"
|
69
|
-
rescue Exception => e
|
70
|
-
Marvin::ExceptionTracker.log(e)
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
module ClassMethods
|
76
|
-
|
77
|
-
# Return an array of all registered handlers, stored in the
|
78
|
-
# class variable @@handlers. Used inside the #handlers instance
|
79
|
-
# method as well as inside things such as register_handler.
|
80
|
-
def handlers
|
81
|
-
@@handlers ||= []
|
82
|
-
end
|
83
|
-
|
84
|
-
# Assigns a new array of handlers and assigns each.
|
85
|
-
def handlers=(new_value)
|
86
|
-
@@handlers = []
|
87
|
-
new_value.to_a.each { |h| register_handler h }
|
88
|
-
end
|
89
|
-
|
90
|
-
# Appends a handler to the list of handlers for this object.
|
91
|
-
# Handlers are called in the order they are registered.
|
92
|
-
def register_handler(handler)
|
93
|
-
self.handlers << handler unless handler.nil? || !handler.respond_to?(:handle)
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|
99
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
require 'rinda/ring'
|
2
|
-
require 'rinda/tuplespace'
|
3
|
-
|
4
|
-
DRb.start_service
|
5
|
-
|
6
|
-
module Marvin
|
7
|
-
module Distributed
|
8
|
-
|
9
|
-
# Handler to provide
|
10
|
-
class DispatchHandler < Marvin::Base
|
11
|
-
|
12
|
-
LOOKUP_TIMEOUT = 0.5
|
13
|
-
|
14
|
-
# Tell the client that we shouldn't be dumped.
|
15
|
-
Marvin::AbstractClient.class_eval { include(DRbUndumped) }
|
16
|
-
|
17
|
-
# Get the ring server - if it exists, we will return the current
|
18
|
-
# instance other wise it follows a few steps to try and find a new
|
19
|
-
# one. Since there can be a delay in getting a response, we'll only
|
20
|
-
# check every 5 messages.
|
21
|
-
def ring_server
|
22
|
-
if @@rs.nil? && (@lookup_attempts ||= 6) > 5
|
23
|
-
@lookup_attempts = 0
|
24
|
-
@@rs = Rinda::RingFinger.finger.lookup_ring(LOOKUP_TIMEOUT)
|
25
|
-
logger.info "Found new ring server => #{@@rs.__drburi}"
|
26
|
-
elsif @@rs.nil?
|
27
|
-
@lookup_attempts += 1
|
28
|
-
end
|
29
|
-
return @@rs
|
30
|
-
rescue RingNotFound
|
31
|
-
@@rs = nil
|
32
|
-
end
|
33
|
-
|
34
|
-
# Takes an incoming messsage and does all the fancy
|
35
|
-
# Stuff with it.
|
36
|
-
def handle(message, options)
|
37
|
-
# Don't forward lines for the moment to halve the traffic.
|
38
|
-
return if message == :incoming_line
|
39
|
-
super(message, options)
|
40
|
-
dispatch(message, options)
|
41
|
-
end
|
42
|
-
|
43
|
-
# Attempts to add a message to the current tuple space,
|
44
|
-
# adding it to a message queue if it can't be added.
|
45
|
-
# If there are many items, it will log a warning.
|
46
|
-
# TODO: Improve it to dump messages to disk at a predefined limit.
|
47
|
-
def dispatch(name, options)
|
48
|
-
options[:dispatched_at] ||= Time.now
|
49
|
-
tuple = [:marvin_event, Marvin::Settings.distributed_namespace, name, options, self.client]
|
50
|
-
begin
|
51
|
-
(@queued_messages ||= []) << tuple
|
52
|
-
if self.ring_server.nil?
|
53
|
-
size = @queued_messages.size
|
54
|
-
if size > 0 && size % 25 == 0
|
55
|
-
logger.warn "Dispatch handler queue is currently holding #{size} items"
|
56
|
-
end
|
57
|
-
else
|
58
|
-
logger.debug "Writing #{@queued_messages.size} message to the ring server"
|
59
|
-
@queued_messages.dup.each do |t|
|
60
|
-
ring_server.write(t)
|
61
|
-
@queued_messages.delete(t)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
rescue
|
65
|
-
# Reset the ring finger to the next choice.
|
66
|
-
logger.debug "Ring server unavailable, resetting..."
|
67
|
-
@@rs = nil
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Register this as a handler, but only if we're
|
72
|
-
# running in "client mode" - in other words, we
|
73
|
-
# want to make sure it won't start up an infinite
|
74
|
-
# loop.
|
75
|
-
def self.register!(*args)
|
76
|
-
# DO NOT register if this is not a normal client.
|
77
|
-
return unless Marvin::Loader.type == :client
|
78
|
-
super
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
module Marvin
|
2
|
-
module Distributed
|
3
|
-
# A method for operating on marvin objects.
|
4
|
-
class DRbClient
|
5
|
-
|
6
|
-
# Wait 1 second on a lookup.
|
7
|
-
LOOKUP_TIMEOUT = 1
|
8
|
-
|
9
|
-
class << self
|
10
|
-
|
11
|
-
@@handlers = []
|
12
|
-
attr_accessor :stopped
|
13
|
-
|
14
|
-
def register_handler(handler)
|
15
|
-
@@handlers << handler unless handler.nil? || !handler.respond_to?(:handle)
|
16
|
-
end
|
17
|
-
|
18
|
-
def dispatch(name, opts, client)
|
19
|
-
Marvin::Logger.debug "Processing Event: #{name}"
|
20
|
-
full_handler_name = :"handle_#{name.to_s.underscore}"
|
21
|
-
@@handlers.each do |handler|
|
22
|
-
has_client = handler.respond_to?(:client=)
|
23
|
-
handler.client = client if has_client
|
24
|
-
if handler.respond_to?(full_handler_name)
|
25
|
-
handler.send(full_handler_name, opts)
|
26
|
-
else
|
27
|
-
handler.handle name, opts
|
28
|
-
end
|
29
|
-
handler.client = nil if has_client
|
30
|
-
end
|
31
|
-
rescue HaltHandlerProcessing => e
|
32
|
-
Marvin::Logger.info "Halting processing chain"
|
33
|
-
rescue Exception => e
|
34
|
-
Marvin::ExceptionTracker.log(e)
|
35
|
-
end
|
36
|
-
|
37
|
-
# Starts up a drb processor / client, and walks through the process of dealing
|
38
|
-
# with it / processing events.
|
39
|
-
def run
|
40
|
-
self.stopped = false
|
41
|
-
Marvin::Logger.info "Starting up DRb Client"
|
42
|
-
DRb.start_service
|
43
|
-
# Loop through, making sure we have a valid
|
44
|
-
# RingFinger and then process events as they
|
45
|
-
# appear.
|
46
|
-
enter_loop!
|
47
|
-
end
|
48
|
-
|
49
|
-
def stop
|
50
|
-
self.stopped = true
|
51
|
-
end
|
52
|
-
|
53
|
-
def ring_server
|
54
|
-
@ring_server = Rinda::RingFinger.finger.lookup_ring(LOOKUP_TIMEOUT) if @ring_server.nil?
|
55
|
-
return @ring_server
|
56
|
-
rescue RingNotFound
|
57
|
-
@ring_server = nil
|
58
|
-
end
|
59
|
-
|
60
|
-
def enter_loop!
|
61
|
-
Marvin::Logger.info "Entering processing loop"
|
62
|
-
while !self.stopped
|
63
|
-
begin
|
64
|
-
unless self.ring_server.blank?
|
65
|
-
event = self.ring_server.take([:marvin_event, Marvin::Settings.distributed_namespace, nil, nil, nil], 2)
|
66
|
-
dispatch(*event[2..-1]) unless event.blank?
|
67
|
-
end
|
68
|
-
rescue
|
69
|
-
# Reset the ring server on event of connection refused etc.
|
70
|
-
@ring_server = nil
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'rinda/ring'
|
2
|
-
require 'rinda/tuplespace'
|
3
|
-
|
4
|
-
module Marvin
|
5
|
-
module Distributed
|
6
|
-
class RingServer
|
7
|
-
|
8
|
-
attr_accessor :tuple_space, :ring_server
|
9
|
-
cattr_accessor :logger
|
10
|
-
self.logger = Marvin::Logger
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
self.tuple_space = Rinda::TupleSpace.new
|
14
|
-
if Marvin::Settings.log_level == :debug
|
15
|
-
observer = self.tuple_space.notify('write', [:marvin_event, Marvin::Settings.distributed_namespace, nil, nil, nil])
|
16
|
-
Thread.start do
|
17
|
-
observer.each do |i|
|
18
|
-
event_name, args = i[1][2..3]
|
19
|
-
Marvin::Logger.logger.debug "Marvin event added - #{event_name.inspect} w/ #{args.inspect}"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
self.ring_server = Rinda::RingServer.new(self.tuple_space)
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.run
|
27
|
-
begin
|
28
|
-
logger.info "Starting up DRb"
|
29
|
-
drb_server = DRb.start_service
|
30
|
-
logger.info "Creating TupleSpace & Ring Server Instances - Running on #{DRb.uri}"
|
31
|
-
self.new
|
32
|
-
logger.info "Started - Joining thread."
|
33
|
-
DRb.thread.join
|
34
|
-
rescue
|
35
|
-
logger.fatal "Error starting ring server - please ensure another instance isn't already running."
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/lib/marvin/handler.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
module Marvin
|
2
|
-
module Handler
|
3
|
-
|
4
|
-
# Received a given +message+ with a set of default
|
5
|
-
# +opts+ (defaulting back to an empty hash), which
|
6
|
-
# will be used to perform some sort of action.
|
7
|
-
def handle(message, opts = {})
|
8
|
-
Marvin::Logger.debug "NOP handle - got message #{message.inspect}"
|
9
|
-
end
|
10
|
-
|
11
|
-
end
|
12
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server
|
2
|
-
class AbstractConnection
|
3
|
-
include Marvin::Dispatchable
|
4
|
-
|
5
|
-
cattr_accessor :connections, :logger, :alive
|
6
|
-
self.connections = []
|
7
|
-
self.logger = Marvin::Logger
|
8
|
-
|
9
|
-
attr_accessor :connection
|
10
|
-
|
11
|
-
# Create a new connection with a given parent
|
12
|
-
# and an incoming buffer of messages
|
13
|
-
def initialize(parent, buffer = [])
|
14
|
-
@connection = parent
|
15
|
-
buffer.each { |line| receive_line(line) }
|
16
|
-
end
|
17
|
-
|
18
|
-
def receive_line(line)
|
19
|
-
dispatch :incoming_line, :line => line
|
20
|
-
event = Marvin::Settings.default_parser.parse(line)
|
21
|
-
dispatch(event.to_incoming_event_name, event.to_hash) unless event.nil?
|
22
|
-
end
|
23
|
-
|
24
|
-
def send_line(line)
|
25
|
-
@connection.send_line(line)
|
26
|
-
end
|
27
|
-
|
28
|
-
def process_connect
|
29
|
-
@alive = true
|
30
|
-
# Send the welcome notice / auth command.
|
31
|
-
command :NOTICE, "AUTH", ":Marvin v#{Marvin.version} initialized, welcome."
|
32
|
-
dispatch :client_connected, :client => self
|
33
|
-
end
|
34
|
-
|
35
|
-
def process_disconnect
|
36
|
-
@@connections.delete(self)
|
37
|
-
@alive = false
|
38
|
-
dispatch :client_disconnected, :client => self
|
39
|
-
end
|
40
|
-
|
41
|
-
class << self
|
42
|
-
|
43
|
-
# Return an array of all registered handlers, stored in the
|
44
|
-
# class variable @@handlers. Used inside the #handlers instance
|
45
|
-
# method as well as inside things such as register_handler.
|
46
|
-
def handlers
|
47
|
-
(@@handlers ||= {})[self] ||= []
|
48
|
-
end
|
49
|
-
|
50
|
-
# Assigns a new array of handlers and assigns each.
|
51
|
-
def handlers=(new_value)
|
52
|
-
(@@handlers ||= {})[self] = []
|
53
|
-
new_value.to_a.each { |h| register_handler h }
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
def dispatch(name, opts = {})
|
59
|
-
opts[:connection] ||= self
|
60
|
-
super
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def command(name, *args)
|
66
|
-
opts = args.extract_options!
|
67
|
-
formatted = [name.to_s.upcase, *args].join(" ")
|
68
|
-
formatted = ":#{opts[:prefix]} #{formatted}" if opts[:prefix]
|
69
|
-
send_line formatted
|
70
|
-
end
|
71
|
-
|
72
|
-
def peer_name
|
73
|
-
return @peer_name unless @peer_name.blank?
|
74
|
-
sock_addr = @connection.get_peername
|
75
|
-
begin
|
76
|
-
@peer_name = Socket.getnameinfo(sock_addr, Socket::NI_NAMEREQD).first
|
77
|
-
rescue
|
78
|
-
@peer_name = Socket.getnameinfo(sock_addr).first
|
79
|
-
end
|
80
|
-
return @peer_name
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
84
|
-
end
|