irc_machine 0.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.
@@ -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: