zss 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.travis.yml +5 -5
- data/Gemfile.lock +12 -4
- data/README.md +10 -1
- data/lib/zss/client.rb +12 -10
- data/lib/zss/configuration.rb +4 -1
- data/lib/zss/error.rb +23 -2
- data/lib/zss/errors.json +59 -0
- data/lib/zss/message.rb +4 -0
- data/lib/zss/message/smi.rb +43 -0
- data/lib/zss/router.rb +42 -0
- data/lib/zss/runner.rb +37 -0
- data/lib/zss/service.rb +147 -0
- data/lib/zss/socket.rb +12 -9
- data/lib/zss/version.rb +1 -1
- data/spec/integration/client_spec.rb +3 -2
- data/spec/integration/service_spec.rb +48 -0
- data/spec/integration/socket_spec.rb +3 -2
- data/spec/spec_broker_helper.rb +55 -7
- data/spec/spec_helper.rb +9 -0
- data/spec/unit/client_spec.rb +1 -1
- data/spec/unit/error_spec.rb +25 -12
- data/spec/unit/message_spec.rb +14 -0
- data/spec/unit/router_spec.rb +97 -0
- data/spec/unit/service_spec.rb +314 -0
- data/spec/unit/socket_spec.rb +40 -30
- data/zss.gemspec +2 -0
- metadata +69 -30
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
NmFiOWM0N2UwNjU2Y2RhODY2OWE1ZDQyN2FhZjk2YTk1OWRmOTI2MA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f3fe063c07e36ab09e3f66202e1ec9b936d4124a
|
4
|
+
data.tar.gz: 8a03c4d06efc0dd89a84b5bdf311712ae6edb205
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
NTAzYTU1NzI4NTVmZmU3NDk2NjQwZGY0NDIyZTJkMmNlYmUzMGE3Yzk5YTAz
|
11
|
-
YTcxYzI2MzBlMzZlNzdkMGUzYTZkYzYyY2ZmZDc0M2U3NTQwNTU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZTJkNTk5NDg2NDE3OWU2MWVlMjY0ZWY5OGFiOTNmYmExY2NiYzFlZGY5N2Mz
|
14
|
-
YjQwMmFlZGM2MDJiZGM4NGEwOWZhNGQxNDE2N2U2YTA0NmZiOWRlNDA1ZDE1
|
15
|
-
YWRjOTA1NWFiODUxNWU0YTFhMmU5YTExY2Q0OTcyZGY2ZDc4Zjc=
|
6
|
+
metadata.gz: f50426fa1b1d3cc52f8c65798ff8943e48c9294e55d00f2e4b4d63def33a1a19a0fc55573873e877420f1c8bdd87e95f884e7586a8c4a7334aa2f12d464a1170
|
7
|
+
data.tar.gz: ac111e8fd24c86206b1e874d9f6f01ced6c16b4bcc32cf88fdbad62f1e01a70c14333842cf15cf63d54892d9bc1d2928a52bf1333063109b328d72bd15c80b52
|
data/.travis.yml
CHANGED
@@ -20,8 +20,8 @@ addons:
|
|
20
20
|
code_climate:
|
21
21
|
repo_token:
|
22
22
|
secure: U6d5emmLhWdFAqrVgtHtXDs1lR2f40is89mZfOp1HbnTQKnClGbmCuEGfeHL8HbaMZjpxFb7g9Ery26E3g1gCsE82sP8SkD0qY46LbWlufRctZWsD4d+TZZZttqo2eNNObKkW5JbzW2pGiRqQb7RCfsxsOnqqhXl3uXVOHK24x4=
|
23
|
-
deploy:
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
# deploy:
|
24
|
+
# provider: rubygems
|
25
|
+
# api_key:
|
26
|
+
# secure: OsOTnuz+qiZe4RY2hOhYsv46LJE7eQf3jZAX5oBBxsSaC6V91SgyHgl1mexMM6r1CPvgOlG4b33AU2Um9NIVrO11fwl/psSeh6zrMf46l5tmn+QCtjOuoM1jtKpomYAPXioH0KkZWoRcqPyNZemZx14YJQW0/fLtrc5xUS20Re0=
|
27
|
+
# gemspec: zss.gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
zss (0.0.
|
4
|
+
zss (0.0.3)
|
5
5
|
activesupport
|
6
|
+
daemons
|
7
|
+
em-zeromq
|
6
8
|
ffi-rzmq
|
7
9
|
hashie
|
8
10
|
msgpack
|
@@ -20,18 +22,24 @@ GEM
|
|
20
22
|
codeclimate-test-reporter (0.3.0)
|
21
23
|
simplecov (>= 0.7.1, < 1.0.0)
|
22
24
|
coderay (1.1.0)
|
25
|
+
daemons (1.1.9)
|
23
26
|
diff-lcs (1.2.5)
|
24
27
|
docile (1.1.5)
|
28
|
+
em-zeromq (0.5.0)
|
29
|
+
eventmachine (>= 1.0.0)
|
30
|
+
ffi (>= 1.0.0)
|
31
|
+
ffi-rzmq (~> 2.0.1)
|
32
|
+
eventmachine (1.0.3)
|
25
33
|
ffi (1.9.3)
|
26
34
|
ffi-rzmq (2.0.1)
|
27
35
|
ffi-rzmq-core (>= 1.0.1)
|
28
36
|
ffi-rzmq-core (1.0.3)
|
29
37
|
ffi (~> 1.9)
|
30
|
-
hashie (3.
|
31
|
-
i18n (0.6.
|
38
|
+
hashie (3.2.0)
|
39
|
+
i18n (0.6.11)
|
32
40
|
json (1.8.1)
|
33
41
|
method_source (0.8.2)
|
34
|
-
minitest (5.
|
42
|
+
minitest (5.4.0)
|
35
43
|
msgpack (0.5.8)
|
36
44
|
multi_json (1.10.1)
|
37
45
|
pry (0.10.0)
|
data/README.md
CHANGED
@@ -76,13 +76,22 @@ PongClient.call("ping/pong", "payload")
|
|
76
76
|
4. Push to the branch (`git push origin my-new-feature`)
|
77
77
|
5. Create new Pull Request
|
78
78
|
|
79
|
+
## Deployment
|
80
|
+
|
81
|
+
Continuous Integration build on master branch is configured to:
|
82
|
+
1. bump gem patch version
|
83
|
+
2. tag version
|
84
|
+
3. deploy to ruby gems
|
85
|
+
|
86
|
+
Major and Minor version are controlled manually, check next chapter.
|
87
|
+
|
79
88
|
## Bump versioning
|
80
89
|
|
81
90
|
We use [bump gem](https://github.com/gregorym/bump) to control gem versioning.
|
82
91
|
|
83
92
|
Bump Patch version
|
84
93
|
|
85
|
-
$ bump
|
94
|
+
$ bump patch
|
86
95
|
|
87
96
|
Bump Minor version
|
88
97
|
|
data/lib/zss/client.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
|
1
|
+
require_relative 'socket'
|
2
2
|
|
3
3
|
module ZSS
|
4
4
|
class Client
|
5
5
|
|
6
6
|
attr_reader :sid, :frontend, :identity, :timeout
|
7
7
|
|
8
|
-
def initialize sid, config =
|
9
|
-
@frontend = config
|
8
|
+
def initialize sid, config = {}
|
9
|
+
@frontend = config[:frontend] || Configuration.default.frontend
|
10
10
|
@sid = sid.to_s.upcase
|
11
|
-
@identity = config
|
12
|
-
@timeout = config
|
11
|
+
@identity = config[:identity] || "client"
|
12
|
+
@timeout = config[:timeout] || 1000
|
13
13
|
end
|
14
14
|
|
15
|
-
def call verb, payload
|
16
|
-
action = verb.to_s.upcase
|
15
|
+
def call verb, payload, headers: {}, timeout: nil
|
16
|
+
action = verb.to_s.upcase
|
17
17
|
address = Message::Address.new(sid: sid, verb: action)
|
18
18
|
|
19
19
|
request = Message.new(
|
@@ -21,7 +21,7 @@ module ZSS
|
|
21
21
|
headers: headers,
|
22
22
|
payload: payload)
|
23
23
|
|
24
|
-
response = socket.call(request)
|
24
|
+
response = socket.call(request, timeout)
|
25
25
|
fail ZSS::Error.new(response.status, response.payload) if response.is_error?
|
26
26
|
|
27
27
|
response.payload
|
@@ -29,10 +29,12 @@ module ZSS
|
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
|
-
def method_missing method,
|
32
|
+
def method_missing method, *args
|
33
33
|
# since we cannot use / on method names we replace _ with /
|
34
34
|
verb = method.to_s.gsub('_', '/')
|
35
|
-
|
35
|
+
payload = args[0]
|
36
|
+
options = args[1] || {}
|
37
|
+
call verb, payload, options
|
36
38
|
end
|
37
39
|
|
38
40
|
def socket
|
data/lib/zss/configuration.rb
CHANGED
data/lib/zss/error.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module ZSS
|
2
4
|
class Error < ::StandardError
|
3
5
|
|
4
|
-
attr_reader :code, :
|
6
|
+
attr_reader :code, :user_message
|
7
|
+
attr_accessor :developer_message
|
5
8
|
|
6
|
-
def initialize
|
9
|
+
def initialize(code, payload)
|
7
10
|
@code = code.to_i
|
8
11
|
@developer_message = payload.developerMessage
|
9
12
|
@user_message = payload.userMessage
|
@@ -11,5 +14,23 @@ module ZSS
|
|
11
14
|
set_backtrace caller
|
12
15
|
end
|
13
16
|
|
17
|
+
def self.[](code)
|
18
|
+
data = get_errors[code.to_s]
|
19
|
+
Error.new(code.to_i, data.body)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def self.get_errors
|
25
|
+
@errors ||= begin
|
26
|
+
path = File.join(
|
27
|
+
File.dirname(File.absolute_path(__FILE__)),
|
28
|
+
'errors.json'
|
29
|
+
)
|
30
|
+
file = File.read(path)
|
31
|
+
Hashie::Mash.new(JSON.parse(file))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
14
35
|
end
|
15
36
|
end
|
data/lib/zss/errors.json
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
{
|
2
|
+
"400": {
|
3
|
+
"code": 400,
|
4
|
+
"body": {
|
5
|
+
"developerMessage": "The request cannot be fulfilled due to bad syntax.",
|
6
|
+
"userMessage": "An error occured",
|
7
|
+
"errorCode": 400
|
8
|
+
}
|
9
|
+
},
|
10
|
+
"401": {
|
11
|
+
"code": 401,
|
12
|
+
"body": {
|
13
|
+
"developerMessage": "User authentication token has expired or is missing",
|
14
|
+
"userMessage": "This resource is only available after logging in.",
|
15
|
+
"errorCode": 401
|
16
|
+
}
|
17
|
+
},
|
18
|
+
"403": {
|
19
|
+
"code": 403,
|
20
|
+
"body": {
|
21
|
+
"developerMessage": "User does not have enough privileges to access this resource.",
|
22
|
+
"userMessage": "You do not have access to this resource.",
|
23
|
+
"errorCode": 403
|
24
|
+
},
|
25
|
+
"headers": {}
|
26
|
+
},
|
27
|
+
"404": {
|
28
|
+
"code": 404,
|
29
|
+
"body": {
|
30
|
+
"developerMessage": "The resource could not be found.",
|
31
|
+
"userMessage": "The content you requested was not found.",
|
32
|
+
"errorCode": 404
|
33
|
+
}
|
34
|
+
},
|
35
|
+
"429": {
|
36
|
+
"code": 429,
|
37
|
+
"body": {
|
38
|
+
"developerMessage": "You have sent too many requests in a given amount of time.",
|
39
|
+
"userMessage": "Please wait a while before trying to access this content again",
|
40
|
+
"errorCode": 429
|
41
|
+
}
|
42
|
+
},
|
43
|
+
"500": {
|
44
|
+
"code": 500,
|
45
|
+
"body": {
|
46
|
+
"developerMessage": "There was an error while processing this request. There is probably something wrong with the API server.",
|
47
|
+
"userMessage": "There was an error while processing this request.",
|
48
|
+
"errorCode": 500
|
49
|
+
}
|
50
|
+
},
|
51
|
+
"599": {
|
52
|
+
"code": 599,
|
53
|
+
"body": {
|
54
|
+
"developerMessage": "Connection timeout while processing this request.",
|
55
|
+
"userMessage": "Connection timeout while processing this request.",
|
56
|
+
"errorCode": 599
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
data/lib/zss/message.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
module ZSS
|
2
|
+
|
3
|
+
class Message
|
4
|
+
|
5
|
+
class SMI
|
6
|
+
|
7
|
+
SMI = 'SMI'
|
8
|
+
|
9
|
+
def self.down sid
|
10
|
+
Message.new(
|
11
|
+
address: Message::Address.new(
|
12
|
+
sid: SMI,
|
13
|
+
verb: 'DOWN'
|
14
|
+
),
|
15
|
+
payload: sid
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.up sid
|
20
|
+
Message.new(
|
21
|
+
address: Message::Address.new(
|
22
|
+
sid: SMI,
|
23
|
+
verb: 'UP'
|
24
|
+
),
|
25
|
+
payload: sid
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.heartbeat sid
|
30
|
+
Message.new(
|
31
|
+
address: Message::Address.new(
|
32
|
+
sid: SMI,
|
33
|
+
verb: 'HEARTBEAT'
|
34
|
+
),
|
35
|
+
payload: sid
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/lib/zss/router.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module ZSS
|
2
|
+
class Router
|
3
|
+
|
4
|
+
def add(context, route, handler = nil)
|
5
|
+
|
6
|
+
fail "Invalid context!" unless context
|
7
|
+
fail "Invalid route: #{route}" unless route
|
8
|
+
|
9
|
+
handler ||= route.to_sym
|
10
|
+
|
11
|
+
fail "Invalid handler: #{handler}" unless context.respond_to? handler
|
12
|
+
|
13
|
+
routes[route.to_s.upcase] = get_proc(context, handler)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(route)
|
17
|
+
handler = routes[route.to_s.upcase]
|
18
|
+
return handler if handler
|
19
|
+
|
20
|
+
error = Error[404]
|
21
|
+
error.developer_message = "Invalid route #{route}!"
|
22
|
+
fail error
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def routes
|
28
|
+
@routes ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_proc(context, handler)
|
32
|
+
receive_headers = context.method(handler).parameters.size == 2
|
33
|
+
|
34
|
+
if receive_headers
|
35
|
+
Proc.new { |p,h| context.send(handler, p, h) }
|
36
|
+
else
|
37
|
+
Proc.new { |p,h| context.send(handler, p) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
data/lib/zss/runner.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'daemons'
|
2
|
+
|
3
|
+
module ZSS
|
4
|
+
class Runner
|
5
|
+
|
6
|
+
def self.run(proc_name)
|
7
|
+
proc_name = proc_name.to_s
|
8
|
+
pid_path = log_path = './log'
|
9
|
+
|
10
|
+
FileUtils.mkdir_p pid_path
|
11
|
+
FileUtils.mkdir_p log_path
|
12
|
+
|
13
|
+
daemon_opts = {
|
14
|
+
multiple: true,
|
15
|
+
dir_mode: :normal,
|
16
|
+
dir: pid_path,
|
17
|
+
log_output: true,
|
18
|
+
stop_proc: lambda do
|
19
|
+
puts "stop #{proc_name} daemon..."
|
20
|
+
$stop_requested = true
|
21
|
+
end
|
22
|
+
}
|
23
|
+
|
24
|
+
puts "Starting #{proc_name}:\n\tPID: #{pid_path}\n\tLOGS: #{log_path}"
|
25
|
+
|
26
|
+
Daemons.run_proc proc_name, daemon_opts do
|
27
|
+
daemon = ZSS::ServiceRegister.get_service
|
28
|
+
|
29
|
+
puts "Started #{proc_name} daemon..."
|
30
|
+
daemon.run
|
31
|
+
|
32
|
+
puts "Stoping #{proc_name} daemon"
|
33
|
+
exit 0
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/zss/service.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'em-zeromq'
|
2
|
+
require_relative 'router'
|
3
|
+
require_relative 'message/smi'
|
4
|
+
|
5
|
+
module ZSS
|
6
|
+
class Service
|
7
|
+
|
8
|
+
attr_reader :sid, :heartbeat, :backend, :identity
|
9
|
+
|
10
|
+
def initialize(sid, config = {})
|
11
|
+
|
12
|
+
fail Error[500] if sid.blank?
|
13
|
+
|
14
|
+
@sid = sid.to_s.upcase
|
15
|
+
@heartbeat = config.try(:heartbeat) || 1000
|
16
|
+
@backend = config.try(:backend) || Configuration.default.backend
|
17
|
+
@router = ZSS::Router.new
|
18
|
+
@identity = "#{sid}##{SecureRandom.uuid}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
Thread.abort_on_exception = true
|
23
|
+
|
24
|
+
context = EM::ZeroMQ::Context.new(1)
|
25
|
+
fail RuntimeError, 'failed to create create_context' unless context
|
26
|
+
|
27
|
+
# puts "Starting SID: '#{sid}' ID: '#{identity}'"
|
28
|
+
# puts "Env: #{ZSS::Environment.env}"
|
29
|
+
# puts "Broker: #{backend}"
|
30
|
+
|
31
|
+
EM.run do
|
32
|
+
# handle interrupts
|
33
|
+
Signal.trap("INT") { stop }
|
34
|
+
Signal.trap("TERM") { stop }
|
35
|
+
|
36
|
+
connect_socket context
|
37
|
+
|
38
|
+
start_heartbeat_worker
|
39
|
+
|
40
|
+
# send up message
|
41
|
+
send Message::SMI.up(sid)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_route(context, route, handler = nil)
|
46
|
+
router.add(context, route, handler)
|
47
|
+
end
|
48
|
+
|
49
|
+
def stop
|
50
|
+
timer.cancel if timer
|
51
|
+
|
52
|
+
# puts "Stoping SID: '#{sid}' ID: '#{socket.identity}'"
|
53
|
+
EM.add_timer do
|
54
|
+
send Message::SMI.down(sid)
|
55
|
+
socket.disconnect backend
|
56
|
+
EM::stop
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
attr_accessor :socket, :router, :timer
|
63
|
+
|
64
|
+
def connect_socket(context)
|
65
|
+
|
66
|
+
@socket = context.socket ZMQ::DEALER
|
67
|
+
fail RuntimeError, 'failed to create socket' unless socket
|
68
|
+
|
69
|
+
socket.identity = identity
|
70
|
+
socket.setsockopt(ZMQ::LINGER, 0)
|
71
|
+
socket.on(:message, &method(:handle_frames))
|
72
|
+
|
73
|
+
socket.connect(backend)
|
74
|
+
end
|
75
|
+
|
76
|
+
def start_heartbeat_worker
|
77
|
+
@timer = EventMachine::PeriodicTimer.new(heartbeat / 1000) do
|
78
|
+
send Message::SMI.heartbeat(sid)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def handle_frames(*frames)
|
83
|
+
# we need to close frame to avoid memory leaks
|
84
|
+
frames = frames.map do |frame|
|
85
|
+
out_frame = frame.copy_out_string
|
86
|
+
frame.close
|
87
|
+
out_frame
|
88
|
+
end
|
89
|
+
|
90
|
+
handle Message.parse(frames)
|
91
|
+
end
|
92
|
+
|
93
|
+
def handle(message)
|
94
|
+
if message.req?
|
95
|
+
handle_request(message)
|
96
|
+
#else
|
97
|
+
# puts "heartbeat response received!"
|
98
|
+
end
|
99
|
+
rescue ZSS::Error => error
|
100
|
+
#puts "Erorr: ZSS::Error raised while processing request: #{e}"
|
101
|
+
reply_error error, message
|
102
|
+
rescue => e
|
103
|
+
#puts "Error while processing request: #{e}"
|
104
|
+
reply_error Error[500], message
|
105
|
+
end
|
106
|
+
|
107
|
+
def handle_request(message)
|
108
|
+
if message.address.sid != sid
|
109
|
+
error = Error[404]
|
110
|
+
error.developer_message = "Invalid SID: #{message.address.sid}!"
|
111
|
+
fail error
|
112
|
+
end
|
113
|
+
|
114
|
+
# the router returns an handler that receives payload and headers
|
115
|
+
handler = router.get(message.address.verb)
|
116
|
+
message.payload = handler.call(message.payload, message.headers)
|
117
|
+
reply message
|
118
|
+
end
|
119
|
+
|
120
|
+
def reply_error(error, message)
|
121
|
+
message.status = error.code
|
122
|
+
message.payload = {
|
123
|
+
errorCode: error.code,
|
124
|
+
userMessage: error.user_message,
|
125
|
+
developerMessage: error.developer_message
|
126
|
+
}
|
127
|
+
message.type = Message::Type::REP
|
128
|
+
send message
|
129
|
+
end
|
130
|
+
|
131
|
+
def reply(message)
|
132
|
+
#puts "reply #{message}"
|
133
|
+
message.status = 200
|
134
|
+
message.type = Message::Type::REP
|
135
|
+
send message
|
136
|
+
end
|
137
|
+
|
138
|
+
def send(msg)
|
139
|
+
frames = msg.to_frames
|
140
|
+
#remove identity frame on request
|
141
|
+
frames.shift if msg.req?
|
142
|
+
success = socket.send_msg(*frames)
|
143
|
+
puts "An Error ocurred while sending message" unless success
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|