typhon 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/typhon CHANGED
@@ -10,15 +10,15 @@ pidfile = nil
10
10
  opt = OptionParser.new
11
11
 
12
12
  opt.on("--config [DIR]", "Directory for configuration file and heads") do |v|
13
- configdir = v
13
+ configdir = v
14
14
  end
15
15
 
16
16
  opt.on("--daemonize", "-d", "Daemonize the process") do |v|
17
- daemon = true
17
+ daemon = true
18
18
  end
19
19
 
20
20
  opt.on("--pid [PIDFILE]", "-p", "Write a pidfile") do |v|
21
- pidfile = v
21
+ pidfile = v
22
22
  end
23
23
 
24
24
  opt.parse!
@@ -26,13 +26,13 @@ opt.parse!
26
26
  raise "The directory #{configdir} does not exist" unless File.directory?(configdir)
27
27
 
28
28
  def stop_and_exit(daemon, pidfile, signal)
29
- Typhon::Log.info("Exiting after signal #{signal}")
29
+ Typhon::Log.info("Exiting after signal #{signal}")
30
30
 
31
- if daemon && pidfile
32
- File.unlink(pidfile)
33
- end
31
+ if daemon && pidfile
32
+ File.unlink(pidfile)
33
+ end
34
34
 
35
- exit
35
+ exit
36
36
  end
37
37
 
38
38
  Signal.trap('INT') { stop_and_exit(daemon, pidfile, :int) }
@@ -41,23 +41,23 @@ Signal.trap('TERM') { stop_and_exit(daemon, pidfile, :term) }
41
41
  typhon = Typhon.new(configdir)
42
42
 
43
43
  Typhon.files.each do |f|
44
- Typhon::Log.info("Tailing log #{f}")
44
+ Typhon::Log.info("Tailing log #{f}")
45
45
  end
46
46
 
47
47
  if daemon
48
- raise "Pidfile #{pidfile} exist" if pidfile && File.exist?(pidfile)
49
-
50
- Typhon.daemonize do
51
- if pidfile
52
- begin
53
- File.open(pidfile, 'w') {|f| f.write(Process.pid) }
54
- rescue
55
- end
56
- end
57
-
58
- Typhon::Log.info("Running in the background as pid #{Process.pid}")
59
- typhon.tail
48
+ raise "Pidfile #{pidfile} exist" if pidfile && File.exist?(pidfile)
49
+
50
+ Typhon.daemonize do
51
+ if pidfile
52
+ begin
53
+ File.open(pidfile, 'w') {|f| f.write(Process.pid) }
54
+ rescue
55
+ end
60
56
  end
61
- else
57
+
58
+ Typhon::Log.info("Running in the background as pid #{Process.pid}")
62
59
  typhon.tail
60
+ end
61
+ else
62
+ typhon.tail
63
63
  end
@@ -1,82 +1,84 @@
1
1
  class Typhon
2
- require 'rubygems'
3
- require 'yaml'
4
- require 'eventmachine'
5
- require 'eventmachine-tail'
6
- require 'typhon/heads'
7
- require 'typhon/log'
8
- require 'typhon/config'
9
- require 'typhon/stompclient'
10
-
11
- class << self
12
- def heads
13
- Heads.heads
14
- end
2
+ require 'rubygems'
3
+ require 'yaml'
4
+ require 'eventmachine'
5
+ require 'eventmachine-tail'
6
+ require 'typhon/heads'
7
+ require 'typhon/log'
8
+ require 'typhon/config'
9
+ require 'typhon/stompclient'
10
+ require 'typhon/ratelimit'
11
+ require 'typhon/head'
12
+
13
+ class << self
14
+ def heads
15
+ Heads.heads
16
+ end
15
17
 
16
- def files
17
- Heads.heads.keys
18
- end
18
+ def files
19
+ Heads.heads.keys
20
+ end
19
21
 
20
- def grow(options, &blk)
21
- raise "Heads need a name" unless options[:name]
22
- raise "Heads need files" unless options[:files]
22
+ def grow(options, &blk)
23
+ raise "Heads need a name" unless options[:name]
24
+ raise "Heads need files" unless options[:files]
23
25
 
24
- Heads.register_head(options[:name], options[:files], blk)
25
- end
26
+ Heads.register_head(options[:name], options[:files], blk)
27
+ end
26
28
 
27
- def stomp=(stomp)
28
- @stomp = stomp
29
- end
29
+ def stomp=(stomp)
30
+ @stomp = stomp
31
+ end
30
32
 
31
- def stomp
32
- @stomp
33
- end
33
+ def stomp
34
+ @stomp
35
+ end
34
36
 
35
- def daemonize
36
- fork do
37
- Process.setsid
38
- exit if fork
39
- Dir.chdir('/tmp')
40
- STDIN.reopen('/dev/null')
41
- STDOUT.reopen('/dev/null', 'a')
42
- STDERR.reopen('/dev/null', 'a')
43
-
44
- yield
45
- end
46
- end
37
+ def daemonize
38
+ fork do
39
+ Process.setsid
40
+ exit if fork
41
+ Dir.chdir('/tmp')
42
+ STDIN.reopen('/dev/null')
43
+ STDOUT.reopen('/dev/null', 'a')
44
+ STDERR.reopen('/dev/null', 'a')
45
+
46
+ yield
47
+ end
47
48
  end
49
+ end
48
50
 
49
- attr_reader :heads
51
+ attr_reader :heads
50
52
 
51
- def initialize(path="/etc/typhon")
52
- @configdir = path
53
+ def initialize(path="/etc/typhon")
54
+ @configdir = path
53
55
 
54
- Config[:configdir] = path
55
- Config.loadconfig
56
+ Config[:configdir] = path
57
+ Config.loadconfig
56
58
 
57
- @heads = Heads.new
58
- @stomp = nil
59
- end
59
+ @heads = Heads.new
60
+ @stomp = nil
61
+ end
62
+
63
+ def tail
64
+ EM.run do
65
+ @heads.loadheads
66
+
67
+ if Config[:stomp]
68
+ Log.debug("Connecting to Stomp Server %s:%d" % [ Config[:stomp][:server], Config[:stomp][:port] ])
69
+ @stomp = EM.connect Config[:stomp][:server], Config[:stomp][:port], Typhon::StompClient, {:auto_reconnect => true, :timeout => 2}
70
+ Typhon.stomp = @stomp
71
+ end
72
+
73
+ EM.add_periodic_timer(10) do
74
+ @heads.loadheads
75
+ end
60
76
 
61
- def tail
62
- EM.run do
63
- @heads.loadheads
64
-
65
- if Config[:stomp]
66
- Log.debug("Connecting to Stomp Server %s:%d" % [ Config[:stomp][:server], Config[:stomp][:port] ])
67
- @stomp = EM.connect Config[:stomp][:server], Config[:stomp][:port], Typhon::StompClient, {:auto_reconnect => true, :timeout => 2}
68
- Typhon.stomp = @stomp
69
- end
70
-
71
- EM.add_periodic_timer(10) do
72
- @heads.loadheads
73
- end
74
-
75
- if Config[:stat_log_frequency] > 0
76
- EM.add_periodic_timer(Config[:stat_log_frequency]) do
77
- @heads.log_stats
78
- end
79
- end
77
+ if Config[:stat_log_frequency] > 0
78
+ EM.add_periodic_timer(Config[:stat_log_frequency]) do
79
+ @heads.log_stats
80
80
  end
81
+ end
81
82
  end
83
+ end
82
84
  end
@@ -1,48 +1,48 @@
1
1
  class Typhon
2
- class Config
3
- include Enumerable
2
+ class Config
3
+ include Enumerable
4
4
 
5
- @settings = {:loglevel => :info, :stomp => false, :stat_log_frequency => 3600}
5
+ @settings = {:loglevel => :info, :stomp => false, :stat_log_frequency => 3600}
6
6
 
7
- class << self
8
- attr_reader :settings
7
+ class << self
8
+ attr_reader :settings
9
9
 
10
- def []=(key,val)
11
- @settings[key] = val
12
- end
10
+ def []=(key,val)
11
+ @settings[key] = val
12
+ end
13
13
 
14
- def [](key)
15
- @settings[key]
16
- end
14
+ def [](key)
15
+ @settings[key]
16
+ end
17
17
 
18
- def include?(key)
19
- @settings.include?(key)
20
- end
18
+ def include?(key)
19
+ @settings.include?(key)
20
+ end
21
21
 
22
- def each
23
- @settings.each_pair do |k, v|
24
- yield({k => v})
25
- end
26
- end
22
+ def each
23
+ @settings.each_pair do |k, v|
24
+ yield({k => v})
25
+ end
26
+ end
27
27
 
28
- def loadconfig
29
- raise "Set configdir" unless @settings.include?(:configdir)
28
+ def loadconfig
29
+ raise "Set configdir" unless @settings.include?(:configdir)
30
30
 
31
- file = File.join([@settings[:configdir], "typhon.yaml"])
31
+ file = File.join([@settings[:configdir], "typhon.yaml"])
32
32
 
33
- raise "Cannot find file #{file}" unless File.exist?(file)
34
- @settings.merge!(YAML.load_file(file))
35
- end
33
+ raise "Cannot find file #{file}" unless File.exist?(file)
34
+ @settings.merge!(YAML.load_file(file))
35
+ end
36
36
 
37
- def method_missing(k, *args, &block)
38
- return @settings[k] if @settings.include?(k)
37
+ def method_missing(k, *args, &block)
38
+ return @settings[k] if @settings.include?(k)
39
39
 
40
- k = k.to_s.gsub("_", ".")
41
- return @settings[k] if @settings.include?(k)
40
+ k = k.to_s.gsub("_", ".")
41
+ return @settings[k] if @settings.include?(k)
42
42
 
43
- super
44
- end
45
- end
43
+ super
44
+ end
46
45
  end
46
+ end
47
47
  end
48
48
 
@@ -0,0 +1,21 @@
1
+ class Typhon
2
+ # heads get loaded into this class on the 'call' method, provides convenient access
3
+ # to stomp, rate limiters etc
4
+ class Head
5
+ def define_singleton_method(*args, &block)
6
+ class << self
7
+ self
8
+ end.send(:define_method, *args, &block)
9
+ end unless method_defined? :define_singleton_method
10
+
11
+ def ratelimit(name, time=60)
12
+ @limiters ||= {}
13
+
14
+ @limiters[name] ||= RateLimit.new(time)
15
+ end
16
+
17
+ def stomp
18
+ Typhon.stomp
19
+ end
20
+ end
21
+ end
@@ -1,160 +1,168 @@
1
1
  class Typhon
2
- class Heads
3
- # these methods are here to help the DSL have somewhere to
4
- # store instances of the heads and some utilities to manage
5
- # them. This is effectively a global named scope that just
6
- # holds blocks of codes
7
- class << self
8
- def register_head(name, files, head)
9
- @heads ||= {}
10
-
11
- [files].flatten.each do |file|
12
- @heads[file] ||= {}
13
-
14
- raise "Already have a head called #{name} for file #{file}" if @heads[file].include?(name)
15
-
16
- @heads[file][name] = head
17
-
18
- Log.debug("Registered a new head: #{name} for file #{file}")
19
- end
20
- end
21
-
22
- def clear!
23
- Log.debug("Clearing previously loaded heads")
24
- @heads = {}
25
- end
26
-
27
- def heads
28
- @heads || {}
29
- end
30
-
31
- def files
32
- @heads.keys
33
- end
34
- end
2
+ class Heads
3
+ # these methods are here to help the DSL have somewhere to
4
+ # store instances of the heads and some utilities to manage
5
+ # them. This is effectively a global named scope that just
6
+ # holds blocks of codes
7
+ class << self
8
+ def register_head(name, files, head)
9
+ @heads ||= {}
35
10
 
36
- def initialize
37
- @dir = File.join(Config.configdir, "heads")
38
- @tails = {}
39
- @linecount = 0
40
- @starttime = Time.now
41
- end
11
+ [files].flatten.each do |file|
12
+ @heads[file] ||= {}
42
13
 
43
- def log_stats
44
- uptime = seconds_to_human((Time.now - @starttime).to_i)
14
+ raise "Already have a head called #{name} for file #{file}" if @heads[file].include?(name)
45
15
 
46
- Log.info("Up for #{uptime} read #{@linecount} lines")
47
- end
16
+ headklass = Head.new
17
+ headklass.define_singleton_method(:call, head)
48
18
 
49
- # Handles a line of text from a log file by finding the
50
- # heads associated with that file and calling them all
51
- def feed(file, pos, text)
52
- return unless Heads.heads.include?(file)
53
-
54
- Heads.heads[file].each_pair do |name, head|
55
- begin
56
- head.call(file, pos, text)
57
- @linecount += 1
58
- rescue Exception => e
59
- Log.error("Failed to handle line from #{file}##{pos} with head #{name}: #{e.class}: #{e}")
60
- end
61
- end
19
+ @heads[file][name] = headklass
20
+
21
+ Log.debug("Registered a new head: #{name} for file #{file}")
62
22
  end
23
+ end
24
+
25
+ def clear!
26
+ Log.debug("Clearing previously loaded heads")
27
+ @heads = {}
28
+ end
63
29
 
64
- # Loads/Reload all the heads from disk, a trigger file is used that
65
- # the user can touch the trigger and it will initiate a complete reload
66
- def loadheads
67
- if File.exist?(triggerfile)
68
- triggerage = File::Stat.new(triggerfile).mtime.to_f
69
- else
70
- triggerage = 0
71
- end
30
+ def heads
31
+ @heads || {}
32
+ end
72
33
 
73
- @loaded ||= 0
34
+ def files
35
+ @heads.keys
36
+ end
37
+ end
74
38
 
75
- if (@loaded < triggerage) || @loaded == 0
76
- Heads.clear!
77
- headfiles.each do |head|
78
- loadhead(head)
79
- end
80
- end
39
+ def initialize
40
+ @dir = File.join(Config.configdir, "heads")
41
+ @tails = {}
42
+ @linecount = 0
43
+ @starttime = Time.now
44
+ end
81
45
 
82
- starttails
46
+ def log_stats
47
+ uptime = seconds_to_human((Time.now - @starttime).to_i)
83
48
 
84
- @loaded = Time.now.to_f
85
- end
49
+ Log.info("Up for #{uptime} read #{@linecount} lines")
50
+ end
86
51
 
87
- # Start EM tailers for each known file. If a file has become orphaned
88
- # by all its heads being removed then close the tail
89
- def starttails
90
- # for all the files that have interested heads start tailers
91
- Typhon.files.each do |file|
92
- unless @tails.include?(file)
93
- Log.debug("Starting a new tailer for #{file}")
94
- @tails[file] = EventMachine::file_tail(file) do |ft, line|
95
- self.feed(ft.path, ft.position, line)
96
- end
97
- end
98
- end
99
-
100
- # for all the tailers make sure there are files, else close the tailer
101
- @tails.keys.each do |file|
102
- unless Typhon.files.include?(file)
103
- Log.debug("Closing tailer for #{file} there are no heads attached")
104
-
105
- begin
106
- @tails[file].close
107
- rescue
108
- end
109
- end
110
- end
111
- end
52
+ # Handles a line of text from a log file by finding the
53
+ # heads associated with that file and calling them all
54
+ def feed(file, pos, text)
55
+ return unless Heads.heads.include?(file)
112
56
 
113
- def loadhead(head)
114
- Log.debug("Loading head #{head}")
115
- load head
57
+ Heads.heads[file].each_pair do |name, head|
58
+ begin
59
+ head.call(file, pos, text)
60
+ @linecount += 1
116
61
  rescue Exception => e
117
- puts "Failed to load #{head}: #{e.class}: #{e}"
118
- p e.backtrace
62
+ Log.error("Failed to handle line from #{file}##{pos} with head #{name}: #{e.class}: #{e}")
63
+ end
64
+ end
65
+ end
66
+
67
+ # Loads/Reload all the heads from disk, a trigger file is used that
68
+ # the user can touch the trigger and it will initiate a complete reload
69
+ def loadheads
70
+ if File.exist?(triggerfile)
71
+ triggerage = File::Stat.new(triggerfile).mtime.to_f
72
+ else
73
+ triggerage = 0
74
+ end
75
+
76
+ @loaded ||= 0
77
+
78
+ if (@loaded < triggerage) || @loaded == 0
79
+ Heads.clear!
80
+ headfiles.each do |head|
81
+ loadhead(head)
119
82
  end
83
+ end
84
+
85
+ starttails
86
+
87
+ @loaded = Time.now.to_f
88
+ end
120
89
 
121
- def headfiles
122
- if File.directory?(@dir)
123
- Dir.entries(@dir).grep(/head.rb$/).map do |f|
124
- File.join([@dir, f])
125
- end
126
- else
127
- raise "#{@dir} is not a directory"
128
- end
90
+ # Start EM tailers for each known file. If a file has become orphaned
91
+ # by all its heads being removed then close the tail
92
+ def starttails
93
+ # for all the files that have interested heads start tailers
94
+ Typhon.files.each do |file|
95
+ unless @tails.include?(file)
96
+ Log.debug("Starting a new tailer for #{file}")
97
+ @tails[file] = EventMachine::file_tail(file) do |ft, line|
98
+ self.feed(ft.path, ft.position, line)
99
+ end
129
100
  end
101
+ end
102
+
103
+ # for all the tailers make sure there are files, else close the tailer
104
+ @tails.keys.each do |file|
105
+ unless Typhon.files.include?(file)
106
+ Log.debug("Closing tailer for #{file} there are no heads attached")
130
107
 
131
- def triggerfile
132
- File.join([@dir, "reload.txt"])
108
+ begin
109
+ @tails[file].close
110
+ rescue
111
+ end
133
112
  end
113
+ end
114
+ end
134
115
 
135
- # borrowed from ohai, thanks Adam.
136
- def seconds_to_human(seconds)
137
- days = seconds.to_i / 86400
138
- seconds -= 86400 * days
139
-
140
- hours = seconds.to_i / 3600
141
- seconds -= 3600 * hours
142
-
143
- minutes = seconds.to_i / 60
144
- seconds -= 60 * minutes
145
-
146
- if days > 1
147
- return sprintf("%d days %02d hours %02d minutes %02d seconds", days, hours, minutes, seconds)
148
- elsif days == 1
149
- return sprintf("%d day %02d hours %02d minutes %02d seconds", days, hours, minutes, seconds)
150
- elsif hours > 0
151
- return sprintf("%d hours %02d minutes %02d seconds", hours, minutes, seconds)
152
- elsif minutes > 0
153
- return sprintf("%d minutes %02d seconds", minutes, seconds)
154
- else
155
- return sprintf("%02d seconds", seconds)
156
- end
116
+ def loadhead(head)
117
+ Log.debug("Loading head #{head}")
118
+ load head
119
+ rescue Exception => e
120
+ Log.error "Failed to load #{head}: #{e.class}: #{e}"
121
+ Log.error e.backtrace
122
+
123
+ if STDOUT.tty?
124
+ puts "Failed to load #{head}: #{e.class}: #{e}"
125
+ p e.backtrace
126
+ end
127
+ end
128
+
129
+ def headfiles
130
+ if File.directory?(@dir)
131
+ Dir.entries(@dir).grep(/head.rb$/).map do |f|
132
+ File.join([@dir, f])
157
133
  end
134
+ else
135
+ raise "#{@dir} is not a directory"
136
+ end
137
+ end
158
138
 
139
+ def triggerfile
140
+ File.join([@dir, "reload.txt"])
159
141
  end
142
+
143
+ # borrowed from ohai, thanks Adam.
144
+ def seconds_to_human(seconds)
145
+ days = seconds.to_i / 86400
146
+ seconds -= 86400 * days
147
+
148
+ hours = seconds.to_i / 3600
149
+ seconds -= 3600 * hours
150
+
151
+ minutes = seconds.to_i / 60
152
+ seconds -= 60 * minutes
153
+
154
+ if days > 1
155
+ return sprintf("%d days %02d hours %02d minutes %02d seconds", days, hours, minutes, seconds)
156
+ elsif days == 1
157
+ return sprintf("%d day %02d hours %02d minutes %02d seconds", days, hours, minutes, seconds)
158
+ elsif hours > 0
159
+ return sprintf("%d hours %02d minutes %02d seconds", hours, minutes, seconds)
160
+ elsif minutes > 0
161
+ return sprintf("%d minutes %02d seconds", minutes, seconds)
162
+ else
163
+ return sprintf("%02d seconds", seconds)
164
+ end
165
+ end
166
+
167
+ end
160
168
  end
@@ -1,55 +1,55 @@
1
1
  class Typhon
2
- class Log
3
- require 'syslog'
2
+ class Log
3
+ require 'syslog'
4
4
 
5
- include Syslog::Constants
5
+ include Syslog::Constants
6
6
 
7
- @configured = false
7
+ @configured = false
8
8
 
9
- @known_levels = [:debug, :info, :warn, :error, :fatal]
9
+ @known_levels = [:debug, :info, :warn, :error, :fatal]
10
10
 
11
- class << self
12
- def log(msg, severity=:debug)
13
- configure unless @configured
11
+ class << self
12
+ def log(msg, severity=:debug)
13
+ configure unless @configured
14
14
 
15
- if @known_levels.index(severity) >= @known_levels.index(@active_level)
16
- Syslog.send(valid_levels[severity.to_sym], "#{from} #{msg}")
17
- end
18
- rescue Exception => e
19
- STDERR.puts("Failed to log: #{e.class}: #{e}: original log message: #{severity}: #{msg}")
20
- STDERR.puts(e.backtrace.join("\n\t"))
21
- end
15
+ if @known_levels.index(severity) >= @known_levels.index(@active_level)
16
+ Syslog.send(valid_levels[severity.to_sym], "#{from} #{msg}")
17
+ end
18
+ rescue Exception => e
19
+ STDERR.puts("Failed to log: #{e.class}: #{e}: original log message: #{severity}: #{msg}")
20
+ STDERR.puts(e.backtrace.join("\n\t"))
21
+ end
22
22
 
23
- def configure
24
- Syslog.close if Syslog.opened?
25
- Syslog.open(File.basename($0))
23
+ def configure
24
+ Syslog.close if Syslog.opened?
25
+ Syslog.open(File.basename($0))
26
26
 
27
- @active_level = Config[:loglevel]
27
+ @active_level = Config[:loglevel]
28
28
 
29
- raise "Unknown log level #{@active_level} specified" unless valid_levels.include?(@active_level)
29
+ raise "Unknown log level #{@active_level} specified" unless valid_levels.include?(@active_level)
30
30
 
31
- @configured = true
32
- end
31
+ @configured = true
32
+ end
33
33
 
34
- # figures out the filename that called us
35
- def from
36
- from = File.basename(caller[4])
37
- end
34
+ # figures out the filename that called us
35
+ def from
36
+ from = File.basename(caller[4])
37
+ end
38
38
 
39
- def valid_levels
40
- {:info => :info,
41
- :warn => :warning,
42
- :debug => :debug,
43
- :fatal => :crit,
44
- :error => :err}
45
- end
39
+ def valid_levels
40
+ {:info => :info,
41
+ :warn => :warning,
42
+ :debug => :debug,
43
+ :fatal => :crit,
44
+ :error => :err}
45
+ end
46
46
 
47
- def method_missing(level, *args, &block)
48
- super unless [:info, :warn, :debug, :fatal, :error].include?(level)
47
+ def method_missing(level, *args, &block)
48
+ super unless [:info, :warn, :debug, :fatal, :error].include?(level)
49
49
 
50
- log(args[0], level)
51
- end
52
- end
50
+ log(args[0], level)
51
+ end
53
52
  end
53
+ end
54
54
  end
55
55
 
@@ -0,0 +1,49 @@
1
+ class Typhon
2
+ class RateLimit
3
+ require 'digest/md5'
4
+
5
+ attr_reader :timespan
6
+
7
+ # timespan - how many seconds you want to track events for.
8
+ # events older than this will drop off the queue
9
+ def initialize(timespan)
10
+ @timespan = timespan
11
+ @events = []
12
+ end
13
+
14
+ # Record that an event happened
15
+ #
16
+ # Just pass in any text, unique text will be tracked individually
17
+ def record(event)
18
+ key = Digest::MD5.hexdigest(event)
19
+
20
+ event = {:k => key,
21
+ :t => Time.now.to_f}
22
+
23
+ @events << event
24
+
25
+ domaint
26
+ end
27
+
28
+ # How many times have the event been seen in the last interval
29
+ def rate(event)
30
+ key = Digest::MD5.hexdigest(event)
31
+
32
+ @events.select{|e| e[:k] == key}.size
33
+ end
34
+
35
+ private
36
+ # Deletes events older than the defined timespan
37
+ def domaint
38
+ @events.each_with_index do |event, idx|
39
+ # events are stored in time order delete them till we find ont thats
40
+ # newer then we can stop looking
41
+ if event[:t].to_f < (Time.now.to_f - @timespan.to_f)
42
+ @events.delete_at(idx)
43
+ else
44
+ return
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,49 +1,49 @@
1
1
  class Typhon
2
- class StompClient < EM::Connection
3
- include EM::Protocols::Stomp
2
+ class StompClient < EM::Connection
3
+ include EM::Protocols::Stomp
4
4
 
5
- def initialize(params={})
6
- @connected = false
7
- @options = {:auto_reconnect => true, :timeout => 2, :max_queue_size => 500}
8
- @queue = EM::Queue.new
9
- end
5
+ def initialize(params={})
6
+ @connected = false
7
+ @options = {:auto_reconnect => true, :timeout => 2, :max_queue_size => 500}
8
+ @queue = EM::Queue.new
9
+ end
10
10
 
11
- def connection_completed
12
- connect :login => Config[:stomp][:user], :passcode => Config[:stomp][:pass]
11
+ def connection_completed
12
+ connect :login => Config[:stomp][:user], :passcode => Config[:stomp][:pass]
13
13
 
14
- Log.debug("Authenticated to %s:%d" % [ Config[:stomp][:server], Config[:stomp][:port] ])
15
- @connected = true
16
- end
14
+ Log.debug("Authenticated to %s:%d" % [ Config[:stomp][:server], Config[:stomp][:port] ])
15
+ @connected = true
16
+ end
17
17
 
18
- def unbind
19
- Log.error("Connection to %s:%d failed" % [ Config[:stomp][:server], Config[:stomp][:port] ])
20
- @connected = false
18
+ def unbind
19
+ Log.error("Connection to %s:%d failed" % [ Config[:stomp][:server], Config[:stomp][:port] ])
20
+ @connected = false
21
21
 
22
- EM.add_timer(@options[:timeout]) do
23
- Log.debug("Connecting to Stomp Server %s:%d" % [ Config[:stomp][:server], Config[:stomp][:port] ])
24
- reconnect Config[:stomp][:server], Config[:stomp][:port]
25
- end
26
- end
22
+ EM.add_timer(@options[:timeout]) do
23
+ Log.debug("Connecting to Stomp Server %s:%d" % [ Config[:stomp][:server], Config[:stomp][:port] ])
24
+ reconnect Config[:stomp][:server], Config[:stomp][:port]
25
+ end
26
+ end
27
27
 
28
- def connected?
29
- (@connected && !error?)
30
- end
28
+ def connected?
29
+ (@connected && !error?)
30
+ end
31
31
 
32
- def publish(topic, message, param={})
33
- if connected?
34
- send(topic, message, param)
35
-
36
- until @queue.empty? do
37
- @queue.pop do |msg|
38
- send(msg[:topic], msg[:message], msg[:param])
39
- end
40
- end
41
- else
42
- if @queue.size < @options[:max_queue_size]
43
- @queue.push({:topic => topic, :message => message, :param => param})
44
- end
45
- end
32
+ def publish(topic, message, param={})
33
+ if connected?
34
+ send(topic, message, param)
35
+
36
+ until @queue.empty? do
37
+ @queue.pop do |msg|
38
+ send(msg[:topic], msg[:message], msg[:param])
39
+ end
40
+ end
41
+ else
42
+ if @queue.size < @options[:max_queue_size]
43
+ @queue.push({:topic => topic, :message => message, :param => param})
46
44
  end
45
+ end
47
46
  end
47
+ end
48
48
  end
49
49
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typhon
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - R.I.Pienaar
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-29 00:00:00 +01:00
18
+ date: 2012-03-04 00:00:00 +00:00
19
19
  default_executable: typhon
20
20
  dependencies: []
21
21
 
@@ -30,9 +30,11 @@ extra_rdoc_files: []
30
30
  files:
31
31
  - bin/typhon
32
32
  - lib/typhon/config.rb
33
- - lib/typhon/stompclient.rb
34
- - lib/typhon/heads.rb
35
33
  - lib/typhon/log.rb
34
+ - lib/typhon/heads.rb
35
+ - lib/typhon/ratelimit.rb
36
+ - lib/typhon/head.rb
37
+ - lib/typhon/stompclient.rb
36
38
  - lib/typhon.rb
37
39
  has_rdoc: true
38
40
  homepage: https://github.com/ripienaar/typhon/