firetower 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ module Firetower
2
+ class Account
3
+ attr_reader :subdomain, :token, :session, :users
4
+
5
+ def initialize(subdomain, token, session, options = {})
6
+ @subdomain = subdomain
7
+ @token = token
8
+ @session = session
9
+ @ssl = options.fetch(:ssl) { false }
10
+ @users = Hash.new do |cache, user_id|
11
+ data = session.get(subdomain, "/users/#{user_id}.json")
12
+ cache[user_id] = data['user']
13
+ end
14
+ end
15
+
16
+ def rooms
17
+ return @rooms if defined?(@rooms)
18
+ @rooms = Hash.new do |h, k|
19
+ raise "No room named #{k} in #{subdomain}"
20
+ end
21
+ data = session.get(subdomain, "/rooms.json")
22
+ data['rooms'].each do |room_data|
23
+ room = Room.new(self, room_data)
24
+ @rooms[room.name] = room
25
+ end
26
+ @rooms
27
+ end
28
+
29
+ def say!(room_name, text)
30
+ room_id = rooms[room_name].id
31
+ session.post(subdomain, "/room/#{room_id}/speak.json", {
32
+ 'message' => {
33
+ 'body' => text
34
+ }
35
+ })
36
+ end
37
+
38
+ def paste!(room_name, text)
39
+ room_id = rooms[room_name].id
40
+ session.post(subdomain, "/room/#{room_id}/speak.json", {
41
+ 'message' => {
42
+ 'body' => text,
43
+ 'type' => 'PasteMessage'
44
+ }
45
+ })
46
+ end
47
+
48
+ def ssl?
49
+ @ssl
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ # <%= program %> configuration initially generated <%= Time.now %>
2
+
3
+ # Go ahead and customize this file to your heart's content! The content is Ruby
4
+ # code, and all code is evaluated in the context of a Firetower::Session object.
5
+
6
+ # CONNECTIONS
7
+
8
+ # You can connect to as many Campfire accounts as you like :-)
9
+ account '<%= subdomain %>', '<%= token %>', :ssl => <%= use_ssl %>
10
+
11
+ # ROOMS
12
+ # Activity in these rooms will tracked by the <%= program %> server
13
+
14
+ <% room_names.each do |room_name| %>
15
+ join '<%= subdomain %>', '<%= room_name %>'
16
+ <% end %>
17
+
18
+ # DEFAULT ROOM
19
+ default '<%= subdomain %>', '<%= room_names.first %>'
20
+
21
+ # Plugins
22
+ use NotifyPlugin
@@ -0,0 +1 @@
1
+ require 'firetower/plugins/core/notify_plugin.rb'
@@ -0,0 +1,42 @@
1
+ module Firetower
2
+ module Plugins
3
+ class NotifyPlugin < Firetower::Session::Listener
4
+
5
+ def startup(session)
6
+ if session.kind == :server
7
+ notify("Firetower", "Firetower is vigilant!")
8
+ end
9
+ end
10
+
11
+ def join(session, room)
12
+ notify("Firetower", "Joined room \"#{room.name}\"")
13
+ end
14
+
15
+ def receive(session, event)
16
+ case event['type']
17
+ when "TextMessage"
18
+ user = event.room.account.users[event['user_id']]
19
+ notify(user['name'], event['body'])
20
+ else
21
+ # NOOP
22
+ end
23
+ end
24
+
25
+ def error(session, description)
26
+ notify("Campfire Error", description)
27
+ end
28
+
29
+ private
30
+
31
+ def notify(*args)
32
+ system('notify-send', '--icon',
33
+ File.expand_path(
34
+ '../images/campfire-logo-for-fluid.png',
35
+ File.dirname(__FILE__)),
36
+ '-c', 'Firetower',
37
+ *args) or raise "Desktop notification failed"
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module Firetower
2
+ class Room
3
+ attr_reader :id, :name, :account
4
+
5
+ def initialize(account, attributes={})
6
+ @account = account
7
+ @id = attributes['id']
8
+ @name = attributes['name']
9
+ end
10
+
11
+ def to_s
12
+ "#{account.subdomain}/#{id} (#{name})"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,62 @@
1
+ module Firetower
2
+ class Server
3
+ attr_reader :session, :log_path, :pid_path
4
+
5
+ def initialize(session, options={})
6
+ @session = session
7
+ @log_path = Pathname(options.fetch(:log_path))
8
+ @pid_path = Pathname(options.fetch(:pid_path))
9
+ @logger = options.fetch(:logger) {
10
+ ::Logger.new(@log_path, 4, 1024000)
11
+ }
12
+ end
13
+
14
+ def run
15
+ trap('INT') do
16
+ @logger.info "Received INT; shutting down."
17
+ EventMachine.stop_event_loop
18
+ @pid_path.unlink if @pid_path.exist?
19
+ end
20
+ EventMachine::run do
21
+ @logger.info "Firetower is starting up"
22
+ open(@pid_path, 'w+') do |pid_file|
23
+ pid_file.puts $$
24
+ end
25
+ @session.subscribed_rooms.each do |room|
26
+ subscribe_to_room(room)
27
+ end
28
+ end
29
+ session.close!
30
+ end
31
+
32
+ def subscribe_to_room(room)
33
+ @logger.info "Subscribing to #{room}"
34
+ stream = Twitter::JSONStream.connect(
35
+ :path => "/room/#{room.id}/live.json",
36
+ :host => 'streaming.campfirenow.com',
37
+ :auth => "#{room.account.token}:x")
38
+
39
+ stream.each_item do |event|
40
+ @logger.info "Processing event:\n #{event}"
41
+ event = JSON.parse(event)
42
+
43
+ (class << event; self; end).send(:define_method, :room){room}
44
+ session.execute_hook(:receive, session, event)
45
+ end
46
+
47
+ stream.on_error do |message|
48
+ @logger.error message
49
+ session.execute_hook(:error, session, message)
50
+ end
51
+
52
+ stream.on_max_reconnects do |timeout, retries|
53
+ @logger.error "Unable to connect after #{retries} attempts"
54
+ session.execute_hook(:error, session,
55
+ "Unable to connect after #{retries} attempts")
56
+ stop_event_loop
57
+ end
58
+ session.execute_hook(:join, session, room)
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,104 @@
1
+ module Firetower
2
+ module Plugins
3
+ end
4
+
5
+ class Session
6
+ include ::Firetower::Plugins
7
+
8
+ include HookR::Hooks
9
+
10
+ attr_reader :accounts
11
+ attr_reader :connections
12
+ attr_reader :subscribed_rooms
13
+ attr_reader :kind
14
+ attr_reader :default_room
15
+
16
+ attr_accessor :logger
17
+
18
+ define_hook :startup, :session
19
+ define_hook :connect, :session, :account
20
+ define_hook :join, :session, :room
21
+ define_hook :receive, :session, :event
22
+ define_hook :error, :session, :description
23
+ define_hook :leave, :session, :room
24
+ define_hook :disconnect, :session, :account
25
+ define_hook :shutdown, :session
26
+
27
+ def initialize(kind=:command, options={})
28
+ @accounts = Hash.new do |hash, subdomain|
29
+ raise "Unknown subdomain '#{subdomain}'"
30
+ end
31
+ @connections = Hash.new do |hash, subdomain|
32
+ connection =
33
+ if accounts[subdomain].ssl?
34
+ connection = Net::HTTP.new("#{subdomain}.campfirenow.com", Net::HTTP.https_default_port)
35
+ connection.use_ssl = true
36
+ connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
37
+ connection
38
+ else
39
+ Net::HTTP.new("#{subdomain}.campfirenow.com", Net::HTTP.http_default_port)
40
+ end
41
+ hash[subdomain] = connection
42
+ end
43
+ @subscribed_rooms = []
44
+ @kind = kind
45
+ @logger = options.fetch(:logger) { ::Logger.new($stderr) }
46
+ end
47
+
48
+ # Declare an account
49
+ def account(subdomain, token, options={})
50
+ accounts[subdomain] = Account.new(subdomain, token, self, options)
51
+ end
52
+
53
+ # Enable a plugin or extension
54
+ def use(class_or_instance, *args)
55
+ case class_or_instance
56
+ when Class then add_listener(class_or_instance.new(*args))
57
+ else add_listener(class_or_instance)
58
+ end
59
+ end
60
+
61
+ def join(subdomain, room_name)
62
+ @subscribed_rooms << accounts[subdomain].rooms[room_name]
63
+ end
64
+
65
+ # Set default room
66
+ def default(subdomain, room_name)
67
+ @default_room = accounts[subdomain].rooms[room_name]
68
+ end
69
+
70
+ def default_room
71
+ @default_room ||= @subscribed_rooms.first
72
+ end
73
+
74
+ def post(subdomain, path, data)
75
+ request = Net::HTTP::Post.new(path)
76
+ request.body = data.to_json
77
+ request['Content-Type'] = 'application/json'
78
+ perform_request(subdomain, request)
79
+ end
80
+
81
+ def get(subdomain, path)
82
+ request = Net::HTTP::Get.new(path)
83
+ request['Accept'] = 'application/json'
84
+ response = perform_request(subdomain, request)
85
+ JSON.parse(response.body)
86
+ end
87
+
88
+ def perform_request(subdomain, request)
89
+ request.basic_auth(accounts[subdomain].token, '')
90
+ response = connections[subdomain].request(request)
91
+ case response
92
+ when Net::HTTPSuccess
93
+ response
94
+ when Net::HTTPClientError, Net::HTTPServerError
95
+ raise "Error (#{response.message}): \n#{JSON.parse(response.body).to_yaml}"
96
+ end
97
+ response
98
+ end
99
+
100
+ def close!
101
+ # TODO
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,6 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe Firetower do
5
+ end
6
+
@@ -0,0 +1,15 @@
1
+
2
+ require File.expand_path(
3
+ File.join(File.dirname(__FILE__), %w[.. lib firetower]))
4
+
5
+ Spec::Runner.configure do |config|
6
+ # == Mock Framework
7
+ #
8
+ # RSpec uses it's own mocking framework by default. If you prefer to
9
+ # use mocha, flexmock or RR, uncomment the appropriate line:
10
+ #
11
+ # config.mock_with :mocha
12
+ # config.mock_with :flexmock
13
+ # config.mock_with :rr
14
+ end
15
+
File without changes
data/version.txt ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
metadata ADDED
@@ -0,0 +1,206 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: firetower
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Avdi Grimm
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-12 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: twitter-stream
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 1
30
+ - 6
31
+ version: 0.1.6
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: eventmachine
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ - 12
44
+ - 10
45
+ version: 0.12.10
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: json
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 1
57
+ - 4
58
+ version: "1.4"
59
+ type: :runtime
60
+ version_requirements: *id003
61
+ - !ruby/object:Gem::Dependency
62
+ name: addressable
63
+ prerelease: false
64
+ requirement: &id004 !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 2
70
+ - 1
71
+ version: "2.1"
72
+ type: :runtime
73
+ version_requirements: *id004
74
+ - !ruby/object:Gem::Dependency
75
+ name: main
76
+ prerelease: false
77
+ requirement: &id005 !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ~>
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 4
83
+ - 2
84
+ version: "4.2"
85
+ type: :runtime
86
+ version_requirements: *id005
87
+ - !ruby/object:Gem::Dependency
88
+ name: servolux
89
+ prerelease: false
90
+ requirement: &id006 !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ - 9
97
+ - 4
98
+ version: 0.9.4
99
+ type: :runtime
100
+ version_requirements: *id006
101
+ - !ruby/object:Gem::Dependency
102
+ name: hookr
103
+ prerelease: false
104
+ requirement: &id007 !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ~>
107
+ - !ruby/object:Gem::Version
108
+ segments:
109
+ - 1
110
+ - 0
111
+ version: "1.0"
112
+ type: :runtime
113
+ version_requirements: *id007
114
+ - !ruby/object:Gem::Dependency
115
+ name: highline
116
+ prerelease: false
117
+ requirement: &id008 !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ~>
120
+ - !ruby/object:Gem::Version
121
+ segments:
122
+ - 1
123
+ - 5
124
+ version: "1.5"
125
+ type: :runtime
126
+ version_requirements: *id008
127
+ - !ruby/object:Gem::Dependency
128
+ name: bones
129
+ prerelease: false
130
+ requirement: &id009 !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ segments:
135
+ - 3
136
+ - 4
137
+ - 7
138
+ version: 3.4.7
139
+ type: :development
140
+ version_requirements: *id009
141
+ description: ""
142
+ email: avdi@avdi.org
143
+ executables:
144
+ - firetower
145
+ extensions: []
146
+
147
+ extra_rdoc_files:
148
+ - History.txt
149
+ - bin/firetower
150
+ - lib/firetower/firetower.conf.erb
151
+ - version.txt
152
+ files:
153
+ - .bnsignore
154
+ - History.txt
155
+ - README.html
156
+ - README.org
157
+ - Rakefile
158
+ - bin/firetower
159
+ - example/bot.rb
160
+ - images/BaldMountainLookout.jpg
161
+ - images/campfire-logo-for-fluid.png
162
+ - lib/firetower.rb
163
+ - lib/firetower/account.rb
164
+ - lib/firetower/firetower.conf.erb
165
+ - lib/firetower/plugins/core/init_v1.rb
166
+ - lib/firetower/plugins/core/notify_plugin.rb
167
+ - lib/firetower/room.rb
168
+ - lib/firetower/server.rb
169
+ - lib/firetower/session.rb
170
+ - spec/firetower_spec.rb
171
+ - spec/spec_helper.rb
172
+ - test/test_firetower.rb
173
+ - version.txt
174
+ has_rdoc: true
175
+ homepage: http://github.com/avdi/firetower
176
+ licenses: []
177
+
178
+ post_install_message:
179
+ rdoc_options:
180
+ - --main
181
+ - README.org
182
+ require_paths:
183
+ - lib
184
+ required_ruby_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ segments:
189
+ - 0
190
+ version: "0"
191
+ required_rubygems_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ segments:
196
+ - 0
197
+ version: "0"
198
+ requirements: []
199
+
200
+ rubyforge_project: firetower
201
+ rubygems_version: 1.3.6
202
+ signing_key:
203
+ specification_version: 3
204
+ summary: A command-line interface to Campfire chats
205
+ test_files:
206
+ - test/test_firetower.rb