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 +6 -0
- data/Gemfile +0 -3
- data/Gemfile.lock +7 -10
- data/README.md +129 -21
- data/bin/hipbot +8 -1
- data/hipbot.gemspec +2 -1
- data/lib/hipbot.rb +8 -7
- data/lib/hipbot/adapters/hipchat/connection.rb +123 -0
- data/lib/hipbot/adapters/hipchat/hipchat.rb +20 -0
- data/lib/hipbot/adapters/{telnet.rb → telnet/connection.rb} +0 -10
- data/lib/hipbot/adapters/telnet/telnet.rb +16 -0
- data/lib/hipbot/bot.rb +10 -9
- data/lib/hipbot/configuration.rb +3 -0
- data/lib/hipbot/http_response.rb +15 -0
- data/lib/hipbot/message.rb +9 -1
- data/lib/hipbot/{encoding.rb → patches/encoding.rb} +0 -0
- data/lib/hipbot/patches/mucclient.rb +147 -0
- data/lib/hipbot/reaction.rb +14 -6
- data/lib/hipbot/response.rb +10 -18
- data/lib/hipbot/room.rb +2 -5
- data/lib/hipbot/version.rb +1 -1
- data/spec/integration/hipbot_spec.rb +33 -4
- data/spec/unit/hipbot_spec.rb +75 -3
- metadata +29 -12
- data/bot.rb +0 -92
- data/lib/hipbot/adapters/hipchat.rb +0 -86
- data/lib/hipbot/mucclient.rb +0 -60
- data/test_server.rb +0 -23
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
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.
|
27
|
-
rspec-core (~> 2.
|
28
|
-
rspec-expectations (~> 2.
|
29
|
-
rspec-mocks (~> 2.
|
30
|
-
rspec-core (2.
|
31
|
-
rspec-expectations (2.
|
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.
|
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
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
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
|
-
*
|
62
|
-
|
63
|
-
|
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
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.
|
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/
|
10
|
-
require 'hipbot/
|
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
|