Class: Butler

Inherits:
Object
  • Object
show all
Extended by:
Log::Comfort
Defined in:
lib/butler/version.rb,
lib/butler.rb,
lib/butler/bot.rb,
lib/butler/dialog.rb,
lib/butler/plugin.rb,
lib/butler/control.rb,
lib/butler/plugins.rb,
lib/butler/session.rb,
lib/butler/debuglog.rb,
lib/butler/irc/user.rb,
lib/butler/irc/topic.rb,
lib/butler/irc/whois.rb,
lib/butler/irc/client.rb,
lib/butler/irc/parser.rb,
lib/butler/irc/socket.rb,
lib/butler/irc/channel.rb,
lib/butler/plugin/more.rb,
lib/butler/irc/hostmask.rb,
lib/butler/irc/userlist.rb,
lib/butler/initialvalues.rb,
lib/butler/plugin/trigger.rb,
lib/butler/irc/channellist.rb,
lib/butler/irc/client/filter.rb,
lib/butler/plugin/configproxy.rb,
lib/butler/irc/client/listener.rb,
lib/butler/irc/parser/commands.rb,
lib/butler/irc/client/listenerlist.rb

Overview

:nodoc:

Defined Under Namespace

Modules: DebugLog, IRC, VERSION Classes: Bot, Control, Dialog, Plugin, Plugins, Session

Constant Summary collapse

IsGem =

REPLACE: IsGem = false

true
Structure =
%w[
	BOTPATH
	BOTPATH/access
	BOTPATH/access/privilege
	BOTPATH/access/role
	BOTPATH/access/user
	BOTPATH/log
	BOTPATH/plugins
	BOTPATH/strings
].map { |e| [e, 0755] }
ConfigurationStructure =

first one is the base-directory

%w[
	BOTPATH/config
	connections
	channels
	plugin
]
EmptyConfig =
{
	'remote' => {
		'host'   => 'localhost',
		'port'   => 7666,
		'active' => false,
	},
	'logging' => {
	},
	'owner' => {
		'username' => nil, # no owner
		'contact'  => 'unknown',
	},
}

Class Attribute Summary collapse

Attributes included from Log::Comfort

#logger

Class Method Summary collapse

Methods included from Log::Comfort

debug, error, exception, fail, info, log, warn

Class Attribute Details

.pathObject

Returns the value of attribute path.



28
29
30
# File 'lib/butler.rb', line 28

def path
  @path
end

Class Method Details

.backup(path, botname, backup) ⇒ Object

creates a backup of all important files of a bot



132
133
134
135
136
137
# File 'lib/butler.rb', line 132

def backup(path, botname, backup)
	path     ||= @path
	bot_path   = "#{path.bots}/#{botname}"
	FileUtils.mkdir_p(File.dirname(backup), :mode => 0755)
	FileUtils.cp_r(bot_path, backup)
end

.create(path, botname, opts = {}) ⇒ Object

creates a new bot



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/butler.rb', line 153

def create(path, botname, opts={})
	path     ||= @path
	bot_path   = "#{path.bots}/#{botname}"
	Structure.each { |dir, mode|
		FileUtils.mkdir_p(dir.sub(/BOTPATH/, bot_path),	:mode => mode)
	}
	conf = Configuration.new(
		ConfigurationStructure.first.sub(/BOTPATH/, bot_path),
		ConfigurationStructure[1..-1]
	)
	EmptyConfig.each { |k,v|
		conf[k] = v
	}
	FileUtils.cp_r(path.plugin_repository, bot_path)
end

.delete(path, botname) ⇒ Object

deletes a bot



170
171
172
173
174
# File 'lib/butler.rb', line 170

def delete(path, botname)
	path     ||= @path
	bot_path   = "#{path.bots}/#{botname}"
	FileUtils.rm_r(bot_path)
end

.exists?(path, botname) ⇒ Boolean

tests if a bot named botname exists

Returns:

  • (Boolean)


140
141
142
143
144
# File 'lib/butler.rb', line 140

def exists?(path, botname)
	path     ||= @path
	bot_path   = "#{path.bots}/#{botname}"
	File.directory?(bot_path)
end

.list(path) ⇒ Object

returns a list with bots



147
148
149
150
# File 'lib/butler.rb', line 147

def list(path)
	path ||= @path
	Dir[path.bots+"/*/"].map { |dir| dir[%r{([^/]+)/$}, 1] }
end

.new(*args, &block) ⇒ Object



184
185
186
# File 'lib/butler.rb', line 184

def new(*args, &block)
	Bot.new(*args, &block)
end

.rename(path, old_name, new_name) ⇒ Object

renames a bot



177
178
179
180
181
182
# File 'lib/butler.rb', line 177

def rename(path, old_name, new_name)
	path         ||= @path
	old_bot_path   = "#{path.bots}/#{old_name}"
	new_bot_path   = "#{path.bots}/#{new_name}"
	FileUtils.mv(old_bot_path, new_bot_path)
end

.start(path, botname, opts = {}, &block) ⇒ Object

start a bot if you provide a block, it will yield the bot instance and you can control it. If not, it will enter the Bot#event_loop. options: -:in_dir => path to the directory the bot can be found [Butler.bots] -:daemonize => whether this script should become a deamon or not [true] -…



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/butler.rb', line 37

def start(path, botname, opts={}, &block)
	Thread.abort_on_exception = true # if $DEBUG # FIXME
	path    ||= @path
	butler    = nil
	
	if opts.delete(:daemonize) then
		start_daemon(path, botname, opts, &block)
	else
		start_interactive(path, botname, opts, &block)
	end
end

.start_daemon(path, botname, opts = {}, &block) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/butler.rb', line 49

def start_daemon(path, botname, opts={}, &block)
	butler, pidfile = nil, nil
	info "Daemonizing"
	pidfile = test_pidfile(path.run, botname)
	daemonize(path.base) { }
	begin
		File.write(pidfile, $$)
		butler  = Bot.new(path, botname, opts)
		path    = butler.path
		$stderr = File.open(path.log+"/error.log", "w")
		$stdout = File.open(path.log+"/out.log", "w")
		trap("SIGHUP") { butler.quit }
		butler.output_to_logfiles
		butler.plugins.load_all
		butler.
		info("Running #{botname} with PID #{$$} as daemon")
		if block then butler.event_loop(&block) else sleep end
	rescue SystemExit => e
		info("Exit, terminating #{botname} (in #{e.backtrace.first}")
	rescue Exception => e
		exception(e)
	else
		info("EventLoop ended, terminating #{botname}")
	ensure
		butler.quit if butler
		File.delete(pidfile) if pidfile and File.exist?(pidfile)
		info("Terminated")
	end
end

.start_interactive(path, botname, opts, &block) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/butler.rb', line 79

def start_interactive(path, botname, opts, &block)
	butler, pidfile = nil, nil
	pidfile = test_pidfile(path.run, botname)
	File.write(pidfile, $$)
	info("Running #{botname} with PID #{$$} interactively")
	butler  = Bot.new(path, botname, opts)
	butler.plugins.load_all
	butler.
	if block then butler.event_loop(&block) else sleep end
rescue SystemExit => e
	info("Exit #{botname} (in #{e.backtrace.first}")
rescue Interrupt => e
	info("Interrupt, terminating #{botname} (in #{e.backtrace.first}")
rescue Exception => e
	exception(e)
ensure
	File.delete(pidfile) if pidfile and File.exist?(pidfile)
	butler.quit if butler #and butler.logged_in? # FIXME, make the commented code happen
	info("Terminated")
end

.stop(path, botname) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/butler.rb', line 114

def stop(path, botname)
	path    ||= @path
	pidfile   = "#{path.run}/#{botname}.pid"
	if File.exist?(pidfile) then
		pid       = File.read(pidfile).to_i
		begin
			Process.kill("HUP", pid)
		rescue Errno::ESRCH; end
		begin
			File.delete(pidfile)
		rescue Errno::ENOENT; end
	end
rescue => e
	exception(e)
	nil
end

.test_pidfile(path, botname) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/butler.rb', line 100

def test_pidfile(path, botname)
	pidfile = "#{path}/#{botname}.pid"
	FileUtils.mkdir_p(path, :mode => 0755)
	raise "Can't write to pid-directory (#{path.run})" if !File.writable?(path)
	if File.exist?(pidfile) && pid = File.read(pidfile) then
		if pid.empty? then
			raise "Already a Butler named '#{botname}' starting up"
		else
			raise "Already a Butler named '#{botname}' running with PID #{pid.chomp}"
		end
	end
	pidfile
end