asir 0.2.0

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.
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
+