typhon 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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/