hipbot 0.0.3 → 0.0.5

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.
data/.travis.yml CHANGED
@@ -2,3 +2,9 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.2
4
4
  - 1.9.3
5
+ notifications:
6
+ email:
7
+ recipients:
8
+ - pewniak747@gmail.com
9
+ - bartosz.kopinski@netguru.pl
10
+
data/Gemfile CHANGED
@@ -11,6 +11,3 @@ gem 'daemons'
11
11
 
12
12
  gem 'rspec'
13
13
  gem 'mocha'
14
-
15
- # Plugins
16
- gem 'google-weather'
data/Gemfile.lock CHANGED
@@ -14,8 +14,6 @@ GEM
14
14
  eventmachine (>= 0.12.9)
15
15
  escape_utils (0.2.4)
16
16
  eventmachine (0.12.10)
17
- google-weather (0.3.0)
18
- httparty (~> 0.5.0)
19
17
  httparty (0.5.2)
20
18
  crack (= 0.1.6)
21
19
  i18n (0.6.0)
@@ -23,14 +21,14 @@ GEM
23
21
  mocha (0.11.4)
24
22
  metaclass (~> 0.0.1)
25
23
  rake (0.9.2.2)
26
- rspec (2.10.0)
27
- rspec-core (~> 2.10.0)
28
- rspec-expectations (~> 2.10.0)
29
- rspec-mocks (~> 2.10.0)
30
- rspec-core (2.10.1)
31
- rspec-expectations (2.10.0)
24
+ rspec (2.11.0)
25
+ rspec-core (~> 2.11.0)
26
+ rspec-expectations (~> 2.11.0)
27
+ rspec-mocks (~> 2.11.0)
28
+ rspec-core (2.11.1)
29
+ rspec-expectations (2.11.2)
32
30
  diff-lcs (~> 1.1.3)
33
- rspec-mocks (2.10.1)
31
+ rspec-mocks (2.11.1)
34
32
  xmpp4r (0.5)
35
33
 
36
34
  PLATFORMS
@@ -41,7 +39,6 @@ DEPENDENCIES
41
39
  daemons
42
40
  em-http-request
43
41
  eventmachine
44
- google-weather
45
42
  httparty
46
43
  i18n
47
44
  mocha
data/README.md CHANGED
@@ -4,16 +4,16 @@
4
4
 
5
5
  Hipbot is a bot for HipChat, written in ruby & eventmachine.
6
6
 
7
- This is a work in progress.
8
-
9
7
  ## Usage
10
8
 
11
- Install via RubyGems
9
+ ### Install
12
10
 
13
11
  ```
14
12
  gem install hipbot
15
13
  ```
16
14
 
15
+ ### Customize
16
+
17
17
  In bot.rb file, subclass Hipbot::Bot and customize robot responses.
18
18
 
19
19
  ``` ruby
@@ -26,28 +26,114 @@ class MyCompanyBot < Hipbot::Bot
26
26
  c.password = 'secret'
27
27
  end
28
28
 
29
- # simple reply to '@robot hello!'
30
29
  on /^hello.*/ do
31
30
  reply('hello!')
32
31
  end
32
+ end
33
+
34
+ MyCompanyBot.start!
35
+ ```
36
+
37
+ You can create a response by providing simple regexp:
38
+
39
+ ``` ruby
40
+ on /^hello.*/ do
41
+ reply('hello!')
42
+ end
43
+ ```
44
+
45
+ Responses can pass arguments from regexps:
46
+
47
+ ``` ruby
48
+ on /my name is (.*)/ do |user_name|
49
+ reply('hello #{user_name}!')
50
+ end
51
+ ```
52
+
53
+ Define multiple regexps for a response:
54
+
55
+ ``` ruby
56
+ on /my name is (.*)/, /I am (.*)/ do |name|
57
+ reply('hello #{user_name}!')
58
+ end
59
+ ```
60
+
61
+ Use :from to only match messages from certain users
62
+
63
+ ``` ruby
64
+ on /status report/, :from => ['tom', 'dave'] do
65
+ reply('all clear')
66
+ end
67
+ ```
68
+
69
+ Use :room to only match messages in certain hipchat rooms
70
+
71
+ ``` ruby
72
+ on /hello/, :room => ['public'] do
73
+ reply('hello!')
74
+ end
75
+ ```
76
+
77
+ Use :global to react to messages that are not sent directly to @robot
78
+
79
+ ``` ruby
80
+ on /hey I just met you/, :global => true do
81
+ reply('and this is crazy...')
82
+ end
83
+ ```
84
+
85
+ (Use with caution!)
86
+
87
+ #### Response helpers
88
+
89
+ Use http helpers (`get`, `post`, `put`, `delete`) to preform a http request:
33
90
 
34
- # tasks with arguments: '@robot deploy to production pls'
35
- on /deploy to (.*) pls/ do |stage|
36
- reply('deploying to #{stage}!')
37
- post("http://#{stage}.example.com") do |http|
38
- reply("deploy server responded with #{http.response_header.status}")
39
- end
91
+ ``` ruby
92
+ on /curl (\S+)/ do |url|
93
+ get url do |response|
94
+ reply(response.code)
95
+ reply(response.headers)
96
+ reply(response.body)
40
97
  end
98
+ end
99
+ ```
41
100
 
42
- # global messages
43
- on /.*hello everyone.*/, global: true do
44
- reply('hello!')
101
+ ``` ruby
102
+ on /ping site/ do
103
+ get 'http://example.com', :ping => "1" # issues http://example.com?ping=1
104
+ end
105
+ ```
106
+
107
+ Inside response you have access to following variables:
108
+
109
+ * `message.body` - sent message
110
+ * `message.sender` - user who sent message
111
+ * `message.mentions` - array of @mentions inside message, without bot
112
+ * `room.name` - name of the current room
113
+
114
+ You can define your own helpers and use them inside responses like this:
115
+
116
+ ``` ruby
117
+ module HipbotHelpers
118
+ def project_name
119
+ "#{room.name}-project"
45
120
  end
46
121
  end
47
122
 
48
- MyCompanyBot.start!
123
+ class Bot < Hipbot::Bot
124
+ configure do |c|
125
+ c.helpers = HipbotHelpers
126
+ # rest of configuration
127
+ end
128
+
129
+ on /what's the project called\?/ do
130
+ reply(project_name)
131
+ end
132
+ end
49
133
  ```
50
134
 
135
+ ### Run
136
+
51
137
  Run hipbot as daemon by saying:
52
138
 
53
139
  ```
@@ -56,13 +142,35 @@ hipbot start
56
142
 
57
143
  Run `hipbot` to see all available commands.
58
144
 
145
+ ## Deploying to Heroku
146
+
147
+ Create a Procfile & add it to your repo:
148
+
149
+ ```
150
+ worker: bundle exec hipbot run
151
+ ```
152
+
153
+ ```
154
+ heroku create
155
+ git push heroku master
156
+ heroku ps:scale web=0
157
+ heroku ps:scale worker=1
158
+ ```
159
+
59
160
  ## TODO:
60
161
 
61
- * add support for custom helpers
62
- * mentions - returns list of @mentions in message
63
- * sender_name - returns sender's first name
64
- * allow injecting custom module to response object, adding arbitrary methods
65
- * handle reconnecting after disconnect/failure
66
- * add support for multiple regexps for one response
67
- * add support for responses in particular room (`on //, :room => ['public'] do ...`)
162
+ * handle auto joining on room invite
163
+ * add database storage with postgresql adapter
164
+ * rewrite SimpleMUCClient
68
165
  * add extended logging
166
+ * handle private messages callbacks in the same way
167
+
168
+ ### Done:
169
+
170
+ * ~~add support for custom helpers~~
171
+ * ~~mentions - returns list of @mentions in message~~
172
+ * ~~sender_name - returns sender's first name~~
173
+ * ~~allow injecting custom module to response object, adding arbitrary methods~~
174
+ * ~~handle reconnecting after disconnect/failure~~
175
+ * ~~add support for multiple regexps for one response~~
176
+ * ~~add support for responses in particular room (`on //, :room => ['public'] do ...`)~~
data/bin/hipbot CHANGED
@@ -2,4 +2,11 @@
2
2
 
3
3
  require 'daemons'
4
4
 
5
- Daemons.run('bot.rb')
5
+ hipbot_file = 'bot.rb'
6
+
7
+ if File.exists?(hipbot_file)
8
+ Daemons.run(hipbot_file)
9
+ else
10
+ puts "File #{hipbot_file} not found!"
11
+ exit 1
12
+ end
data/hipbot.gemspec CHANGED
@@ -20,5 +20,6 @@ Gem::Specification.new do |gem|
20
20
  gem.add_runtime_dependency "eventmachine", ["~> 0.12.10"]
21
21
  gem.add_runtime_dependency "em-http-request", ["~> 0.3.0"]
22
22
  gem.add_runtime_dependency "xmpp4r", ["~> 0.5"]
23
- gem.add_runtime_dependency "google-weather", ["~> 0.3.0"]
23
+ gem.add_development_dependency "rspec", ['~> 2.11.0']
24
+ gem.add_development_dependency "mocha", ['~> 0.11.4']
24
25
  end
data/lib/hipbot.rb CHANGED
@@ -3,18 +3,19 @@ require 'eventmachine'
3
3
  require 'em-http-request'
4
4
  require 'xmpp4r'
5
5
  require 'xmpp4r/muc'
6
- require 'hipbot/mucclient'
7
- require 'hipbot/encoding'
8
6
 
9
- require 'hipbot/adapters/hipchat'
10
- require 'hipbot/adapters/telnet'
7
+ require 'hipbot/patches/mucclient'
8
+ require 'hipbot/patches/encoding'
9
+
10
+ require 'hipbot/adapters/hipchat/hipchat'
11
+ require 'hipbot/adapters/hipchat/connection'
12
+ require 'hipbot/adapters/telnet/telnet'
13
+ require 'hipbot/adapters/telnet/connection'
11
14
  require 'hipbot/bot'
12
15
  require 'hipbot/configuration'
13
16
  require 'hipbot/message'
14
17
  require 'hipbot/reaction'
15
18
  require 'hipbot/response'
19
+ require 'hipbot/http_response'
16
20
  require 'hipbot/room'
17
21
  require 'hipbot/version'
18
-
19
- # Plugins
20
- require 'google_weather'
@@ -0,0 +1,123 @@
1
+ module Hipbot
2
+ module Adapters
3
+ module Hipchat
4
+ class Connection
5
+ def initialize bot
6
+ initialize_bot(bot)
7
+ initialize_jabber
8
+ initialize_rooms
9
+ join_rooms
10
+ setup_timers
11
+ end
12
+
13
+ def reply room, message
14
+ send_message(room, message)
15
+ end
16
+
17
+ def restart!
18
+ leave_rooms
19
+ initialize_jabber
20
+ initialize_rooms
21
+ join_rooms
22
+ end
23
+
24
+ private
25
+
26
+ def initialize_rooms
27
+ @muc_browser = Jabber::MUC::MUCBrowser.new(@jabber)
28
+ @rooms = @muc_browser.muc_rooms('conf.hipchat.com').map { |jid, name|
29
+ ::Hipbot::Room.new(jid, name)
30
+ }
31
+ end
32
+
33
+ def initialize_bot bot
34
+ @bot = bot
35
+ @bot.connection = self
36
+ end
37
+
38
+ def initialize_jabber
39
+ @jabber ||= ::Jabber::Client.new(@bot.jid)
40
+ @jabber.connect
41
+ @jabber.auth(@bot.password)
42
+ @jabber.send(::Jabber::Presence.new.set_type(:available))
43
+ end
44
+
45
+ def join_rooms
46
+ rooms.each do |room|
47
+ puts "Joining #{room.name}"
48
+
49
+ # TODO rewrite (Simple)MUCClient to handle many rooms from one object
50
+ # as there is no need to create distinct objects and callback for each
51
+ # room since all of them have to process same data from @jabber stream.
52
+ # We probably should be able to do something like this:
53
+ # @jabber.set_presence([room1, room2], :available)
54
+ # @jabber.on_event do |time, jid, message| # JID includes sender and room/chat
55
+ # @jabber.send(jid, message)
56
+ room.connection = ::Jabber::MUC::SimpleMUCClient.new(@jabber)
57
+ room.connection.on_message do |time, sender, message|
58
+ puts "#{room.name} > #{time} <#{sender}> #{message}"
59
+ begin
60
+ @bot.tell(sender, room, message)
61
+ rescue => e
62
+ puts e.inspect
63
+ e.backtrace.each do |line|
64
+ puts line
65
+ end
66
+ end
67
+ end
68
+
69
+ # TODO Get and store all user data from HipChat API
70
+ room.users = []
71
+ room.connection.on_join do |time, nick|
72
+ room.users << nick
73
+ end
74
+ room.connection.on_leave do |time, nick|
75
+ room.users.delete(nick)
76
+ end
77
+ room.connection.join("#{room.jid}/#{@bot.name}", nil, :history => false)
78
+ end
79
+
80
+ # TODO handle sending private messages with 'reply'.
81
+ # Simplest way is to add room object for each private chat with param
82
+ # to distinguish whether to use conf or chat domain
83
+ # rooms.first.connection.on_private_message do |time, jid, message|
84
+ # send_message rooms.first, 'hello!', jid
85
+
86
+ ## Alternative sending:
87
+ # msg = ::Jabber::Message.new(jid, 'hello!')
88
+ # msg.type = :chat
89
+ # @jabber.send(msg)
90
+
91
+ ## We can trigger normal message callback but 'reply' won't work since hipchat PM uses
92
+ ## different jid (user_room@chat.hipchat.com/client_name)
93
+ # rooms.first.connection.message_block.call(time, sender, message)
94
+ # end
95
+ end
96
+
97
+ def leave_rooms
98
+ rooms.each do |room|
99
+ puts "Leaving #{room.name}"
100
+ room.connection.exit
101
+ end
102
+ end
103
+
104
+ def setup_timers
105
+ ::EM::add_periodic_timer(10) {
106
+ if !@jabber.nil? && @jabber.is_disconnected?
107
+ initialize_jabber
108
+ join_rooms
109
+ end
110
+ }
111
+ end
112
+
113
+ def send_message room, message, jid = nil
114
+ room.connection.say(message, jid)
115
+ end
116
+
117
+ def rooms
118
+ @rooms || []
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,20 @@
1
+ module Hipbot
2
+ module Adapters
3
+ module Hipchat
4
+ delegate :reply, to: :connection
5
+
6
+ def start!
7
+ ::EM::run do
8
+ ::EM.error_handler do |e|
9
+ puts e.inspect
10
+ e.backtrace.each do |line|
11
+ puts line
12
+ end
13
+ end
14
+
15
+ Connection.new(self)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,10 +1,6 @@
1
1
  module Hipbot
2
2
  module Adapters
3
3
  module Telnet
4
- def reply room, message
5
- connection.send_data("#{self}:#{room}:#{message}\n")
6
- end
7
-
8
4
  class Connection < EM::Connection
9
5
  def initialize bot
10
6
  @bot = bot
@@ -16,12 +12,6 @@ module Hipbot
16
12
  @bot.tell(sender, room, message)
17
13
  end
18
14
  end
19
-
20
- def start!
21
- ::EM::run do
22
- ::EM::connect('0.0.0.0', 3001, Connection, self)
23
- end
24
- end
25
15
  end
26
16
  end
27
17
  end