quark 0.1.4 → 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/quark +32 -4
- data/lib/quark.rb +2 -215
- data/lib/quark/base_server.rb +13 -0
- data/lib/quark/command_processor.rb +83 -0
- data/lib/quark/commands/fetch.rb +1 -1
- data/lib/quark/commands/observe.rb +1 -1
- data/lib/quark/commands/peek.rb +5 -3
- data/lib/quark/commands/ping.rb +1 -1
- data/lib/quark/errors.rb +5 -0
- data/lib/quark/server.rb +111 -0
- data/lib/quark/servers/http.rb +6 -4
- data/lib/quark/servers/socket.rb +21 -0
- data/lib/quark/servers/tcp.rb +17 -0
- data/lib/quark/servers/udp.rb +17 -0
- data/lib/quark/servers/websocket.rb +52 -0
- metadata +61 -87
data/bin/quark
CHANGED
@@ -30,17 +30,26 @@ module Quark
|
|
30
30
|
|
31
31
|
# -----------------------------------------------------------------------------
|
32
32
|
opts.on('-S', '--socket FILE', 'Location of the Unix socket to accept commands from') do |file|
|
33
|
-
Quark::Config.set("quark.socket",
|
33
|
+
Quark::Config.set("quark.socket.enabled", true)
|
34
|
+
Quark::Config.set("quark.socket.path", file)
|
34
35
|
end
|
35
36
|
|
36
37
|
# -----------------------------------------------------------------------------
|
37
38
|
opts.on('-a', '--address ADDR', 'The IP address for all servers to listen on') do |addr|
|
38
|
-
Quark::Config.
|
39
|
+
Quark::Config.get("quark",{}).each do |k,v|
|
40
|
+
if v.is_a?(Hash) and not v.get(:address).nil?
|
41
|
+
Quark::Config.set("quark.#{k}.address", addr)
|
42
|
+
end
|
43
|
+
end
|
39
44
|
end
|
40
45
|
|
41
46
|
# -----------------------------------------------------------------------------
|
42
|
-
opts.on('-p', '--port PORT', 'The
|
43
|
-
Quark::Config.
|
47
|
+
opts.on('-p', '--port PORT', 'The port for all servers to listen on') do |port|
|
48
|
+
Quark::Config.get("quark",{}).each do |k,v|
|
49
|
+
if v.is_a?(Hash) and not v.get(:port).nil?
|
50
|
+
Quark::Config.set("quark.#{k}.port", port.to_i)
|
51
|
+
end
|
52
|
+
end
|
44
53
|
end
|
45
54
|
|
46
55
|
# -----------------------------------------------------------------------------
|
@@ -87,11 +96,13 @@ module Quark
|
|
87
96
|
|
88
97
|
# -----------------------------------------------------------------------------
|
89
98
|
opts.on('', '--http-address ADDR', 'The IP address for the HTTP server to listen on') do |addr|
|
99
|
+
Quark::Config.set("quark.http.enabled", true)
|
90
100
|
Quark::Config.set("quark.http.address", addr)
|
91
101
|
end
|
92
102
|
|
93
103
|
# -----------------------------------------------------------------------------
|
94
104
|
opts.on('', '--http-port PORT', 'The HTTP port to listen on') do |port|
|
105
|
+
Quark::Config.set("quark.http.enabled", true)
|
95
106
|
Quark::Config.set("quark.http.port", port.to_i)
|
96
107
|
end
|
97
108
|
|
@@ -100,6 +111,23 @@ module Quark
|
|
100
111
|
Quark::Config.set("quark.http.cors", mode)
|
101
112
|
end
|
102
113
|
|
114
|
+
# -----------------------------------------------------------------------------
|
115
|
+
opts.on('-W', '--[no-]ws', 'Enable/disable Websocket server') do |mode|
|
116
|
+
Quark::Config.set("quark.websocket.enabled", mode)
|
117
|
+
end
|
118
|
+
|
119
|
+
# -----------------------------------------------------------------------------
|
120
|
+
opts.on('', '--ws-address ADDR', 'The IP address for the Websocket server to listen on') do |addr|
|
121
|
+
Quark::Config.set("quark.websocket.enabled", true)
|
122
|
+
Quark::Config.set("quark.websocket.address", addr)
|
123
|
+
end
|
124
|
+
|
125
|
+
# -----------------------------------------------------------------------------
|
126
|
+
opts.on('', '--ws-port PORT', 'The Websocket port to listen on') do |port|
|
127
|
+
Quark::Config.set("quark.websocket.enabled", true)
|
128
|
+
Quark::Config.set("quark.websocket.port", port.to_i)
|
129
|
+
end
|
130
|
+
|
103
131
|
# -----------------------------------------------------------------------------
|
104
132
|
opts.on('-D', '--debug', 'Enable debug mode') do
|
105
133
|
Quark::Config.set("debug", true)
|
data/lib/quark.rb
CHANGED
@@ -4,219 +4,6 @@ require 'redis'
|
|
4
4
|
require 'hiredis'
|
5
5
|
require 'em-synchrony'
|
6
6
|
require 'multi_json'
|
7
|
+
require 'quark/errors'
|
7
8
|
require 'quark/config'
|
8
|
-
|
9
|
-
module Quark
|
10
|
-
class Error < Exception; end
|
11
|
-
class ArgumentError < Error; end
|
12
|
-
class InvalidCommand < Error; end
|
13
|
-
|
14
|
-
module SocketServer
|
15
|
-
Dir[File.join(File.dirname(__FILE__), "quark", "commands", "*.rb")].each do |rb|
|
16
|
-
require "#{rb.gsub(/\.rb$/,'')}"
|
17
|
-
end
|
18
|
-
|
19
|
-
def post_init()
|
20
|
-
self.setup()
|
21
|
-
end
|
22
|
-
|
23
|
-
def receive_data(data)
|
24
|
-
puts "DEBUG: Received '#{data}'" if Quark::Config.get("debug")
|
25
|
-
send_json(Quark::SocketServer.process_command(data))
|
26
|
-
end
|
27
|
-
|
28
|
-
def send_json(data)
|
29
|
-
send_data(MultiJson.dump(data)+"\n")
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.setup(redis, prefix='quark')
|
33
|
-
@redis = redis
|
34
|
-
@_prefix = prefix
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.process_command(data)
|
38
|
-
# if the data perfectly resembles a graphite-formatted metric (without a command prefix)
|
39
|
-
# then assume the command is "observe"
|
40
|
-
if Quark::Config.get("quark.graphite_compat") and data =~ /^[\w\.\-]+ -?[\d\.]+ \d{10,13}$/
|
41
|
-
command = "OBSERVE"
|
42
|
-
arguments = data.chomp
|
43
|
-
else
|
44
|
-
command, arguments = data.chomp.split(' ',2)
|
45
|
-
end
|
46
|
-
|
47
|
-
begin
|
48
|
-
if methods.include?(:"process_command_#{command.downcase}")
|
49
|
-
rv = send(:"process_command_#{command.downcase}", arguments)
|
50
|
-
if rv.nil?
|
51
|
-
return {
|
52
|
-
:success => true
|
53
|
-
}
|
54
|
-
else
|
55
|
-
return {
|
56
|
-
:success => true,
|
57
|
-
:command => data.chomp,
|
58
|
-
:results => rv
|
59
|
-
}
|
60
|
-
end
|
61
|
-
else
|
62
|
-
raise Quark::InvalidCommand.new("Unknown command '#{command.upcase}'")
|
63
|
-
end
|
64
|
-
|
65
|
-
rescue Quark::Error => e
|
66
|
-
return {
|
67
|
-
:success => false,
|
68
|
-
:command => data.chomp,
|
69
|
-
:error => {
|
70
|
-
:class => e.class.name,
|
71
|
-
:message => e.message
|
72
|
-
}
|
73
|
-
}
|
74
|
-
|
75
|
-
rescue Exception => e
|
76
|
-
return {
|
77
|
-
:success => false,
|
78
|
-
:command => data.chomp,
|
79
|
-
:error => {
|
80
|
-
:class => e.class.name,
|
81
|
-
:message => e.message,
|
82
|
-
:backtrace => e.backtrace
|
83
|
-
}
|
84
|
-
}
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def unbind()
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
class Server
|
93
|
-
def self.setup()
|
94
|
-
Quark::Config.set("quark.address", "127.0.0.1")
|
95
|
-
Quark::Config.set("quark.port", 12161)
|
96
|
-
Quark::Config.set("quark.blocksize", 3600000)
|
97
|
-
Quark::Config.set("quark.tcp.enabled", true)
|
98
|
-
Quark::Config.set("quark.udp.enabled", false)
|
99
|
-
Quark::Config.set("quark.http.enabled", false)
|
100
|
-
Quark::Config.set("quark.http.port", 12180)
|
101
|
-
Quark::Config.set("quark.http.cors", false)
|
102
|
-
Quark::Config.set("quark.graphite_compat", true)
|
103
|
-
Quark::Config.set("debug", false)
|
104
|
-
nil
|
105
|
-
end
|
106
|
-
|
107
|
-
def self.connect()
|
108
|
-
@redis = Redis.new({
|
109
|
-
:host => Quark::Config.get("redis.host", "127.0.0.1"),
|
110
|
-
:port => Quark::Config.get("redis.port", 6379).to_i,
|
111
|
-
:db => Quark::Config.get("redis.db", 0).to_i
|
112
|
-
})
|
113
|
-
|
114
|
-
@_prefix = Quark::Config.get("redis.prefix", "quark")
|
115
|
-
|
116
|
-
Quark::SocketServer.setup(@redis, @_prefix)
|
117
|
-
end
|
118
|
-
|
119
|
-
def self.run()
|
120
|
-
connect() unless defined?(@redis)
|
121
|
-
|
122
|
-
@address = Quark::Config.get("quark.address")
|
123
|
-
@port = Quark::Config.get("quark.port")
|
124
|
-
@filename = Quark::Config.get("quark.socket")
|
125
|
-
|
126
|
-
EM.run do
|
127
|
-
Signal.trap("INT") { Quark::Server.quit() }
|
128
|
-
Signal.trap("TERM") { Quark::Server.quit() }
|
129
|
-
|
130
|
-
if Quark::Config.get("debug")
|
131
|
-
puts "Debug mode is ON"
|
132
|
-
end
|
133
|
-
|
134
|
-
# socket
|
135
|
-
if not @filename.nil? and File.writable?(File.dirname(@filename))
|
136
|
-
puts "Starting socket server at #{@filename}..."
|
137
|
-
EM::start_server(@filename, Quark::SocketServer)
|
138
|
-
end
|
139
|
-
|
140
|
-
# UDP server
|
141
|
-
if Quark::Config.get("quark.udp.enabled") === true
|
142
|
-
@udp_address = Quark::Config.get("quark.udp.address", @address)
|
143
|
-
@udp_port = Quark::Config.get("quark.udp.port", @port)
|
144
|
-
|
145
|
-
puts "Starting UDP server on #{@udp_address}:#{@udp_port}..."
|
146
|
-
EM::open_datagram_socket(@udp_address, @udp_port, Quark::SocketServer)
|
147
|
-
end
|
148
|
-
|
149
|
-
# TCP server
|
150
|
-
if Quark::Config.get("quark.tcp.enabled") === true
|
151
|
-
@tcp_address = Quark::Config.get("quark.tcp.address", @address)
|
152
|
-
@tcp_port = Quark::Config.get("quark.tcp.port", @port)
|
153
|
-
|
154
|
-
puts "Starting TCP server on #{@tcp_address}:#{@tcp_port}..."
|
155
|
-
EM::start_server(@tcp_address, @tcp_port, Quark::SocketServer)
|
156
|
-
end
|
157
|
-
|
158
|
-
# HTTP server
|
159
|
-
if Quark::Config.get("quark.http.enabled") === true
|
160
|
-
@http_address = Quark::Config.get("quark.http.address", @address)
|
161
|
-
@http_port = Quark::Config.get("quark.http.port", 12180)
|
162
|
-
|
163
|
-
puts "Starting HTTP server on #{@http_address}:#{@http_port}..."
|
164
|
-
require 'quark/servers/http'
|
165
|
-
|
166
|
-
Quark::Server::HttpServer.new({
|
167
|
-
:address => @http_address,
|
168
|
-
:port => @http_port
|
169
|
-
}).run()
|
170
|
-
end
|
171
|
-
|
172
|
-
if Quark::Config.get("quark.graphite_compat")
|
173
|
-
puts "Graphite compatibility mode enabled: all sockets will accept Graphite-formatted metrics as observations"
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def self.daemonize()
|
179
|
-
return @_service if defined?(@_service)
|
180
|
-
|
181
|
-
@_service = proc do
|
182
|
-
self.run()
|
183
|
-
end
|
184
|
-
|
185
|
-
EM.defer(@_service)
|
186
|
-
return @_service
|
187
|
-
end
|
188
|
-
|
189
|
-
|
190
|
-
# removes metrics that match keys and (optionally) are older than 'to'
|
191
|
-
# if 'to' is negative, it is assumed to be n-seconds ago
|
192
|
-
#
|
193
|
-
def self.purge(keys, to=nil)
|
194
|
-
keys = [@_prefix, keys, '*'].join(':') if not keys.start_with?(@_prefix)
|
195
|
-
now = (Time.now.to_f * 1000).to_i
|
196
|
-
rv = []
|
197
|
-
|
198
|
-
@redis.keys(keys).each do |key|
|
199
|
-
x, name, block = key.split(':', 3)
|
200
|
-
block = block.to_i
|
201
|
-
|
202
|
-
if ((to = Integer(to)) rescue false)
|
203
|
-
if to < 0
|
204
|
-
to = now - (-1 * to * 1000)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
if to.nil? or block < (to/Quark::Config.get("quark.blocksize")).to_i
|
209
|
-
@redis.del(key)
|
210
|
-
rv << key
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
rv
|
215
|
-
end
|
216
|
-
|
217
|
-
def self.quit()
|
218
|
-
puts "Stopping Quark..."
|
219
|
-
EM.stop()
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
9
|
+
require 'quark/server'
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Quark
|
2
|
+
module CommandProcessor
|
3
|
+
Dir[File.join(File.dirname(__FILE__), "commands", "*.rb")].each do |cmd|
|
4
|
+
cmd = File.basename(cmd, '.rb')
|
5
|
+
require "quark/commands/#{cmd}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def post_init()
|
9
|
+
end
|
10
|
+
|
11
|
+
def receive_data(data)
|
12
|
+
puts "DEBUG: Received '#{data.chomp.strip}'" if Quark::Config.get("debug")
|
13
|
+
data = Quark::CommandProcessor.process_command(data)
|
14
|
+
send_json(data)
|
15
|
+
data
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_json(data)
|
19
|
+
data = MultiJson.dump(data)+"\n"
|
20
|
+
puts "DEBUG: Replying with #{data.chomp}" if Quark::Config.get("debug")
|
21
|
+
send_data(data)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.setup(redis, prefix='quark')
|
25
|
+
@redis = redis
|
26
|
+
@_prefix = prefix
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.process_command(data)
|
30
|
+
# if the data perfectly resembles a graphite-formatted metric (without a command prefix)
|
31
|
+
# then assume the command is "observe"
|
32
|
+
if Quark::Config.get("quark.graphite_compat") and data =~ /^[\w\.\-]+ -?[\d\.]+ \d{10,13}$/
|
33
|
+
command = "OBSERVE"
|
34
|
+
arguments = data.chomp
|
35
|
+
else
|
36
|
+
command, arguments = data.chomp.split(' ',2)
|
37
|
+
end
|
38
|
+
|
39
|
+
begin
|
40
|
+
if methods.include?(:"process_command_#{command.downcase}")
|
41
|
+
rv = send(:"process_command_#{command.downcase}", arguments)
|
42
|
+
if rv.nil?
|
43
|
+
return {
|
44
|
+
:success => true
|
45
|
+
}
|
46
|
+
else
|
47
|
+
return {
|
48
|
+
:success => true,
|
49
|
+
:command => data.chomp,
|
50
|
+
:results => rv
|
51
|
+
}
|
52
|
+
end
|
53
|
+
else
|
54
|
+
raise Quark::InvalidCommand.new("Unknown command '#{command.upcase}'")
|
55
|
+
end
|
56
|
+
|
57
|
+
rescue Quark::Error => e
|
58
|
+
return {
|
59
|
+
:success => false,
|
60
|
+
:command => data.chomp,
|
61
|
+
:error => {
|
62
|
+
:class => e.class.name,
|
63
|
+
:message => e.message
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
rescue Exception => e
|
68
|
+
return {
|
69
|
+
:success => false,
|
70
|
+
:command => data.chomp,
|
71
|
+
:error => {
|
72
|
+
:class => e.class.name,
|
73
|
+
:message => e.message,
|
74
|
+
:backtrace => e.backtrace
|
75
|
+
}
|
76
|
+
}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def unbind()
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/quark/commands/fetch.rb
CHANGED
data/lib/quark/commands/peek.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Quark
|
2
|
-
module
|
3
|
-
def process_command_peek(data)
|
2
|
+
module CommandProcessor
|
3
|
+
def self.process_command_peek(data)
|
4
4
|
rv = {}
|
5
5
|
keys = @redis.keys("#{@_prefix}:#{data}:*")
|
6
6
|
peek_keys = []
|
@@ -17,9 +17,11 @@ module Quark
|
|
17
17
|
|
18
18
|
# now that we have the most recent bucket, pull the most recent value from that bucket
|
19
19
|
peek_keys.each do |peek|
|
20
|
-
|
20
|
+
data = @redis.hgetall(peek).sort{|a,b|
|
21
21
|
a[0] <=> b[0]
|
22
22
|
}.last
|
23
|
+
|
24
|
+
rv[peek.split(':')[1]] = [data[0].to_i, data[1].to_f]
|
23
25
|
end
|
24
26
|
|
25
27
|
return rv
|
data/lib/quark/commands/ping.rb
CHANGED
data/lib/quark/errors.rb
ADDED
data/lib/quark/server.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'quark/base_server'
|
2
|
+
require 'quark/command_processor'
|
3
|
+
|
4
|
+
|
5
|
+
module Quark
|
6
|
+
class Server
|
7
|
+
def self.setup()
|
8
|
+
Quark::Config.set("debug", false)
|
9
|
+
Quark::Config.set("quark.blocksize", 3600000)
|
10
|
+
Quark::Config.set("quark.graphite_compat", true)
|
11
|
+
Quark::Config.set("quark.http.address", "127.0.0.1")
|
12
|
+
Quark::Config.set("quark.http.cors", false)
|
13
|
+
Quark::Config.set("quark.http.enabled", false)
|
14
|
+
Quark::Config.set("quark.http.port", 12180)
|
15
|
+
Quark::Config.set("quark.socket.path", "/var/run/quark.sock")
|
16
|
+
Quark::Config.set("quark.tcp.address", "127.0.0.1")
|
17
|
+
Quark::Config.set("quark.tcp.enabled", true)
|
18
|
+
Quark::Config.set("quark.tcp.port", 12161)
|
19
|
+
Quark::Config.set("quark.udp.address", "127.0.0.1")
|
20
|
+
Quark::Config.set("quark.udp.enabled", false)
|
21
|
+
Quark::Config.set("quark.udp.port", 12161)
|
22
|
+
Quark::Config.set("quark.websocket.address", "127.0.0.1")
|
23
|
+
Quark::Config.set("quark.websocket.enabled", false)
|
24
|
+
Quark::Config.set("quark.websocket.port", 12181)
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.connect()
|
29
|
+
@redis = Redis.new({
|
30
|
+
:host => Quark::Config.get("redis.host", "127.0.0.1"),
|
31
|
+
:port => Quark::Config.get("redis.port", 6379).to_i,
|
32
|
+
:db => Quark::Config.get("redis.db", 0).to_i
|
33
|
+
})
|
34
|
+
|
35
|
+
@_prefix = Quark::Config.get("redis.prefix", "quark")
|
36
|
+
|
37
|
+
Quark::CommandProcessor.setup(@redis, @_prefix)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.run()
|
41
|
+
connect() unless defined?(@redis)
|
42
|
+
|
43
|
+
EM.run do
|
44
|
+
Signal.trap("INT") { Quark::Server.quit() }
|
45
|
+
Signal.trap("TERM") { Quark::Server.quit() }
|
46
|
+
|
47
|
+
if Quark::Config.get("debug")
|
48
|
+
puts "Debug mode is ON"
|
49
|
+
end
|
50
|
+
|
51
|
+
Dir[File.join(File.dirname(__FILE__), 'servers', '*.rb')].each do |server|
|
52
|
+
server = File.basename(server,'.rb')
|
53
|
+
|
54
|
+
# dynamically load and run all enabled servers
|
55
|
+
if Quark::Config.get("quark.#{server.downcase}.enabled") === true
|
56
|
+
require "quark/servers/#{server.downcase}"
|
57
|
+
Quark::Server.const_get("#{server.capitalize}Server").start()
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if Quark::Config.get("quark.graphite_compat")
|
62
|
+
puts "Graphite compatibility mode enabled: all sockets will accept Graphite-formatted metrics as observations"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.daemonize()
|
68
|
+
return @_service if defined?(@_service)
|
69
|
+
|
70
|
+
@_service = proc do
|
71
|
+
self.run()
|
72
|
+
end
|
73
|
+
|
74
|
+
EM.defer(@_service)
|
75
|
+
return @_service
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# removes metrics that match keys and (optionally) are older than 'to'
|
80
|
+
# if 'to' is negative, it is assumed to be n-seconds ago
|
81
|
+
#
|
82
|
+
def self.purge(keys, to=nil)
|
83
|
+
keys = [@_prefix, keys, '*'].join(':') if not keys.start_with?(@_prefix)
|
84
|
+
now = (Time.now.to_f * 1000).to_i
|
85
|
+
rv = []
|
86
|
+
|
87
|
+
@redis.keys(keys).each do |key|
|
88
|
+
x, name, block = key.split(':', 3)
|
89
|
+
block = block.to_i
|
90
|
+
|
91
|
+
if ((to = Integer(to)) rescue false)
|
92
|
+
if to < 0
|
93
|
+
to = now - (-1 * to * 1000)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
if to.nil? or block < (to/Quark::Config.get("quark.blocksize")).to_i
|
98
|
+
@redis.del(key)
|
99
|
+
rv << key
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
rv
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.quit()
|
107
|
+
puts "Stopping Quark..."
|
108
|
+
EM.stop()
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/lib/quark/servers/http.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Quark
|
2
2
|
class Server
|
3
|
-
class HttpServer
|
3
|
+
class HttpServer < BaseServer
|
4
4
|
require 'sinatra'
|
5
5
|
require 'sinatra/cross_origin'
|
6
6
|
require 'thin'
|
@@ -35,15 +35,15 @@ module Quark
|
|
35
35
|
end
|
36
36
|
|
37
37
|
get '/call/:command/?*' do
|
38
|
-
MultiJson.dump(Quark::
|
38
|
+
MultiJson.dump(Quark::CommandProcessor.process_command("#{params[:command].upcase} #{params[:splat].first.gsub('/',' ')}".strip))
|
39
39
|
end
|
40
40
|
|
41
41
|
get '/observe/:metric/:value/?' do
|
42
|
-
MultiJson.dump(Quark::
|
42
|
+
MultiJson.dump(Quark::CommandProcessor.process_command_observe("#{params[:metric]} #{params[:value]} #{(Time.now.to_f * 1000).to_i}"))
|
43
43
|
end
|
44
44
|
|
45
45
|
get '/observe/:metric/:value/:timestamp/?' do
|
46
|
-
MultiJson.dump(Quark::
|
46
|
+
MultiJson.dump(Quark::CommandProcessor.process_command_observe("#{params[:metric]} #{params[:value]} #{params[:timestamp]}"))
|
47
47
|
end
|
48
48
|
|
49
49
|
def _quark_command(command, payload)
|
@@ -69,6 +69,8 @@ module Quark
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def run()
|
72
|
+
puts "Starting #{self.class.to_s} server on #{@_options.get(:address)}:#{@_options.get(:port)}..."
|
73
|
+
|
72
74
|
Thin::Logging.silent = true unless Quark::Config.get("debug")
|
73
75
|
Thin::Server.start(@_options.get(:address,'127.0.0.1'), @_options.get(:port, 12180).to_i, Base.new(), {
|
74
76
|
:signals => false,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
module Quark
|
3
|
+
class Server
|
4
|
+
class SocketServer < BaseServer
|
5
|
+
require 'eventmachine'
|
6
|
+
|
7
|
+
def initialize(options=nil)
|
8
|
+
@_options = options || Quark::Config.get("quark.socket",{})
|
9
|
+
end
|
10
|
+
|
11
|
+
def run()
|
12
|
+
puts "Starting #{self.class.to_s} server at #{@_options.get(:path)}..."
|
13
|
+
EM::start_server(@_options.get(:path, "/var/run/quark.sock"), Quark::CommandProcessor)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.to_s()
|
17
|
+
"socket"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
module Quark
|
3
|
+
class Server
|
4
|
+
class TcpServer < BaseServer
|
5
|
+
require 'eventmachine'
|
6
|
+
|
7
|
+
def initialize(options=nil)
|
8
|
+
@_options = options || Quark::Config.get("quark.tcp",{})
|
9
|
+
end
|
10
|
+
|
11
|
+
def run()
|
12
|
+
puts "Starting #{self.class.to_s} server on #{@_options.get(:address)}:#{@_options.get(:port)}..."
|
13
|
+
EM::start_server(@_options.get(:address, '127.0.0.1'), @_options.get(:port, 12161).to_i, Quark::CommandProcessor)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
module Quark
|
3
|
+
class Server
|
4
|
+
class UdpServer < BaseServer
|
5
|
+
require 'eventmachine'
|
6
|
+
|
7
|
+
def initialize(options=nil)
|
8
|
+
@_options = options || Quark::Config.get("quark.udp",{})
|
9
|
+
end
|
10
|
+
|
11
|
+
def run()
|
12
|
+
puts "Starting #{self.class.to_s} server on #{@_options.get(:address)}:#{@_options.get(:port)}..."
|
13
|
+
EM::open_datagram_socket(@_options.get(:address, '127.0.0.1'), @_options.get(:port, 12161).to_i, Quark::CommandProcessor)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
module Quark
|
3
|
+
class Server
|
4
|
+
class WebsocketServer < BaseServer
|
5
|
+
require 'eventmachine'
|
6
|
+
require 'em-websocket'
|
7
|
+
|
8
|
+
class WebsocketProcessor
|
9
|
+
include Quark::CommandProcessor
|
10
|
+
|
11
|
+
def initialize(ws)
|
12
|
+
@ws = ws
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_data(data)
|
16
|
+
@ws.send(data)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(options=nil)
|
21
|
+
@_options = options || Quark::Config.get("quark.websocket",{})
|
22
|
+
end
|
23
|
+
|
24
|
+
def run()
|
25
|
+
puts "Starting #{self.class.to_s} server on #{@_options.get(:address)}:#{@_options.get(:port)}..."
|
26
|
+
|
27
|
+
EM::WebSocket.run({
|
28
|
+
:host => @_options.get(:address, "127.0.0.1"),
|
29
|
+
:port => @_options.get(:port, 12181).to_i
|
30
|
+
}) do |ws|
|
31
|
+
processor = WebsocketProcessor.new(ws)
|
32
|
+
|
33
|
+
ws.onopen do
|
34
|
+
processor.post_init()
|
35
|
+
end
|
36
|
+
|
37
|
+
ws.onclose do
|
38
|
+
processor.unbind()
|
39
|
+
end
|
40
|
+
|
41
|
+
ws.onmessage do |data|
|
42
|
+
processor.receive_data(data)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.to_s()
|
48
|
+
"Websocket"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quark
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
4
5
|
prerelease:
|
5
|
-
version: 0.1.4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Gary Hetzel
|
@@ -12,149 +12,115 @@ cert_chain: []
|
|
12
12
|
date: 2014-05-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
type: :runtime
|
16
|
-
version_requirements: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - '='
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: 1.7.9
|
21
|
-
none: false
|
22
|
-
prerelease: false
|
23
15
|
name: multi_json
|
24
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirement: &20685860 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
25
18
|
requirements:
|
26
|
-
- -
|
19
|
+
- - =
|
27
20
|
- !ruby/object:Gem::Version
|
28
21
|
version: 1.7.9
|
29
|
-
none: false
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
22
|
type: :runtime
|
32
|
-
version_requirements: !ruby/object:Gem::Requirement
|
33
|
-
requirements:
|
34
|
-
- - ~>
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: 1.0.0
|
37
|
-
none: false
|
38
23
|
prerelease: false
|
24
|
+
version_requirements: *20685860
|
25
|
+
- !ruby/object:Gem::Dependency
|
39
26
|
name: eventmachine
|
40
|
-
requirement: !ruby/object:Gem::Requirement
|
27
|
+
requirement: &20685400 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
41
29
|
requirements:
|
42
30
|
- - ~>
|
43
31
|
- !ruby/object:Gem::Version
|
44
32
|
version: 1.0.0
|
45
|
-
none: false
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
33
|
type: :runtime
|
48
|
-
version_requirements: !ruby/object:Gem::Requirement
|
49
|
-
requirements:
|
50
|
-
- - ~>
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: 3.0.0
|
53
|
-
none: false
|
54
34
|
prerelease: false
|
35
|
+
version_requirements: *20685400
|
36
|
+
- !ruby/object:Gem::Dependency
|
55
37
|
name: redis
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
38
|
+
requirement: &20701280 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
57
40
|
requirements:
|
58
41
|
- - ~>
|
59
42
|
- !ruby/object:Gem::Version
|
60
43
|
version: 3.0.0
|
61
|
-
none: false
|
62
|
-
- !ruby/object:Gem::Dependency
|
63
44
|
type: :runtime
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ~>
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 0.5.2
|
69
|
-
none: false
|
70
45
|
prerelease: false
|
46
|
+
version_requirements: *20701280
|
47
|
+
- !ruby/object:Gem::Dependency
|
71
48
|
name: hiredis
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirement: &20700820 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
73
51
|
requirements:
|
74
52
|
- - ~>
|
75
53
|
- !ruby/object:Gem::Version
|
76
54
|
version: 0.5.2
|
77
|
-
none: false
|
78
|
-
- !ruby/object:Gem::Dependency
|
79
55
|
type: :runtime
|
80
|
-
version_requirements: !ruby/object:Gem::Requirement
|
81
|
-
requirements:
|
82
|
-
- - ~>
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
version: 1.0.3
|
85
|
-
none: false
|
86
56
|
prerelease: false
|
57
|
+
version_requirements: *20700820
|
58
|
+
- !ruby/object:Gem::Dependency
|
87
59
|
name: em-synchrony
|
88
|
-
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirement: &20700220 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
89
62
|
requirements:
|
90
63
|
- - ~>
|
91
64
|
- !ruby/object:Gem::Version
|
92
65
|
version: 1.0.3
|
93
|
-
none: false
|
94
|
-
- !ruby/object:Gem::Dependency
|
95
66
|
type: :runtime
|
96
|
-
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *20700220
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: em-websocket
|
71
|
+
requirement: &20699700 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
97
73
|
requirements:
|
98
|
-
- -
|
74
|
+
- - ~>
|
99
75
|
- !ruby/object:Gem::Version
|
100
|
-
version: 0.
|
101
|
-
|
76
|
+
version: 0.5.1
|
77
|
+
type: :runtime
|
102
78
|
prerelease: false
|
79
|
+
version_requirements: *20699700
|
80
|
+
- !ruby/object:Gem::Dependency
|
103
81
|
name: hashlib
|
104
|
-
requirement: !ruby/object:Gem::Requirement
|
82
|
+
requirement: &20699020 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
105
84
|
requirements:
|
106
85
|
- - ! '>='
|
107
86
|
- !ruby/object:Gem::Version
|
108
87
|
version: 0.0.35
|
109
|
-
none: false
|
110
|
-
- !ruby/object:Gem::Dependency
|
111
88
|
type: :runtime
|
112
|
-
version_requirements: !ruby/object:Gem::Requirement
|
113
|
-
requirements:
|
114
|
-
- - ! '>='
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
version: '0'
|
117
|
-
none: false
|
118
89
|
prerelease: false
|
90
|
+
version_requirements: *20699020
|
91
|
+
- !ruby/object:Gem::Dependency
|
119
92
|
name: sinatra
|
120
|
-
requirement: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ! '>='
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
93
|
+
requirement: &20698360 !ruby/object:Gem::Requirement
|
125
94
|
none: false
|
126
|
-
- !ruby/object:Gem::Dependency
|
127
|
-
type: :runtime
|
128
|
-
version_requirements: !ruby/object:Gem::Requirement
|
129
95
|
requirements:
|
130
96
|
- - ! '>='
|
131
97
|
- !ruby/object:Gem::Version
|
132
98
|
version: '0'
|
133
|
-
|
99
|
+
type: :runtime
|
134
100
|
prerelease: false
|
101
|
+
version_requirements: *20698360
|
102
|
+
- !ruby/object:Gem::Dependency
|
135
103
|
name: sinatra-cross_origin
|
136
|
-
requirement: !ruby/object:Gem::Requirement
|
137
|
-
requirements:
|
138
|
-
- - ! '>='
|
139
|
-
- !ruby/object:Gem::Version
|
140
|
-
version: '0'
|
104
|
+
requirement: &20697860 !ruby/object:Gem::Requirement
|
141
105
|
none: false
|
142
|
-
- !ruby/object:Gem::Dependency
|
143
|
-
type: :runtime
|
144
|
-
version_requirements: !ruby/object:Gem::Requirement
|
145
106
|
requirements:
|
146
107
|
- - ! '>='
|
147
108
|
- !ruby/object:Gem::Version
|
148
109
|
version: '0'
|
149
|
-
|
110
|
+
type: :runtime
|
150
111
|
prerelease: false
|
112
|
+
version_requirements: *20697860
|
113
|
+
- !ruby/object:Gem::Dependency
|
151
114
|
name: thin
|
152
|
-
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirement: &20697320 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
153
117
|
requirements:
|
154
118
|
- - ! '>='
|
155
119
|
- !ruby/object:Gem::Version
|
156
120
|
version: '0'
|
157
|
-
|
121
|
+
type: :runtime
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *20697320
|
158
124
|
description: A small service for logging and retrieving timeseries metrics into a
|
159
125
|
Redis server
|
160
126
|
email: garyhetzel@gmail.com
|
@@ -164,12 +130,20 @@ extensions: []
|
|
164
130
|
extra_rdoc_files: []
|
165
131
|
files:
|
166
132
|
- lib/quark.rb
|
133
|
+
- lib/quark/servers/socket.rb
|
134
|
+
- lib/quark/servers/websocket.rb
|
135
|
+
- lib/quark/servers/udp.rb
|
167
136
|
- lib/quark/servers/http.rb
|
137
|
+
- lib/quark/servers/tcp.rb
|
168
138
|
- lib/quark/config.rb
|
169
|
-
- lib/quark/
|
170
|
-
- lib/quark/commands/ping.rb
|
139
|
+
- lib/quark/command_processor.rb
|
171
140
|
- lib/quark/commands/peek.rb
|
141
|
+
- lib/quark/commands/fetch.rb
|
172
142
|
- lib/quark/commands/observe.rb
|
143
|
+
- lib/quark/commands/ping.rb
|
144
|
+
- lib/quark/errors.rb
|
145
|
+
- lib/quark/server.rb
|
146
|
+
- lib/quark/base_server.rb
|
173
147
|
- bin/quark
|
174
148
|
homepage: https://github.com/ghetzel/quark
|
175
149
|
licenses: []
|
@@ -178,20 +152,20 @@ rdoc_options: []
|
|
178
152
|
require_paths:
|
179
153
|
- lib
|
180
154
|
required_ruby_version: !ruby/object:Gem::Requirement
|
155
|
+
none: false
|
181
156
|
requirements:
|
182
157
|
- - ! '>='
|
183
158
|
- !ruby/object:Gem::Version
|
184
159
|
version: '0'
|
185
|
-
none: false
|
186
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
187
162
|
requirements:
|
188
163
|
- - ! '>='
|
189
164
|
- !ruby/object:Gem::Version
|
190
165
|
version: '0'
|
191
|
-
none: false
|
192
166
|
requirements: []
|
193
167
|
rubyforge_project:
|
194
|
-
rubygems_version: 1.8.
|
168
|
+
rubygems_version: 1.8.11
|
195
169
|
signing_key:
|
196
170
|
specification_version: 3
|
197
171
|
summary: A miniscule timeseries metrics logging service
|