flamethrower 0.3.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  module Flamethrower
2
- module Server
2
+ module Connection
3
3
  include Flamethrower::Irc::Commands
4
4
 
5
5
  attr_accessor :campfire_connection, :current_user, :dispatcher, :irc_channels
@@ -11,6 +11,7 @@ module Flamethrower
11
11
  end
12
12
 
13
13
  def after_connect
14
+ send_welcome
14
15
  send_motd
15
16
  populate_irc_channels
16
17
  populate_my_user
@@ -23,10 +24,10 @@ module Flamethrower
23
24
  end
24
25
 
25
26
  def receive_data(msg)
26
- messages = msg.split("\r\n")
27
- messages.each do |message|
28
- dispatcher.handle_message(Flamethrower::Irc::Message.new(message))
27
+ @data ||= ::BufferedTokenizer.new("\r\n")
28
+ @data.extract(msg).each do |message|
29
29
  ::FLAMETHROWER_LOGGER.debug "<< #{message}"
30
+ dispatcher.handle_message(Flamethrower::Irc::Message.new(message))
30
31
  end
31
32
  end
32
33
 
@@ -1,9 +1,9 @@
1
1
  module Flamethrower
2
2
  class Dispatcher
3
- attr_reader :server
3
+ attr_reader :connection
4
4
 
5
- def initialize(server)
6
- @server = server
5
+ def initialize(connection)
6
+ @connection = connection
7
7
  end
8
8
 
9
9
  def handle_message(message)
@@ -14,11 +14,11 @@ module Flamethrower
14
14
  private
15
15
 
16
16
  def find_channel_or_error(name, error=Flamethrower::Irc::Codes::ERR_BADCHANNELKEY)
17
- channel = server.irc_channels.detect {|channel| channel.name == name}
17
+ channel = connection.irc_channels.detect {|channel| channel.name == name}
18
18
  if channel && block_given?
19
19
  yield(channel)
20
20
  else
21
- server.send_message(server.error(error))
21
+ connection.send_message(connection.error(error))
22
22
  end
23
23
  end
24
24
 
@@ -33,44 +33,44 @@ module Flamethrower
33
33
 
34
34
  def handle_ping(message)
35
35
  hostname = message.parameters.first
36
- server.send_pong(hostname)
36
+ connection.send_pong(hostname)
37
37
  end
38
38
 
39
39
  def handle_user(message)
40
40
  username, hostname, servername, realname = message.parameters
41
- server.current_user.username = username unless server.current_user.username
42
- server.current_user.hostname = hostname unless server.current_user.hostname
43
- server.current_user.servername = servername unless server.current_user.servername
44
- server.current_user.realname = realname unless server.current_user.realname
45
- if server.current_user.nick_set? && server.current_user.user_set?
46
- server.after_connect
41
+ connection.current_user.username ||= username
42
+ connection.current_user.hostname ||= hostname
43
+ connection.current_user.servername ||= servername
44
+ connection.current_user.realname ||= realname
45
+ if connection.current_user.nick_set? && connection.current_user.user_set?
46
+ connection.after_connect
47
47
  end
48
48
  end
49
49
 
50
50
  def handle_nick(message)
51
51
  nickname = message.parameters.first
52
- server.current_user.nickname = nickname
53
- if server.current_user.nick_set? && server.current_user.user_set?
54
- server.after_connect
52
+ connection.current_user.nickname = nickname
53
+ if connection.current_user.nick_set? && connection.current_user.user_set?
54
+ connection.after_connect
55
55
  end
56
56
  end
57
57
 
58
58
  def handle_topic(message)
59
59
  find_channel_or_error(message.parameters.first) do |channel|
60
60
  channel.to_campfire.send_topic(message.parameters.last) if message.parameters.size > 1
61
- server.send_topic(channel)
61
+ connection.send_topic(channel)
62
62
  end
63
63
  end
64
64
 
65
65
  def handle_mode(message)
66
66
  first_param = message.parameters.first
67
67
  error = Flamethrower::Irc::Codes::ERR_UNKNOWNCOMMAND
68
- if first_param == server.current_user.nickname
69
- server.send_user_mode
68
+ if first_param == connection.current_user.nickname
69
+ connection.send_user_mode
70
70
  return
71
71
  else
72
72
  find_channel_or_error(first_param, error) do |channel|
73
- server.send_channel_mode(channel)
73
+ connection.send_channel_mode(channel)
74
74
  end
75
75
  end
76
76
  end
@@ -78,26 +78,27 @@ module Flamethrower
78
78
  def handle_join(message)
79
79
  find_channel_or_error(message.parameters.first) do |channel|
80
80
  room = channel.to_campfire
81
- channel.users << server.current_user
81
+ channel.users << connection.current_user
82
82
  room.join
83
83
  room.start
84
+ connection.send_join(connection.current_user, channel)
84
85
  end
85
86
  end
86
87
 
87
88
  def handle_away(message)
88
89
  away_message = message.parameters.first
89
- if away_message.empty?
90
- server.current_user.away_message = nil
91
- server.send_unaway
90
+ if !away_message || away_message.empty?
91
+ connection.current_user.away_message = nil
92
+ connection.send_unaway
92
93
  else
93
- server.current_user.away_message = away_message
94
- server.send_nowaway
94
+ connection.current_user.away_message = away_message
95
+ connection.send_nowaway
95
96
  end
96
97
  end
97
98
 
98
99
  def handle_who(message)
99
100
  find_channel_or_error(message.parameters.first) do |channel|
100
- server.send_who(channel)
101
+ connection.send_who(channel)
101
102
  end
102
103
  end
103
104
 
@@ -105,12 +106,12 @@ module Flamethrower
105
106
  find_channel_or_error(message.parameters.first) do |channel|
106
107
  room = channel.to_campfire
107
108
  room.stop
108
- server.send_part(server.current_user, channel)
109
+ connection.send_part(connection.current_user, channel)
109
110
  end
110
111
  end
111
112
 
112
113
  def handle_quit(message)
113
- server.irc_channels.each {|c| c.to_campfire.stop}
114
+ connection.irc_channels.each {|c| c.to_campfire.stop}
114
115
  end
115
116
  end
116
117
  end
@@ -1,6 +1,7 @@
1
1
  module Flamethrower
2
2
  module Irc
3
3
  module Codes
4
+ RPL_WLCM = '001'
4
5
  RPL_UMODEIS = 221
5
6
  RPL_UNAWAY = 305
6
7
  RPL_NOWAWAY = 306
@@ -3,10 +3,13 @@ module Flamethrower
3
3
  module Commands
4
4
  include Flamethrower::Irc::Codes
5
5
 
6
+ def send_welcome
7
+ send_message reply(RPL_WLCM, ":Welcome to Flamethrower")
8
+ end
9
+
6
10
  def send_motd
7
11
  send_messages do |messages|
8
12
  messages << reply(RPL_MOTDSTART, ":MOTD")
9
- messages << reply(RPL_MOTD, ":Welcome to Flamethrower")
10
13
  messages << reply(RPL_MOTD, ":Fetching channel list from campfire...")
11
14
  end
12
15
  end
@@ -66,6 +69,10 @@ module Flamethrower
66
69
  send_message reply(RPL_UMODEIS, @current_user.mode)
67
70
  end
68
71
 
72
+ def send_join(user, channel)
73
+ send_message ":#{user.to_s} JOIN #{channel.name}"
74
+ end
75
+
69
76
  def send_part(user, channel)
70
77
  send_message ":#{user.to_s} PART #{channel.name}"
71
78
  end
@@ -1,6 +1,6 @@
1
1
  module Flamethrower
2
2
  class EventConnection < EventMachine::Connection
3
- include Flamethrower::Server
3
+ include Flamethrower::Connection
4
4
 
5
5
  attr_accessor :server
6
6
 
@@ -22,13 +22,19 @@ module Flamethrower
22
22
  end
23
23
 
24
24
  class EventServer
25
- attr_reader :host, :port, :campfire_connection, :connections
25
+ attr_reader :host, :port, :ascii_conversion, :campfire_connection, :connections
26
+ ASCII_DEFAULTS = {
27
+ 'enabled' => true
28
+ }
26
29
 
27
- def initialize(host, port, domain, token)
28
- @host = host || "0.0.0.0"
29
- @port = port || 6667
30
- @domain = domain
31
- @token = token
30
+ def initialize(options = {})
31
+ @host = options['host'] || "0.0.0.0"
32
+ @port = options['port'] || 6667
33
+ @domain = options['domain']
34
+ @token = options['token']
35
+ @ascii_conversion = options['ascii_conversion'] ?
36
+ ASCII_DEFAULTS.merge(options['ascii_conversion']) :
37
+ ASCII_DEFAULTS
32
38
  @connections = []
33
39
  end
34
40
 
@@ -1,6 +1,6 @@
1
1
  module Flamethrower
2
- class MockServer
3
- include Flamethrower::Server
2
+ class MockConnection
3
+ include Flamethrower::Connection
4
4
 
5
5
  def send_data(msg)
6
6
  end
@@ -9,5 +9,9 @@ module Flamethrower
9
9
  Flamethrower::Campfire::Connection.new("mydomain", "mytoken", self)
10
10
  end
11
11
 
12
+ def server
13
+ Flamethrower::EventServer.new
14
+ end
15
+
12
16
  end
13
17
  end
@@ -0,0 +1 @@
1
+ {"messages":[{"type":"KickMessage","room_id":347348,"created_at":"2011/05/02 04:30:15 +0000","id":344873939,"body":null,"user_id":899091},{"type":"TimestampMessage","room_id":347348,"created_at":"2011/05/02 17:45:00 +0000","id":345107174,"body":null,"user_id":null},{"type":"EnterMessage","room_id":347348,"created_at":"2011/05/02 17:45:17 +0000","id":345107175,"body":null,"user_id":734581},{"type":"EnterMessage","room_id":347348,"created_at":"2011/05/02 17:45:58 +0000","id":345107527,"body":null,"user_id":899091},{"type":"TextMessage","room_id":347348,"created_at":"2011/05/02 17:46:33 +0000","id":345107811,"body":"http://www.berkeleytwpschools.com/bts/Potter/Classroom%20Web%20Pages/Library/Links%20of%20the%20Month/___zumuhead.html_files/sad-eyes-dog-puppy-clip-art-thumb3033696.jpg","user_id":899091},{"type":"TimestampMessage","room_id":347348,"created_at":"2011/05/02 18:00:00 +0000","id":345116388,"body":null,"user_id":null},{"type":"KickMessage","room_id":347348,"created_at":"2011/05/02 18:00:27 +0000","id":345116389,"body":null,"user_id":734581},{"type":"KickMessage","room_id":347348,"created_at":"2011/05/02 18:00:27 +0000","id":345116395,"body":null,"user_id":899091},{"type":"TimestampMessage","room_id":347348,"created_at":"2011/05/09 04:00:00 +0000","id":347880310,"body":null,"user_id":null},{"type":"EnterMessage","room_id":347348,"created_at":"2011/05/09 04:01:34 +0000","id":347880311,"body":null,"user_id":734581}]}
@@ -0,0 +1 @@
1
+ {"room_id":73541,"created_at":"2010/12/14 20:09:23 +0000","body":"http://example.com/kitties.jpg","id":289361911,"user_id":489198,"type":"TextMessage"}
@@ -0,0 +1 @@
1
+ {"room_id":73541,"created_at":"2011/01/26 16:34:46 +0000","body":"--- \n:author_username: jeresig\n:author_avatar_url: http://a1.twimg.com/profile_images/1181631474/john_normal.jpg\n:message: \"A hilarious video pops up after you unsubscribe from Groupon emails: http://j.mp/hpes49 Punish the developer!\"\n:id: 30293022537162752\n","id":304070140,"user_id":703609,"type":"TweetMessage"}
@@ -1,7 +1,7 @@
1
1
  $:.unshift File.join(File.dirname(__FILE__), "../lib")
2
2
 
3
3
  require 'flamethrower'
4
- require 'server/mock_server'
4
+ require 'server/mock_connection'
5
5
  require 'webmock/rspec'
6
6
  require 'json'
7
7
  require 'time'
@@ -2,26 +2,26 @@ require File.join(File.dirname(__FILE__), "../../spec_helper")
2
2
 
3
3
  describe Flamethrower::Campfire::Connection do
4
4
  before do
5
- @server = Flamethrower::MockServer.new
6
- @connection = @server.campfire_connection
5
+ @connection = Flamethrower::MockConnection.new
6
+ @campfire_connection = @connection.campfire_connection
7
7
  end
8
8
 
9
9
  describe "#fetch_my_user" do
10
- it "retrieves my user and stores it on the connection" do
10
+ it "retrieves my user and stores it on the campfire_connection" do
11
11
  stub_request(:get, "https://mydomain.campfirenow.com/users/me.json").
12
12
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
13
13
  to_return(:status => 200, :body => json_fixture("user"))
14
- EM.run_block { @connection.fetch_my_user }
15
- @server.current_user.nickname.should == "blake"
14
+ EM.run_block { @campfire_connection.fetch_my_user }
15
+ @connection.current_user.nickname.should == "blake"
16
16
  end
17
17
 
18
18
  it "renames your current user to the new current user" do
19
- @server.current_user = Flamethrower::Irc::User.new(:nickname => "bob")
19
+ @connection.current_user = Flamethrower::Irc::User.new(:nickname => "bob")
20
20
  stub_request(:get, "https://mydomain.campfirenow.com/users/me.json").
21
21
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
22
22
  to_return(:status => 200, :body => json_fixture("user"))
23
- @server.should_receive(:send_message).with(":bob NICK blake")
24
- EM.run_block { @connection.fetch_my_user }
23
+ @connection.should_receive(:send_message).with(":bob NICK blake")
24
+ EM.run_block { @campfire_connection.fetch_my_user }
25
25
  end
26
26
  end
27
27
 
@@ -30,8 +30,8 @@ describe Flamethrower::Campfire::Connection do
30
30
  stub_request(:get, "https://mydomain.campfirenow.com/rooms.json").
31
31
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
32
32
  to_return(:status => 200, :body => json_fixture("rooms"))
33
- EM.run_block { @connection.fetch_rooms }
34
- room = @server.irc_channels.first.to_campfire
33
+ EM.run_block { @campfire_connection.fetch_rooms }
34
+ room = @connection.irc_channels.first.to_campfire
35
35
  room.number.should == 347348
36
36
  room.name.should == "Room 1"
37
37
  room.topic.should == "some topic"
@@ -41,7 +41,7 @@ describe Flamethrower::Campfire::Connection do
41
41
  stub_request(:get, "https://mydomain.campfirenow.com/rooms.json").
42
42
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
43
43
  to_return(:status => 200, :body => json_fixture("rooms"))
44
- EM.run_block { @connection.fetch_rooms }
44
+ EM.run_block { @campfire_connection.fetch_rooms }
45
45
  assert_requested(:get, "https://mydomain.campfirenow.com/rooms.json") {|req| req.headers['Authorization'].should == ["mytoken", "x"]}
46
46
  end
47
47
 
@@ -49,14 +49,17 @@ describe Flamethrower::Campfire::Connection do
49
49
  stub_request(:get, "https://mydomain.campfirenow.com/rooms.json").
50
50
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
51
51
  to_return(:status => 400)
52
- EM.run_block { @connection.fetch_rooms }
53
- @server.irc_channels.should == []
52
+ EM.run_block { @campfire_connection.fetch_rooms }
53
+ @connection.irc_channels.should == []
54
54
  end
55
55
 
56
- xit "sends a motd error message if unable to fetch room list" do
57
- @connection.should_receive(:campfire_get).and_raise(SocketError)
58
- @server.should_receive(:send_message).with(@server.reply(Flamethrower::Irc::Codes::RPL_MOTD, ":ERROR: Unable to fetch room list! Check your connection?"))
59
- @connection.rooms.should == []
56
+ it "sends a motd error message if unable to fetch room list" do
57
+ stub_request(:get, "https://mydomain.campfirenow.com/rooms.json").
58
+ with(:headers => {'Authorization'=>['mytoken', 'x']}).
59
+ to_timeout
60
+ @connection.should_receive(:send_message).with(@connection.reply(Flamethrower::Irc::Codes::RPL_MOTD, ":ERROR: Unable to make API call GET /rooms.json. Check your connection?"))
61
+ EM.run_block { @campfire_connection.fetch_rooms }
62
+ @connection.irc_channels.should == []
60
63
  end
61
64
  end
62
65
 
@@ -75,6 +75,72 @@ describe Flamethrower::Campfire::Message do
75
75
  end
76
76
  end
77
77
 
78
+ describe "#image_urls" do
79
+ it "returns a standalone image url" do
80
+ @message.body = "http://example.com/kitties.jpg"
81
+ @message.image_urls.should == ["http://example.com/kitties.jpg"]
82
+ end
83
+
84
+ it "supports jpeg" do
85
+ @message.body = "http://example.com/kitties.jpeg"
86
+ @message.image_urls.should == ["http://example.com/kitties.jpeg"]
87
+ end
88
+
89
+ it "supports gif" do
90
+ @message.body = "http://example.com/kitties.gif"
91
+ @message.image_urls.should == ["http://example.com/kitties.gif"]
92
+ end
93
+
94
+ it "supports png" do
95
+ @message.body = "http://example.com/kitties.png"
96
+ @message.image_urls.should == ["http://example.com/kitties.png"]
97
+ end
98
+
99
+ it "supports multiple images" do
100
+ @message.body = "http://example.com/kitties.png http://blah.com/duppy-pogs.png"
101
+ @message.image_urls.should == ["http://example.com/kitties.png", "http://blah.com/duppy-pogs.png"]
102
+ end
103
+
104
+ it "supports interleaved urls with messages" do
105
+ @message.body = "check this out: http://example.com/kitties.png"
106
+ @message.image_urls.should == ["http://example.com/kitties.png"]
107
+ end
108
+
109
+ it "supports upcased image extensions" do
110
+ @message.body = "check this out: http://example.com/kitties.PNG"
111
+ @message.image_urls.should == ["http://example.com/kitties.PNG"]
112
+ end
113
+
114
+ it "supports https image links" do
115
+ @message.body = "check this out: https://example.com/kitties.png"
116
+ @message.image_urls.should == ["https://example.com/kitties.png"]
117
+ end
118
+ end
119
+
120
+ describe "#has_images?" do
121
+ it "returns true if there are images present in the body" do
122
+ @message.body = "look ma! kitties! http://example.com/kitties.jpg"
123
+ @message.should have_images
124
+ end
125
+
126
+ it "returns false if there are no images present in the body" do
127
+ @message.body = "i love lamp, i really do"
128
+ @message.should_not have_images
129
+ end
130
+ end
131
+
132
+ describe "#needs_conversion?" do
133
+ it "returns true if the image hasn't been converted yet" do
134
+ @message.body = "look ma! kitties! http://example.com/kitties.jpg"
135
+ @message.should be_needs_image_conversion
136
+ end
137
+
138
+ it "returns false if the image has already been converted" do
139
+ @message.set_ascii_image("LOLCATS ASCII HERE!")
140
+ @message.should_not be_needs_image_conversion
141
+ end
142
+ end
143
+
78
144
  describe "#mark_delivered!" do
79
145
  it "sets the status to delivered" do
80
146
  @message.status.should_not == "delivered"
@@ -2,9 +2,9 @@ require File.join(File.dirname(__FILE__), "../../spec_helper")
2
2
 
3
3
  describe Flamethrower::Campfire::Room do
4
4
  before do
5
- @server = Flamethrower::MockServer.new
5
+ @connection = Flamethrower::MockConnection.new
6
6
  @room = Flamethrower::Campfire::Room.new("mydomain", "mytoken", "id" => 347348, "topic" => "some topic", "name" => "some name")
7
- @room.server = @server
7
+ @room.connection = @connection
8
8
  @user = Flamethrower::Campfire::User.new('name' => "bob", 'id' => 489198)
9
9
  @user2 = Flamethrower::Campfire::User.new('name' => "bill", 'id' => 123456)
10
10
  end
@@ -30,6 +30,38 @@ describe Flamethrower::Campfire::Room do
30
30
  end
31
31
  end
32
32
 
33
+ describe "#on_reconnect" do
34
+ it "writes to the log that it reconnected" do
35
+ message = "Reconnected to some name stream"
36
+ ::FLAMETHROWER_LOGGER.should_receive(:debug).with(message)
37
+
38
+ @room.on_reconnect
39
+ end
40
+ end
41
+
42
+ describe "#on_max_reconnects" do
43
+ before do
44
+ @room.instance_variable_set("@stream", mock(:stream))
45
+ end
46
+
47
+ it "writes to the log that it has failed to reconnect" do
48
+ @room.stub(:setup_reconnect)
49
+ message = "Failed to reconnect to some name, restarting room in 20 seconds"
50
+ ::FLAMETHROWER_LOGGER.should_receive(:debug).with(message)
51
+
52
+ @room.on_max_reconnects
53
+ end
54
+ end
55
+
56
+ describe "#on_error" do
57
+ it "writes to the log that there was an error" do
58
+ message = "There was an error connecting to some name stream"
59
+ ::FLAMETHROWER_LOGGER.should_receive(:debug).with(message)
60
+
61
+ @room.on_error
62
+ end
63
+ end
64
+
33
65
  describe "#send_topic!" do
34
66
  it "sets the topic when the campfire API returns 200" do
35
67
  stub_request(:put, "https://mydomain.campfirenow.com/room/347348.json").
@@ -47,6 +79,40 @@ describe Flamethrower::Campfire::Room do
47
79
  EM.run_block { @room.send_topic("some updated topic") }
48
80
  @room.topic.should == "some old topic"
49
81
  end
82
+
83
+ it "sends a motd error message if the send_topic call times out" do
84
+ stub_request(:put, "https://mydomain.campfirenow.com/room/347348.json").
85
+ with(:headers => {'Authorization'=>['mytoken', 'x'], 'Content-Type'=>'application/json'}).
86
+ to_timeout
87
+ @connection.should_receive(:send_message).with(@connection.reply(Flamethrower::Irc::Codes::RPL_MOTD, ":ERROR: Unable to make API call PUT /room/347348.json. Check your connection?"))
88
+ @room.instance_variable_set("@topic", "some old topic")
89
+ EM.run_block { @room.send_topic("some updated topic") }
90
+ @room.topic.should == "some old topic"
91
+ end
92
+ end
93
+
94
+ describe "#stop" do
95
+ it "should stop the stream" do
96
+ EventMachine.stub(:cancel_timer)
97
+ @room.instance_variable_set("@stream", mock(:stream, :stop => nil))
98
+ @room.stream.should_receive(:stop)
99
+ @room.stop
100
+ end
101
+
102
+ it "should cancel the timers" do
103
+ timer = mock(:timer)
104
+ @room.instance_variable_set("@polling_timer", timer)
105
+ @room.instance_variable_set("@periodic_timer", timer)
106
+ EventMachine.should_receive(:cancel_timer).with(timer).twice
107
+ @room.stop
108
+ end
109
+
110
+ it "should flip all the appropriate stop booleans" do
111
+ EventMachine.stub(:cancel_timer)
112
+ @room.stop
113
+ @room.should_not be_alive
114
+ @room.instance_variable_get("@room_info_set").should be_false
115
+ end
50
116
  end
51
117
 
52
118
  describe "#fetch_room_info" do
@@ -54,6 +120,7 @@ describe Flamethrower::Campfire::Room do
54
120
  stub_request(:get, "https://mydomain.campfirenow.com/room/347348.json").
55
121
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
56
122
  to_return(:status => 200, :body => json_fixture("room"))
123
+ @room.stub(:fetch_recent_messages)
57
124
  end
58
125
 
59
126
  it "retrieves a list of users and stores them as user objects" do
@@ -71,6 +138,31 @@ describe Flamethrower::Campfire::Room do
71
138
  EM.run_block { @room.fetch_room_info }
72
139
  assert_requested(:get, "https://mydomain.campfirenow.com/room/347348.json") {|req| req.headers['Authorization'].should == ["mytoken", "x"]}
73
140
  end
141
+
142
+ it "calls fetch_recent_messages if the room_info_set is false" do
143
+ @room.instance_variable_set("@room_info_sent", false)
144
+ @room.should_receive(:fetch_recent_messages)
145
+ EM.run_block { @room.fetch_room_info }
146
+ end
147
+
148
+ it "doesn't call fetch_recent_messages if the room_info_sent = true" do
149
+ @room.instance_variable_set("@room_info_sent", true)
150
+ @room.should_not_receive(:fetch_recent_messages)
151
+ EM.run_block { @room.fetch_room_info }
152
+ end
153
+ end
154
+
155
+ describe "#fetch_recent_messages" do
156
+ before do
157
+ stub_request(:get, "https://mydomain.campfirenow.com/room/347348/recent.json?limit=10").
158
+ with(:headers => {'Authorization'=>['mytoken', 'x']}).
159
+ to_return(:status => 200, :body => json_fixture("recent_messages"))
160
+ end
161
+
162
+ it "retrieves the most recent 10 messages and sends them to the inbound message queue" do
163
+ EM.run_block { @room.fetch_recent_messages }
164
+ @room.instance_variable_get("@users_to_fetch").size.should == 7
165
+ end
74
166
  end
75
167
 
76
168
  describe "#resolve renames" do
@@ -87,12 +179,48 @@ describe Flamethrower::Campfire::Room do
87
179
  bob2.name = "Bob Hope"
88
180
  new_users = [blake2, bob2, bill]
89
181
 
90
- @room.server.should_receive(:send_rename).with("blake", "Blake_Smith")
91
- @room.server.should_receive(:send_rename).with("bob", "Bob_Hope")
182
+ @room.connection.should_receive(:send_rename).with("blake", "Blake_Smith")
183
+ @room.connection.should_receive(:send_rename).with("bob", "Bob_Hope")
184
+ @room.resolve_renames(old_users, new_users)
185
+ end
186
+
187
+ it "doesn't rename if old_users has a user that new_users doesn't" do
188
+ blake = Flamethrower::Campfire::User.new('id' => 1, 'name' => 'blake')
189
+ bob = Flamethrower::Campfire::User.new('id' => 2, 'name' => 'bob')
190
+ bill = Flamethrower::Campfire::User.new('id' => 3, 'name' => 'bill')
191
+ old_users = [blake, bob, bill]
192
+ new_users = [blake, bob]
193
+
194
+ @room.connection.should_not_receive(:send_rename)
92
195
  @room.resolve_renames(old_users, new_users)
93
196
  end
94
197
  end
95
198
 
199
+ describe "#fetch_images" do
200
+ it "makes a call to the image ascii service to convert the image" do
201
+ stub_request(:get, "http://skeeter.blakesmith.me/?image_url=http://example.com/kitties.jpg&width=80").
202
+ to_return(:status => 200, :body => "LOLCAT ASCII ART HERE!")
203
+ @message = Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("streaming_image_message")))
204
+ @room.instance_variable_get("@images_to_fetch") << @message
205
+ EM.run_block { @room.fetch_images }
206
+ expected_body = "http://example.com/kitties.jpg\n"
207
+ expected_body << "LOLCAT ASCII ART HERE!"
208
+ @message.body.should == expected_body
209
+ end
210
+
211
+ context "when the image get call fails" do
212
+ it "marks the message as failed and puts it into the failed messages" do
213
+ stub_request(:get, "http://skeeter.blakesmith.me/?image_url=http://example.com/kitties.jpg&width=80").
214
+ to_return(:status => 400, :body => "An error has occured")
215
+ @message = Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("streaming_image_message")))
216
+ @message.user = mock('user')
217
+ @room.instance_variable_get("@images_to_fetch") << @message
218
+ EM.run_block { @room.fetch_images }
219
+ @room.instance_variable_get("@failed_messages").size.should == 1
220
+ end
221
+ end
222
+ end
223
+
96
224
  describe "#fetch_users" do
97
225
  it "makes a call to the campfire api to fetch user information" do
98
226
  stub_request(:get, "https://mydomain.campfirenow.com/users/734581.json").
@@ -104,9 +232,8 @@ describe Flamethrower::Campfire::Room do
104
232
  end
105
233
 
106
234
  it "fetches using the 'user_id' field if a streaming message" do
107
- stub_request(:get, "https://mytoken:x@mydomain.campfirenow.com/users/734581.json").to_return(:body => json_fixture("user"), :status => 200)
108
235
  @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
109
- @room.should_receive(:campfire_get).with("/users/734581.json").and_return(mock(:post, :callback => nil))
236
+ @room.should_receive(:campfire_get).with("/users/734581.json").and_return(mock(:get, :callback => nil))
110
237
  EM.run_block { @room.fetch_users }
111
238
  end
112
239
 
@@ -115,7 +242,9 @@ describe Flamethrower::Campfire::Room do
115
242
  stub_request(:get, "https://mydomain.campfirenow.com/users/734581.json").
116
243
  with(:headers => {'Authorization'=>['mytoken', 'x']}).
117
244
  to_return(:status => 200, :body => json_fixture("user"))
118
- @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
245
+ json = JSON.parse(json_fixture('enter_message'))
246
+ json['direction'] = 'inbound'
247
+ @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(json)
119
248
  EM.run_block { @room.fetch_users }
120
249
  message = @room.inbound_messages.pop.user.number.should == 734581
121
250
  end
@@ -130,6 +259,15 @@ describe Flamethrower::Campfire::Room do
130
259
  EM.run_block { @room.fetch_users }
131
260
  message = @room.inbound_messages.size.should == 0
132
261
  end
262
+
263
+ it "marks the message as failed and puts it into failed messages" do
264
+ stub_request(:get, "https://mydomain.campfirenow.com/users/734581.json").
265
+ with(:headers => {'Authorization'=>['mytoken', 'x']}).
266
+ to_return(:status => 400, :body => json_fixture("user"))
267
+ @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
268
+ EM.run_block { @room.fetch_users }
269
+ message = @room.instance_variable_get("@failed_messages").size.should == 1
270
+ end
133
271
  end
134
272
  end
135
273
 
@@ -149,18 +287,37 @@ describe Flamethrower::Campfire::Room do
149
287
  EM.run_block { @room.join }
150
288
  @room.joined.should be_false
151
289
  end
290
+
291
+ it "sends a motd error message if the join call times out" do
292
+ stub_request(:post, "https://mydomain.campfirenow.com/room/347348/join.json").
293
+ with(:headers => {'Authorization'=>['mytoken', 'x'], 'Content-Type'=>'application/json'}).
294
+ to_timeout
295
+ @connection.should_receive(:send_message).with(@connection.reply(Flamethrower::Irc::Codes::RPL_MOTD, ":ERROR: Unable to make API call POST /room/347348/join.json. Check your connection?"))
296
+ EM.run_block { @room.join }
297
+ @room.joined.should be_false
298
+ end
152
299
  end
153
300
 
154
301
  describe "#connect" do
155
302
  it "initializes the twitter jsonstream with the right options" do
156
- Twitter::JSONStream.should_receive(:connect).with(:path => "/room/347348/live.json", :host => "streaming.campfirenow.com", :auth => "mytoken:x")
303
+ stream = mock(:stream, :on_reconnect => nil, :on_error => nil, :on_max_reconnects => nil)
304
+ Twitter::JSONStream.should_receive(:connect).with(:path => "/room/347348/live.json", :host => "streaming.campfirenow.com", :auth => "mytoken:x").and_return(stream)
305
+ @room.connect
306
+ end
307
+
308
+ it "sets up the stream callbacks" do
309
+ stream = mock(:stream, :on_reconnect => nil, :on_error => nil, :on_max_reconnects => nil)
310
+ Twitter::JSONStream.should_receive(:connect).with(:path => "/room/347348/live.json", :host => "streaming.campfirenow.com", :auth => "mytoken:x").and_return(stream)
311
+
312
+ @room.should_receive(:setup_stream_callbacks)
157
313
  @room.connect
158
314
  end
159
315
  end
160
316
 
161
317
  describe "#fetch_messages" do
162
318
  before do
163
- Twitter::JSONStream.stub(:connect).and_return("stream")
319
+ stream = mock(:stream, :on_reconnect => nil, :on_error => nil, :on_max_reconnects => nil)
320
+ Twitter::JSONStream.stub(:connect).and_return(stream)
164
321
  @item = json_fixture("streaming_message")
165
322
  @room.users << @user
166
323
  @room.connect
@@ -188,6 +345,11 @@ describe Flamethrower::Campfire::Room do
188
345
  @room.inbound_messages.pop.room.should == @room
189
346
  end
190
347
 
348
+ it "marks the message as inbound" do
349
+ @room.fetch_messages
350
+ @room.inbound_messages.pop.should be_inbound
351
+ end
352
+
191
353
  it "discards timestamp messages altogether" do
192
354
  item = json_fixture("timestamp_message")
193
355
  @room.stream.stub(:each_item).and_yield(item)
@@ -202,23 +364,46 @@ describe Flamethrower::Campfire::Room do
202
364
  @room.stream.stub(:each_item).and_yield(enter_message.to_json)
203
365
  @room.fetch_messages
204
366
  @room.instance_variable_get("@users_to_fetch").size.should == 1
367
+ @room.instance_variable_get("@inbound_messages").size.should == 0
368
+ end
369
+
370
+ it "puts messages that have an image url in the into the images_to_fetch queue" do
371
+ image_message = json_fixture("streaming_image_message")
372
+ @room.stream.stub(:each_item).and_yield(image_message)
373
+ @room.fetch_messages
374
+ @room.instance_variable_get("@inbound_messages").size.should == 0
375
+ @room.instance_variable_get("@images_to_fetch").size.should == 1
376
+ end
377
+
378
+ it "doesn't make the call to the image ascii service if the option is disabled" do
379
+ @room.connection.server.ascii_conversion['enabled'] = false
380
+ image_message = json_fixture("streaming_image_message")
381
+ @room.stream.stub(:each_item).and_yield(image_message)
382
+ @room.fetch_messages
383
+ @room.instance_variable_get("@users_to_fetch").size.should == 0
384
+ @room.instance_variable_get("@images_to_fetch").size.should == 0
385
+ @room.instance_variable_get("@inbound_messages").size.should == 1
205
386
  end
206
387
  end
207
388
 
208
389
  describe "#say" do
209
390
  it "queues a campfire message given a message body" do
210
- message = Flamethrower::Campfire::Message.new('body' => 'Hello there', 'user' => @user, 'room' => @room)
211
391
  @room.say('Hello there')
212
392
  popped_message = @room.outbound_messages.pop
213
393
  popped_message.body.should == 'Hello there'
214
394
  end
215
395
 
216
396
  it "takes an optional message type" do
217
- message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room)
218
397
  @room.say('Hello there', 'TextMessage')
219
398
  popped_message = @room.outbound_messages.pop
220
399
  popped_message.message_type.should == 'TextMessage'
221
400
  end
401
+
402
+ it "marks the message as an outbound message" do
403
+ @room.say('Hello there', 'TextMessage')
404
+ popped_message = @room.outbound_messages.pop
405
+ popped_message.should be_outbound
406
+ end
222
407
  end
223
408
 
224
409
  describe "#translate_nicknames" do
@@ -240,25 +425,47 @@ describe Flamethrower::Campfire::Room do
240
425
  end
241
426
 
242
427
  describe "#requeue_failed_messages" do
243
- it "queues a message whos retry_at is greater than now" do
428
+ it "queues an outbound message whos retry_at is greater than now" do
244
429
  Time.stub(:now).and_return(Time.parse("9:00AM"))
245
- message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room)
430
+ message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room, 'direction' => 'outbound')
246
431
  message.retry_at = Time.parse("9:00:01AM")
432
+ message.status = "failed"
247
433
  @room.failed_messages << message
248
434
  @room.requeue_failed_messages
249
435
  @room.outbound_messages.size.should == 1
250
436
  @room.failed_messages.size.should == 0
251
437
  end
252
438
 
439
+ it "queues an inbound message whos retry_at is greater than now" do
440
+ Time.stub(:now).and_return(Time.parse("9:00AM"))
441
+ message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room, 'direction' => 'inbound')
442
+ message.retry_at = Time.parse("9:00:01AM")
443
+ message.status = "failed"
444
+ @room.failed_messages << message
445
+ @room.requeue_failed_messages
446
+ @room.inbound_messages.size.should == 1
447
+ @room.failed_messages.size.should == 0
448
+ end
449
+
253
450
  it "doesn't queue a message whos retry_at is less than now" do
254
451
  Time.stub(:now).and_return(Time.parse("9:00AM"))
255
- message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room)
452
+ message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room, 'direction' => 'outbound')
256
453
  message.retry_at = Time.parse("8:59AM")
454
+ message.status = "failed"
257
455
  @room.failed_messages << message
258
456
  @room.requeue_failed_messages
259
457
  @room.outbound_messages.size.should == 0
260
458
  @room.failed_messages.size.should == 1
261
459
  end
460
+
461
+ it "marks the message as pending when it requeues" do
462
+ Time.stub(:now).and_return(Time.parse("9:00AM"))
463
+ message = Flamethrower::Campfire::Message.new('type' => 'TextMessage', 'body' => 'Hello there', 'user' => @user, 'room' => @room, 'direction' => 'inbound')
464
+ message.mark_failed!
465
+ @room.failed_messages << message
466
+ @room.requeue_failed_messages
467
+ message.should be_pending
468
+ end
262
469
  end
263
470
 
264
471
  describe "#post_messages" do