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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +2 -0
  4. data/lib/core_extensions.rb +207 -0
  5. data/lib/sumac.rb +94 -0
  6. data/lib/sumac/adapter.rb +5 -0
  7. data/lib/sumac/adapter/closed.rb +7 -0
  8. data/lib/sumac/argument_error.rb +5 -0
  9. data/lib/sumac/call_dispatcher.rb +70 -0
  10. data/lib/sumac/call_processor.rb +93 -0
  11. data/lib/sumac/closed_error.rb +5 -0
  12. data/lib/sumac/closer.rb +53 -0
  13. data/lib/sumac/connection.rb +94 -0
  14. data/lib/sumac/exposed_object.rb +131 -0
  15. data/lib/sumac/exposed_object_child.rb +158 -0
  16. data/lib/sumac/forgoten.rb +5 -0
  17. data/lib/sumac/handshake.rb +48 -0
  18. data/lib/sumac/id_allocator.rb +99 -0
  19. data/lib/sumac/local_reference.rb +16 -0
  20. data/lib/sumac/local_references.rb +80 -0
  21. data/lib/sumac/message.rb +19 -0
  22. data/lib/sumac/message/exchange.rb +30 -0
  23. data/lib/sumac/message/exchange/base.rb +15 -0
  24. data/lib/sumac/message/exchange/call_request.rb +96 -0
  25. data/lib/sumac/message/exchange/call_response.rb +83 -0
  26. data/lib/sumac/message/exchange/compatibility_notification.rb +53 -0
  27. data/lib/sumac/message/exchange/forget_notification.rb +77 -0
  28. data/lib/sumac/message/exchange/id.rb +30 -0
  29. data/lib/sumac/message/exchange/initialization_notification.rb +52 -0
  30. data/lib/sumac/message/exchange/notification.rb +9 -0
  31. data/lib/sumac/message/exchange/shutdown_notification.rb +27 -0
  32. data/lib/sumac/message/object.rb +72 -0
  33. data/lib/sumac/message/object/array.rb +57 -0
  34. data/lib/sumac/message/object/base.rb +21 -0
  35. data/lib/sumac/message/object/boolean.rb +45 -0
  36. data/lib/sumac/message/object/exception.rb +66 -0
  37. data/lib/sumac/message/object/exposed.rb +79 -0
  38. data/lib/sumac/message/object/exposed_child.rb +86 -0
  39. data/lib/sumac/message/object/float.rb +45 -0
  40. data/lib/sumac/message/object/hash_table.rb +75 -0
  41. data/lib/sumac/message/object/integer.rb +45 -0
  42. data/lib/sumac/message/object/native_exception.rb +56 -0
  43. data/lib/sumac/message/object/null.rb +44 -0
  44. data/lib/sumac/message/object/string.rb +45 -0
  45. data/lib/sumac/message_error.rb +5 -0
  46. data/lib/sumac/messenger.rb +65 -0
  47. data/lib/sumac/native_error.rb +17 -0
  48. data/lib/sumac/no_method_error.rb +9 -0
  49. data/lib/sumac/reference.rb +68 -0
  50. data/lib/sumac/remote_entry.rb +42 -0
  51. data/lib/sumac/remote_object.rb +39 -0
  52. data/lib/sumac/remote_object_child.rb +38 -0
  53. data/lib/sumac/remote_reference.rb +16 -0
  54. data/lib/sumac/remote_references.rb +70 -0
  55. data/lib/sumac/scheduler.rb +56 -0
  56. data/lib/sumac/shutdown.rb +32 -0
  57. data/lib/sumac/stale_object_error.rb +5 -0
  58. data/lib/sumac/unexposable_object_error.rb +9 -0
  59. data/lib/sumac/worker_pool.rb +35 -0
  60. data/test/test_id_allocator.rb +25 -0
  61. 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,5 @@
1
+ class Sumac
2
+ class MessageError < StandardError
3
+
4
+ end
5
+ 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,9 @@
1
+ class Sumac
2
+ class NoMethodError < StandardError
3
+
4
+ def message
5
+ "method is undefined or has not been exposed"
6
+ end
7
+
8
+ end
9
+ 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