sumac 0.0.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.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/README.md +2 -0
- data/lib/core_extensions.rb +207 -0
- data/lib/sumac.rb +94 -0
- data/lib/sumac/adapter.rb +5 -0
- data/lib/sumac/adapter/closed.rb +7 -0
- data/lib/sumac/argument_error.rb +5 -0
- data/lib/sumac/call_dispatcher.rb +70 -0
- data/lib/sumac/call_processor.rb +93 -0
- data/lib/sumac/closed_error.rb +5 -0
- data/lib/sumac/closer.rb +53 -0
- data/lib/sumac/connection.rb +94 -0
- data/lib/sumac/exposed_object.rb +131 -0
- data/lib/sumac/exposed_object_child.rb +158 -0
- data/lib/sumac/forgoten.rb +5 -0
- data/lib/sumac/handshake.rb +48 -0
- data/lib/sumac/id_allocator.rb +99 -0
- data/lib/sumac/local_reference.rb +16 -0
- data/lib/sumac/local_references.rb +80 -0
- data/lib/sumac/message.rb +19 -0
- data/lib/sumac/message/exchange.rb +30 -0
- data/lib/sumac/message/exchange/base.rb +15 -0
- data/lib/sumac/message/exchange/call_request.rb +96 -0
- data/lib/sumac/message/exchange/call_response.rb +83 -0
- data/lib/sumac/message/exchange/compatibility_notification.rb +53 -0
- data/lib/sumac/message/exchange/forget_notification.rb +77 -0
- data/lib/sumac/message/exchange/id.rb +30 -0
- data/lib/sumac/message/exchange/initialization_notification.rb +52 -0
- data/lib/sumac/message/exchange/notification.rb +9 -0
- data/lib/sumac/message/exchange/shutdown_notification.rb +27 -0
- data/lib/sumac/message/object.rb +72 -0
- data/lib/sumac/message/object/array.rb +57 -0
- data/lib/sumac/message/object/base.rb +21 -0
- data/lib/sumac/message/object/boolean.rb +45 -0
- data/lib/sumac/message/object/exception.rb +66 -0
- data/lib/sumac/message/object/exposed.rb +79 -0
- data/lib/sumac/message/object/exposed_child.rb +86 -0
- data/lib/sumac/message/object/float.rb +45 -0
- data/lib/sumac/message/object/hash_table.rb +75 -0
- data/lib/sumac/message/object/integer.rb +45 -0
- data/lib/sumac/message/object/native_exception.rb +56 -0
- data/lib/sumac/message/object/null.rb +44 -0
- data/lib/sumac/message/object/string.rb +45 -0
- data/lib/sumac/message_error.rb +5 -0
- data/lib/sumac/messenger.rb +65 -0
- data/lib/sumac/native_error.rb +17 -0
- data/lib/sumac/no_method_error.rb +9 -0
- data/lib/sumac/reference.rb +68 -0
- data/lib/sumac/remote_entry.rb +42 -0
- data/lib/sumac/remote_object.rb +39 -0
- data/lib/sumac/remote_object_child.rb +38 -0
- data/lib/sumac/remote_reference.rb +16 -0
- data/lib/sumac/remote_references.rb +70 -0
- data/lib/sumac/scheduler.rb +56 -0
- data/lib/sumac/shutdown.rb +32 -0
- data/lib/sumac/stale_object_error.rb +5 -0
- data/lib/sumac/unexposable_object_error.rb +9 -0
- data/lib/sumac/worker_pool.rb +35 -0
- data/test/test_id_allocator.rb +25 -0
- metadata +145 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
class Sumac
|
|
2
|
+
class Message
|
|
3
|
+
class Object
|
|
4
|
+
class HashTable < Base
|
|
5
|
+
|
|
6
|
+
def initialize(connection)
|
|
7
|
+
super
|
|
8
|
+
@entries = nil
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def parse_json_structure(json_structure)
|
|
12
|
+
raise MessageError unless json_structure.is_a?(::Hash) &&
|
|
13
|
+
json_structure['message_type'] == 'object' &&
|
|
14
|
+
json_structure['object_type'] == 'hash_table'
|
|
15
|
+
raise MessageError unless json_structure['entries'].is_a?(::Array)
|
|
16
|
+
@entries = json_structure['entries'].map do |entry|
|
|
17
|
+
raise MessageError unless entry.is_a?(::Hash) && entry.include?('key') && entry.include?('value')
|
|
18
|
+
{
|
|
19
|
+
'key' => Object.from_json_structure(@connection, entry['key']),
|
|
20
|
+
'value' => Object.from_json_structure(@connection, entry['value'])
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def parse_native_object(native_object)
|
|
27
|
+
raise MessageError unless native_object.is_a?(::Hash)
|
|
28
|
+
@entries = native_object.map do |key, value|
|
|
29
|
+
{
|
|
30
|
+
'key' => Object.from_native_object(@connection, key),
|
|
31
|
+
'value' => Object.from_native_object(@connection, value)
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_json_structure
|
|
38
|
+
raise MessageError unless setup?
|
|
39
|
+
json_entries = @entries.map do |entry|
|
|
40
|
+
{
|
|
41
|
+
'key' => entry['key'].to_json_structure,
|
|
42
|
+
'value' => entry['value'].to_json_structure
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
{
|
|
46
|
+
'message_type' => 'object',
|
|
47
|
+
'object_type' => 'hash_table',
|
|
48
|
+
'entries' => json_entries
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_native_object
|
|
53
|
+
raise MessageError unless setup?
|
|
54
|
+
@entries.map { |entry| [entry['key'].to_native_object, entry['value'].to_native_object] }.to_h
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def invert_orgin
|
|
58
|
+
raise MessageError unless setup?
|
|
59
|
+
@entries.each do |entry|
|
|
60
|
+
entry['key'].invert_orgin if entry['key'].respond_to?(:invert_orgin)
|
|
61
|
+
entry['value'].invert_orgin if entry['value'].respond_to?(:invert_orgin)
|
|
62
|
+
end
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def setup?
|
|
69
|
+
@entries != nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class Sumac
|
|
2
|
+
class Message
|
|
3
|
+
class Object
|
|
4
|
+
class Integer < Base
|
|
5
|
+
|
|
6
|
+
def initialize(connection)
|
|
7
|
+
super
|
|
8
|
+
@value = nil
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def parse_json_structure(json_structure)
|
|
12
|
+
raise MessageError unless json_structure.is_a?(::Hash) &&
|
|
13
|
+
json_structure['message_type'] == 'object' &&
|
|
14
|
+
json_structure['object_type'] == 'integer'
|
|
15
|
+
raise MessageError unless json_structure['value'].is_a?(::Numeric)
|
|
16
|
+
@value = json_structure['value'].to_i
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def parse_native_object(native_object)
|
|
21
|
+
raise MessageError unless native_object.is_a?(::Integer)
|
|
22
|
+
@value = native_object
|
|
23
|
+
nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_json_structure
|
|
27
|
+
raise MessageError unless setup?
|
|
28
|
+
{'message_type' => 'object', 'object_type' => 'integer', 'value' => @value}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_native_object
|
|
32
|
+
raise MessageError unless setup?
|
|
33
|
+
@value
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def setup?
|
|
39
|
+
@value != nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
class Sumac
|
|
2
|
+
class Message
|
|
3
|
+
class Object
|
|
4
|
+
class NativeException < Base
|
|
5
|
+
|
|
6
|
+
def initialize(connection)
|
|
7
|
+
super
|
|
8
|
+
@type = nil
|
|
9
|
+
@message = nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parse_json_structure(json_structure)
|
|
13
|
+
raise MessageError unless json_structure.is_a?(::Hash) &&
|
|
14
|
+
json_structure['message_type'] == 'object' &&
|
|
15
|
+
json_structure['object_type'] == 'native_exception'
|
|
16
|
+
raise MessageError unless json_structure['type'].is_a?(::String)
|
|
17
|
+
@type = json_structure['type']
|
|
18
|
+
if json_structure['message']
|
|
19
|
+
raise MessageError unless json_structure['message'].is_a?(::String)
|
|
20
|
+
@message = json_structure['message']
|
|
21
|
+
end
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def parse_native_object(native_object)
|
|
26
|
+
raise MessageError unless native_object.kind_of?(::Exception)
|
|
27
|
+
@type = native_object.class.to_s
|
|
28
|
+
@message = native_object.message
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def to_json_structure
|
|
33
|
+
raise MessageError unless setup?
|
|
34
|
+
{
|
|
35
|
+
'message_type' => 'object',
|
|
36
|
+
'object_type' => 'native_exception',
|
|
37
|
+
'type' => @type,
|
|
38
|
+
'message' => @message
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_native_object
|
|
43
|
+
raise MessageError unless setup?
|
|
44
|
+
NativeError.new(@type, @message)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def setup?
|
|
50
|
+
@type != nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class Sumac
|
|
2
|
+
class Message
|
|
3
|
+
class Object
|
|
4
|
+
class Null < Base
|
|
5
|
+
|
|
6
|
+
def initialize(connection)
|
|
7
|
+
super
|
|
8
|
+
@setup = false
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def parse_json_structure(json_structure)
|
|
12
|
+
raise MessageError unless json_structure.is_a?(::Hash) &&
|
|
13
|
+
json_structure['message_type'] == 'object' &&
|
|
14
|
+
json_structure['object_type'] == 'null'
|
|
15
|
+
@setup = true
|
|
16
|
+
nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def parse_native_object(native_object)
|
|
20
|
+
raise MessageError unless native_object == nil
|
|
21
|
+
@setup = true
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_json_structure
|
|
26
|
+
raise MessageError unless setup?
|
|
27
|
+
{'message_type' => 'object', 'object_type' => 'null'}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_native_object
|
|
31
|
+
raise MessageError unless setup?
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def setup?
|
|
38
|
+
@setup
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class Sumac
|
|
2
|
+
class Message
|
|
3
|
+
class Object
|
|
4
|
+
class String < Base
|
|
5
|
+
|
|
6
|
+
def initialize(connection)
|
|
7
|
+
super
|
|
8
|
+
@value = nil
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def parse_json_structure(json_structure)
|
|
12
|
+
raise MessageError unless json_structure.is_a?(::Hash) &&
|
|
13
|
+
json_structure['message_type'] == 'object' &&
|
|
14
|
+
json_structure['object_type'] == 'string'
|
|
15
|
+
raise MessageError unless json_structure['value'].is_a?(::String)
|
|
16
|
+
@value = json_structure['value']
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def parse_native_object(native_object)
|
|
21
|
+
raise MessageError unless native_object.is_a?(::String)
|
|
22
|
+
@value = native_object
|
|
23
|
+
nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_json_structure
|
|
27
|
+
raise MessageError unless setup?
|
|
28
|
+
{'message_type' => 'object', 'object_type' => 'string', 'value' => @value}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_native_object
|
|
32
|
+
raise MessageError unless setup?
|
|
33
|
+
@value
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def setup?
|
|
39
|
+
@value != nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
class Sumac
|
|
2
|
+
class Messenger
|
|
3
|
+
|
|
4
|
+
def initialize(connection)
|
|
5
|
+
raise "argument 'connection' must be a Connection" unless connection.is_a?(Connection)
|
|
6
|
+
@connection = connection
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def send(message)
|
|
10
|
+
raise unless message.is_a?(Message::Exchange)
|
|
11
|
+
raise if @connection.at?([:kill, :close])
|
|
12
|
+
message.invert_orgin
|
|
13
|
+
message_string = message.to_json
|
|
14
|
+
begin
|
|
15
|
+
@connection.messenger_adapter.send(message_string)
|
|
16
|
+
rescue Adapter::ClosedError
|
|
17
|
+
unless @connection.at?(:close)
|
|
18
|
+
@connection.to(:kill)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def receive(message_string)
|
|
25
|
+
begin
|
|
26
|
+
process(message_string)
|
|
27
|
+
rescue MessageError
|
|
28
|
+
@connection.sumac.trigger(:protocol_error)
|
|
29
|
+
unless @connection.at?(:close)
|
|
30
|
+
@connection.to(:kill)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def close
|
|
36
|
+
begin
|
|
37
|
+
@connection.messenger_adapter.close
|
|
38
|
+
rescue Adapter::ClosedError
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def process(message_string)
|
|
45
|
+
exchange = Message::Exchange.from_json(@connection, message_string)
|
|
46
|
+
case exchange
|
|
47
|
+
when Message::Exchange::CompatibilityNotification, Message::Exchange::InitializationNotification
|
|
48
|
+
@connection.handshake.receive(exchange)
|
|
49
|
+
when Message::Exchange::CallRequest
|
|
50
|
+
@connection.call_processor.receive(exchange)
|
|
51
|
+
when Message::Exchange::CallResponse
|
|
52
|
+
@connection.call_dispatcher.receive(exchange)
|
|
53
|
+
when Message::Exchange::ShutdownNotification
|
|
54
|
+
@connection.shutdown.receive(exchange)
|
|
55
|
+
when Message::Exchange::ForgetNotification
|
|
56
|
+
reference = exchange.reference
|
|
57
|
+
reference.remote_forget_request
|
|
58
|
+
else
|
|
59
|
+
raise MessageError
|
|
60
|
+
end
|
|
61
|
+
nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class Sumac
|
|
2
|
+
class NativeError < StandardError
|
|
3
|
+
|
|
4
|
+
attr_reader :native_type, :native_message
|
|
5
|
+
|
|
6
|
+
def initialize(native_type, native_message)
|
|
7
|
+
super()
|
|
8
|
+
@native_type = native_type
|
|
9
|
+
@native_message = native_message
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def message
|
|
13
|
+
"#{@native_type} -> #{@native_message}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
class Sumac
|
|
2
|
+
class Reference
|
|
3
|
+
include QueuedStateMachine
|
|
4
|
+
|
|
5
|
+
state :active, initial: true
|
|
6
|
+
state :forget_requested
|
|
7
|
+
state :detached
|
|
8
|
+
state :stale
|
|
9
|
+
|
|
10
|
+
transition from: :active, to: [:forget_requested, :detached, :stale]
|
|
11
|
+
transition from: :forget_requested, to: [:detached, :stale]
|
|
12
|
+
transition from: :detached, to: :stale
|
|
13
|
+
|
|
14
|
+
on_transition(from: :active, to: [:forget_requested, :stale]) do
|
|
15
|
+
send_forget_notification
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
on_transition(to: :stale) do
|
|
19
|
+
remove
|
|
20
|
+
@forget_condition_variable.broadcast
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_reader :exposed_id
|
|
24
|
+
|
|
25
|
+
def initialize(connection, exposed_id)
|
|
26
|
+
super()
|
|
27
|
+
raise "argument 'connection' must be a Connection" unless connection.is_a?(Connection)
|
|
28
|
+
@connection = connection
|
|
29
|
+
raise unless exposed_id.is_a?(Integer)
|
|
30
|
+
@exposed_id = exposed_id
|
|
31
|
+
@forget_condition_variable = ConditionVariable.new
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def local_forget_request
|
|
35
|
+
to(:forget_requested) if at?(:active)
|
|
36
|
+
@forget_condition_variable.wait(@connection.mutex) if at?([:forget_requested, :detached])
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def remote_forget_request
|
|
40
|
+
raise if at?([:detached, :stale])
|
|
41
|
+
to(:stale)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def send_forget_notification
|
|
45
|
+
message = Message::Exchange::ForgetNotification.new(@connection)
|
|
46
|
+
message.reference = self
|
|
47
|
+
@connection.messenger.send(message)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def detach
|
|
51
|
+
to(:detached)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def callable?
|
|
55
|
+
at?(:active)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def destroy
|
|
59
|
+
raise unless at?(:detached)
|
|
60
|
+
to(:stale)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def stale?
|
|
64
|
+
at?(:stale)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
class Sumac
|
|
2
|
+
class RemoteEntry
|
|
3
|
+
|
|
4
|
+
def initialize
|
|
5
|
+
@mutex = Mutex.new
|
|
6
|
+
@condition_variable = ConditionVariable.new
|
|
7
|
+
@value = nil
|
|
8
|
+
@value_set = false
|
|
9
|
+
@complete = false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def cancel
|
|
13
|
+
@mutex.synchronize do
|
|
14
|
+
@complete = true
|
|
15
|
+
@value_set = false
|
|
16
|
+
@value = false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def get
|
|
21
|
+
@mutex.synchronize do
|
|
22
|
+
@condition_variable.wait(@mutex) unless complete?
|
|
23
|
+
raise ClosedError unless @value_set
|
|
24
|
+
@value
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def set(new_value = nil)
|
|
29
|
+
@mutex.synchronize do
|
|
30
|
+
@value_set = true
|
|
31
|
+
@complete = true
|
|
32
|
+
@value = new_value
|
|
33
|
+
@condition_variable.broadcast
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def complete?
|
|
38
|
+
@complete
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
end
|