sub_zero 0.0.1 → 0.0.3
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.
- checksums.yaml +4 -4
- data/LICENSE +20 -0
- data/README.md +1 -1
- data/bin/sub_zero +6 -0
- data/example/auditing/Gemfile +4 -0
- data/example/auditing/README.md +5 -0
- data/example/auditing/Rakefile +2 -0
- data/example/auditing/auditing.gemspec +25 -0
- data/example/auditing/config.yml +2 -0
- data/example/auditing/lib/auditing/handlers/logs.rb +30 -0
- data/example/auditing/lib/auditing/handlers/status.rb +29 -0
- data/example/auditing/lib/auditing/version.rb +3 -0
- data/example/auditing/lib/auditing.rb +21 -0
- data/example/auditing-client/run.rb +42 -0
- data/lib/sub_zero/cli/app.rb +7 -0
- data/lib/sub_zero/cli/new.rb +89 -0
- data/lib/sub_zero/cli/templates/ruby/client/client.tt +2 -0
- data/lib/sub_zero/cli/templates/ruby/service/Gemfile +8 -0
- data/lib/sub_zero/cli/templates/ruby/service/bin.tt +44 -0
- data/lib/sub_zero/cli/templates/ruby/service/handler.tt +1 -0
- data/lib/sub_zero/cli/templates/ruby/service/lib.tt +47 -0
- data/lib/sub_zero/cli/templates/ruby/service/rvmrc.tt +1 -0
- data/lib/sub_zero/cli/templates/ruby/service/serviceyml.tt +12 -0
- data/lib/sub_zero/cli/templates/ruby/service/verbs.tt +1 -0
- data/lib/sub_zero/cli/templates/ruby/service/version.tt +3 -0
- data/lib/sub_zero/cli.rb +6 -0
- data/lib/sub_zero/client/configuration.rb +12 -0
- data/lib/sub_zero/client/socket.rb +92 -0
- data/lib/sub_zero/client.rb +70 -0
- data/lib/sub_zero/main/common.rb +11 -0
- data/lib/sub_zero/main.rb +64 -0
- data/lib/sub_zero/version.rb +1 -1
- data/lib/sub_zero.rb +16 -2
- data/spec/spec_helper.rb +0 -0
- data/sub_zero.gemspec +10 -4
- data/thoughts.md +60 -0
- metadata +110 -6
- data/LICENSE.txt +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c3d06f3806bd38f972069cccc381a5e14a10552
|
4
|
+
data.tar.gz: 201442b45283cc753950167905a088a450ec613a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59833793e76d2543ad4ed8948f852b7a8b13b0db67e44352cf55c4df36044b16669f84cd8a6e5df9e8134a7c20f36a245bbe760b7fd3c5a30696ebe61b56dacf
|
7
|
+
data.tar.gz: 2aee09d0ea9f147d2acf510203f0b71d7619876b8dbe5750d32f6153f1710ce0e6aad0cdfdd1d96013a96643928c36a11becfc4c5f7b02e61efc2ce1eed31b3c
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 ClubJudge B.V.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
data/bin/sub_zero
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'auditing/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'auditing'
|
8
|
+
spec.version = Auditing::VERSION
|
9
|
+
spec.authors = ['Victor Rodrigues']
|
10
|
+
spec.email = ['victorc.rodrigues@gmail.com']
|
11
|
+
spec.description = %q{SubZero app example}
|
12
|
+
spec.summary = %q{SubZero app example}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
|
24
|
+
spec.add_dependency 'sub_zero'
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Auditing
|
2
|
+
module Handlers
|
3
|
+
class Logs < SubZero::Service::Handler
|
4
|
+
|
5
|
+
def create
|
6
|
+
Log.create params
|
7
|
+
reply :ok
|
8
|
+
end
|
9
|
+
|
10
|
+
def index
|
11
|
+
reply_with Log.all
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
__END__
|
19
|
+
|
20
|
+
#params is the message payload desserialized from messagepack
|
21
|
+
|
22
|
+
#request_id is accessible through here
|
23
|
+
|
24
|
+
#reply(verb, payload = nil)
|
25
|
+
|
26
|
+
#reply_with(content) => same verb
|
27
|
+
#reply_with(verb, content) => other verb
|
28
|
+
(both serialize content to msgpack)
|
29
|
+
|
30
|
+
#logger might be very useful
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Auditing
|
2
|
+
module Handlers
|
3
|
+
class Status < SubZero::Service::Handler
|
4
|
+
|
5
|
+
def show
|
6
|
+
reply :working
|
7
|
+
end
|
8
|
+
|
9
|
+
def count
|
10
|
+
reply_with Log.count
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
__END__
|
18
|
+
|
19
|
+
#params is the message payload desserialized from messagepack
|
20
|
+
|
21
|
+
#request_id is accessible through here
|
22
|
+
|
23
|
+
#reply(verb, payload = nil)
|
24
|
+
|
25
|
+
#reply_with(content) => same verb
|
26
|
+
#reply_with(verb, content) => other verb
|
27
|
+
(both serialize content to msgpack)
|
28
|
+
|
29
|
+
#logger might be very useful
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __FILE__)
|
4
|
+
|
5
|
+
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
6
|
+
|
7
|
+
module Auditing
|
8
|
+
extend SubZero::Service
|
9
|
+
|
10
|
+
sid :auditing
|
11
|
+
|
12
|
+
verbs log: 'logs#create',
|
13
|
+
retrieve: 'logs#index',
|
14
|
+
status: 'status#show',
|
15
|
+
'status/count' => 'status#count'
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
__END__
|
20
|
+
|
21
|
+
verbs targets classes will try to be required / constantized from auditing/ or auditing/handlers as they are declared
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'sub_zero'
|
2
|
+
|
3
|
+
Auditing = SubZero.client(:auditing)
|
4
|
+
|
5
|
+
# or
|
6
|
+
|
7
|
+
Auditing = SubZero.client :auditing do |c|
|
8
|
+
c.timeout = 5000
|
9
|
+
# what else? retry?
|
10
|
+
end
|
11
|
+
|
12
|
+
# fire and forget, just waits the Broker ACK to not care anymore, opens a thread
|
13
|
+
Auditing.log! author: 'Pedro Alvares Cabral', action: 'discovered Brazil.. heh.'
|
14
|
+
|
15
|
+
# waits for reply
|
16
|
+
ronconcon_logs = Auditing.index(author: 'Marques de Pombal')
|
17
|
+
|
18
|
+
# for more complex verbs, the base method call:
|
19
|
+
|
20
|
+
Auditing.call! 'bugs/report', error: 'error while trying to log'
|
21
|
+
|
22
|
+
Auditing.call 'stats/count'
|
23
|
+
|
24
|
+
Auditing.stats_count
|
25
|
+
|
26
|
+
# some sugar to sync call might be
|
27
|
+
|
28
|
+
Auditing['stats/count']
|
29
|
+
|
30
|
+
|
31
|
+
Auditing.stats! do |stats|
|
32
|
+
DeveloperChatRoom.push "Availabilty: #{stats[:availability]}"
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# reply:
|
37
|
+
|
38
|
+
# ACK:NOK { error: { message: '', code: '', … } } (BROKER)
|
39
|
+
# STATS/COUNT:OK
|
40
|
+
# STATS/COUNT:NOK { error: { message: '', code: '', … }}
|
41
|
+
# retry strategy
|
42
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module SubZero
|
2
|
+
module CLI
|
3
|
+
class New < ::Thor
|
4
|
+
include ::Thor::Actions
|
5
|
+
|
6
|
+
attr_accessor :name
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.dirname(__FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
class_option :language, desc: 'language template to use', default: 'ruby', type: :string
|
13
|
+
class_option :test_framework, desc: 'test framework to use', default: 'rspec'
|
14
|
+
class_option :with_rvm, desc: 'include .rvmrc', default: true
|
15
|
+
|
16
|
+
desc 'service NAME', 'Creates a SubZero service'
|
17
|
+
def service name=nil
|
18
|
+
if name.nil?
|
19
|
+
say "You must supply a name!"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
|
23
|
+
say "Creating #{name} service..."
|
24
|
+
create_service name, options
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'client NAME', 'Creates a SubZero client'
|
28
|
+
def client name=nil
|
29
|
+
if name.nil?
|
30
|
+
say "You must supply a name!"
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
say "Creating #{name} client..."
|
35
|
+
create_client name, options
|
36
|
+
end
|
37
|
+
|
38
|
+
#######
|
39
|
+
private
|
40
|
+
#######
|
41
|
+
|
42
|
+
def create_client name, options
|
43
|
+
self.name = name # ERB ... :/
|
44
|
+
template("templates/#{options[:language]}/client.tt", "#{name}/lib/#{name}.rb")
|
45
|
+
|
46
|
+
# TODO
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_service name, options
|
50
|
+
# |-- Gemfile
|
51
|
+
# |-- bin
|
52
|
+
# | `-- name
|
53
|
+
# |-- config
|
54
|
+
# | |-- service.yml
|
55
|
+
# | `-- verbs.rb
|
56
|
+
# |-- lib
|
57
|
+
# | |-- handlers
|
58
|
+
# | | `-- handler.rb
|
59
|
+
# | `-- name.rb
|
60
|
+
# |-- rvmrc
|
61
|
+
# `-- spec
|
62
|
+
# `-- name_spec.rb
|
63
|
+
|
64
|
+
name = name.downcase
|
65
|
+
self.name = name # ERB ... :/
|
66
|
+
template("templates/#{options[:language]}/service/Gemfile", "#{name}/Gemfile")
|
67
|
+
template("templates/#{options[:language]}/service/bin.tt", "#{name}/bin/#{name}")
|
68
|
+
chmod("#{name}/bin/#{name}", 0755)
|
69
|
+
template("templates/#{options[:language]}/service/serviceyml.tt", "#{name}/config/service.yml")
|
70
|
+
template("templates/#{options[:language]}/service/verbs.tt", "#{name}/config/verbs.rb")
|
71
|
+
template("templates/#{options[:language]}/service/lib.tt", "#{name}/lib/#{name}.rb")
|
72
|
+
template("templates/#{options[:language]}/service/version.tt", "#{name}/lib/#{name}/version.rb")
|
73
|
+
template("templates/#{options[:language]}/service/handler.tt", "#{name}/lib/handlers/handler.rb")
|
74
|
+
|
75
|
+
test = options[:test_framework] == "rspec" ? :spec : :test
|
76
|
+
create_file "#{name}/#{test}/#{name}_#{test}.rb"
|
77
|
+
|
78
|
+
if options[:with_rvm]
|
79
|
+
template("templates/#{options[:language]}/service/rvmrc.tt", "#{name}/.rvmrc")
|
80
|
+
end
|
81
|
+
|
82
|
+
empty_directory "#{name}/doc"
|
83
|
+
|
84
|
+
say "all done! you can start a development server with bin/#{name} run"
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- mode: ruby -*-
|
3
|
+
|
4
|
+
require 'rubygems' unless defined?(Gem)
|
5
|
+
|
6
|
+
require 'bundler/setup'
|
7
|
+
Bundler.require
|
8
|
+
|
9
|
+
require_relative '../lib/<%= name.downcase %>.rb'
|
10
|
+
|
11
|
+
service = SubZero::Main.boot ARGV
|
12
|
+
|
13
|
+
daemon_opts = {
|
14
|
+
multiple: false,
|
15
|
+
dir_mode: :normal,
|
16
|
+
dir: service.cli_args[:pid_path], # FIXME
|
17
|
+
log_output: true,
|
18
|
+
stop_proc: lambda { $stop_requested = true }
|
19
|
+
}
|
20
|
+
|
21
|
+
Daemons.run_proc '<%= name %>', daemon_opts do
|
22
|
+
daemon = <%= name.capitalize %>::Main.new service
|
23
|
+
|
24
|
+
start = Time.now
|
25
|
+
ping_at = start + 5
|
26
|
+
|
27
|
+
Signal.trap('INT') { daemon.do_exit_cleanup; exit }
|
28
|
+
|
29
|
+
loop do
|
30
|
+
daemon.poll_sockets
|
31
|
+
|
32
|
+
now = Time.now
|
33
|
+
if now >= ping_at
|
34
|
+
daemon.ping
|
35
|
+
ping_at = now + 15
|
36
|
+
end
|
37
|
+
|
38
|
+
break if $stop_requested
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
daemon.do_exit_cleanup
|
43
|
+
exit 0
|
44
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# TODO
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative "<%= name.capitalize %>/version"
|
2
|
+
|
3
|
+
module <%= name.capitalize %>
|
4
|
+
class Main
|
5
|
+
include SubZero::Common
|
6
|
+
|
7
|
+
def initialize service
|
8
|
+
@config = service.config
|
9
|
+
log "INITing socket"
|
10
|
+
end
|
11
|
+
|
12
|
+
def poll_sockets
|
13
|
+
print '.'
|
14
|
+
sleep 1
|
15
|
+
end
|
16
|
+
|
17
|
+
def ping
|
18
|
+
log "ping..."
|
19
|
+
end
|
20
|
+
|
21
|
+
#######
|
22
|
+
private
|
23
|
+
#######
|
24
|
+
|
25
|
+
def send_announce_packet
|
26
|
+
$sent = Time.now
|
27
|
+
@socket.send_string "SRV", ZMQ::SNDMORE
|
28
|
+
@socket.send_string 0.to_s, ZMQ::SNDMORE
|
29
|
+
@socket.send_string "UP", ZMQ::SNDMORE
|
30
|
+
|
31
|
+
payload = { id: @config['service']['id'], sid: @config['service']['sid'] }.to_msgpack
|
32
|
+
@socket.send_string payload
|
33
|
+
end
|
34
|
+
|
35
|
+
def init_socket
|
36
|
+
@context = ZMQ::Context.new
|
37
|
+
|
38
|
+
@socket = @context.socket ZMQ::DEALER
|
39
|
+
@socket.identity = @config['service']['id']
|
40
|
+
@socket.connect "tcp://#{@config['service']['broker_host']}:#{@config['service']['broker_port']}"
|
41
|
+
|
42
|
+
@poller = ZMQ::Poller.new
|
43
|
+
@poller.register @socket, ZMQ::POLLIN
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 2.0@<%= name.capitalize %> --create
|
@@ -0,0 +1 @@
|
|
1
|
+
# TODO
|
data/lib/sub_zero/cli.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'ffi-rzmq'
|
2
|
+
require 'msgpack'
|
3
|
+
|
4
|
+
module SubZero
|
5
|
+
class Client
|
6
|
+
module Socket
|
7
|
+
|
8
|
+
class SocketError < StandardError; end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def zeromq_fetch verb, payload = {}, options = {}
|
13
|
+
result = []
|
14
|
+
|
15
|
+
zeromq_context do |context|
|
16
|
+
zeromq_socket context do |socket|
|
17
|
+
rid = SecureRandom.uuid
|
18
|
+
zeromq_send socket, "REQ:#{sid}", rid, verb, payload.to_msgpack, options.to_msgpack
|
19
|
+
result = zeromq_result(socket, rid, verb)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def zeromq_context
|
27
|
+
context = ZMQ::Context.create(1)
|
28
|
+
fail SocketError, 'failed to create context' unless context
|
29
|
+
yield context
|
30
|
+
ensure
|
31
|
+
zcc!(context.terminate) if context
|
32
|
+
end
|
33
|
+
|
34
|
+
def zeromq_socket context
|
35
|
+
socket = context.socket ZMQ::DEALER
|
36
|
+
socket.identity = SecureRandom.hex(10)
|
37
|
+
zcc! socket.connect("tcp://#{config[:ip]}:#{config[:port]}")
|
38
|
+
yield socket
|
39
|
+
ensure
|
40
|
+
zcc! socket.close
|
41
|
+
end
|
42
|
+
|
43
|
+
def zeromq_send socket, *msgs
|
44
|
+
last = msgs.pop
|
45
|
+
msgs.each { |m| zcc! socket.send_string m, ZMQ::SNDMORE }
|
46
|
+
zcc! socket.send_string last
|
47
|
+
end
|
48
|
+
|
49
|
+
def zeromq_check_code! result_code
|
50
|
+
return if ZMQ::Util.resultcode_ok? result_code
|
51
|
+
|
52
|
+
fail SocketError, "operation failed, errno [#{ZMQ::Util.errno}], " +
|
53
|
+
"description [#{ZMQ::Util.error_string}]"
|
54
|
+
end
|
55
|
+
|
56
|
+
alias :zcc! :zeromq_check_code!
|
57
|
+
|
58
|
+
def zeromq_result socket, rid, verb
|
59
|
+
result = []
|
60
|
+
zcc! socket.recv_strings(result)
|
61
|
+
|
62
|
+
zeromq_validate_result! rid, verb, result
|
63
|
+
|
64
|
+
routing_info = MessagePack.unpack(result.pop)
|
65
|
+
payload = MessagePack.unpack(result.pop)
|
66
|
+
rep_verb = result.pop
|
67
|
+
status = rep_verb.end_with?('NOK') ? :error : :ok
|
68
|
+
|
69
|
+
[status, payload]
|
70
|
+
end
|
71
|
+
|
72
|
+
def zeromq_validate_result! rid, verb, result
|
73
|
+
type, rep_rid, rep_verb, payload = result
|
74
|
+
|
75
|
+
common = "result: #{result}"
|
76
|
+
|
77
|
+
unless type == "REP:#{sid}" || type == 'BRO'
|
78
|
+
fail SocketError, "unexpected result type: #{type}. " + common
|
79
|
+
end
|
80
|
+
|
81
|
+
unless rid == rep_rid
|
82
|
+
fail SocketError, "rid mismatch. sent: #{rid}, received: #{rep_id}. " + common
|
83
|
+
end
|
84
|
+
|
85
|
+
unless rep_verb == "#{verb}:OK" || rep_verb == "#{verb}:NOK"
|
86
|
+
fail SocketError, "reply verb mismatch: #{rep_verb}. " + common
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'active_support/string_inquirer'
|
2
|
+
|
3
|
+
module SubZero
|
4
|
+
class Client
|
5
|
+
autoload :Configuration, 'sub_zero/client/configuration'
|
6
|
+
autoload :Socket, 'sub_zero/client/socket'
|
7
|
+
|
8
|
+
include Socket
|
9
|
+
|
10
|
+
attr_reader :sid, :config
|
11
|
+
|
12
|
+
def initialize sid
|
13
|
+
@sid, @config = sid.to_s.upcase, Configuration.default
|
14
|
+
yield @config if block_given?
|
15
|
+
end
|
16
|
+
|
17
|
+
def call verb, payload = {}, options = {}
|
18
|
+
sz_verb = verb.to_s.upcase.gsub('_', '/')
|
19
|
+
status, result = zeromq_fetch(sz_verb, payload, options)
|
20
|
+
result = handle_result(status, result)
|
21
|
+
block_given? ? yield(result) : result
|
22
|
+
end
|
23
|
+
|
24
|
+
def call! verb, payload = {}, options = {}, &block
|
25
|
+
call verb, payload, options, &block
|
26
|
+
end
|
27
|
+
|
28
|
+
def [] verb
|
29
|
+
call verb
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_missing method, payload = {}, options = {}, &block
|
33
|
+
if method.to_s.end_with? '!'
|
34
|
+
call! method.delete('!'), payload, options, &block
|
35
|
+
else
|
36
|
+
call method, payload, options, &block
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_result status, result
|
41
|
+
case status
|
42
|
+
when :ok
|
43
|
+
result
|
44
|
+
when :error
|
45
|
+
fail Error.new(result['error'])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Error < ::StandardError
|
50
|
+
|
51
|
+
attr_reader :result
|
52
|
+
|
53
|
+
def initialize result
|
54
|
+
super result['message']
|
55
|
+
set_backtrace caller
|
56
|
+
@result = result
|
57
|
+
end
|
58
|
+
|
59
|
+
def code
|
60
|
+
result['code']
|
61
|
+
end
|
62
|
+
|
63
|
+
def status
|
64
|
+
ActiveSupport::StringInquirer.new self.code.to_s.downcase
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative 'main/common'
|
2
|
+
|
3
|
+
module SubZero
|
4
|
+
module Main
|
5
|
+
include Common
|
6
|
+
extend self
|
7
|
+
|
8
|
+
attr_accessor :config, :cli_args
|
9
|
+
|
10
|
+
def boot cli_args
|
11
|
+
log "booting..."
|
12
|
+
|
13
|
+
log "\tloading service.yml"
|
14
|
+
@config = load_config
|
15
|
+
log "\tparsing CLI args"
|
16
|
+
@cli_args = parse_cli_args cli_args
|
17
|
+
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
#######
|
22
|
+
private
|
23
|
+
#######
|
24
|
+
|
25
|
+
|
26
|
+
def usage(s)
|
27
|
+
$stderr.puts "<%= name %> v#{SubZero::VERSION}" # change to const for the service!
|
28
|
+
$stderr.puts s
|
29
|
+
$stderr.puts "Usage: #{File.basename($0)}: [-p port] [-l log_path] [-pp pid_path]"
|
30
|
+
exit(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_cli_args args
|
34
|
+
opts = {}
|
35
|
+
|
36
|
+
port = @config['service']['broker_port']
|
37
|
+
pid_path = log_path = File.join( File.dirname(__FILE__), '..')
|
38
|
+
|
39
|
+
loop { case ARGV[0]
|
40
|
+
when '-p' then ARGV.shift; port = ARGV.shift
|
41
|
+
when '-l' then ARGV.shift; log_path = ARGV.shift
|
42
|
+
when '-pp' then ARGV.shift; pid_path = ARGV.shift
|
43
|
+
when /^-/ then usage("Unknown option: #{ARGV[0].inspect}")
|
44
|
+
else break
|
45
|
+
end; }
|
46
|
+
|
47
|
+
opts[:port] = port
|
48
|
+
opts[:log_path] = log_path
|
49
|
+
opts[:pid_path] = pid_path
|
50
|
+
|
51
|
+
opts
|
52
|
+
end
|
53
|
+
|
54
|
+
def load_config
|
55
|
+
begin
|
56
|
+
YAML.load_file('config/service.yml')[env]
|
57
|
+
rescue => ex
|
58
|
+
log "could not load config file! (#{ex.message})", 'ERROR'
|
59
|
+
exit 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/sub_zero/version.rb
CHANGED
data/lib/sub_zero.rb
CHANGED
@@ -1,5 +1,19 @@
|
|
1
|
-
require
|
1
|
+
require 'yaml'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
require 'thor'
|
5
|
+
require 'thor/group'
|
6
|
+
|
7
|
+
require_relative 'sub_zero/version'
|
8
|
+
require_relative 'sub_zero/main'
|
2
9
|
|
3
10
|
module SubZero
|
4
|
-
|
11
|
+
autoload :CLI, 'sub_zero/cli'
|
12
|
+
autoload :Client, 'sub_zero/client'
|
13
|
+
extend self
|
14
|
+
|
15
|
+
def client service_id
|
16
|
+
block_given? ? Client.new(service_id, &block) : Client.new(service_id)
|
17
|
+
end
|
18
|
+
|
5
19
|
end
|
data/spec/spec_helper.rb
ADDED
File without changes
|
data/sub_zero.gemspec
CHANGED
@@ -6,8 +6,8 @@ require 'sub_zero/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "sub_zero"
|
8
8
|
spec.version = SubZero::VERSION
|
9
|
-
spec.authors = ["Victor Rodrigues"]
|
10
|
-
spec.email = ["victorc.rodrigues@gmail.com"]
|
9
|
+
spec.authors = ["Victor Rodrigues", "Bruno Antunes"]
|
10
|
+
spec.email = ["victorc.rodrigues@gmail.com", "sardaukar.siet@gmail.com"]
|
11
11
|
spec.description = %q{ZeroMQ SOA solution}
|
12
12
|
spec.summary = %q{ZeroMQ GREAT SOA solution}
|
13
13
|
spec.homepage = ""
|
@@ -18,6 +18,12 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'rspec'
|
24
|
+
|
25
|
+
spec.add_dependency 'thor'
|
26
|
+
spec.add_dependency 'msgpack'
|
27
|
+
spec.add_dependency 'ffi-rzmq'
|
28
|
+
spec.add_dependency 'activesupport'
|
23
29
|
end
|
data/thoughts.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
SubZero is meant to be a way for us to dab into polyglot architectures.
|
2
|
+
|
3
|
+
SubZero itself is made up of 3 parts:
|
4
|
+
|
5
|
+
Broker
|
6
|
+
======
|
7
|
+
|
8
|
+
The traffic cop of the scheme. The Broker mediates requests between Services and Clients. Clients and Services cannot talk directly. Responsabilities:
|
9
|
+
|
10
|
+
- route messages between components
|
11
|
+
- know of active instances of certain Services
|
12
|
+
- have a TTL scheme to guess when components are down
|
13
|
+
- manage retries
|
14
|
+
|
15
|
+
Services
|
16
|
+
========
|
17
|
+
|
18
|
+
Services exchange messages with clients. When a service boots up, it must register with the Broker before accepting work.
|
19
|
+
|
20
|
+
Clients
|
21
|
+
=======
|
22
|
+
|
23
|
+
Cients send requests to the Broker for specific Service IDs (but not instances of Services).
|
24
|
+
|
25
|
+
Messages
|
26
|
+
--------
|
27
|
+
|
28
|
+
There are two types of messages: Broker to Client( or Service) and Client (or Service) to Broker. Since the Broker has a DEALER socket, all of its outgoing messages are prefixed with an ID.
|
29
|
+
|
30
|
+
Typical envelope:
|
31
|
+
|
32
|
+
<pre>
|
33
|
+
ID - string matching the ZMQ identity of a socket (only for outgoing messages from the Broker)
|
34
|
+
RID - UUID that is preserved on all messages pertaining to this request
|
35
|
+
TYPE and optionally SUBTYPE after ':' - examples:
|
36
|
+
BRO (when Broker replies to PINGs from services)
|
37
|
+
SRV (when Service boots up and announces itself)
|
38
|
+
CLI:SID (Client asking for a Service reply)
|
39
|
+
REQ:ID (Broker forwarding Client request to Service)
|
40
|
+
SRV:ID (Service replying to Broker about client request)
|
41
|
+
REP:SID (Broker forwards Service reply to Clent)
|
42
|
+
VERB - can be PING, PONG, UP, ACK, SORT, TAG, etc. Victor suggested subverbs and I agree or else we'll have huge verb handlers on all Services
|
43
|
+
PAYLOAD - a MessagePack serialized hash
|
44
|
+
</pre>
|
45
|
+
|
46
|
+
|
47
|
+
Intended flow for Service authoring
|
48
|
+
===================================
|
49
|
+
|
50
|
+
1. sub_zero new service X
|
51
|
+
2. cd X
|
52
|
+
3. edit config.yml to set broker options (URI, port, etc.)
|
53
|
+
4. add routes to verbs.rb
|
54
|
+
5. create class with handlers (subclass of SubZero::Handler ?)
|
55
|
+
6. when production-ready, run cap deploy to install it on /services (or whatever) in PRD
|
56
|
+
7. call /etc/init.d/sub_zero start X in PRD to start service
|
57
|
+
|
58
|
+
Variations:
|
59
|
+
- sub_zero new service X --lang=scala ? To use different file templates?
|
60
|
+
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sub_zero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Rodrigues
|
8
|
+
- Bruno Antunes
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-
|
12
|
+
date: 2013-08-26 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: bundler
|
@@ -38,21 +39,123 @@ dependencies:
|
|
38
39
|
- - '>='
|
39
40
|
- !ruby/object:Gem::Version
|
40
41
|
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: thor
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: msgpack
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: ffi-rzmq
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: activesupport
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
41
112
|
description: ZeroMQ SOA solution
|
42
113
|
email:
|
43
114
|
- victorc.rodrigues@gmail.com
|
44
|
-
|
115
|
+
- sardaukar.siet@gmail.com
|
116
|
+
executables:
|
117
|
+
- sub_zero
|
45
118
|
extensions: []
|
46
119
|
extra_rdoc_files: []
|
47
120
|
files:
|
48
121
|
- .gitignore
|
49
122
|
- Gemfile
|
50
|
-
- LICENSE
|
123
|
+
- LICENSE
|
51
124
|
- README.md
|
52
125
|
- Rakefile
|
126
|
+
- bin/sub_zero
|
127
|
+
- example/auditing-client/run.rb
|
128
|
+
- example/auditing/Gemfile
|
129
|
+
- example/auditing/README.md
|
130
|
+
- example/auditing/Rakefile
|
131
|
+
- example/auditing/auditing.gemspec
|
132
|
+
- example/auditing/config.yml
|
133
|
+
- example/auditing/lib/auditing.rb
|
134
|
+
- example/auditing/lib/auditing/handlers/logs.rb
|
135
|
+
- example/auditing/lib/auditing/handlers/status.rb
|
136
|
+
- example/auditing/lib/auditing/version.rb
|
53
137
|
- lib/sub_zero.rb
|
138
|
+
- lib/sub_zero/cli.rb
|
139
|
+
- lib/sub_zero/cli/app.rb
|
140
|
+
- lib/sub_zero/cli/new.rb
|
141
|
+
- lib/sub_zero/cli/templates/ruby/client/client.tt
|
142
|
+
- lib/sub_zero/cli/templates/ruby/service/Gemfile
|
143
|
+
- lib/sub_zero/cli/templates/ruby/service/bin.tt
|
144
|
+
- lib/sub_zero/cli/templates/ruby/service/handler.tt
|
145
|
+
- lib/sub_zero/cli/templates/ruby/service/lib.tt
|
146
|
+
- lib/sub_zero/cli/templates/ruby/service/rvmrc.tt
|
147
|
+
- lib/sub_zero/cli/templates/ruby/service/serviceyml.tt
|
148
|
+
- lib/sub_zero/cli/templates/ruby/service/verbs.tt
|
149
|
+
- lib/sub_zero/cli/templates/ruby/service/version.tt
|
150
|
+
- lib/sub_zero/client.rb
|
151
|
+
- lib/sub_zero/client/configuration.rb
|
152
|
+
- lib/sub_zero/client/socket.rb
|
153
|
+
- lib/sub_zero/main.rb
|
154
|
+
- lib/sub_zero/main/common.rb
|
54
155
|
- lib/sub_zero/version.rb
|
156
|
+
- spec/spec_helper.rb
|
55
157
|
- sub_zero.gemspec
|
158
|
+
- thoughts.md
|
56
159
|
homepage: ''
|
57
160
|
licenses:
|
58
161
|
- MIT
|
@@ -73,8 +176,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
176
|
version: '0'
|
74
177
|
requirements: []
|
75
178
|
rubyforge_project:
|
76
|
-
rubygems_version: 2.0.
|
179
|
+
rubygems_version: 2.0.7
|
77
180
|
signing_key:
|
78
181
|
specification_version: 4
|
79
182
|
summary: ZeroMQ GREAT SOA solution
|
80
|
-
test_files:
|
183
|
+
test_files:
|
184
|
+
- spec/spec_helper.rb
|
data/LICENSE.txt
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
Copyright (c) 2013 Victor Rodrigues
|
2
|
-
|
3
|
-
MIT License
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
a copy of this software and associated documentation files (the
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
included in all copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|