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.
- 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
data/lib/asir/client.rb
ADDED
|
@@ -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
|
+
|
data/lib/asir/coder.rb
ADDED
|
@@ -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
|
+
|