irc_machine 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ /log/
6
+ /irc_machine.json
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm @irc_machine --create
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
@@ -0,0 +1,56 @@
1
+ IRC Machine
2
+ ===========
3
+
4
+ An IRC bot with a RESTful HTTP interface, built on Ruby and [EventMachine](http://rubyeventmachine.com/).
5
+
6
+ Design philosophy: simple to the point of under-engineered, make it work for the 90% case.
7
+
8
+ # something like this might work
9
+ git clone git://github.com/pda/irc_machine
10
+ cd irc_machine
11
+ cp example.json irc_machine.json
12
+
13
+ # run it
14
+ ./bin/irc_machined run
15
+ # ctrl+c
16
+
17
+ # daemonize it
18
+ ./bin/irc_machined start
19
+ # stop the daemon
20
+ ./bin/irc_machined stop
21
+
22
+ # or maybe even this (chances aren't good, though)
23
+ gem install irc_machine
24
+ irc_machined run
25
+
26
+
27
+ HTTP interface
28
+ --------------
29
+
30
+ The RESTful HTTP API is provided by `IrcMachine::Plugin::Rest`. It listens on port 8421 by default. And you can't change the default.
31
+
32
+ * `GET /channels` returns a JSON list of channels the bot is probably in.
33
+ * `PUT /channels/{name}` joins a channel.
34
+ * `DELETE /channels/{name}` parts a channel.
35
+ * `POST /channels/{name}` sends a text/plain message to a channel, auto-joins if required.
36
+ * `POST /channels/{name}/github` accepts GitHub post-receive hook notifications, notifies channel.
37
+
38
+
39
+ Plugins
40
+ -------
41
+
42
+ Plugins are objects which might respond to `#start` or `#receive_line`, and might use a reference to the `IrcMachine::Session` instance to send IRC commands.
43
+
44
+
45
+ Contributors
46
+ ------------
47
+
48
+ * [Paul Annesley](https://github.com/pda)
49
+ * [Eric Anderson](https://github.com/ericanderson)
50
+ * [Anton Lindström](https://github.com/antonlindstrom)
51
+
52
+
53
+ Meh.
54
+ ----
55
+
56
+ © Paul Annesley, 2011, [MIT license](http://www.opensource.org/licenses/mit-license.php)
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path("../../lib", __FILE__)
3
+
4
+ require 'irc_machine/cli_shared'
5
+
6
+ IrcMachine::Session.new(IRC_MACHINE).start
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path("../../lib", __FILE__)
3
+
4
+ require 'rubygems'
5
+ require 'daemons'
6
+
7
+ require 'irc_machine/cli_shared'
8
+
9
+ daemon_defaults = {
10
+ :app_name => 'irc_machine',
11
+ :dir_mode => :normal,
12
+ :dir => ".",
13
+ :multiple => false,
14
+ :backtrace => true,
15
+ :monitor => false,
16
+ :log_dir => File.expand_path("../../log", __FILE__),
17
+ :log_output => true
18
+ }
19
+
20
+ IRC_MACHINE[:daemon] ||= {}
21
+
22
+ daemon_params = daemon_defaults.merge(IRC_MACHINE[:daemon])
23
+
24
+ FileUtils.mkdir_p(daemon_params[:log_dir])
25
+
26
+ Daemons.run(File.expand_path("../irc_machine", __FILE__), daemon_params)
@@ -0,0 +1,13 @@
1
+ {
2
+ "server": "localhost",
3
+ "port": 6667,
4
+ "nick": "im",
5
+ "user": "irc_machine",
6
+ "realname": "IRC Machine",
7
+ "channels": [ "#irc_machine", "#secret the_key" ],
8
+ "verbose": true,
9
+ "udp_port": 8421,
10
+ "http_port": 8421,
11
+ "bind_address": "127.0.0.1",
12
+ "ssl": false
13
+ }
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "irc_machine/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "irc_machine"
7
+ s.version = IrcMachine::VERSION
8
+ s.authors = ["Paul Annesley"]
9
+ s.email = ["paul@annesley.cc"]
10
+ s.homepage = "https://github.com/pda/irc_machine"
11
+ s.summary = %q{irc machine}
12
+ s.description = %q{An IRC bot using EventMachine, and perhaps ØMQ one day.}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency "eventmachine"
20
+ s.add_dependency "eventmachine_httpserver"
21
+ s.add_dependency "rack"
22
+ s.add_dependency "daemons"
23
+
24
+ s.add_development_dependency "bundler"
25
+ s.add_development_dependency "rake"
26
+
27
+ end
@@ -0,0 +1,21 @@
1
+ %w{
2
+ ostruct
3
+ eventmachine
4
+ evma_httpserver
5
+ evma_httpserver/response
6
+ rack
7
+ }.each do |name|
8
+ require name
9
+ end
10
+
11
+ %w{
12
+ commands
13
+ irc_connection
14
+ session
15
+ state
16
+ plugin
17
+ plugin/base
18
+ plugin/reloader
19
+ }.each do |name|
20
+ require "irc_machine/#{name}"
21
+ end
@@ -0,0 +1,6 @@
1
+ require "json"
2
+ require 'irc_machine/monkey_patches'
3
+ require 'irc_machine'
4
+
5
+ ENV['IRC_MACHINE_CONF'] ||= File.expand_path("./irc_machine.json")
6
+ IRC_MACHINE = JSON.load(open(ENV['IRC_MACHINE_CONF'])).symbolize_keys
@@ -0,0 +1,38 @@
1
+ module IrcMachine
2
+ module Commands
3
+
4
+ def raw(raw)
5
+ puts ">> #{raw}"
6
+ irc_connection.send_data "#{raw}\r\n"
7
+ end
8
+
9
+ def user(user, name)
10
+ raw "USER #{user} 8 * :#{name}"
11
+ end
12
+
13
+ def password(password)
14
+ raw "PASS #{password}"
15
+ end
16
+
17
+ def nick(nick)
18
+ raw "NICK #{nick}"
19
+ end
20
+
21
+ def join(channel, key = nil)
22
+ raw "JOIN #{channel}".tap { |c| c << " #{key}" if key }
23
+ end
24
+
25
+ def part(channel)
26
+ raw "PART #{channel}"
27
+ end
28
+
29
+ def quit(reason)
30
+ raw "QUIT :#{reason}"
31
+ end
32
+
33
+ def msg(to, text)
34
+ raw "PRIVMSG #{to} :#{text}"
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,32 @@
1
+ module IrcMachine
2
+ module Controller
3
+ class ChannelsController < HttpController
4
+
5
+ def list
6
+ content_type "application/json"
7
+ ok session.state.channels.to_json << "\n"
8
+ end
9
+
10
+ def join
11
+ session.join channel(match), request.GET["key"]
12
+ end
13
+
14
+ def part
15
+ session.part channel(match)
16
+ end
17
+
18
+ def message
19
+ input = request.body.gets
20
+ source = request.env["HTTP_X_AUTH"] || request.ip || "unknown"
21
+ session.msg channel(match), "[#{source}] #{input.chomp}" if input
22
+ end
23
+
24
+ private
25
+
26
+ def channel(match)
27
+ "#" + match[1]
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,12 @@
1
+ module IrcMachine
2
+ module Controller
3
+ class GithubNotificationsController < HttpController
4
+
5
+ def notify
6
+ session.msg "##{match[1]}",
7
+ Plugin::GithubNotification.new(request.body.read).message
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,54 @@
1
+ module IrcMachine
2
+ class Core < Plugin::Base
3
+
4
+ def connected
5
+ session.password options.password unless options.password.nil?
6
+ session.user options.user, options.realname
7
+ session.nick options.nick
8
+ session.state.nick = options.nick
9
+ EM::add_timer(5) do
10
+ options.channels.each { |c| session.join *c.split } if options.channels
11
+ end
12
+ end
13
+
14
+ def terminate
15
+ session.quit "shutting down"
16
+ end
17
+
18
+ def receive_line(line)
19
+
20
+ puts "[core] << #{line}" if options.verbose
21
+
22
+ case line
23
+
24
+ when /^PING (.*)/
25
+ session.raw "PONG #{$1}"
26
+
27
+ when /^:#{self_pattern} JOIN :(\S+)/
28
+ channels << $1
29
+
30
+ when /^:#{self_pattern} PART :(\S+)/
31
+ channels.delete $1
32
+
33
+ when /^:\S+ 475 \S+ (\S+) :(.*)$/
34
+ puts "[core] #{$1}: #{$2}"
35
+
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def options
42
+ session.options
43
+ end
44
+
45
+ def self_pattern
46
+ Regexp.escape(session.state.nick) + '!\S+@\S+'
47
+ end
48
+
49
+ def channels
50
+ session.state.channels
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ module IrcMachine
2
+ module CoreRoutes
3
+
4
+ CHANNEL_REGEXP ||= %r{^/channels/([\w-]+)$}
5
+
6
+ def draw_routes
7
+ get "/channels", "ChannelsController#list"
8
+ put CHANNEL_REGEXP, "ChannelsController#join"
9
+ delete CHANNEL_REGEXP, "ChannelsController#part"
10
+ post CHANNEL_REGEXP, "ChannelsController#message"
11
+
12
+ post %r{^/channels/([\w-]+)/github$}, "GithubNotificationsController#notify"
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module IrcMachine
2
+ class HttpController
3
+
4
+ def self.dispatch(session, request, method, match)
5
+ new(session, request, match).tap do |c|
6
+ c.send method
7
+ end.response
8
+ end
9
+
10
+ def initialize(session, request, match)
11
+ @session = session
12
+ @request = request
13
+ @match = match
14
+ @response = Rack::Response.new
15
+ end
16
+
17
+ attr_reader :session
18
+ attr_reader :request, :response
19
+ attr_reader :match
20
+
21
+ def ok(content)
22
+ @response.status = 200
23
+ @response.write content
24
+ end
25
+
26
+ def not_found
27
+ @response.status = 404
28
+ end
29
+
30
+ def content_type(type)
31
+ @response["Content-Type"] = type
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,66 @@
1
+ require "evma_httpserver/response"
2
+ require "stringio"
3
+
4
+ module IrcMachine
5
+ class HttpRouter
6
+
7
+ include CoreRoutes
8
+
9
+ def initialize(session)
10
+ @session = session
11
+ @routes = { get: [], put: [], delete:[], post: [] }
12
+ draw_routes
13
+ end
14
+
15
+ def route(env)
16
+ request = Rack::Request.new(env)
17
+
18
+ match = lookup_route_match(request.request_method, request.path)
19
+
20
+ puts "%s %s %s => %s" % [
21
+ self.class,
22
+ request.request_method,
23
+ request.path,
24
+ match.destination.inspect
25
+ ]
26
+
27
+ response = case match.destination
28
+ when String
29
+ name, method = match.destination.split("#")
30
+ klass = IrcMachine::Controller.const_get(name)
31
+ klass.dispatch(@session, request, method, match.match)
32
+ else
33
+ Rack::Response.new "Unhandled destination: #{match.destination.class}", 500
34
+ end
35
+
36
+ response.finish
37
+ end
38
+
39
+ def get(route, destination); connect :get, route, destination; end
40
+ def put(route, destination); connect :put, route, destination; end
41
+ def delete(route, destination); connect :delete, route, destination; end
42
+ def post(route, destination); connect :post, route, destination; end
43
+
44
+ def connect(method, pattern, destination)
45
+ @routes[method] << [ pattern, destination ]
46
+ end
47
+
48
+ private
49
+
50
+ def lookup_route_match(request_method, path)
51
+ # this is pretty bad..
52
+ request_method = request_method.downcase.to_sym
53
+ route_match = OpenStruct.new
54
+ _, route_match.destination = @routes[request_method].detect do |(pattern,destination)|
55
+ if pattern.is_a? Regexp
56
+ route_match.match = pattern.match(path)
57
+ else
58
+ route_match.match = nil
59
+ pattern == path
60
+ end
61
+ end
62
+ route_match
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,74 @@
1
+ require "socket"
2
+
3
+ module IrcMachine
4
+
5
+ class HttpServer < EM::Connection
6
+
7
+ include EM::HttpServer
8
+
9
+ attr_accessor :router
10
+
11
+ def process_http_request
12
+ send_response(*router.route(rack_env))
13
+ rescue => e
14
+ puts "!! #{self.class} rescued #{e.inspect}"
15
+ puts " " + e.backtrace.join("\n ")
16
+ send_response 500, {}, [ e.inspect, "\n" ]
17
+ end
18
+
19
+ def send_response(status, headers, body)
20
+ EM::DelegatedHttpResponse.new(self).tap do |r|
21
+ r.status = status
22
+ r.headers = headers
23
+ # Rack body is only guaranteed to respond to #each
24
+ r.content = "".tap { |c| body.each { |b| c << b } }
25
+ r.send_response
26
+ end
27
+ end
28
+
29
+ def rack_env
30
+ # TODO: map headers to HTTP_... keys.
31
+ {
32
+ "rack.version" => [1, 1],
33
+ "rack.url_scheme" => @http_protocol,
34
+ "rack.input" => StringIO.new((@http_post_content || "")),
35
+ "rack.errors" => open("/dev/null", "w"), # muahaha
36
+ "rack.multithread" => false,
37
+ "rack.multiprocess" => false,
38
+ "rack.run_once" => false,
39
+
40
+ "REQUEST_METHOD" => @http_request_method,
41
+ "SCRIPT_NAME" => "", # see PATH_INFO
42
+ "PATH_INFO" => @http_path_info,
43
+ "QUERY_STRING" => @http_query_string,
44
+ "SERVER_NAME" => nil, # illegally nil
45
+ "SERVER_PORT" => nil, # illegally nil
46
+ "REMOTE_ADDR" => remote_ip, # not in spec
47
+
48
+ "HTTP_COOKIE" => @http_cookie,
49
+ "HTTP_IF_NONE_MATCH" => @http_if_none_match,
50
+ "HTTP_CONTENT_TYPE" => @http_content_type,
51
+ "HTTP_X_AUTH" => headers["X-Auth"],
52
+ }
53
+ end
54
+
55
+ def remote_ip
56
+ port, ip = Socket.unpack_sockaddr_in(get_peername)
57
+ ip
58
+ end
59
+
60
+ def headers
61
+ @headers ||= parse_headers(@http_headers)
62
+ end
63
+
64
+ # ghetto
65
+ def parse_headers(header)
66
+ header.split("\x00").inject({}) do |headers, line|
67
+ headers[$1] = $2 if line =~ /^([^:]+):\s*(.*)$/
68
+ headers
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,50 @@
1
+ module IrcMachine
2
+ class IrcConnection < EM::Connection
3
+ include EM::Protocols::LineText2
4
+
5
+ def initialize(opts)
6
+ @ssl = opts[:ssl]
7
+ @session = opts[:session]
8
+ end
9
+
10
+ alias_method :orig_post_init, :post_init
11
+
12
+ def post_init
13
+ if @ssl
14
+ @session.log "Initializing SSL connection"
15
+ @ssl_buffer = ""
16
+ start_tls
17
+ else
18
+ orig_post_init
19
+ end
20
+ end
21
+
22
+ def ssl_handshake_completed
23
+ @session.log "SSL handshake complete"
24
+ orig_post_init
25
+ buffer = @ssl_buffer
26
+ @ssl_buffer = nil
27
+ send_data buffer
28
+ end
29
+
30
+ def send_data(data)
31
+ if @ssl_buffer
32
+ @ssl_buffer << data
33
+ else
34
+ super(data)
35
+ end
36
+ end
37
+
38
+ def receive_line(line)
39
+ @session.receive_line(line)
40
+ rescue => e
41
+ @session.log "!! #{self.class} rescued #{e.inspect}"
42
+ @session.log(" " + e.backtrace.join("\n "))
43
+ end
44
+
45
+ def unbind
46
+ @session.log "Disconnected"
47
+ @session.disconnected
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,13 @@
1
+ class Hash
2
+ def symbolize_keys
3
+ inject({}) do |h, (k,v)|
4
+ h[k.to_sym] = case v
5
+ when Hash
6
+ v.symbolize_keys
7
+ else
8
+ v
9
+ end
10
+ h
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ module IrcMachine
2
+ module Plugin
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ module IrcMachine
2
+ module Plugin
3
+ class Base
4
+ def initialize(session)
5
+ @session = session
6
+ end
7
+ attr_reader :session
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,58 @@
1
+ require "json"
2
+ require "cgi"
3
+ require "ostruct"
4
+
5
+ module IrcMachine
6
+ module Plugin
7
+
8
+ class GithubNotifier < Plugin::Base
9
+ end
10
+
11
+ class GithubNotification
12
+
13
+ attr_reader :data
14
+
15
+ def initialize(body)
16
+ json = CGI.parse(body)["payload"][0]
17
+ @data = OpenStruct.new(JSON.parse(json))
18
+ end
19
+
20
+ def repo_name
21
+ data.repository["name"]
22
+ end
23
+
24
+ def commit_count
25
+ data.commits.size
26
+ end
27
+
28
+ def branch
29
+ data.ref.split("/").last
30
+ end
31
+
32
+ def authors
33
+ data.commits.map{ |c| OpenStruct.new c["author"] }
34
+ end
35
+
36
+ def author_usernames
37
+ authors.map{ |a| a.username }.uniq
38
+ end
39
+
40
+ def compare_url
41
+ data.compare
42
+ end
43
+
44
+ def message
45
+ "%d commit%s by %s pushed to %s/%s: %s" % [
46
+ commit_count,
47
+ commit_count == 1 ? "" : "s",
48
+ author_usernames.join(", "),
49
+ repo_name,
50
+ branch,
51
+ compare_url
52
+ ]
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,7 @@
1
+ class IrcMachine::Plugin::Hello < IrcMachine::Plugin::Base
2
+ def receive_line(line)
3
+ if line =~ /^:\S+ PRIVMSG (#+\S+) :hello$/
4
+ session.msg $1, "world"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ class IrcMachine::Plugin::Reloader < IrcMachine::Plugin::Base
2
+
3
+ def receive_line(line)
4
+ if line =~ /^:\S+ PRIVMSG #{session.state.nick} :reload$/
5
+ self.class.load_all
6
+ end
7
+ end
8
+
9
+ def self.load_all
10
+ files = %w{
11
+ core
12
+ core_routes
13
+
14
+ udp_server
15
+
16
+ http_controller
17
+ http_router
18
+ http_server
19
+
20
+ controller/channels_controller
21
+ controller/github_notifications_controller
22
+
23
+ plugin/github_notifier
24
+ plugin/base
25
+ plugin/hello
26
+ plugin/reloader
27
+ }.each do |name|
28
+ puts "loading: #{name}"
29
+ load "irc_machine/#{name}.rb"
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,97 @@
1
+ module IrcMachine
2
+ class Session
3
+ include Commands
4
+
5
+ attr_reader :options
6
+ attr_reader :state
7
+ attr_accessor :irc_connection
8
+
9
+ def initialize(options)
10
+ IrcMachine::Plugin::Reloader.load_all
11
+
12
+ @options = OpenStruct.new(options)
13
+ @state = State.new
14
+ @router = HttpRouter.new(self)
15
+ @plugins = [
16
+ Core.new(self),
17
+ Plugin::Hello.new(self),
18
+ Plugin::Reloader.new(self),
19
+ Plugin::GithubNotifier.new(self)
20
+ ]
21
+ end
22
+
23
+ def start
24
+ EM.run do
25
+
26
+ signal_traps
27
+
28
+ log "Connecting to #{options.server}:#{options.port}"
29
+ EM.connect(
30
+ options.server,
31
+ options.port,
32
+ IrcConnection,
33
+ {:ssl => @options.ssl, :session => self}
34
+ ) do |c|
35
+ self.irc_connection = c
36
+ end
37
+
38
+ log "Starting HTTP API on port #{options.http_port}"
39
+ EM.start_server "0.0.0.0", options.http_port, HttpServer do |c|
40
+ c.router = @router
41
+ end
42
+
43
+ log "Starting UDP API on port #{options.udp_port}"
44
+ EM.open_datagram_socket "0.0.0.0", options.udp_port, UdpServer do |c|
45
+ c.session = self
46
+ end
47
+
48
+ dispatch :connected
49
+ end
50
+ end
51
+
52
+ def disconnected
53
+ if @shutdown
54
+ log "Stopping EventMachine"
55
+ EM.stop
56
+ else
57
+ log "Waiting to reconnect"
58
+ EM.add_timer(2) do
59
+ log "Reconnecting to #{options.server}:#{options.port}"
60
+ irc_connection.reconnect options.server, options.port
61
+ @state.reset
62
+ dispatch :connected
63
+ end
64
+ end
65
+ end
66
+
67
+ def receive_line(line)
68
+ dispatch :receive_line, line
69
+ end
70
+
71
+ def log message
72
+ puts "! " << message if options.verbose
73
+ end
74
+
75
+ private
76
+
77
+ def dispatch(method, *params)
78
+ @plugins.each { |p| p.send(method, *params) if p.respond_to? method }
79
+ end
80
+
81
+ def signal_traps
82
+ Signal.trap("INT") { shutdown }
83
+ end
84
+
85
+ def shutdown
86
+ @shutdown = true
87
+ Signal.trap("INT") do
88
+ Signal.trap("INT", "DEFAULT")
89
+ puts "\nStopping EventMachine, interrupt again to force exit"
90
+ EM.stop
91
+ end
92
+ puts "\nQuitting IRC, interrupt again to stop EventMachine"
93
+ dispatch :terminate
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,21 @@
1
+ module IrcMachine
2
+ class State
3
+
4
+ attr_accessor :nick
5
+ attr_accessor :channels
6
+
7
+ def initialize
8
+ reset
9
+ end
10
+
11
+ def reset
12
+ @nick = nil
13
+ @channels = []
14
+ end
15
+
16
+ def channel?(channel)
17
+ channels.include? channel
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ module IrcMachine
2
+
3
+ class UdpServer < EM::Connection
4
+
5
+ attr_writer :session
6
+
7
+ def receive_data(data)
8
+ if data =~ /^PRIVMSG (#+\S+) :(.{1,1024})/
9
+ @session.msg $1, $2
10
+ else
11
+ puts "Unrecognized UDP: " << data.inspect
12
+ end
13
+ rescue => e
14
+ puts "!! #{self.class} rescued #{e.inspect}"
15
+ puts " " + e.backtrace.join("\n ")
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,3 @@
1
+ module IrcMachine
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: irc_machine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Paul Annesley
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: eventmachine
16
+ requirement: &70147236217340 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70147236217340
25
+ - !ruby/object:Gem::Dependency
26
+ name: eventmachine_httpserver
27
+ requirement: &70147236216920 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70147236216920
36
+ - !ruby/object:Gem::Dependency
37
+ name: rack
38
+ requirement: &70147236216500 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70147236216500
47
+ - !ruby/object:Gem::Dependency
48
+ name: daemons
49
+ requirement: &70147236216080 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70147236216080
58
+ - !ruby/object:Gem::Dependency
59
+ name: bundler
60
+ requirement: &70147236215660 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70147236215660
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: &70147236215240 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70147236215240
80
+ description: An IRC bot using EventMachine, and perhaps ØMQ one day.
81
+ email:
82
+ - paul@annesley.cc
83
+ executables:
84
+ - irc_machine
85
+ - irc_machined
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - .gitignore
90
+ - .rvmrc
91
+ - Gemfile
92
+ - README.md
93
+ - Rakefile
94
+ - bin/irc_machine
95
+ - bin/irc_machined
96
+ - example.json
97
+ - irc_machine.gemspec
98
+ - lib/irc_machine.rb
99
+ - lib/irc_machine/cli_shared.rb
100
+ - lib/irc_machine/commands.rb
101
+ - lib/irc_machine/controller/channels_controller.rb
102
+ - lib/irc_machine/controller/github_notifications_controller.rb
103
+ - lib/irc_machine/core.rb
104
+ - lib/irc_machine/core_routes.rb
105
+ - lib/irc_machine/http_controller.rb
106
+ - lib/irc_machine/http_router.rb
107
+ - lib/irc_machine/http_server.rb
108
+ - lib/irc_machine/irc_connection.rb
109
+ - lib/irc_machine/monkey_patches.rb
110
+ - lib/irc_machine/plugin.rb
111
+ - lib/irc_machine/plugin/base.rb
112
+ - lib/irc_machine/plugin/github_notifier.rb
113
+ - lib/irc_machine/plugin/hello.rb
114
+ - lib/irc_machine/plugin/reloader.rb
115
+ - lib/irc_machine/session.rb
116
+ - lib/irc_machine/state.rb
117
+ - lib/irc_machine/udp_server.rb
118
+ - lib/irc_machine/version.rb
119
+ homepage: https://github.com/pda/irc_machine
120
+ licenses: []
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ none: false
127
+ requirements:
128
+ - - ! '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 1.8.11
140
+ signing_key:
141
+ specification_version: 3
142
+ summary: irc machine
143
+ test_files: []
144
+ has_rdoc: