asir 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/.gitignore +11 -0
  2. data/Gemfile +16 -0
  3. data/README.textile +50 -0
  4. data/Rakefile +83 -0
  5. data/VERSION +1 -0
  6. data/asir.gemspec +36 -0
  7. data/asir.riterate.yml +114 -0
  8. data/bin/asir +6 -0
  9. data/doc/Rakefile +8 -0
  10. data/doc/asir-sequence.pic +84 -0
  11. data/doc/asir-sequence.svg +1559 -0
  12. data/doc/sequence.pic +430 -0
  13. data/example/asir_control.sh +24 -0
  14. data/example/asir_control_client_http.rb +14 -0
  15. data/example/asir_control_client_zmq.rb +15 -0
  16. data/example/config/asir_config.rb +63 -0
  17. data/example/delayed_service.rb +15 -0
  18. data/example/ex01.rb +12 -0
  19. data/example/ex02.rb +12 -0
  20. data/example/ex03.rb +19 -0
  21. data/example/ex04.rb +33 -0
  22. data/example/ex05.rb +16 -0
  23. data/example/ex06.rb +26 -0
  24. data/example/ex07.rb +28 -0
  25. data/example/ex08.rb +30 -0
  26. data/example/ex09.rb +25 -0
  27. data/example/ex10.rb +24 -0
  28. data/example/ex11.rb +48 -0
  29. data/example/ex12.rb +34 -0
  30. data/example/ex13.rb +35 -0
  31. data/example/ex14.rb +30 -0
  32. data/example/ex15.rb +13 -0
  33. data/example/ex16.rb +33 -0
  34. data/example/ex17.rb +41 -0
  35. data/example/ex18.rb +62 -0
  36. data/example/ex19.rb +32 -0
  37. data/example/ex20.rb +28 -0
  38. data/example/ex21.rb +28 -0
  39. data/example/ex22.rb +15 -0
  40. data/example/ex23.rb +20 -0
  41. data/example/ex24.rb +35 -0
  42. data/example/example_helper.rb +51 -0
  43. data/example/sample_service.rb +162 -0
  44. data/example/unsafe_service.rb +12 -0
  45. data/hack_night/README.txt +18 -0
  46. data/hack_night/exercise/prob-1.rb +18 -0
  47. data/hack_night/exercise/prob-2.rb +21 -0
  48. data/hack_night/exercise/prob-3.rb +16 -0
  49. data/hack_night/exercise/prob-4.rb +36 -0
  50. data/hack_night/exercise/prob-5.rb +36 -0
  51. data/hack_night/exercise/prob-6.rb +95 -0
  52. data/hack_night/exercise/prob-7.rb +34 -0
  53. data/hack_night/solution/math_service.rb +11 -0
  54. data/hack_night/solution/prob-1.rb +12 -0
  55. data/hack_night/solution/prob-2.rb +15 -0
  56. data/hack_night/solution/prob-3.rb +17 -0
  57. data/hack_night/solution/prob-4.rb +37 -0
  58. data/hack_night/solution/prob-5.rb +21 -0
  59. data/hack_night/solution/prob-6.rb +33 -0
  60. data/hack_night/solution/prob-7.rb +36 -0
  61. data/lab/phony_proc.rb +31 -0
  62. data/lib/asir.rb +253 -0
  63. data/lib/asir/additional_data.rb +25 -0
  64. data/lib/asir/channel.rb +130 -0
  65. data/lib/asir/client.rb +111 -0
  66. data/lib/asir/code_block.rb +57 -0
  67. data/lib/asir/code_more.rb +50 -0
  68. data/lib/asir/coder.rb +26 -0
  69. data/lib/asir/coder/base64.rb +19 -0
  70. data/lib/asir/coder/chain.rb +30 -0
  71. data/lib/asir/coder/identity.rb +23 -0
  72. data/lib/asir/coder/json.rb +30 -0
  73. data/lib/asir/coder/marshal.rb +17 -0
  74. data/lib/asir/coder/null.rb +23 -0
  75. data/lib/asir/coder/proc.rb +22 -0
  76. data/lib/asir/coder/sign.rb +48 -0
  77. data/lib/asir/coder/xml.rb +213 -0
  78. data/lib/asir/coder/yaml.rb +33 -0
  79. data/lib/asir/coder/zlib.rb +21 -0
  80. data/lib/asir/configuration.rb +32 -0
  81. data/lib/asir/error.rb +34 -0
  82. data/lib/asir/identity.rb +36 -0
  83. data/lib/asir/initialization.rb +23 -0
  84. data/lib/asir/log.rb +82 -0
  85. data/lib/asir/main.rb +396 -0
  86. data/lib/asir/message.rb +31 -0
  87. data/lib/asir/message/delay.rb +35 -0
  88. data/lib/asir/object_resolving.rb +15 -0
  89. data/lib/asir/result.rb +39 -0
  90. data/lib/asir/retry_behavior.rb +54 -0
  91. data/lib/asir/transport.rb +241 -0
  92. data/lib/asir/transport/beanstalk.rb +217 -0
  93. data/lib/asir/transport/broadcast.rb +34 -0
  94. data/lib/asir/transport/buffer.rb +115 -0
  95. data/lib/asir/transport/composite.rb +19 -0
  96. data/lib/asir/transport/connection_oriented.rb +180 -0
  97. data/lib/asir/transport/delay.rb +38 -0
  98. data/lib/asir/transport/delegation.rb +53 -0
  99. data/lib/asir/transport/fallback.rb +36 -0
  100. data/lib/asir/transport/file.rb +88 -0
  101. data/lib/asir/transport/http.rb +54 -0
  102. data/lib/asir/transport/local.rb +21 -0
  103. data/lib/asir/transport/null.rb +14 -0
  104. data/lib/asir/transport/payload_io.rb +52 -0
  105. data/lib/asir/transport/rack.rb +73 -0
  106. data/lib/asir/transport/retry.rb +41 -0
  107. data/lib/asir/transport/stream.rb +35 -0
  108. data/lib/asir/transport/subprocess.rb +30 -0
  109. data/lib/asir/transport/tcp_socket.rb +34 -0
  110. data/lib/asir/transport/webrick.rb +50 -0
  111. data/lib/asir/transport/zmq.rb +110 -0
  112. data/lib/asir/uuid.rb +32 -0
  113. data/lib/asir/version.rb +3 -0
  114. data/spec/const_get_speed_spec.rb +33 -0
  115. data/spec/debug_helper.rb +20 -0
  116. data/spec/example_spec.rb +88 -0
  117. data/spec/json_spec.rb +128 -0
  118. data/spec/spec_helper.rb +3 -0
  119. data/spec/xml_spec.rb +144 -0
  120. data/stylesheets/slides.css +105 -0
  121. 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,14 @@
1
+ module ASIR
2
+ class Transport
3
+ # !SLIDE
4
+ # Null Transport
5
+ #
6
+ # Never send Message.
7
+ class Null < self
8
+ def _send_message message, message_payload
9
+ nil
10
+ end
11
+ end
12
+ # !SLIDE END
13
+ end
14
+ 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
+