coffeemaker 0.0.1.beta.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in coffeemaker.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/coffeemaker ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'coffeemaker/runner'
4
+
5
+ cm = Coffeemaker::Runner.new(ARGV)
6
+ cm.start
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "coffeemaker/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "coffeemaker"
7
+ s.version = Coffeemaker::VERSION
8
+ s.authors = ["Paweł Pacana"]
9
+ s.email = ["pawel.pacana@gmail.com"]
10
+ s.homepage = "http://drug.org.pl/projects/coffeemaker"
11
+ s.summary = %q{IRC bot, how unexpected!}
12
+ s.description = %q{IRC bot that serves as foundation for greater ideas. "Not Invented Here" applies greatly.}
13
+
14
+ s.rubyforge_project = "coffeemaker"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency "eventmachine", "~> 1.0.0.beta.3"
22
+ s.add_runtime_dependency "activesupport"
23
+ end
data/goliath.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'goliath/connection'
2
+ require 'goliath/api'
3
+
4
+ module Goliath
5
+ module Constants
6
+ IRC_CONNECTION = 'IRC_CONNECTION'
7
+ end
8
+
9
+ class Request
10
+ alias_method :initialize_without_irc, :initialize
11
+
12
+ def initialize(app, conn, env)
13
+ initialize_without_irc(app, conn, env)
14
+ env[IRC_CONNECTION] = conn.irc
15
+ end
16
+ end
17
+ end
18
+
data/http.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'coffeemaker'
2
+ require 'coffeemaker/goliath'
3
+ require 'json'
4
+
5
+ module Coffeemaker
6
+ class HTTP
7
+ class Connection < Goliath::Connection
8
+ attr_accessor :irc
9
+ end
10
+
11
+ class Router < Goliath::API
12
+ get '/:channel' do
13
+ run Stream.new
14
+ end
15
+ end
16
+
17
+ class Stream < Goliath::API
18
+ def on_close(env)
19
+ env[IRC_CONNECTION].part(env[:channel])
20
+ end
21
+
22
+ def response(env)
23
+ env[:channel] = params[:channel]
24
+ env[IRC_CONNECTION].join(env[:channel])
25
+
26
+ env[IRC_CONNECTION].on_message = Proc.new do |msg|
27
+ env.stream_send("#{msg.to_json}\n")
28
+ end
29
+ streaming_response(202, {'X-Stream' => 'Goliath'})
30
+ end
31
+ end
32
+
33
+ def initialize(options)
34
+ @host = options.delete(:http_host)
35
+ @port = options.delete(:http_port)
36
+ @options = options
37
+ end
38
+
39
+ def start(irc_connection)
40
+ Goliath.env = :production
41
+ @http = EM.start_server(@host, @port, Coffeemaker::HTTP::Connection) do |c|
42
+ c.port = 8080
43
+ c.irc = irc_connection
44
+ c.status = {}
45
+ c.config = {}
46
+ c.options = {}
47
+ c.logger = Logger.new(STDOUT)
48
+ c.app = Goliath::Rack::Builder.build(Coffeemaker::HTTP::Router, Coffeemaker::HTTP::Router.new)
49
+ c.api = Coffeemaker::HTTP::Stream.new
50
+ end
51
+ end
52
+
53
+ def stop
54
+ EM.stop_server(@http)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,21 @@
1
+ require 'coffeemaker/bot/irc'
2
+
3
+ module Coffeemaker
4
+ class Bot
5
+ class Irc
6
+ module Commands
7
+ def join(channel)
8
+ send_command :join, channel
9
+ end
10
+
11
+ def part(channel)
12
+ send_command :part, channel
13
+ end
14
+
15
+ def message(recipient, text)
16
+ send_command :privmsg, recipient, ":#{text}"
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,61 @@
1
+ require 'coffeemaker/bot/irc'
2
+ require 'coffeemaker/bot/irc/message'
3
+ require 'coffeemaker/bot/irc/commands'
4
+ require 'eventmachine'
5
+
6
+ module Coffeemaker
7
+ class Bot
8
+ class Irc
9
+ module Connection
10
+ class Error < StandardError; end
11
+
12
+ include ::EM::Deferrable
13
+ include ::EM::Protocols::LineText2
14
+ include ::Coffeemaker::Bot::Irc::Commands
15
+
16
+ attr_accessor :port, :host, :options, :on_message
17
+
18
+ def connection_completed
19
+ @reconnecting = false
20
+ @connected = true
21
+ _send_command :user, [options[:nick]] * 4
22
+ _send_command :nick, options[:nick]
23
+ succeed
24
+ end
25
+
26
+ def receive_line(data)
27
+ msg = ::Coffeemaker::Bot::Irc::Message.new(data)
28
+ case msg.command
29
+ when :ping
30
+ send_command :pong
31
+ when :privmsg, :topic, :part, :join
32
+ on_message.call(msg) if on_message
33
+ end
34
+ end
35
+
36
+ def unbind
37
+ @deferred_status = nil
38
+ if @connected or @reconnecting
39
+ EM.add_timer(1) do
40
+ reconnect(@host, @port)
41
+ end
42
+ @connected = false
43
+ @reconnecting = true
44
+ else
45
+ raise Error, "unable to connect to server #{@host}:#{@port}"
46
+ end
47
+ end
48
+
49
+ private
50
+ def _send_command(name, *args)
51
+ cmd = [name.to_s.upcase] + args
52
+ send_data("#{cmd.flatten.join(' ')}\r\n")
53
+ end
54
+
55
+ def send_command(name, *args)
56
+ callback { _send_command(name, *args) }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,96 @@
1
+ require 'coffeemaker'
2
+
3
+ module Coffeemaker
4
+ class Bot
5
+ class Irc
6
+ class Message
7
+ attr_accessor :raw, :prefix, :params
8
+
9
+ def initialize(msg = nil)
10
+ @raw = msg
11
+ parse if msg
12
+ end
13
+
14
+ def numeric_reply?
15
+ !!numeric_reply
16
+ end
17
+
18
+ def numeric_reply
19
+ @numeric_reply ||= @command.match(/^\d\d\d$/)
20
+ end
21
+
22
+ def nick
23
+ return unless @prefix
24
+ @nick ||= @prefix[/^(\S+)!/, 1]
25
+ end
26
+
27
+ def user
28
+ return unless @prefix
29
+ @user ||= @prefix[/^\S+!(\S+)@/, 1]
30
+ end
31
+
32
+ def host
33
+ return unless @prefix
34
+ @host ||= @prefix[/@(\S+)$/, 1]
35
+ end
36
+
37
+ def server
38
+ return unless @prefix
39
+ return if @prefix.match(/[@!]/)
40
+ @server ||= @prefix[/^(\S+)/, 1]
41
+ end
42
+
43
+ def error?
44
+ !!error
45
+ end
46
+
47
+ def error
48
+ return @error if @error
49
+ @error = @command.to_i if numeric_reply? && @command[/[45]\d\d/]
50
+ end
51
+
52
+ def channel?
53
+ !!channel
54
+ end
55
+
56
+ def channel
57
+ return @channel if @channel
58
+ if regular_command? and params.first.start_with?("#")
59
+ @channel = params.first
60
+ end
61
+ end
62
+
63
+ def message
64
+ return @message if @message
65
+ if error?
66
+ @message = error.to_s
67
+ elsif regular_command?
68
+ @message = params.last
69
+ end
70
+ end
71
+
72
+ def command
73
+ @command.downcase.to_sym
74
+ end
75
+
76
+ private
77
+ def parse
78
+ match = @raw.match(/(^:(\S+) )?(\S+)(.*)/)
79
+ _, @prefix, @command, raw_params = match.captures
80
+
81
+ raw_params.strip!
82
+ if match = raw_params.match(/:(.*)/)
83
+ @params = match.pre_match.split(" ")
84
+ @params << match[1]
85
+ else
86
+ @params = raw_params.split(" ")
87
+ end
88
+ end
89
+
90
+ def regular_command?
91
+ %w(privmsg join part quit).include? @command.downcase
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,35 @@
1
+ require 'coffeemaker/bot'
2
+ require 'coffeemaker/bot/irc/connection'
3
+ require 'active_support/core_ext/module/delegation'
4
+
5
+ module Coffeemaker
6
+ class Bot
7
+ class Irc
8
+ include EM::Deferrable
9
+
10
+ attr_reader :connection
11
+ delegate :join, :part, :privmsg, to: :connection
12
+
13
+ def initialize(options)
14
+ @host = options.delete(:irc_host)
15
+ @port = options.delete(:irc_port)
16
+ @callback = options.delete(:on_message)
17
+ @options = options
18
+ end
19
+
20
+ def start
21
+ @connection = EM.connect(@host, @port, Connection) do |c|
22
+ c.host = @host
23
+ c.port = @port
24
+ c.on_message = @callback
25
+ c.options = @options
26
+ c.callback { succeed }
27
+ end
28
+ end
29
+
30
+ def stop
31
+ @connection.close_connection
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ require 'coffeemaker/bot/irc'
2
+
3
+ module Coffeemaker
4
+ class Bot
5
+ def initialize(options)
6
+ @irc = Irc.new(options)
7
+ end
8
+
9
+ def start(&block)
10
+ @irc.start.callback do
11
+ block.call(@irc) if block_given?
12
+ end
13
+ end
14
+
15
+ def stop
16
+ @irc.stop
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,62 @@
1
+ require 'coffeemaker/bot'
2
+ require 'eventmachine'
3
+ require 'optparse'
4
+ require 'logger'
5
+
6
+ module Coffeemaker
7
+ class Runner
8
+ def initialize(argv)
9
+ @options = default_options
10
+ parse_options!(argv)
11
+
12
+ if logfile = @options.delete(:logfile)
13
+ @logger = Logger.new(logfile =~ /stdout/i ? STDOUT : logfile)
14
+ end
15
+ @channels = @options.delete(:channels)
16
+ end
17
+
18
+ def start
19
+ EM.run do
20
+ bot = Coffeemaker::Bot.new(@options)
21
+ bot.start do |irc|
22
+ @channels.each { |channel| irc.join(channel) }
23
+ end
24
+
25
+ trap ("INT") do
26
+ bot.stop
27
+ EM.stop
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+ def default_options
34
+ {
35
+ irc_host: 'localhost',
36
+ irc_port: 6667,
37
+ nick: 'coffeemaker',
38
+ channels: [],
39
+ on_message: Proc.new { |msg| @logger.info(msg) if @logger }
40
+ }
41
+ end
42
+
43
+ def parse_options!(argv)
44
+ OptionParser.new do |option|
45
+ option.default_argv = argv
46
+ option.banner = "Usage: coffeemaker [options]"
47
+ option.on('-n NICK') { |nick| @options[:nick] = nick }
48
+ option.on('-p PORT', Numeric) { |port| @options[:irc_port] = port }
49
+ option.on('-s HOST') { |host| @options[:irc_host] = host }
50
+ option.on('-c CHANNELS', 'comma-separated list of channels') { |channels| @options[:channels] = channels.split }
51
+ option.on('-l LOG_FILE', 'path to log file or STDOUT') { |logfile| @options[:logfile] = logfile }
52
+ option.on('--help') { puts option; exit }
53
+ begin
54
+ option.parse!
55
+ rescue OptionParser::RequiredArgument, OptionParser::InvalidOption
56
+ puts option
57
+ exit
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ module Coffeemaker
2
+ VERSION = "0.0.1.beta.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ require 'coffeemaker/version'
2
+
3
+ module Coffeemaker
4
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: coffeemaker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.beta.1
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Paweł Pacana
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-28 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: eventmachine
16
+ requirement: &23452580 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0.beta.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *23452580
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ requirement: &23450520 !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: *23450520
36
+ description: IRC bot that serves as foundation for greater ideas. "Not Invented Here"
37
+ applies greatly.
38
+ email:
39
+ - pawel.pacana@gmail.com
40
+ executables:
41
+ - coffeemaker
42
+ extensions: []
43
+ extra_rdoc_files: []
44
+ files:
45
+ - .gitignore
46
+ - Gemfile
47
+ - Rakefile
48
+ - bin/coffeemaker
49
+ - coffeemaker.gemspec
50
+ - goliath.rb
51
+ - http.rb
52
+ - lib/coffeemaker.rb
53
+ - lib/coffeemaker/bot.rb
54
+ - lib/coffeemaker/bot/irc.rb
55
+ - lib/coffeemaker/bot/irc/commands.rb
56
+ - lib/coffeemaker/bot/irc/connection.rb
57
+ - lib/coffeemaker/bot/irc/message.rb
58
+ - lib/coffeemaker/runner.rb
59
+ - lib/coffeemaker/version.rb
60
+ homepage: http://drug.org.pl/projects/coffeemaker
61
+ licenses: []
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>'
76
+ - !ruby/object:Gem::Version
77
+ version: 1.3.1
78
+ requirements: []
79
+ rubyforge_project: coffeemaker
80
+ rubygems_version: 1.8.10
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: IRC bot, how unexpected!
84
+ test_files: []
85
+ has_rdoc: