flamethrower 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  *.swp
2
2
  *.swo
3
3
  *.swn
4
+ *.gem
@@ -16,15 +16,17 @@ in the MOTD message. /join anyone of these and start chatting.
16
16
 
17
17
  You can also create a YAML file with domain and token specified like so:
18
18
 
19
- domain: mydomain
20
- token: aoeu1234
19
+ domain: mydomain
20
+ token: aoeu1234
21
21
 
22
22
  Then start flamethrower like so:
23
23
 
24
- flamethrower -c ~/myconfig.yml
24
+ flamethrower -c ~/myconfig.yml
25
25
 
26
26
  === A work in progress
27
27
 
28
+ TODO: Switch Net::HTTP sync calls to async EM::HttpRequest calls.
29
+
28
30
  Flamethrower is a work in progress. Right now basic messaging works, but
29
31
  it still needs a lot of love. If you find it useful and would like to see
30
32
  it do something, please submit a patch (with tests please)!. Bug reports are
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.1.0
@@ -56,4 +56,10 @@ end
56
56
  FLAMETHROWER_LOGGER = Logger.new(options['logger'] || STDOUT)
57
57
 
58
58
  server = Flamethrower::EventServer.new(options['host'], options['port'], options['domain'], options['token'])
59
+
60
+ trap("INT") do
61
+ FLAMETHROWER_LOGGER.info("Received shutdown signal, killing connections")
62
+ server.stop
63
+ end
64
+
59
65
  server.start
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{flamethrower}
8
- s.version = "0.0.1"
8
+ s.version = "0.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Blake Smith"]
12
- s.date = %q{2010-12-22}
12
+ s.date = %q{2011-01-12}
13
13
  s.default_executable = %q{flamethrower}
14
14
  s.description = %q{Flamethrower gives you the power to use your awesome irc client to talk in your campfire rooms.}
15
15
  s.email = %q{blakesmith0@gmail.com}
@@ -48,11 +48,16 @@ Gem::Specification.new do |s|
48
48
  "spec/fixtures/leave_message.json",
49
49
  "spec/fixtures/message.json",
50
50
  "spec/fixtures/paste_message.json",
51
+ "spec/fixtures/paste_message_with_pound.json",
51
52
  "spec/fixtures/room.json",
52
53
  "spec/fixtures/room_update.json",
53
54
  "spec/fixtures/rooms.json",
54
55
  "spec/fixtures/speak_message.json",
55
56
  "spec/fixtures/streaming_message.json",
57
+ "spec/fixtures/timestamp_message.json",
58
+ "spec/fixtures/upload_message.json",
59
+ "spec/fixtures/upload_url_sample",
60
+ "spec/fixtures/user.json",
56
61
  "spec/spec_helper.rb",
57
62
  "spec/unit/campfire/connection_spec.rb",
58
63
  "spec/unit/campfire/message_spec.rb",
@@ -1,7 +1,7 @@
1
1
  module Flamethrower
2
2
  module Campfire
3
3
  class Message
4
- attr_accessor :body, :user, :room, :message_type, :status, :retry_at
4
+ attr_accessor :body, :user, :room, :message_type, :status, :retry_at, :user_id
5
5
 
6
6
  RETRY_SECONDS = 15
7
7
 
@@ -9,6 +9,7 @@ module Flamethrower
9
9
  @body = params['body']
10
10
  @user = params['user']
11
11
  @room = params['room']
12
+ @user_id = params['user_id']
12
13
  @message_type = params['type']
13
14
  @status = "pending"
14
15
  end
@@ -34,6 +35,8 @@ module Flamethrower
34
35
  irc_string = ":#{@user.to_irc.to_s} PART #{@room.to_irc.name}"
35
36
  when "PasteMessage"
36
37
  irc_string = ":#{@user.to_irc.to_s} PRIVMSG #{@room.to_irc.name} :#{@body}"
38
+ else
39
+ return
37
40
  end
38
41
  Flamethrower::Irc::Message.new(irc_string)
39
42
  end
@@ -13,6 +13,7 @@ module Flamethrower
13
13
  @token = token
14
14
  @inbound_messages = Queue.new
15
15
  @outbound_messages = Queue.new
16
+ @users_to_fetch = Queue.new
16
17
  @failed_messages = []
17
18
  @number = params['id']
18
19
  @name = params['name']
@@ -52,6 +53,7 @@ module Flamethrower
52
53
  fetch_messages
53
54
  post_messages
54
55
  requeue_failed_messages
56
+ fetch_users
55
57
  messages_to_send = to_irc.retrieve_irc_messages
56
58
  messages_to_send.each do |m|
57
59
  ::FLAMETHROWER_LOGGER.debug "Sending irc message #{m.to_s}"
@@ -91,7 +93,29 @@ module Flamethrower
91
93
  ::FLAMETHROWER_LOGGER.debug "Got json message #{params.inspect}"
92
94
  params['user'] = @users.find {|u| u.number == params['user_id'] }
93
95
  params['room'] = self
94
- @inbound_messages << Flamethrower::Campfire::Message.new(params)
96
+ message = Flamethrower::Campfire::Message.new(params)
97
+ unless message.message_type == "TimestampMessage"
98
+ unless message.user
99
+ @users_to_fetch << message
100
+ else
101
+ @inbound_messages << message
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ def fetch_users
108
+ until @users_to_fetch.empty?
109
+ message = @users_to_fetch.pop
110
+ response = campfire_get("/users/#{message.user_id}.json")
111
+ case response
112
+ when Net::HTTPOK
113
+ json = JSON.parse(response.body)
114
+ user = Flamethrower::Campfire::User.new(json['user'])
115
+ message.user = user
116
+ @users << user
117
+ @inbound_messages << message
118
+ end
95
119
  end
96
120
  end
97
121
 
@@ -47,7 +47,7 @@ module Flamethrower
47
47
  private
48
48
 
49
49
  def display_message?(message)
50
- message.message_type != "TimestampMessage"
50
+ message && message.message_type != "TimestampMessage"
51
51
  end
52
52
 
53
53
  end
@@ -3,26 +3,65 @@ module Flamethrower
3
3
  include Flamethrower::Server
4
4
 
5
5
  attr_accessor :server
6
+
7
+ def unbind
8
+ @server.connections.delete(self)
9
+ end
6
10
  end
7
11
 
8
12
  class EventServer
9
- attr_reader :host, :port, :campfire_connection
13
+ attr_reader :host, :port, :campfire_connection, :connections
10
14
 
11
15
  def initialize(host, port, domain, token)
12
16
  @host = host || "0.0.0.0"
13
17
  @port = port || 6667
14
18
  @domain = domain
15
19
  @token = token
20
+ @connections = []
16
21
  end
17
22
 
18
23
  def start
19
24
  EventMachine::run do
20
25
  FLAMETHROWER_LOGGER.info "Flamethrower started at #{@host}:#{@port} on domain #{@domain}"
21
- EventMachine::start_server(@host, @port, EventConnection) do |connection|
26
+ @signature = EventMachine::start_server(@host, @port, EventConnection) do |connection|
27
+ @connections << connection
22
28
  connection.server = self
23
29
  connection.campfire_connection = Flamethrower::Campfire::Connection.new(@domain, @token, connection)
24
30
  end
25
31
  end
26
32
  end
33
+
34
+ def stop
35
+ FLAMETHROWER_LOGGER.info("Killing room threads")
36
+ @connections.each do |connection|
37
+ connection.irc_channels.map do |channel|
38
+ channel.to_campfire.kill_thread!
39
+ end
40
+ end
41
+ EventMachine.stop_server(@signature)
42
+ die_safely
43
+ end
44
+
45
+ def die_safely
46
+ FLAMETHROWER_LOGGER.info("Waiting for streams and connections to die")
47
+ if streams_alive? && connections_alive?
48
+ EventMachine.add_periodic_timer(1) { die_safely }
49
+ else
50
+ FLAMETHROWER_LOGGER.info("Done.")
51
+ EventMachine.stop
52
+ end
53
+ end
54
+
55
+ def streams_alive?
56
+ @connections.any? do |connection|
57
+ connection.irc_channels.any? do |channel|
58
+ channel.to_campfire.alive?
59
+ end
60
+ end
61
+ end
62
+
63
+ def connections_alive?
64
+ @connections.size <= 0
65
+ end
27
66
  end
28
67
  end
@@ -0,0 +1 @@
1
+ {"room_id":73541,"created_at":"2011/01/12 16:45:37 +0000","body":"#secure_asset_host: secure-assets-uat.example.com\nsecure_asset_host: assets1-uat.example.com","id":298515252,"user_id":627807,"type":"PasteMessage"}
@@ -0,0 +1 @@
1
+ {"room_id":73541,"created_at":"2010/12/14 20:09:23 +0000","body":null,"id":289361911,"user_id":489198,"type":"TimestampMessage"}
@@ -0,0 +1 @@
1
+ {"room_id":73541,"created_at":"2011/01/12 15:24:25 +0000","body":"Steak.jpeg","id":298466819,"user_id":786985,"type":"UploadMessage"}
@@ -0,0 +1 @@
1
+ The upload_message.json fixture generated this URL: https://thepoint.campfirenow.com/room/73541/uploads/1711244/Steak.jpeg
@@ -0,0 +1 @@
1
+ {"user":{"type":"Member","created_at":"2010/11/10 03:47:24 +0000","admin":true,"email_address":"bsmith@groupon.com","id":734581,"name":"blake"}}
@@ -4,6 +4,7 @@ require 'flamethrower'
4
4
  require 'server/mock_server'
5
5
  require 'json'
6
6
  require 'fakeweb'
7
+ require 'time'
7
8
 
8
9
  ::FLAMETHROWER_LOGGER = Logger.new("/dev/null") unless Object.const_defined?("FLAMETHROWER_LOGGER")
9
10
 
@@ -27,6 +27,16 @@ describe Flamethrower::Campfire::Message do
27
27
  @message.to_irc.to_s.should == ":#{@irc_user.to_s} PRIVMSG #{@channel.name} :thebody"
28
28
  end
29
29
 
30
+ it "returns if the message type is unhandled" do
31
+ json = JSON.parse(json_fixture('enter_message'))
32
+ json['type'] = "BogusMessage"
33
+ message = Flamethrower::Campfire::Message.new(json)
34
+ message.user = @campfire_user
35
+ message.room = @room
36
+ Flamethrower::Irc::Message.should_not_receive(:new)
37
+ message.to_irc.should be_nil
38
+ end
39
+
30
40
  it "converts a EnterMessage to a join irc message" do
31
41
  json = JSON.parse(json_fixture('enter_message'))
32
42
  message = Flamethrower::Campfire::Message.new(json)
@@ -57,7 +57,40 @@ describe Flamethrower::Campfire::Room do
57
57
  @room.fetch_room_info
58
58
  FakeWeb.last_request['authorization'].should == "Basic #{Base64::encode64("#{@room.token}:x").chomp}"
59
59
  end
60
+ end
61
+
62
+ describe "#fetch_users" do
63
+ it "makes a call to the campfire api to fetch user information" do
64
+ FakeWeb.register_uri(:get, "https://mytoken:x@mydomain.campfirenow.com/users/734581.json", :body => json_fixture("user"), :status => ["200", "OK"])
65
+ @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
66
+ @room.fetch_users
67
+ @room.users.map(&:name).should == ["blake"]
68
+ end
69
+
70
+ it "fetches using the 'user_id' field if a streaming message" do
71
+ FakeWeb.register_uri(:get, "https://mytoken:x@mydomain.campfirenow.com/users/734581.json", :body => json_fixture("user"), :status => ["200", "OK"])
72
+ @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
73
+ @room.should_receive(:campfire_get).with("/users/734581.json")
74
+ @room.fetch_users
75
+ end
76
+
77
+ context "successfully get user info" do
78
+ it "enqueues an EnterMessage into @inbound_messages for displaying in irc" do
79
+ FakeWeb.register_uri(:get, "https://mytoken:x@mydomain.campfirenow.com/users/734581.json", :body => json_fixture("user"), :status => ["200", "OK"])
80
+ @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
81
+ @room.fetch_users
82
+ message = @room.inbound_messages.pop.user.number.should == 734581
83
+ end
84
+ end
60
85
 
86
+ context "fails to get user info" do
87
+ it "doesn't enqueue an EnterMessage" do
88
+ FakeWeb.register_uri(:get, "https://mytoken:x@mydomain.campfirenow.com/users/734581.json", :status => ["400", "Bad Request"])
89
+ @room.instance_variable_get("@users_to_fetch") << Flamethrower::Campfire::Message.new(JSON.parse(json_fixture("enter_message")))
90
+ @room.fetch_users
91
+ message = @room.inbound_messages.size.should == 0
92
+ end
93
+ end
61
94
  end
62
95
 
63
96
  describe "#join" do
@@ -79,45 +112,13 @@ describe Flamethrower::Campfire::Room do
79
112
  end
80
113
  end
81
114
 
82
- describe "#thread" do
83
- before do
84
- Kernel.stub(:sleep)
85
- end
86
-
87
- context "in a Thread" do
88
- it "calls connect at the start of the thread" do
89
- @room.stub(:fetch_messages)
90
- @room.stub(:post_messages)
91
- @room.should_receive(:connect).at_least(1).times
92
- @room.start_thread
93
- @room.kill_thread!
94
- end
95
-
96
- it "fetches messages from the stream" do
97
- @room.stub(:connect)
98
- @room.stub(:post_messages)
99
- @room.should_receive(:fetch_messages).at_least(1).times
100
- @room.start_thread
101
- @room.kill_thread!
102
- end
103
-
104
- it "posts messages to the campfire API" do
105
- @room.stub(:connect)
106
- @room.stub(:fetch_messages)
107
- @room.should_receive(:post_messages).at_least(1).times
108
- @room.start_thread
109
- @room.kill_thread!
110
- end
111
-
112
- end
113
- end
114
-
115
115
  describe "#fetch_messages" do
116
116
  before do
117
117
  Twitter::JSONStream.stub(:connect).and_return("stream")
118
- item = json_fixture("streaming_message")
118
+ @item = json_fixture("streaming_message")
119
+ @room.users << @user
119
120
  @room.connect
120
- @room.stream.stub(:each_item).and_yield(item)
121
+ @room.stream.stub(:each_item).and_yield(@item)
121
122
  end
122
123
 
123
124
  it "iterates over each stream item and sends to the message queue" do
@@ -132,7 +133,6 @@ describe Flamethrower::Campfire::Room do
132
133
 
133
134
  it "maps the message sender to the right user" do
134
135
  @room.users << @user2
135
- @room.users << @user
136
136
  @room.fetch_messages
137
137
  @room.inbound_messages.pop.user.should == @user
138
138
  end
@@ -141,6 +141,22 @@ describe Flamethrower::Campfire::Room do
141
141
  @room.fetch_messages
142
142
  @room.inbound_messages.pop.room.should == @room
143
143
  end
144
+
145
+ it "discards timestamp messages altogether" do
146
+ item = json_fixture("timestamp_message")
147
+ @room.stream.stub(:each_item).and_yield(item)
148
+ @room.fetch_messages
149
+ @room.instance_variable_get("@inbound_messages").size.should == 0
150
+ @room.instance_variable_get("@users_to_fetch").size.should == 0
151
+ end
152
+
153
+ it "puts messages that don't have an existing user into the users_to_fetch queue" do
154
+ enter_message = JSON.parse(json_fixture("streaming_message"))
155
+ enter_message['user_id'] = 98765
156
+ @room.stream.stub(:each_item).and_yield(enter_message.to_json)
157
+ @room.fetch_messages
158
+ @room.instance_variable_get("@users_to_fetch").size.should == 1
159
+ end
144
160
  end
145
161
 
146
162
  describe "#say" do
@@ -46,6 +46,11 @@ describe Flamethrower::Irc::Channel do
46
46
  @channel.retrieve_irc_messages.should be_empty
47
47
  end
48
48
 
49
+ it "doesn't add messages that return nil from to_irc" do
50
+ @room.inbound_messages << nil
51
+ @channel.retrieve_irc_messages.should be_empty
52
+ end
53
+
49
54
  xit "doesn't send the message if the source is the current user" do
50
55
  message = Flamethrower::Campfire::Message.new('body' => 'Hello there', 'user' => @campfire_user, 'room' => @room, 'type' => 'TextMessage')
51
56
  @room.inbound_messages << message
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flamethrower
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 0
9
8
  - 1
10
- version: 0.0.1
9
+ - 0
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Blake Smith
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-22 00:00:00 -06:00
18
+ date: 2011-01-12 00:00:00 -06:00
19
19
  default_executable: flamethrower
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -101,11 +101,16 @@ files:
101
101
  - spec/fixtures/leave_message.json
102
102
  - spec/fixtures/message.json
103
103
  - spec/fixtures/paste_message.json
104
+ - spec/fixtures/paste_message_with_pound.json
104
105
  - spec/fixtures/room.json
105
106
  - spec/fixtures/room_update.json
106
107
  - spec/fixtures/rooms.json
107
108
  - spec/fixtures/speak_message.json
108
109
  - spec/fixtures/streaming_message.json
110
+ - spec/fixtures/timestamp_message.json
111
+ - spec/fixtures/upload_message.json
112
+ - spec/fixtures/upload_url_sample
113
+ - spec/fixtures/user.json
109
114
  - spec/spec_helper.rb
110
115
  - spec/unit/campfire/connection_spec.rb
111
116
  - spec/unit/campfire/message_spec.rb