hipbot 0.0.5 → 0.1.0

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/.gitignore CHANGED
@@ -1 +1,2 @@
1
1
  *.gem
2
+ test_bot.rb
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gem 'rake'
4
4
  gem 'eventmachine'
@@ -1,25 +1,32 @@
1
1
  GEM
2
- remote: http://rubygems.org/
2
+ remote: https://rubygems.org/
3
3
  specs:
4
4
  active_support (3.0.0)
5
5
  activesupport (= 3.0.0)
6
6
  activesupport (3.0.0)
7
- addressable (2.2.8)
8
- crack (0.1.6)
7
+ addressable (2.3.2)
8
+ cookiejar (0.3.0)
9
9
  daemons (1.1.8)
10
10
  diff-lcs (1.1.3)
11
- em-http-request (0.3.0)
12
- addressable (>= 2.0.0)
13
- escape_utils
14
- eventmachine (>= 0.12.9)
15
- escape_utils (0.2.4)
16
- eventmachine (0.12.10)
17
- httparty (0.5.2)
18
- crack (= 0.1.6)
11
+ em-http-request (1.0.2)
12
+ addressable (>= 2.2.3)
13
+ cookiejar
14
+ em-socksify
15
+ eventmachine (>= 1.0.0.beta.4)
16
+ http_parser.rb (>= 0.5.3)
17
+ em-socksify (0.2.0)
18
+ eventmachine (>= 1.0.0.beta.4)
19
+ eventmachine (1.0.0.rc.4)
20
+ http_parser.rb (0.5.3)
21
+ httparty (0.8.3)
22
+ multi_json (~> 1.0)
23
+ multi_xml
19
24
  i18n (0.6.0)
20
25
  metaclass (0.0.1)
21
- mocha (0.11.4)
26
+ mocha (0.12.1)
22
27
  metaclass (~> 0.0.1)
28
+ multi_json (1.3.6)
29
+ multi_xml (0.5.1)
23
30
  rake (0.9.2.2)
24
31
  rspec (2.11.0)
25
32
  rspec-core (~> 2.11.0)
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Hipbot
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/pewniak747/hipbot.png?branch=master)](http://travis-ci.org/pewniak747/hipbot)
4
+ [![Code Climate](https://codeclimate.com/github/pewniak747/hipbot.png)](https://codeclimate.com/github/pewniak747/hipbot)
4
5
 
5
6
  Hipbot is a bot for HipChat, written in ruby & eventmachine.
6
7
 
@@ -84,6 +85,8 @@ end
84
85
 
85
86
  (Use with caution!)
86
87
 
88
+ For more examples, check out (https://github.com/pewniak747/hipbot/tree/master/examples)
89
+
87
90
  #### Response helpers
88
91
 
89
92
  Use http helpers (`get`, `post`, `put`, `delete`) to preform a http request:
@@ -159,14 +162,14 @@ heroku ps:scale worker=1
159
162
 
160
163
  ## TODO:
161
164
 
162
- * handle auto joining on room invite
163
- * add database storage with postgresql adapter
164
- * rewrite SimpleMUCClient
165
+ * add plugins support
165
166
  * add extended logging
166
- * handle private messages callbacks in the same way
167
167
 
168
168
  ### Done:
169
169
 
170
+ * ~~rewrite SimpleMUCClient~~
171
+ * ~~handle private messages callbacks~~
172
+ * ~~handle auto joining on room invite~~
170
173
  * ~~add support for custom helpers~~
171
174
  * ~~mentions - returns list of @mentions in message~~
172
175
  * ~~sender_name - returns sender's first name~~
@@ -0,0 +1,23 @@
1
+ # example bot that simulates intelligence
2
+ # using http://cleverbot.com/ api
3
+
4
+ require 'hipbot'
5
+ require 'cleverbot'
6
+ require 'htmlentities'
7
+
8
+ class CleverHipbot < Hipbot::Bot
9
+ configure do |c|
10
+ c.jid = ENV['HIPBOT_JID']
11
+ c.password = ENV['HIPBOT_PASSWORD']
12
+ c.name = ENV['HIPBOT_NAME']
13
+ end
14
+
15
+ cleverbot = ::Cleverbot::Client.new
16
+
17
+ on /(.+)/ do |message|
18
+ coder = HTMLEntities.new
19
+ reply(coder.decode(cleverbot.write(message)))
20
+ end
21
+ end
22
+
23
+ CleverHipbot.start!
@@ -0,0 +1,35 @@
1
+ # Pull out a random image from the Google Images API and display it
2
+ # Uses: google_image_api http://rubygems.org/gems/google_image_api
3
+ # Author Rushi Vishavadia <rushi.v@gmail.com>
4
+
5
+ require 'hipbot'
6
+ require 'google_image_api'
7
+
8
+ class SampleBot < Hipbot::Bot
9
+ configure do |c|
10
+ c.jid = ENV['HIPBOT_JID']
11
+ c.password = ENV['HIPBOT_PASSWORD']
12
+ c.name = ENV['HIPBOT_NAME']
13
+ end
14
+
15
+ on /\Aimage (.+)/i do |img_str|
16
+ max = 8 # max number of results you want to pull a random
17
+ puts img_str
18
+ begin
19
+ results = GoogleImageApi.find(img_str, :rsz => max)
20
+ if results.raw_data["responseStatus"] == 200 and results.images.size > 0
21
+ reply(results.images.take(max).sample['unescapedUrl'])
22
+ elsif results.raw_data["responseStatus"] == 200 and results.images.size == 0
23
+ reply("I'm sorry I couldn't find an image for #{img_str}")
24
+ else
25
+ reply("I'm sorry, an error occurred. Try again please") # Most likely a 403
26
+ end
27
+ rescue => e
28
+ reply("I'm sorry, an error occurred trying to find that image")
29
+ p e.message
30
+ p e.backtrace
31
+ end
32
+ end
33
+ end
34
+
35
+ SampleBot.start!
@@ -1,10 +1,11 @@
1
1
  require 'active_support/all'
2
+ require 'ostruct'
2
3
  require 'eventmachine'
3
4
  require 'em-http-request'
4
5
  require 'xmpp4r'
5
6
  require 'xmpp4r/muc'
6
7
 
7
- require 'hipbot/patches/mucclient'
8
+ require 'hipbot/patches/hipchat_client'
8
9
  require 'hipbot/patches/encoding'
9
10
 
10
11
  require 'hipbot/adapters/hipchat/hipchat'
@@ -13,9 +14,11 @@ require 'hipbot/adapters/telnet/telnet'
13
14
  require 'hipbot/adapters/telnet/connection'
14
15
  require 'hipbot/bot'
15
16
  require 'hipbot/configuration'
17
+ require 'hipbot/collection'
18
+ require 'hipbot/http_response'
16
19
  require 'hipbot/message'
17
20
  require 'hipbot/reaction'
18
21
  require 'hipbot/response'
19
- require 'hipbot/http_response'
20
22
  require 'hipbot/room'
23
+ require 'hipbot/user'
21
24
  require 'hipbot/version'
@@ -3,120 +3,153 @@ module Hipbot
3
3
  module Hipchat
4
4
  class Connection
5
5
  def initialize bot
6
- initialize_bot(bot)
7
- initialize_jabber
8
- initialize_rooms
9
- join_rooms
6
+ @bot = bot
7
+ @bot.connection = self
8
+
9
+ return unless setup_bot
10
10
  setup_timers
11
11
  end
12
12
 
13
- def reply room, message
14
- send_message(room, message)
13
+ def restart!
14
+ exit_all_rooms # TODO: Nice quit
15
+ setup_bot
15
16
  end
16
17
 
17
- def restart!
18
- leave_rooms
19
- initialize_jabber
18
+ def send_to_room(room, message)
19
+ @client.send_message(:groupchat, room.id, message)
20
+ end
21
+
22
+ def send_to_user(user, message)
23
+ @client.send_message(:chat, user.id, message)
24
+ end
25
+
26
+ def set_topic(room, topic)
27
+ @client.send_message(:groupchat, room.id, nil, topic)
28
+ end
29
+
30
+ def set_presence(status = nil, type = :available)
31
+ @client.set_presence(type, nil, status)
32
+ end
33
+
34
+ private
35
+
36
+ def setup_bot
37
+ return unless initialize_client
20
38
  initialize_rooms
39
+ initialize_users
40
+ initialize_callbacks
21
41
  join_rooms
42
+ set_presence('Hello humans!')
43
+ true
22
44
  end
23
45
 
24
- private
46
+ def initialize_client
47
+ ::Jabber.debug = true
48
+ @client = ::Jabber::MUC::HipchatClient.new(@bot.jid + '/' + @bot.name)
49
+ @client.connect(@bot.password)
50
+ end
25
51
 
26
52
  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
- }
53
+ Room.bot = @bot
54
+ @client.get_rooms.each do |r|
55
+ Room.create(r[:item].jid, r[:item].iname, topic: r[:details]['topic'])
56
+ end
57
+ true
31
58
  end
32
59
 
33
- def initialize_bot bot
34
- @bot = bot
35
- @bot.connection = self
60
+ def initialize_users
61
+ User.bot = @bot
62
+ @client.get_users.each do |v|
63
+ params = {
64
+ email: v[:vcard]['EMAIL/USERID'],
65
+ mention: v[:item].attributes['mention_name'],
66
+ title: v[:vcard]['TITLE'],
67
+ photo: v[:vcard]['PHOTO'],
68
+ }
69
+ User.create(v[:item].jid, v[:item].iname, params)
70
+ end
71
+ true
36
72
  end
37
73
 
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))
74
+ def join_rooms
75
+ if Room.empty?
76
+ Jabber::debuglog "No rooms to join"
77
+ return false
78
+ end
79
+ Room.each do |room_jid, _|
80
+ @client.join(room_jid)
81
+ end
82
+ true
43
83
  end
44
84
 
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
85
+ def exit_all_rooms
86
+ Room.each do |room_jid, _|
87
+ @client.exit(room_jid, 'bye bye!')
88
+ end
89
+ end
90
+
91
+ def initialize_callbacks
92
+ @client.on_message do |room_jid, user_name, message|
93
+ room = Room[room_jid]
94
+ user = User[user_name]
95
+ next if room.nil? && user.nil?
96
+ room.params.topic = message.subject if message.subject.present?
97
+ next if user_name == @bot.name || message.body.blank?
98
+ Jabber::debuglog "[#{Time.now}] <#{room.name}> #{user_name}: #{message.body}"
99
+ begin
100
+ @bot.react(user, room, message.body)
101
+ rescue => e
102
+ Jabber::debuglog e.inspect
103
+ e.backtrace.each do |line|
104
+ Jabber::debuglog line
66
105
  end
67
106
  end
107
+ end
68
108
 
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
109
+ @client.on_private_message do |user_jid, message|
110
+ user = User[user_jid]
111
+ next if user.blank? || user.name == @bot.name
112
+ if message.body.nil?
113
+ # if message.active?
114
+ # elsif message.inactive?
115
+ # elsif message.composing?
116
+ # elsif message.gone?
117
+ # elsif message.paused?
118
+ # end
119
+ else
120
+ @bot.react(user, nil, message.body)
73
121
  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
122
  end
79
123
 
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
124
+ @client.on_invite do |room_jid, user_name, room_name, topic|
125
+ Room.create(room_jid, room_name, topic: topic)
126
+ @client.join(room_jid)
127
+ end
96
128
 
97
- def leave_rooms
98
- rooms.each do |room|
99
- puts "Leaving #{room.name}"
100
- room.connection.exit
129
+ @client.on_presence do |room_jid, user_name, pres|
130
+ room = Room[room_jid]
131
+ next if room.blank? || user_name.blank?
132
+ user = User[user_name]
133
+ if pres == 'unavailable'
134
+ if user_name == @bot.name
135
+ room.delete
136
+ elsif user.present?
137
+ room.user_ids.delete(user.id)
138
+ end
139
+ elsif pres.blank? && user.present? && room.user_ids.exclude?(user.id)
140
+ room.user_ids << user.id
141
+ end
101
142
  end
143
+
144
+ @client.activate_callbacks
102
145
  end
103
146
 
104
147
  def setup_timers
105
- ::EM::add_periodic_timer(10) {
106
- if !@jabber.nil? && @jabber.is_disconnected?
107
- initialize_jabber
108
- join_rooms
109
- end
148
+ ::EM::add_periodic_timer(60) {
149
+ @client.keep_alive(@bot.password) if @client.present?
110
150
  }
111
151
  end
112
152
 
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
153
  end
121
154
  end
122
155
  end
@@ -1,8 +1,6 @@
1
1
  module Hipbot
2
2
  module Adapters
3
3
  module Hipchat
4
- delegate :reply, to: :connection
5
-
6
4
  def start!
7
5
  ::EM::run do
8
6
  ::EM.error_handler do |e|
@@ -15,6 +13,10 @@ module Hipbot
15
13
  Connection.new(self)
16
14
  end
17
15
  end
16
+
17
+ def method_missing(sym, *args, &block)
18
+ connection.send sym, *args, &block
19
+ end
18
20
  end
19
21
  end
20
22
  end
@@ -9,7 +9,7 @@ module Hipbot
9
9
 
10
10
  def receive_data(data)
11
11
  sender, room, message = *data.strip.split(':')
12
- @bot.tell(sender, room, message)
12
+ @bot.react(sender, room, message)
13
13
  end
14
14
  end
15
15
  end
@@ -1,7 +1,7 @@
1
1
  module Hipbot
2
2
  module Adapters
3
3
  module Telnet
4
- def reply room, message
4
+ def send_to_room room, message
5
5
  connection.send_data("#{self}:#{room}:#{message}\n")
6
6
  end
7
7