scamp 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +48 -28
- data/examples/bot.rb +27 -21
- data/lib/scamp/action.rb +13 -5
- data/lib/scamp/connection.rb +6 -6
- data/lib/scamp/matcher.rb +29 -6
- data/lib/scamp/messages.rb +31 -0
- data/lib/scamp/rooms.rb +113 -0
- data/lib/scamp/users.rb +7 -15
- data/lib/scamp/version.rb +1 -1
- data/lib/scamp.rb +12 -9
- data/scamp.gemspec +2 -1
- data/spec/lib/scamp_spec.rb +407 -15
- data/spec/spec_helper.rb +7 -1
- metadata +26 -14
- data/lib/scamp/channels.rb +0 -112
data/README.md
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
A framework for writing [Campfire](http://campfirenow.com/) bots. Scamp is in early development so use it at your own risk, pull requests welcome.
|
4
4
|
|
5
|
+
Scamp is designed to be simple, to get out of your way and to let you do what you want. It doesn't have any baggage, so no administration web interfaces, no built in commands. It's a blank slate for you to build on.
|
6
|
+
|
7
|
+
If you like or use Scamp I'd love to hear from you. Drop me at line at will at 37signals dot com and tell me how you are using it.
|
8
|
+
|
5
9
|
## Requirements
|
6
10
|
|
7
11
|
Ruby >= 1.9.2 (At least for the named captures)
|
@@ -28,10 +32,10 @@ Matchers are tested in order and all that satisfy the match and conditions will
|
|
28
32
|
end
|
29
33
|
|
30
34
|
#
|
31
|
-
# A special user and
|
35
|
+
# A special user and room method is available in match blocks.
|
32
36
|
#
|
33
37
|
match "a user said" do
|
34
|
-
say "#{user} said something in
|
38
|
+
say "#{user} said something in room #{room}"
|
35
39
|
end
|
36
40
|
|
37
41
|
match "Hello!" do
|
@@ -39,35 +43,42 @@ Matchers are tested in order and all that satisfy the match and conditions will
|
|
39
43
|
end
|
40
44
|
|
41
45
|
#
|
42
|
-
#
|
46
|
+
# You can play awesome sounds
|
43
47
|
#
|
44
|
-
match
|
45
|
-
|
48
|
+
match "ohmy" do
|
49
|
+
play "yeah"
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Limit the match to certain rooms, users or both.
|
54
|
+
#
|
55
|
+
match /^Lets match (.+)$/, :conditions => {:room => "Some Room"} do
|
56
|
+
say "Only said if room name mathces /someregex/"
|
46
57
|
end
|
47
58
|
|
48
59
|
match "some text", :conditions => {:user => "Some User"} do
|
49
60
|
say "Only said if user name mathces /someregex/"
|
50
61
|
end
|
51
62
|
|
52
|
-
match /some other text/, :conditions => {:user => "Some User", :
|
63
|
+
match /some other text/, :conditions => {:user => "Some User", :room => 123456} do
|
53
64
|
say "You can mix conditions"
|
54
65
|
end
|
55
66
|
|
56
67
|
#
|
57
|
-
# Named
|
68
|
+
# Named captures become avaiable in your match block
|
58
69
|
#
|
59
70
|
match /^say (?<yousaid>.+)$/ do
|
60
71
|
say "You said #{yousaid}"
|
61
72
|
end
|
62
73
|
|
63
74
|
#
|
64
|
-
# You can say multiple times, and you can specify an alternate
|
65
|
-
# Default behaviour is to 'say' in the
|
75
|
+
# You can say multiple times, and you can specify an alternate room.
|
76
|
+
# Default behaviour is to 'say' in the room that caused the match.
|
66
77
|
#
|
67
78
|
match "something" do
|
68
|
-
say "#{user} said something in
|
69
|
-
say "#{user} said something in
|
70
|
-
say "#{user} said something in
|
79
|
+
say "#{user} said something in room #{room}"
|
80
|
+
say "#{user} said something in room #{room}", 237872
|
81
|
+
say "#{user} said something in room #{room}", "System Administration"
|
71
82
|
end
|
72
83
|
|
73
84
|
#
|
@@ -86,34 +97,36 @@ Matchers are tested in order and all that satisfy the match and conditions will
|
|
86
97
|
end
|
87
98
|
end
|
88
99
|
|
89
|
-
# Connect and join some
|
100
|
+
# Connect and join some rooms
|
90
101
|
scamp.connect!([293788, "Monitoring"])
|
91
102
|
|
92
|
-
In the
|
103
|
+
In the room/user conditions you can use the name, regex or ID of a user or room, in say you can ise a string or ID, eg:
|
93
104
|
|
94
|
-
:conditions => {:
|
95
|
-
:conditions => {:
|
96
|
-
:conditions => {:
|
105
|
+
:conditions => {:room => /someregex/}
|
106
|
+
:conditions => {:room => "some string"}
|
107
|
+
:conditions => {:room => 123456}
|
97
108
|
|
98
109
|
:conditions => {:user => /someregex/}
|
99
110
|
:conditions => {:user => "some string"}
|
100
111
|
:conditions => {:user => 123456}
|
101
112
|
|
102
|
-
say "#{user} said something in
|
103
|
-
say "#{user} said something in
|
113
|
+
say "#{user} said something in room #{room}", 237872
|
114
|
+
say "#{user} said something in room #{room}", "System Administration"
|
104
115
|
|
105
|
-
|
116
|
+
By default Scamp listens to itself. This could either be fun, or dangerous, you decide. You can turn this off by passing :first\_match\_only => true in the initialisation options
|
106
117
|
|
107
|
-
|
108
|
-
* Allow multiple values for conditions, eg: :conditions => {:channel => [/someregex/, "Some channel"]}
|
109
|
-
* Add paste/play support
|
110
|
-
* Add option to stop bot responding to itself
|
118
|
+
scamp = Scamp.new(:api_key => "YOUR API KEY", :subdomain => "yoursubdomain", :first_match_only => true)
|
111
119
|
|
112
|
-
|
120
|
+
Scamp will listen to all messages that are sent on the rooms it is listening on and doesn't need to be addressed by name. If you prefer to only trigger bot commands when you address your bot directly add the :required\_prefix initialisation option:
|
113
121
|
|
114
|
-
|
115
|
-
|
116
|
-
|
122
|
+
scamp = Scamp.new(:api_key => "YOUR API KEY", :subdomain => "yoursubdomain", :required_prefix => 'Bot: ')
|
123
|
+
|
124
|
+
Scamp will now require commands to begin with 'Bot: ' (or whatever you have specified), and will strip out this prefix before handing the message onto your match block.
|
125
|
+
|
126
|
+
## TODO
|
127
|
+
|
128
|
+
* Allow multiple values for conditions, eg: :conditions => {:room => ["This room", "Some room"]}
|
129
|
+
* Add paste support
|
117
130
|
|
118
131
|
## How to contribute
|
119
132
|
|
@@ -130,6 +143,13 @@ Here's the most direct way to get your work merged into the project:
|
|
130
143
|
|
131
144
|
Take a look at the TODO list or known issues for some inspiration if you need it.
|
132
145
|
|
146
|
+
## Thanks
|
147
|
+
|
148
|
+
First class support, commits and pull requests, thanks guys!
|
149
|
+
|
150
|
+
* [Caius Durling](http://caius.name/)
|
151
|
+
* Sudara Williams of [Ramen Music](http://ramenmusic.com)
|
152
|
+
|
133
153
|
## License
|
134
154
|
|
135
155
|
Copyright (C) 2011 by Will Jessop
|
data/examples/bot.rb
CHANGED
@@ -7,15 +7,15 @@ require 'scamp'
|
|
7
7
|
scamp = Scamp.new(:api_key => "YOUR API KEY", :subdomain => "37s")
|
8
8
|
|
9
9
|
scamp.behaviour do
|
10
|
-
# Match some regex limited to a
|
11
|
-
match /^
|
12
|
-
# Reply in the current
|
13
|
-
say "Match some regex limited to a
|
10
|
+
# Match some regex limited to a room condition based on a room id
|
11
|
+
match /^room id (.+)$/, :conditions => {:room => 401839} do
|
12
|
+
# Reply in the current room
|
13
|
+
say "Match some regex limited to a room condition based on a room id"
|
14
14
|
end
|
15
15
|
|
16
|
-
# Limit a match to a
|
17
|
-
match "
|
18
|
-
say "Limit a match to a
|
16
|
+
# Limit a match to a room condition based on a string
|
17
|
+
match "room name check", :conditions => {:room => "Monitoring"} do
|
18
|
+
say "Limit a match to a room condition based on a string"
|
19
19
|
end
|
20
20
|
|
21
21
|
# Limit a match to a user condition based on a string
|
@@ -28,10 +28,10 @@ scamp.behaviour do
|
|
28
28
|
say "Limit a match to a user condition based on an ID"
|
29
29
|
end
|
30
30
|
|
31
|
-
# Limit a match to a
|
32
|
-
match /^something (.+)$/, :conditions => {:
|
33
|
-
# Reply in the current
|
34
|
-
say "Limit a match to a
|
31
|
+
# Limit a match to a room & user condition combined
|
32
|
+
match /^something (.+)$/, :conditions => {:room => "Monitoring", :user => "Will Jessop"} do
|
33
|
+
# Reply in the current room
|
34
|
+
say "Limit a match to a room & user condition combined"
|
35
35
|
end
|
36
36
|
|
37
37
|
# Match text with a regex, access the captures from the match object
|
@@ -44,23 +44,29 @@ scamp.behaviour do
|
|
44
44
|
say "You said #{yousaid}"
|
45
45
|
end
|
46
46
|
|
47
|
-
# Simple string match, interpolating the
|
47
|
+
# Simple string match, interpolating the room and user in response.
|
48
48
|
match "something" do |data|
|
49
|
-
# Send the response to a different
|
50
|
-
say "#{user} said something in
|
49
|
+
# Send the response to a different room
|
50
|
+
say "#{user} said something in room #{room}", "Robot Army"
|
51
51
|
|
52
|
-
# Send the response to a different
|
53
|
-
say "#{user} said something in
|
52
|
+
# Send the response to a different room, using the room ID
|
53
|
+
say "#{user} said something in room #{room}", 293788
|
54
54
|
|
55
|
-
# Send the response to the originating
|
56
|
-
say "#{user} said something in
|
55
|
+
# Send the response to the originating room
|
56
|
+
say "#{user} said something in room #{room}"
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
|
-
|
59
|
+
# Play some sounds
|
60
|
+
match "ohmy" do
|
61
|
+
play "yeah"
|
62
|
+
play "drama"
|
63
|
+
end
|
64
|
+
|
65
|
+
match "multi-condition match", :conditions => {:room => [401839, "Monitoring"], :user => ["Will Jessop", "Noah Lorang"]} do
|
66
|
+
# Reply in the current room
|
61
67
|
say "multi-condition match"
|
62
68
|
end
|
63
69
|
end
|
64
70
|
|
65
|
-
# FIXME: this does if the
|
71
|
+
# FIXME: this does if the room doesn't exist. Need a better error.
|
66
72
|
scamp.connect!([293788, "Monitoring"])
|
data/lib/scamp/action.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Actions are run in the context of a Scamp::Action.
|
3
|
-
# This allows us to make
|
3
|
+
# This allows us to make room, user etc. methods
|
4
4
|
# available on a per-message basis
|
5
5
|
#
|
6
6
|
|
@@ -27,8 +27,12 @@ class Scamp
|
|
27
27
|
end if match.respond_to?(:names) # 1.8 doesn't support named captures
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
|
30
|
+
def room_id
|
31
|
+
@message[:room_id]
|
32
|
+
end
|
33
|
+
|
34
|
+
def room
|
35
|
+
bot.room_name_for @message[:room_id]
|
32
36
|
end
|
33
37
|
|
34
38
|
def user
|
@@ -53,8 +57,12 @@ class Scamp
|
|
53
57
|
bot.command_list
|
54
58
|
end
|
55
59
|
|
56
|
-
def say(msg,
|
57
|
-
bot.say(msg,
|
60
|
+
def say(msg, room_id_or_name = room_id)
|
61
|
+
bot.say(msg, room_id_or_name)
|
62
|
+
end
|
63
|
+
|
64
|
+
def play(sound, room_id_or_name = room_id)
|
65
|
+
bot.play(sound, room_id_or_name)
|
58
66
|
end
|
59
67
|
end
|
60
68
|
end
|
data/lib/scamp/connection.rb
CHANGED
@@ -2,19 +2,19 @@ class Scamp
|
|
2
2
|
module Connection
|
3
3
|
private
|
4
4
|
|
5
|
-
def connect(api_key,
|
5
|
+
def connect(api_key, room_list)
|
6
6
|
EventMachine.run do
|
7
7
|
|
8
|
-
# Check for
|
8
|
+
# Check for rooms to join, and join them
|
9
9
|
EventMachine::add_periodic_timer(5) do
|
10
|
-
while id = @
|
10
|
+
while id = @rooms_to_join.pop
|
11
11
|
join_and_stream(id)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
logger.debug "Adding #{
|
17
|
-
@
|
15
|
+
populate_room_list do
|
16
|
+
logger.debug "Adding #{room_list.join ', '} to list of rooms to join"
|
17
|
+
@rooms_to_join = room_list.map{|c| room_id(c) }
|
18
18
|
end
|
19
19
|
|
20
20
|
end
|
data/lib/scamp/matcher.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Scamp
|
2
2
|
class Matcher
|
3
|
-
attr_accessor :conditions, :trigger, :action, :bot
|
3
|
+
attr_accessor :conditions, :trigger, :action, :bot, :required_prefix
|
4
4
|
|
5
5
|
def initialize(bot, params = {})
|
6
6
|
params ||= {}
|
@@ -26,6 +26,10 @@ class Scamp
|
|
26
26
|
private
|
27
27
|
|
28
28
|
def triggered_by(message_text)
|
29
|
+
if message_text && required_prefix
|
30
|
+
message_text = handle_prefix(message_text)
|
31
|
+
return false unless message_text
|
32
|
+
end
|
29
33
|
if trigger.is_a? String
|
30
34
|
return true if trigger == message_text
|
31
35
|
elsif trigger.is_a? Regexp
|
@@ -36,6 +40,25 @@ class Scamp
|
|
36
40
|
false
|
37
41
|
end
|
38
42
|
|
43
|
+
def handle_prefix(message_text)
|
44
|
+
return false unless message_text
|
45
|
+
if required_prefix.is_a? String
|
46
|
+
if required_prefix == message_text[0...required_prefix.length]
|
47
|
+
message_text.gsub(required_prefix,'')
|
48
|
+
else
|
49
|
+
false
|
50
|
+
end
|
51
|
+
elsif required_prefix.is_a? Regexp
|
52
|
+
if required_prefix.match message_text
|
53
|
+
message_text.gsub(required_prefix,'')
|
54
|
+
else
|
55
|
+
false
|
56
|
+
end
|
57
|
+
else
|
58
|
+
false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
39
62
|
def run(msg, match = nil)
|
40
63
|
action_run = Action.new(bot, action, msg)
|
41
64
|
action_run.matches = match if match
|
@@ -45,18 +68,18 @@ class Scamp
|
|
45
68
|
def conditions_satisfied_by(msg)
|
46
69
|
bot.logger.debug "Checking message against #{conditions.inspect}"
|
47
70
|
|
48
|
-
# item will be :
|
71
|
+
# item will be :user or :room
|
49
72
|
# cond is the int or string value.
|
50
73
|
conditions.each do |item, cond|
|
51
74
|
bot.logger.debug "Checking #{item} against #{cond}"
|
52
75
|
bot.logger.debug "msg is #{msg.inspect}"
|
53
76
|
if cond.is_a? Integer
|
54
|
-
# bot.logger.debug "item is #{msg[{:
|
55
|
-
return false unless msg[{:
|
77
|
+
# bot.logger.debug "item is #{msg[{:room => :room_id, :user => :user_id}[item]]}"
|
78
|
+
return false unless msg[{:room => :room_id, :user => :user_id}[item]] == cond
|
56
79
|
elsif cond.is_a? String
|
57
80
|
case item
|
58
|
-
when :
|
59
|
-
return false unless bot.
|
81
|
+
when :room
|
82
|
+
return false unless bot.room_name_for(msg[:room_id]) == cond
|
60
83
|
when :user
|
61
84
|
return false unless bot.username_for(msg[:user_id]) == cond
|
62
85
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Scamp
|
2
|
+
module Messages
|
3
|
+
|
4
|
+
def say(message, room_id_or_name)
|
5
|
+
send_message(room_id_or_name, message, "Textmessage")
|
6
|
+
end
|
7
|
+
|
8
|
+
def play(sound, room_id_or_name)
|
9
|
+
send_message(room_id_or_name, sound, "SoundMessage")
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# curl -vvv -H 'Content-Type: application/json' -d '{"message":{"body":"Yeeeeeaaaaaahh", "type":"Textmessage"}}' -u API_KEY:X https://37s.campfirenow.com/room/293788/speak.json
|
15
|
+
def send_message(room_id_or_name, payload, type)
|
16
|
+
# post 'speak', :body => {:message => {:body => message, :type => type}}.to_json
|
17
|
+
room_id = room_id(room_id_or_name)
|
18
|
+
url = "https://#{subdomain}.campfirenow.com/room/#{room_id}/speak.json"
|
19
|
+
http = EventMachine::HttpRequest.new(url).post :head => {'Content-Type' => 'application/json', 'authorization' => [api_key, 'X']}, :body => Yajl::Encoder.encode({:message => {:body => payload, :type => type}})
|
20
|
+
http.errback { logger.error "Couldn't connect to #{url} to post message \"#{payload}\" to room #{room_id}" }
|
21
|
+
http.callback {
|
22
|
+
if http.response_header.status == 200
|
23
|
+
logger.debug "Posted message \"#{payload}\" to room #{room_id}"
|
24
|
+
else
|
25
|
+
logger.error "Couldn't post message \"#{payload}\" to room #{room_id} using url #{url}, http response from the API was #{http.response_header.status}"
|
26
|
+
end
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/scamp/rooms.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
class Scamp
|
2
|
+
module Rooms
|
3
|
+
# TextMessage (regular chat message),
|
4
|
+
# PasteMessage (pre-formatted message, rendered in a fixed-width font),
|
5
|
+
# SoundMessage (plays a sound as determined by the message, which can be either “rimshot”, “crickets”, or “trombone”),
|
6
|
+
# TweetMessage (a Twitter status URL to be fetched and inserted into the chat)
|
7
|
+
|
8
|
+
def paste(text, room)
|
9
|
+
end
|
10
|
+
|
11
|
+
def upload
|
12
|
+
end
|
13
|
+
|
14
|
+
def join(room_id)
|
15
|
+
logger.info "Joining room #{room_id}"
|
16
|
+
url = "https://#{subdomain}.campfirenow.com/room/#{room_id}/join.json"
|
17
|
+
http = EventMachine::HttpRequest.new(url).post :head => {'Content-Type' => 'application/json', 'authorization' => [api_key, 'X']}
|
18
|
+
|
19
|
+
http.errback { logger.error "Error joining room: #{room_id}" }
|
20
|
+
http.callback {
|
21
|
+
yield if block_given?
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def room_id(room_id_or_name)
|
26
|
+
if room_id_or_name.is_a? Integer
|
27
|
+
return room_id_or_name
|
28
|
+
else
|
29
|
+
return room_id_from_room_name(room_id_or_name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def room_name_for(room_id)
|
34
|
+
data = room_cache_data(room_id)
|
35
|
+
return data["name"] if data
|
36
|
+
room_id.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def room_cache_data(room_id)
|
42
|
+
return room_cache[room_id] if room_cache.has_key? room_id
|
43
|
+
fetch_room_data(room_id)
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
|
47
|
+
def populate_room_list
|
48
|
+
url = "https://#{subdomain}.campfirenow.com/rooms.json"
|
49
|
+
http = EventMachine::HttpRequest.new(url).get :head => {'authorization' => [api_key, 'X']}
|
50
|
+
http.errback { logger.error "Couldn't connect to url #{url} to fetch room list" }
|
51
|
+
http.callback {
|
52
|
+
if http.response_header.status == 200
|
53
|
+
logger.debug "Fetched room list"
|
54
|
+
new_rooms = {}
|
55
|
+
Yajl::Parser.parse(http.response)['rooms'].each do |c|
|
56
|
+
new_rooms[c["name"]] = c
|
57
|
+
end
|
58
|
+
# No idea why using the "rooms" accessor here doesn't
|
59
|
+
# work but accessing the ivar directly does. There's
|
60
|
+
# Probably a bug.
|
61
|
+
@rooms = new_rooms # replace existing room list
|
62
|
+
yield if block_given?
|
63
|
+
else
|
64
|
+
logger.error "Couldn't fetch room list with url #{url}, http response from API was #{http.response_header.status}"
|
65
|
+
end
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def fetch_room_data(room_id)
|
70
|
+
url = "https://#{subdomain}.campfirenow.com/room/#{room_id}.json"
|
71
|
+
http = EventMachine::HttpRequest.new(url).get :head => {'authorization' => [api_key, 'X']}
|
72
|
+
http.errback { logger.error "Couldn't connect to #{url} to fetch room data for room #{room_id}" }
|
73
|
+
http.callback {
|
74
|
+
if http.response_header.status == 200
|
75
|
+
logger.debug "Fetched room data for #{room_id}"
|
76
|
+
room = Yajl::Parser.parse(http.response)['room']
|
77
|
+
room_cache[room["id"]] = room
|
78
|
+
|
79
|
+
room['users'].each do |u|
|
80
|
+
update_user_cache_with(u["id"], u)
|
81
|
+
end
|
82
|
+
else
|
83
|
+
logger.error "Couldn't fetch room data for room #{room_id} with url #{url}, http response from API was #{http.response_header.status}"
|
84
|
+
end
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def join_and_stream(id)
|
89
|
+
join(id) do
|
90
|
+
logger.info "Joined room #{id} successfully"
|
91
|
+
fetch_room_data(id)
|
92
|
+
stream(id)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def stream(room_id)
|
97
|
+
json_parser = Yajl::Parser.new :symbolize_keys => true
|
98
|
+
json_parser.on_parse_complete = method(:process_message)
|
99
|
+
|
100
|
+
url = "https://streaming.campfirenow.com/room/#{room_id}/live.json"
|
101
|
+
# Timeout per https://github.com/igrigorik/em-http-request/wiki/Redirects-and-Timeouts
|
102
|
+
http = EventMachine::HttpRequest.new(url, :connect_timeout => 20, :inactivity_timeout => 0).get :head => {'authorization' => [api_key, 'X']}
|
103
|
+
http.errback { logger.error "Couldn't stream room #{room_id} at url #{url}" }
|
104
|
+
http.callback { logger.info "Disconnected from #{url}"; rooms_to_join << room_id}
|
105
|
+
http.stream {|chunk| json_parser << chunk }
|
106
|
+
end
|
107
|
+
|
108
|
+
def room_id_from_room_name(room_name)
|
109
|
+
logger.debug "Looking for room id for #{room_name}"
|
110
|
+
rooms[room_name]["id"]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/scamp/users.rb
CHANGED
@@ -1,16 +1,5 @@
|
|
1
1
|
class Scamp
|
2
2
|
module Users
|
3
|
-
|
4
|
-
# <user>
|
5
|
-
# <id type="integer">1</id>
|
6
|
-
# <name>Jason Fried</name>
|
7
|
-
# <email-address>jason@37signals.com</email-address>
|
8
|
-
# <admin type="boolean">true</admin>
|
9
|
-
# <created-at type="datetime">2009-11-20T16:41:39Z</created-at>
|
10
|
-
# <type>Member</type>
|
11
|
-
# <avatar-url>http://asset0.37img.com/global/.../avatar.png</avatar-url>
|
12
|
-
# </user>
|
13
|
-
|
14
3
|
# Return the user_id if we haven't got the real name and
|
15
4
|
# kick off a user data fetch
|
16
5
|
def username_for(user_id)
|
@@ -24,13 +13,16 @@ class Scamp
|
|
24
13
|
def fetch_data_for(user_id)
|
25
14
|
url = "https://#{subdomain}.campfirenow.com/users/#{user_id}.json"
|
26
15
|
http = EventMachine::HttpRequest.new(url).get(:head => {'authorization' => [api_key, 'X'], "Content-Type" => "application/json"})
|
27
|
-
logger.debug http.inspect
|
28
16
|
http.callback do
|
29
|
-
|
30
|
-
|
17
|
+
if http.response_header.status == 200
|
18
|
+
logger.debug "Got the data for #{user_id}"
|
19
|
+
update_user_cache_with(user_id, Yajl::Parser.parse(http.response)['user'])
|
20
|
+
else
|
21
|
+
logger.error "Couldn't fetch user data for user #{user_id} with url #{url}, http response from API was #{http.response_header.status}"
|
22
|
+
end
|
31
23
|
end
|
32
24
|
http.errback do
|
33
|
-
logger.error "Couldn't fetch user data for #{user_id}
|
25
|
+
logger.error "Couldn't connect to #{url} to fetch user data for user #{user_id}"
|
34
26
|
end
|
35
27
|
end
|
36
28
|
|
data/lib/scamp/version.rb
CHANGED
data/lib/scamp.rb
CHANGED
@@ -5,17 +5,20 @@ require "logger"
|
|
5
5
|
|
6
6
|
require "scamp/version"
|
7
7
|
require 'scamp/connection'
|
8
|
-
require 'scamp/
|
8
|
+
require 'scamp/rooms'
|
9
9
|
require 'scamp/users'
|
10
10
|
require 'scamp/matcher'
|
11
11
|
require 'scamp/action'
|
12
|
+
require 'scamp/messages'
|
12
13
|
|
13
14
|
class Scamp
|
14
15
|
include Connection
|
15
|
-
include
|
16
|
+
include Rooms
|
16
17
|
include Users
|
18
|
+
include Messages
|
17
19
|
|
18
|
-
attr_accessor :
|
20
|
+
attr_accessor :rooms, :user_cache, :room_cache, :matchers, :api_key, :subdomain,
|
21
|
+
:logger, :verbose, :first_match_only, :required_prefix, :rooms_to_join
|
19
22
|
|
20
23
|
def initialize(options = {})
|
21
24
|
options ||= {}
|
@@ -31,10 +34,10 @@ class Scamp
|
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
34
|
-
@
|
35
|
-
@
|
37
|
+
@rooms_to_join = []
|
38
|
+
@rooms = {}
|
36
39
|
@user_cache = {}
|
37
|
-
@
|
40
|
+
@room_cache = {}
|
38
41
|
@matchers ||= []
|
39
42
|
end
|
40
43
|
|
@@ -42,9 +45,9 @@ class Scamp
|
|
42
45
|
instance_eval &block
|
43
46
|
end
|
44
47
|
|
45
|
-
def connect!(
|
48
|
+
def connect!(room_list)
|
46
49
|
logger.info "Starting up"
|
47
|
-
connect(api_key,
|
50
|
+
connect(api_key, room_list)
|
48
51
|
end
|
49
52
|
|
50
53
|
def command_list
|
@@ -73,7 +76,7 @@ class Scamp
|
|
73
76
|
|
74
77
|
def match trigger, params={}, &block
|
75
78
|
params ||= {}
|
76
|
-
matchers << Matcher.new(self, {:trigger => trigger, :action => block, :conditions => params[:conditions]})
|
79
|
+
matchers << Matcher.new(self, {:trigger => trigger, :action => block, :conditions => params[:conditions], :required_prefix => required_prefix})
|
77
80
|
end
|
78
81
|
|
79
82
|
def process_message(msg)
|
data/scamp.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.version = Scamp::VERSION
|
8
8
|
s.authors = ["Will Jessop"]
|
9
9
|
s.email = ["will@willj.net"]
|
10
|
-
s.homepage = ""
|
10
|
+
s.homepage = "https://github.com/wjessop/Scamp"
|
11
11
|
s.summary = %q{Eventmachine based Campfire bot framework}
|
12
12
|
s.description = %q{Eventmachine based Campfire bot framework}
|
13
13
|
|
@@ -22,4 +22,5 @@ Gem::Specification.new do |s|
|
|
22
22
|
|
23
23
|
s.add_development_dependency "rspec", "~> 2.6.0"
|
24
24
|
s.add_development_dependency "mocha", "~> 0.10.0"
|
25
|
+
s.add_development_dependency "webmock", "~> 1.7.6"
|
25
26
|
end
|