quark 0.0.7 → 0.1.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 CHANGED
@@ -7,28 +7,24 @@ module Quark
7
7
  class CLI
8
8
  class<<self
9
9
  def run()
10
- Quark::Config.set("quark.address", "127.0.0.1")
11
- Quark::Config.set("quark.port", 12161)
12
- Quark::Config.set("quark.blocksize", 3600000)
13
- Quark::Config.set("quark.udp.enabled", false)
14
- Quark::Config.set("quark.graphite_compat", true)
15
- Quark::Config.set("debug", false)
10
+ # sets default options
11
+ Quark::Server.setup()
16
12
 
17
13
  (OptionParser.new do |opts|
18
14
  opts.banner = "Usage: quark [options]"
19
15
 
20
16
  # -----------------------------------------------------------------------------
21
- opts.on('-H', '--redis-host HOST', 'Hostname of the Redis server to write to') do |host|
17
+ opts.on('', '--redis-host HOST', 'Hostname of the Redis server to write to') do |host|
22
18
  Quark::Config.set("redis.host", host)
23
19
  end
24
20
 
25
21
  # -----------------------------------------------------------------------------
26
- opts.on('-P', '--redis-port PORT', 'Hostname of the Redis server to write to') do |port|
22
+ opts.on('', '--redis-port PORT', 'Hostname of the Redis server to write to') do |port|
27
23
  Quark::Config.set("redis.port", port)
28
24
  end
29
25
 
30
26
  # -----------------------------------------------------------------------------
31
- opts.on('-N', '--redis-prefix PREFIX', 'The string used to prefix keys in Redis') do |prefix|
27
+ opts.on('', '--redis-prefix PREFIX', 'The string used to prefix keys in Redis') do |prefix|
32
28
  Quark::Config.set("redis.prefix", prefix)
33
29
  end
34
30
 
@@ -38,12 +34,12 @@ module Quark
38
34
  end
39
35
 
40
36
  # -----------------------------------------------------------------------------
41
- opts.on('-a', '--tcp-address ADDR', 'The IP address for the TCP server to listen on') do |addr|
37
+ opts.on('-a', '--address ADDR', 'The IP address for the TCP server to listen on') do |addr|
42
38
  Quark::Config.set("quark.address", addr)
43
39
  end
44
40
 
45
41
  # -----------------------------------------------------------------------------
46
- opts.on('-p', '--tcp-port PORT', 'The TCP port to listen on') do |port|
42
+ opts.on('-p', '--port PORT', 'The TCP port to listen on') do |port|
47
43
  Quark::Config.set("quark.port", port)
48
44
  end
49
45
 
@@ -53,13 +49,23 @@ module Quark
53
49
  end
54
50
 
55
51
  # -----------------------------------------------------------------------------
56
- opts.on('-U', '--udp', 'Create a UDP server') do
57
- Quark::Config.set("quark.udp.enabled", true)
52
+ opts.on('-T', '--[no-]tcp', 'Create a TCP server') do |mode|
53
+ Quark::Config.set("quark.tcp.enabled", mode)
58
54
  end
59
55
 
60
56
  # -----------------------------------------------------------------------------
61
- opts.on('-D', '--debug', 'Enable debug mode') do
62
- Quark::Config.set("debug", true)
57
+ opts.on('', '--tcp-address ADDR', 'The IP address for the TCP server to listen on') do |addr|
58
+ Quark::Config.set("quark.tcp.address", addr)
59
+ end
60
+
61
+ # -----------------------------------------------------------------------------
62
+ opts.on('', '--tcp-port PORT', 'The TCP port to listen on') do |port|
63
+ Quark::Config.set("quark.tcp.port", port)
64
+ end
65
+
66
+ # -----------------------------------------------------------------------------
67
+ opts.on('-U', '--[no-]udp', 'Create a UDP server') do |mode|
68
+ Quark::Config.set("quark.udp.enabled", mode)
63
69
  end
64
70
 
65
71
  # -----------------------------------------------------------------------------
@@ -74,6 +80,25 @@ module Quark
74
80
  Quark::Config.set("quark.udp.port", port)
75
81
  end
76
82
 
83
+ # -----------------------------------------------------------------------------
84
+ opts.on('-H', '--[no-]http', 'Create an HTTP server') do |mode|
85
+ Quark::Config.set("quark.http.enabled", mode)
86
+ end
87
+
88
+ # -----------------------------------------------------------------------------
89
+ opts.on('', '--http-address ADDR', 'The IP address for the HTTP server to listen on') do |addr|
90
+ Quark::Config.set("quark.http.address", addr)
91
+ end
92
+
93
+ # -----------------------------------------------------------------------------
94
+ opts.on('', '--http-port PORT', 'The HTTP port to listen on') do |port|
95
+ Quark::Config.set("quark.http.port", port)
96
+ end
97
+
98
+ # -----------------------------------------------------------------------------
99
+ opts.on('-D', '--debug', 'Enable debug mode') do
100
+ Quark::Config.set("debug", true)
101
+ end
77
102
 
78
103
  # -----------------------------------------------------------------------------
79
104
  opts.on('', '--[no-]graphite', 'Enable/disable Graphite socket compatibility mode') do |mode|
data/lib/quark.rb CHANGED
@@ -5,6 +5,7 @@ require 'hiredis'
5
5
  require 'em-synchrony'
6
6
  require 'multi_json'
7
7
  require 'quark/config'
8
+ require 'quark/servers/http'
8
9
 
9
10
 
10
11
  module Quark
@@ -28,6 +29,14 @@ module Quark
28
29
  end
29
30
 
30
31
  def receive_data(data)
32
+ send_json(Quark::SocketServer.process_command(data))
33
+ end
34
+
35
+ def send_json(data)
36
+ send_data(MultiJson.dump(data)+"\n")
37
+ end
38
+
39
+ def self.process_command(data)
31
40
  # if the data perfectly resembles a graphite-formatted metric (without a command prefix)
32
41
  # then assume the command is "observe"
33
42
  if Quark::Config.get("quark.graphite_compat") and data =~ /^[\w\.\-]+ -?[\d\.]+ \d{10,13}$/
@@ -41,32 +50,32 @@ module Quark
41
50
  if methods.include?(:"process_command_#{command.downcase}")
42
51
  rv = send(:"process_command_#{command.downcase}", arguments)
43
52
  if rv.nil?
44
- send_json({
53
+ return {
45
54
  :success => true
46
- })
55
+ }
47
56
  else
48
- send_json({
57
+ return {
49
58
  :success => true,
50
59
  :command => data.chomp,
51
60
  :results => rv
52
- })
61
+ }
53
62
  end
54
63
  else
55
64
  raise Quark::InvalidCommand.new("Unknown command '#{command.upcase}'")
56
65
  end
57
66
 
58
67
  rescue Quark::Error => e
59
- send_json({
68
+ return {
60
69
  :success => false,
61
70
  :command => data.chomp,
62
71
  :error => {
63
72
  :class => e.class.name,
64
73
  :message => e.message
65
74
  }
66
- })
75
+ }
67
76
 
68
77
  rescue Exception => e
69
- send_json({
78
+ return {
70
79
  :success => false,
71
80
  :command => data.chomp,
72
81
  :error => {
@@ -74,34 +83,48 @@ module Quark
74
83
  :message => e.message,
75
84
  :backtrace => e.backtrace
76
85
  }
77
- })
86
+ }
78
87
  end
79
88
  end
80
89
 
81
- def send_json(data)
82
- send_data(MultiJson.dump(data)+"\n")
83
- end
84
-
85
90
  def unbind()
86
91
  end
87
92
  end
88
93
 
89
94
  class Server
95
+ def self.setup()
96
+ Quark::Config.set("quark.address", "127.0.0.1")
97
+ Quark::Config.set("quark.port", 12161)
98
+ Quark::Config.set("quark.blocksize", 3600000)
99
+ Quark::Config.set("quark.tcp.enabled", true)
100
+ Quark::Config.set("quark.udp.enabled", false)
101
+ Quark::Config.set("quark.http.enabled", false)
102
+ Quark::Config.set("quark.http.port", 12180)
103
+ Quark::Config.get("quark.http.cors", false)
104
+ Quark::Config.set("quark.graphite_compat", true)
105
+ Quark::Config.set("debug", false)
106
+ end
107
+
90
108
  def self.run()
91
109
  @address = Quark::Config.get("quark.address")
92
110
  @port = Quark::Config.get("quark.port")
93
111
  @filename = Quark::Config.get("quark.socket")
94
112
 
95
113
  EM.run do
114
+ Signal.trap("INT") { Quark::Server.quit() }
115
+ Signal.trap("TERM") { Quark::Server.quit() }
116
+
96
117
  if Quark::Config.get("debug")
97
118
  puts "Debug mode is ON"
98
119
  end
99
120
 
121
+ # socket
100
122
  if not @filename.nil? and File.writable?(File.dirname(@filename))
101
123
  puts "Starting socket server at #{@filename}..."
102
124
  EM::start_server(@filename, Quark::SocketServer)
103
125
  end
104
126
 
127
+ # UDP server
105
128
  if Quark::Config.get("quark.udp.enabled") === true
106
129
  @udp_address = Quark::Config.get("quark.udp.address", @address)
107
130
  @udp_port = Quark::Config.get("quark.udp.port", @port)
@@ -110,15 +133,33 @@ module Quark
110
133
  EM::open_datagram_socket(@udp_address, @udp_port, Quark::SocketServer)
111
134
  end
112
135
 
113
- if not @address.nil? and not @port.nil?
136
+ # TCP server
137
+ if Quark::Config.get("quark.tcp.enabled") === true
114
138
  puts "Starting TCP server on #{@address}:#{@port}..."
115
139
  EM::start_server(@address, @port, Quark::SocketServer)
116
140
  end
117
141
 
142
+ # HTTP server
143
+ if Quark::Config.get("quark.http.enabled") === true
144
+ @http_address = Quark::Config.get("quark.http.address", @address)
145
+ @http_port = Quark::Config.get("quark.http.port", 12180)
146
+
147
+ puts "Starting HTTP server on #{@http_address}:#{@http_port}..."
148
+ Quark::Server::HttpServer.new({
149
+ :address => @http_address,
150
+ :port => @http_port
151
+ }).run()
152
+ end
153
+
118
154
  if Quark::Config.get("quark.graphite_compat")
119
155
  puts "Graphite compatibility mode enabled: all sockets will accept Graphite-formatted metrics as observations"
120
156
  end
121
157
  end
122
158
  end
159
+
160
+ def self.quit()
161
+ puts "Stopping Quark..."
162
+ EM.stop()
163
+ end
123
164
  end
124
165
  end
@@ -1,6 +1,6 @@
1
1
  module Quark
2
2
  module SocketServer
3
- def process_command_fetch(data)
3
+ def self.process_command_fetch(data)
4
4
  raise Quark::ArgumentError.new("FETCH command requires at least 1 argument") if data.nil? or data.empty?
5
5
 
6
6
  rv = {}
@@ -1,6 +1,6 @@
1
1
  module Quark
2
2
  module SocketServer
3
- def process_command_observe(data)
3
+ def self.process_command_observe(data)
4
4
  id, value, timestamp = data.chomp.split(' ')
5
5
  timestamp = timestamp.to_i
6
6
 
@@ -2,7 +2,7 @@ module Quark
2
2
  module SocketServer
3
3
  require 'socket'
4
4
 
5
- def process_command_ping(data)
5
+ def self.process_command_ping(data)
6
6
  return {
7
7
  :alive => true,
8
8
  :hostname => Socket.gethostname(),
@@ -0,0 +1,70 @@
1
+ module Quark
2
+ class Server
3
+ class HttpServer
4
+ require 'sinatra'
5
+ require 'sinatra/cross_origin'
6
+ require 'thin'
7
+
8
+ class Base < Sinatra::Base
9
+ configure do
10
+ mime_type :json, 'application/json'
11
+
12
+ if Quark::Config.get("quark.http.cors") === true
13
+ set :allow_origin, :any
14
+ set :allow_methods, [:get, :post, :options]
15
+ set :allow_credentials, true
16
+ enable :cross_origin
17
+ end
18
+ end
19
+
20
+ before do
21
+ if Quark::Config.get("quark.http.cors") === true
22
+ headers 'Access-Control-Allow-Headers' => 'origin, x-requested-with, accept'
23
+ end
24
+
25
+ content_type :json
26
+ end
27
+
28
+ get '/?' do
29
+ MultiJson.dump({
30
+ :status => :ok,
31
+ :config => Quark::Config.all()
32
+ })
33
+ end
34
+
35
+ get '/call/:command/?*' do
36
+ MultiJson.dump(Quark::SocketServer.process_command("#{params[:command].upcase} #{params[:splat].first.gsub('/',' ')}".strip))
37
+ end
38
+
39
+ def _quark_command(command, payload)
40
+ io = nil
41
+
42
+ case settings.quark_protocol
43
+ when :tcp
44
+ io = TCPSocket.new(settings.quark_host, settings.quark_port)
45
+ io.puts("#{command.upcase} #{payload}".strip)
46
+ rv = io.gets()
47
+ when :socket
48
+ io = Socket.new(settings.quark_socket)
49
+ io.puts("#{command.upcase} #{payload}".strip)
50
+ rv = io.gets()
51
+ end
52
+
53
+ return MultiJson.load(rv)
54
+ end
55
+ end
56
+
57
+ def initialize(options=nil)
58
+ @_options = options || Quark::Config.get("quark.http",{})
59
+ end
60
+
61
+ def run()
62
+ Thin::Logging.silent = true unless Quark::Config.get("debug")
63
+ Thin::Server.start(@_options.get(:address,'127.0.0.1'), @_options.get(:port, 12180).to_i, Base.new(), {
64
+ :signals => false,
65
+ :threaded => true,
66
+ })
67
+ end
68
+ end
69
+ end
70
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quark
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2014-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
16
- requirement: &15249980 !ruby/object:Gem::Requirement
16
+ requirement: &5731120 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - =
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.7.9
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *15249980
24
+ version_requirements: *5731120
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: eventmachine
27
- requirement: &15249020 !ruby/object:Gem::Requirement
27
+ requirement: &5730020 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.0.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *15249020
35
+ version_requirements: *5730020
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: redis
38
- requirement: &15248140 !ruby/object:Gem::Requirement
38
+ requirement: &5728780 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 3.0.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *15248140
46
+ version_requirements: *5728780
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: hiredis
49
- requirement: &15263700 !ruby/object:Gem::Requirement
49
+ requirement: &5742700 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 0.5.2
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *15263700
57
+ version_requirements: *5742700
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: em-synchrony
60
- requirement: &15262720 !ruby/object:Gem::Requirement
60
+ requirement: &5739540 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.0.3
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *15262720
68
+ version_requirements: *5739540
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: hashlib
71
- requirement: &15261440 !ruby/object:Gem::Requirement
71
+ requirement: &5737440 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,7 +76,40 @@ dependencies:
76
76
  version: 0.0.35
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *15261440
79
+ version_requirements: *5737440
80
+ - !ruby/object:Gem::Dependency
81
+ name: sinatra
82
+ requirement: &5359100 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: *5359100
91
+ - !ruby/object:Gem::Dependency
92
+ name: sinatra-cross_origin
93
+ requirement: &5356080 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :runtime
100
+ prerelease: false
101
+ version_requirements: *5356080
102
+ - !ruby/object:Gem::Dependency
103
+ name: thin
104
+ requirement: &5352680 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: *5352680
80
113
  description: A small service for logging and retrieving timeseries metrics into a
81
114
  Redis server
82
115
  email: garyhetzel@gmail.com
@@ -86,6 +119,7 @@ extensions: []
86
119
  extra_rdoc_files: []
87
120
  files:
88
121
  - lib/quark.rb
122
+ - lib/quark/servers/http.rb
89
123
  - lib/quark/config.rb
90
124
  - lib/quark/commands/peek.rb
91
125
  - lib/quark/commands/fetch.rb