asir 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/Gemfile +16 -0
- data/README.textile +50 -0
- data/Rakefile +83 -0
- data/VERSION +1 -0
- data/asir.gemspec +36 -0
- data/asir.riterate.yml +114 -0
- data/bin/asir +6 -0
- data/doc/Rakefile +8 -0
- data/doc/asir-sequence.pic +84 -0
- data/doc/asir-sequence.svg +1559 -0
- data/doc/sequence.pic +430 -0
- data/example/asir_control.sh +24 -0
- data/example/asir_control_client_http.rb +14 -0
- data/example/asir_control_client_zmq.rb +15 -0
- data/example/config/asir_config.rb +63 -0
- data/example/delayed_service.rb +15 -0
- data/example/ex01.rb +12 -0
- data/example/ex02.rb +12 -0
- data/example/ex03.rb +19 -0
- data/example/ex04.rb +33 -0
- data/example/ex05.rb +16 -0
- data/example/ex06.rb +26 -0
- data/example/ex07.rb +28 -0
- data/example/ex08.rb +30 -0
- data/example/ex09.rb +25 -0
- data/example/ex10.rb +24 -0
- data/example/ex11.rb +48 -0
- data/example/ex12.rb +34 -0
- data/example/ex13.rb +35 -0
- data/example/ex14.rb +30 -0
- data/example/ex15.rb +13 -0
- data/example/ex16.rb +33 -0
- data/example/ex17.rb +41 -0
- data/example/ex18.rb +62 -0
- data/example/ex19.rb +32 -0
- data/example/ex20.rb +28 -0
- data/example/ex21.rb +28 -0
- data/example/ex22.rb +15 -0
- data/example/ex23.rb +20 -0
- data/example/ex24.rb +35 -0
- data/example/example_helper.rb +51 -0
- data/example/sample_service.rb +162 -0
- data/example/unsafe_service.rb +12 -0
- data/hack_night/README.txt +18 -0
- data/hack_night/exercise/prob-1.rb +18 -0
- data/hack_night/exercise/prob-2.rb +21 -0
- data/hack_night/exercise/prob-3.rb +16 -0
- data/hack_night/exercise/prob-4.rb +36 -0
- data/hack_night/exercise/prob-5.rb +36 -0
- data/hack_night/exercise/prob-6.rb +95 -0
- data/hack_night/exercise/prob-7.rb +34 -0
- data/hack_night/solution/math_service.rb +11 -0
- data/hack_night/solution/prob-1.rb +12 -0
- data/hack_night/solution/prob-2.rb +15 -0
- data/hack_night/solution/prob-3.rb +17 -0
- data/hack_night/solution/prob-4.rb +37 -0
- data/hack_night/solution/prob-5.rb +21 -0
- data/hack_night/solution/prob-6.rb +33 -0
- data/hack_night/solution/prob-7.rb +36 -0
- data/lab/phony_proc.rb +31 -0
- data/lib/asir.rb +253 -0
- data/lib/asir/additional_data.rb +25 -0
- data/lib/asir/channel.rb +130 -0
- data/lib/asir/client.rb +111 -0
- data/lib/asir/code_block.rb +57 -0
- data/lib/asir/code_more.rb +50 -0
- data/lib/asir/coder.rb +26 -0
- data/lib/asir/coder/base64.rb +19 -0
- data/lib/asir/coder/chain.rb +30 -0
- data/lib/asir/coder/identity.rb +23 -0
- data/lib/asir/coder/json.rb +30 -0
- data/lib/asir/coder/marshal.rb +17 -0
- data/lib/asir/coder/null.rb +23 -0
- data/lib/asir/coder/proc.rb +22 -0
- data/lib/asir/coder/sign.rb +48 -0
- data/lib/asir/coder/xml.rb +213 -0
- data/lib/asir/coder/yaml.rb +33 -0
- data/lib/asir/coder/zlib.rb +21 -0
- data/lib/asir/configuration.rb +32 -0
- data/lib/asir/error.rb +34 -0
- data/lib/asir/identity.rb +36 -0
- data/lib/asir/initialization.rb +23 -0
- data/lib/asir/log.rb +82 -0
- data/lib/asir/main.rb +396 -0
- data/lib/asir/message.rb +31 -0
- data/lib/asir/message/delay.rb +35 -0
- data/lib/asir/object_resolving.rb +15 -0
- data/lib/asir/result.rb +39 -0
- data/lib/asir/retry_behavior.rb +54 -0
- data/lib/asir/transport.rb +241 -0
- data/lib/asir/transport/beanstalk.rb +217 -0
- data/lib/asir/transport/broadcast.rb +34 -0
- data/lib/asir/transport/buffer.rb +115 -0
- data/lib/asir/transport/composite.rb +19 -0
- data/lib/asir/transport/connection_oriented.rb +180 -0
- data/lib/asir/transport/delay.rb +38 -0
- data/lib/asir/transport/delegation.rb +53 -0
- data/lib/asir/transport/fallback.rb +36 -0
- data/lib/asir/transport/file.rb +88 -0
- data/lib/asir/transport/http.rb +54 -0
- data/lib/asir/transport/local.rb +21 -0
- data/lib/asir/transport/null.rb +14 -0
- data/lib/asir/transport/payload_io.rb +52 -0
- data/lib/asir/transport/rack.rb +73 -0
- data/lib/asir/transport/retry.rb +41 -0
- data/lib/asir/transport/stream.rb +35 -0
- data/lib/asir/transport/subprocess.rb +30 -0
- data/lib/asir/transport/tcp_socket.rb +34 -0
- data/lib/asir/transport/webrick.rb +50 -0
- data/lib/asir/transport/zmq.rb +110 -0
- data/lib/asir/uuid.rb +32 -0
- data/lib/asir/version.rb +3 -0
- data/spec/const_get_speed_spec.rb +33 -0
- data/spec/debug_helper.rb +20 -0
- data/spec/example_spec.rb +88 -0
- data/spec/json_spec.rb +128 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/xml_spec.rb +144 -0
- data/stylesheets/slides.css +105 -0
- metadata +173 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'asir/transport/stream'
|
2
|
+
require 'asir/transport/payload_io'
|
3
|
+
|
4
|
+
module ASIR
|
5
|
+
class Transport
|
6
|
+
# !SLIDE
|
7
|
+
# File Transport
|
8
|
+
#
|
9
|
+
# Send Message one-way to a file.
|
10
|
+
# Can be used as a log or named pipe service.
|
11
|
+
class File < Stream
|
12
|
+
include PayloadIO # _write, _read
|
13
|
+
attr_accessor :file, :mode, :perms, :stream
|
14
|
+
|
15
|
+
def initialize opts = nil; @one_way = true; super; end
|
16
|
+
|
17
|
+
# Writes a Message payload String.
|
18
|
+
def _send_message message, message_payload
|
19
|
+
_write message_payload, stream
|
20
|
+
ensure
|
21
|
+
close if ::File.pipe?(file)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns a Message payload String.
|
25
|
+
def _receive_message stream, additional_data
|
26
|
+
[ _read(stream), nil ]
|
27
|
+
end
|
28
|
+
|
29
|
+
# one-way; no Result.
|
30
|
+
def _send_result message, result, result_payload, stream, message_state
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# one-way; no Result.
|
35
|
+
def _receive_result message, opaque_result
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# !SLIDE
|
40
|
+
# File Transport Support
|
41
|
+
|
42
|
+
def stream
|
43
|
+
@stream ||=
|
44
|
+
begin
|
45
|
+
stream = ::File.open(file, mode || "w+")
|
46
|
+
::File.chmod(perms, file) rescue nil if @perms
|
47
|
+
after_connect!(stream) if respond_to?(:after_connect!)
|
48
|
+
stream
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# !SLIDE
|
53
|
+
# Process (receive) messages from a file.
|
54
|
+
|
55
|
+
def serve_file!
|
56
|
+
::File.open(file, "r") do | stream |
|
57
|
+
@running = true
|
58
|
+
serve_stream! stream, nil # One-way: no result stream.
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# !SLIDE
|
63
|
+
# Named Pipe Server
|
64
|
+
|
65
|
+
def prepare_pipe_server!
|
66
|
+
# _log [ :prepare_pipe_server!, file ]
|
67
|
+
unless ::File.exist? file
|
68
|
+
system(cmd = "mkfifo #{file.inspect}") or raise "cannot run #{cmd.inspect}"
|
69
|
+
::File.chmod(perms, file) rescue nil if perms
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def run_pipe_server!
|
74
|
+
# _log [ :run_pipe_server!, file ]
|
75
|
+
with_server_signals! do
|
76
|
+
@running = true
|
77
|
+
while @running
|
78
|
+
serve_file!
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# !SLIDE END
|
84
|
+
end
|
85
|
+
# !SLIDE END
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'asir'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
gem 'httpclient'
|
5
|
+
require 'httpclient'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module ASIR
|
9
|
+
class Transport
|
10
|
+
# !SLIDE
|
11
|
+
# HTTP Transport
|
12
|
+
#
|
13
|
+
# Using HTTPClient.
|
14
|
+
class HTTP < self
|
15
|
+
attr_accessor :uri, :server, :debug
|
16
|
+
|
17
|
+
# Client-side: HTTPClient
|
18
|
+
|
19
|
+
def client
|
20
|
+
@client ||=
|
21
|
+
Channel.new(:on_connect =>
|
22
|
+
lambda { | channel | ::HTTPClient.new })
|
23
|
+
end
|
24
|
+
|
25
|
+
def close
|
26
|
+
@client.close if @client
|
27
|
+
ensure
|
28
|
+
@client = nil unless Channel === @client
|
29
|
+
end
|
30
|
+
|
31
|
+
# Send the Message payload String using HTTP POST.
|
32
|
+
# Returns the HTTPClient::Request response object.
|
33
|
+
def _send_message message, message_payload
|
34
|
+
client.with_stream! do | client |
|
35
|
+
client.post(uri, message_payload)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Recieve the Result payload String from the opaque
|
40
|
+
# HTTPClient::Request response object returned from #_send_message.
|
41
|
+
def _receive_result message, http_result_message
|
42
|
+
# $stderr.puts " ### http_result_message.content.encoding = #{http_result_message.content.encoding.inspect}" rescue nil
|
43
|
+
# $stderr.puts " ### http_result_message.content = #{http_result_message.content.inspect}" rescue nil
|
44
|
+
http_result_message.content.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
48
|
+
APPLICATION_BINARY = 'application/binary'.freeze
|
49
|
+
|
50
|
+
end
|
51
|
+
# !SLIDE END
|
52
|
+
end # class
|
53
|
+
end # module
|
54
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ASIR
|
2
|
+
class Transport
|
3
|
+
# !SLIDE
|
4
|
+
# Local Transport
|
5
|
+
#
|
6
|
+
# Send Message to same process.
|
7
|
+
# Requires Identity Coder.
|
8
|
+
class Local < self
|
9
|
+
# Returns Result object after invoking Message.
|
10
|
+
def _send_message message, message_payload
|
11
|
+
invoke_message!(message)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns Result object from #send_message.
|
15
|
+
def _receive_result message, opaque_result
|
16
|
+
opaque_result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
# !SLIDE END
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module ASIR
|
2
|
+
class Transport
|
3
|
+
# !SLIDE
|
4
|
+
# Payload IO for Transport
|
5
|
+
#
|
6
|
+
# Framing
|
7
|
+
# * Line containing the number of bytes in the payload.
|
8
|
+
# * The payload bytes.
|
9
|
+
# * Blank line.
|
10
|
+
module PayloadIO
|
11
|
+
class UnexpectedResponse < Error; end
|
12
|
+
|
13
|
+
NEWLINE = "\n"
|
14
|
+
|
15
|
+
def _write payload, stream
|
16
|
+
stream.puts payload.size
|
17
|
+
stream.write payload
|
18
|
+
stream.write NEWLINE
|
19
|
+
stream.flush
|
20
|
+
stream
|
21
|
+
end
|
22
|
+
|
23
|
+
def _read stream
|
24
|
+
size = stream.readline.chomp.to_i
|
25
|
+
payload = stream.read(size)
|
26
|
+
stream.readline
|
27
|
+
payload
|
28
|
+
end
|
29
|
+
|
30
|
+
def _read_line_and_expect! stream, regexp
|
31
|
+
line = stream.readline
|
32
|
+
unless match = regexp.match(line)
|
33
|
+
_log { "_read_line_and_expect! #{stream} #{regexp.inspect} !~ #{line.inspect}" }
|
34
|
+
raise UnexpectedResponse, "expected #{regexp.inspect}, received #{line.inspect}"
|
35
|
+
end
|
36
|
+
match
|
37
|
+
end
|
38
|
+
|
39
|
+
# !SLIDE pause
|
40
|
+
def close
|
41
|
+
if @stream
|
42
|
+
_before_close! stream if respond_to?(:_before_close!)
|
43
|
+
@stream.close
|
44
|
+
end
|
45
|
+
ensure
|
46
|
+
@stream = nil unless Channel === @stream
|
47
|
+
end
|
48
|
+
|
49
|
+
# !SLIDE resume
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'asir/transport/http'
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
module ASIR
|
5
|
+
class Transport
|
6
|
+
# !SLIDE
|
7
|
+
# Rack Transport
|
8
|
+
class Rack < HTTP
|
9
|
+
# Receive the Message payload String from the Rack::Request object.
|
10
|
+
# Returns the [ Rack::Request, Rack::Response ] as the message_state.
|
11
|
+
def _receive_message rack_req_res, additional_data
|
12
|
+
body = rack_req_res.first.body.read
|
13
|
+
[ body, rack_req_res ]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Send the Result payload String in the Rack::Response object as application/binary.
|
17
|
+
def _send_result message, result, result_payload, rack_rq_rs, message_state
|
18
|
+
rack_response = rack_rq_rs[1]
|
19
|
+
rack_response[CONTENT_TYPE] = APPLICATION_BINARY
|
20
|
+
rack_response.write result_payload
|
21
|
+
end
|
22
|
+
|
23
|
+
# Constructs a Rackable App from this Transport.
|
24
|
+
def rack_app &blk
|
25
|
+
App.new(self, &blk)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Rack Transport Application.
|
29
|
+
class App
|
30
|
+
def initialize transport = nil, &blk
|
31
|
+
@app = transport
|
32
|
+
instance_eval &blk if blk
|
33
|
+
end
|
34
|
+
|
35
|
+
def call env
|
36
|
+
@app.call(env)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Rack application handler.
|
41
|
+
def call(env)
|
42
|
+
rq = ::Rack::Request.new(env)
|
43
|
+
rs = ::Rack::Response.new
|
44
|
+
rack_rq_rs = [ rq, rs ]
|
45
|
+
serve_message! rack_rq_rs, rack_rq_rs
|
46
|
+
rs.finish # => [ status, header, rbody ]
|
47
|
+
end
|
48
|
+
|
49
|
+
###############################
|
50
|
+
# Dummy server.
|
51
|
+
|
52
|
+
def prepare_server! opts = { }
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# WEBrick under Rack.
|
57
|
+
def run_server!
|
58
|
+
#require 'rack/handler'
|
59
|
+
u = URI.parse(uri); port = u.port # <= REFACTOR
|
60
|
+
::Rack::Handler::WEBrick.run \
|
61
|
+
::Rack::ShowExceptions.new(::Rack::Lint.new(self.rack_app)),
|
62
|
+
:Port => port
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def stop_server!
|
67
|
+
# NOT IMPLEMENTED
|
68
|
+
self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
# !SLIDE END
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'asir/transport/delegation'
|
2
|
+
require 'asir/retry_behavior'
|
3
|
+
|
4
|
+
module ASIR
|
5
|
+
class Transport
|
6
|
+
# !SLIDE
|
7
|
+
# Retry Transport
|
8
|
+
class Retry < self
|
9
|
+
include Delegation, RetryBehavior
|
10
|
+
|
11
|
+
# The transport to delegate to.
|
12
|
+
attr_accessor :transport
|
13
|
+
# Proc to call(transport, message) before retry.
|
14
|
+
attr_accessor :before_retry
|
15
|
+
|
16
|
+
def _send_message message, message_payload
|
17
|
+
first_exception = nil
|
18
|
+
with_retry do | action, data |
|
19
|
+
case action
|
20
|
+
when :try
|
21
|
+
transport.send_message(message)
|
22
|
+
when :rescue #, exc
|
23
|
+
first_exception ||= data
|
24
|
+
_handle_send_message_exception! transport, message, data
|
25
|
+
when :retry #, exc
|
26
|
+
before_retry.call(self, message) if before_retry
|
27
|
+
when :failed
|
28
|
+
@on_failed_message.call(self, message) if @on_failed_message
|
29
|
+
if first_exception && @reraise_first_exception
|
30
|
+
$! = first_exception
|
31
|
+
raise
|
32
|
+
end
|
33
|
+
nil # fallback to raise RetryError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
# !SLIDE END
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ASIR
|
2
|
+
class Transport
|
3
|
+
# !SLIDE
|
4
|
+
# Stream Transport
|
5
|
+
#
|
6
|
+
# Base class handles Messages on a stream.
|
7
|
+
# Stream Transports require a Coder that encodes to and from String payloads.
|
8
|
+
class Stream < self
|
9
|
+
|
10
|
+
# !SLIDE
|
11
|
+
# Serve all Messages from a stream.
|
12
|
+
def serve_stream! in_stream, out_stream
|
13
|
+
with_server_signals! do
|
14
|
+
while @running && ! in_stream.eof?
|
15
|
+
begin
|
16
|
+
serve_stream_message! in_stream, out_stream
|
17
|
+
rescue Error::Terminate => err
|
18
|
+
@running = false
|
19
|
+
_log [ :serve_stream_terminate, err ]
|
20
|
+
rescue ::Exception => err
|
21
|
+
_log [ :serve_stream_error, err ]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# !SLIDE
|
28
|
+
# Serve a Message from a stream.
|
29
|
+
def serve_stream_message! in_stream, out_stream
|
30
|
+
serve_message! in_stream, out_stream
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# !SLIDE END
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'asir/transport/local'
|
2
|
+
|
3
|
+
module ASIR
|
4
|
+
class Transport
|
5
|
+
# !SLIDE
|
6
|
+
# Subprocess Transport
|
7
|
+
#
|
8
|
+
# Send one-way Message to a forked subprocess.
|
9
|
+
class Subprocess < Local
|
10
|
+
def initialize *args
|
11
|
+
@one_way = true; super
|
12
|
+
end
|
13
|
+
|
14
|
+
def _send_message message, message_payload
|
15
|
+
Process.fork do
|
16
|
+
send_result(super, nil, nil)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# one-way; no Result
|
21
|
+
def _receive_result message, opaque_result
|
22
|
+
end
|
23
|
+
|
24
|
+
# one-way; no Result
|
25
|
+
def _send_result message, result, result_payload, stream, message_state
|
26
|
+
end
|
27
|
+
end
|
28
|
+
# !SLIDE END
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'asir/transport/connection_oriented'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module ASIR
|
5
|
+
class Transport
|
6
|
+
# !SLIDE
|
7
|
+
# TCP Socket Transport
|
8
|
+
class TcpSocket < ConnectionOriented
|
9
|
+
# !SLIDE
|
10
|
+
# TCP Socket Client
|
11
|
+
def _client_connect!
|
12
|
+
sock = TCPSocket.open(address, port)
|
13
|
+
end
|
14
|
+
|
15
|
+
# !SLIDE
|
16
|
+
# TCP Socket Server
|
17
|
+
def _server!
|
18
|
+
@server = TCPServer.open(port)
|
19
|
+
@server.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, false)
|
20
|
+
end
|
21
|
+
|
22
|
+
def _server_accept_connection! server
|
23
|
+
server.accept
|
24
|
+
end
|
25
|
+
|
26
|
+
def _server_close_connection! stream
|
27
|
+
stream.close rescue nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# !SLIDE END
|
31
|
+
end # class
|
32
|
+
end # module
|
33
|
+
|
34
|
+
|