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,111 @@
1
+ module ASIR
2
+ # !SLIDE
3
+ # Client support for any Module
4
+ #
5
+ # Extend Module with #client proxy support.
6
+ module Client
7
+ # !SLIDE
8
+ # Client Mixin
9
+ def self.included target
10
+ super
11
+ target.extend ModuleMethods if Module === target
12
+ target.send(:include, InstanceMethods) if Class === target
13
+ end
14
+
15
+ module CommonMethods
16
+ def client_options &blk
17
+ client._configure(&blk)
18
+ end
19
+ end
20
+
21
+ module ModuleMethods
22
+ include CommonMethods
23
+ # Proxies are cached for Module/Class methods because serialization will not include
24
+ # Transport.
25
+ def client
26
+ @_asir_client ||= ASIR::Client::Proxy.new(self)
27
+ end
28
+ end
29
+
30
+ module InstanceMethods
31
+ include CommonMethods
32
+ # Proxies are not cached in instances because receiver is to be serialized by
33
+ # its Transport's Coder.
34
+ def client
35
+ ASIR::Client::Proxy.new(self)
36
+ end
37
+ end
38
+
39
+ # !SLIDE
40
+ # Client Proxy
41
+ #
42
+ # Provide client interface proxy to a service.
43
+ class Proxy
44
+ attr_accessor :receiver
45
+
46
+ # Accept messages as a proxy for the receiver.
47
+ # Blocks are used represent a "continuation" for the Result.
48
+ def send selector, *arguments, &block
49
+ message = Message.new(@receiver, selector, arguments, block, self)
50
+ message = @before_send_message.call(message) if @before_send_message
51
+ @__configure.call(message) if @__configure
52
+ result = transport.send_message(message)
53
+ result
54
+ end
55
+ # Accept all other messages to be encoded and transported to a service.
56
+ alias :method_missing :send
57
+
58
+ # !SLIDE
59
+ # Client Transport
60
+ attr_accessor :transport
61
+
62
+ def transport
63
+ @transport ||= Transport::Local.new
64
+ end
65
+
66
+ # !SLIDE
67
+ # Proxy Configuration
68
+
69
+ # A Proc to call with the Message object before sending to transport#send_message(message).
70
+ # Must return a Message object.
71
+ attr_accessor :before_send_message
72
+
73
+ # If true, this Message is one-way, even if the Transport is bi-directional.
74
+ attr_accessor :_one_way
75
+
76
+ # A Proc to call with the Message object before sending to transport#send_message(message).
77
+ # See #_configure.
78
+ attr_accessor :__configure
79
+
80
+ # Returns a new Client Proxy with a block to be called with the Message.
81
+ # This block can configure additional options of the Message before
82
+ # it is sent to the Transport.
83
+ def _configure &blk
84
+ proxy = self.dup
85
+ proxy.__configure = blk
86
+ proxy
87
+ end
88
+ alias :_options :_configure
89
+
90
+ # !SLIDE
91
+ # Configuration Callbacks
92
+
93
+ def initialize rcvr
94
+ key = Module === (@receiver = rcvr) ? @receiver : @receiver.class
95
+ (@@config_callbacks[key] ||
96
+ @@config_callbacks[key.name] ||
97
+ @@config_callbacks[nil] ||
98
+ IDENTITY_LAMBDA).call(self)
99
+ end
100
+
101
+ @@config_callbacks ||= { }
102
+ def self.config_callbacks
103
+ @@config_callbacks
104
+ end
105
+
106
+ # !SLIDE END
107
+ end
108
+ # !SLIDE END
109
+ end
110
+ # !SLIDE END
111
+ end
@@ -0,0 +1,57 @@
1
+ module ASIR
2
+ # !SLIDE
3
+ # Code Block
4
+ #
5
+ # Encode/decode Message#block.
6
+ module CodeBlock
7
+ # Most coders cannot serialize Procs.
8
+ # But we can attempt to serialize a String representing a Proc.
9
+ def encode_block!
10
+ obj = nil
11
+ if @block && ! ::String === @block_code
12
+ obj ||= self.dup
13
+ obj.block_code = CodeBlock.block_to_code(obj.block)
14
+ obj.block = nil
15
+ end
16
+ obj
17
+ end
18
+
19
+ def decode_block!
20
+ if ::String === @block_code
21
+ @block ||= CodeBlock.code_to_block(@block_code)
22
+ @block_code = nil
23
+ end
24
+ self
25
+ end
26
+
27
+ # Returns a block_cache Hash.
28
+ # Flushed every 1000 accesses.
29
+ def self.block_cache
30
+ cache = Thread.current[:'ASIR::CodeBlock.block_cache'] ||= { }
31
+ count = Thread.current[:'ASIR::CodeBlock.block_cache_count'] ||= 0
32
+ count += 1
33
+ if count >= 1000
34
+ cache.clear
35
+ count = 0
36
+ end
37
+ Thread.current[:'ASIR::CodeBlock.block_cache_count'] = count
38
+ cache
39
+ end
40
+
41
+ # Uses ruby2ruby, if loaded.
42
+ def self.block_to_code block
43
+ (block_cache[block.object_id] ||=
44
+ [ block.respond_to?(:to_ruby) && block.to_ruby, block ]).
45
+ first
46
+ end
47
+
48
+ # Calls eval.
49
+ # May be unsafe.
50
+ def self.code_to_block code
51
+ (block_cache[code.dup.freeze] ||=
52
+ [ eval(@block_code), code ]).
53
+ first
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,50 @@
1
+ module ASIR
2
+ # !SLIDE
3
+ # Code More
4
+ #
5
+ # Help encode/decode and resolve receiver class.
6
+ module CodeMore
7
+ include ObjectResolving # resolve_object()
8
+ include CodeBlock # encode_block!, decode_block!
9
+
10
+ def encode_more!
11
+ obj = encode_block! # may self.dup
12
+ unless ::String === @receiver_class
13
+ obj ||= self.dup # dont dup twice.
14
+ obj.receiver = @receiver.name if ::Module === @receiver
15
+ obj.receiver_class = @receiver_class.name
16
+ if resp = obj.result and resp.message == self
17
+ resp.message = obj
18
+ end
19
+ end
20
+ obj || self
21
+ end
22
+
23
+ def decode_more!
24
+ decode_block!
25
+ if ::String === @receiver_class
26
+ @receiver_class = resolve_object(@receiver_class)
27
+ @receiver = resolve_object(@receiver) if ::Module === @receiver_class
28
+ unless @receiver_class === @receiver
29
+ raise Error, "receiver #{@receiver.class.name} is not a #{@receiver_class}"
30
+ end
31
+ end
32
+ self
33
+ end
34
+
35
+ # Mixin for Result.
36
+ module Result
37
+ def encode_more!
38
+ @message = @message.encode_more! if @message
39
+ self
40
+ end
41
+
42
+ def decode_more!
43
+ @message = @message.decode_more! if @message
44
+ self
45
+ end
46
+ end
47
+ end
48
+ # !SLIDE END
49
+ end
50
+
@@ -0,0 +1,26 @@
1
+ module ASIR
2
+ # !SLIDE
3
+ # Coder
4
+ #
5
+ # Define encoding and decoding for Messages and Results along a Transport.
6
+ class Coder
7
+ include Log, Initialization
8
+
9
+ def encode obj
10
+ _encode obj
11
+ end
12
+
13
+ def decode obj
14
+ obj and _decode obj
15
+ end
16
+
17
+ # Coder subclasses:
18
+ def _subclass_responsibility *args
19
+ raise "subclass responsibility"
20
+ end
21
+ alias :_encode :_subclass_responsibility
22
+ alias :_decode :_subclass_responsibility
23
+ end
24
+ # !SLIDE END
25
+ end
26
+
@@ -0,0 +1,19 @@
1
+ require 'asir'
2
+
3
+ require 'base64'
4
+
5
+ module ASIR
6
+ class Coder
7
+ class Base64 < self
8
+ def _encode obj
9
+ raise TypeError unless String === obj
10
+ ::Base64.encode64(obj)
11
+ end
12
+ def _decode obj
13
+ raise TypeError unless String === obj
14
+ ::Base64.decode64(obj)
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,30 @@
1
+ module ASIR
2
+ class Coder
3
+ # !SLIDE
4
+ # Chain Coder
5
+ # Chain multiple Coders as one.
6
+ #
7
+ # @@@ text
8
+ # message --> | e1 | --> | e2 | --> | eN | -->
9
+ # result <-- | d1 | <-- | d2 | <-- | dN | <--
10
+ # @@@
11
+ class Chain < self
12
+ attr_accessor :encoders
13
+
14
+ def _encode obj
15
+ encoders.each do | e |
16
+ obj = e.dup.encode(obj)
17
+ end
18
+ obj
19
+ end
20
+
21
+ def _decode obj
22
+ encoders.reverse_each do | e |
23
+ obj = e.dup.decode(obj)
24
+ end
25
+ obj
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,23 @@
1
+ require 'asir/coder'
2
+
3
+ module ASIR
4
+ class Coder
5
+ # !SLIDE
6
+ # Identity Coder
7
+ # Perform no encode/decode.
8
+ class Identity < self
9
+ def _encode obj
10
+ obj
11
+ end
12
+
13
+ def _decode obj
14
+ obj
15
+ end
16
+
17
+ # Completely stateless.
18
+ def dup; self; end
19
+ end
20
+ # !SLIDE END
21
+ end
22
+ end
23
+
@@ -0,0 +1,30 @@
1
+ require 'asir'
2
+
3
+ module ASIR
4
+ class Coder
5
+ # !SLIDE
6
+ # JSON Coder
7
+ #
8
+ # Note: Symbols are not handled.
9
+ # The actual JSON expression is wrapped with an Array.
10
+ class JSON < self
11
+ def _encode obj
12
+ [ obj ].to_json
13
+ end
14
+
15
+ def _decode obj
16
+ parser = ::JSON.parser.new(obj)
17
+ ary = parser.parse
18
+ ary.first
19
+ end
20
+ end
21
+ # !SLIDE END
22
+ end
23
+ end
24
+
25
+ if RUBY_PLATFORM =~ /java/
26
+ require 'json'
27
+ else
28
+ require 'json/ext'
29
+ end
30
+
@@ -0,0 +1,17 @@
1
+ module ASIR
2
+ class Coder
3
+ # !SLIDE
4
+ # Marshal Coder
5
+ # Use Ruby Marshal for encode/decode.
6
+ class Marshal < self
7
+ def _encode obj
8
+ ::Marshal.dump(obj)
9
+ end
10
+
11
+ def _decode obj
12
+ ::Marshal.load(obj)
13
+ end
14
+ end # class
15
+ # !SLIDE END
16
+ end # class
17
+ end # module
@@ -0,0 +1,23 @@
1
+ require 'asir/coder'
2
+
3
+ module ASIR
4
+ class Coder
5
+ # !SLIDE
6
+ # Null Coder
7
+ # Always encode/decode as nil.
8
+ class Null < self
9
+ def _encode obj
10
+ nil
11
+ end
12
+
13
+ def _decode obj
14
+ nil
15
+ end
16
+
17
+ # Completely stateless.
18
+ def dup; self; end
19
+ end
20
+ # !SLIDE END
21
+ end
22
+ end
23
+
@@ -0,0 +1,22 @@
1
+ require 'asir'
2
+
3
+ module ASIR
4
+ class Coder
5
+ # !SLIDE
6
+ # Proc Coder
7
+ # Generic Proc-based coder.
8
+ class Proc < self
9
+ # Procs that take one argument.
10
+ attr_accessor :encoder, :decoder
11
+
12
+ def _encode obj
13
+ @encoder.call(obj)
14
+ end
15
+ def _decode obj
16
+ @decoder.call(obj)
17
+ end
18
+ end
19
+ # !SLIDE END
20
+ end
21
+ end
22
+
@@ -0,0 +1,48 @@
1
+ require 'digest/sha1'
2
+
3
+ module ASIR
4
+ class Coder
5
+ # !SLIDE
6
+ # Sign Coder
7
+ #
8
+ # Sign payload during encode, check signature during decode.
9
+ #
10
+ # Signature is the digest of secret + payload.
11
+ #
12
+ # Encode payload as Hash containing the digest function name, signature and payload.
13
+ # Decode and validate Hash containing the digest function name, signature and payload.
14
+ #
15
+ class Sign < self
16
+ attr_accessor :secret, :function
17
+
18
+ def _encode obj
19
+ payload = obj.to_s
20
+ { :function => function,
21
+ :signature => ::Digest.const_get(function).
22
+ new.hexdigest(secret + payload),
23
+ :payload => payload }
24
+ end
25
+
26
+ def _decode obj
27
+ raise SignatureError, "expected Hash, given #{obj.class}" unless Hash === obj
28
+ payload = obj[:payload]
29
+ raise SignatureError, "signature invalid" unless obj == _encode(payload)
30
+ payload
31
+ end
32
+
33
+ # !SLIDE
34
+ # Sign Coder Support
35
+
36
+ # Signature Error.
37
+ class SignatureError < Error; end
38
+
39
+ def initialize_before_opts
40
+ @function = :SHA1
41
+ end
42
+ # !SLIDE END
43
+ end
44
+ # !SLIDE END
45
+ end # class
46
+ end # class
47
+
48
+