diff --git a/client/Ruby/README.md b/client/Ruby/README.md new file mode 100644 index 0000000..272a4dc --- /dev/null +++ b/client/Ruby/README.md @@ -0,0 +1,38 @@ +# juno-ruby-client +Ruby client for JunoDB
+ +[Documentation](https://github.com/VaibhavA19/junodb/tree/dev/client/Ruby/docs)
+[SampleScript](https://github.com/VaibhavA19/junodb/blob/dev/client/Ruby/sample.rb)
+[ConfigFile](https://github.com/VaibhavA19/junodb/blob/dev/client/Ruby/juno.yml) + +### Work Directory: [juno] +# Gem Tasks +### Build gem +``` +cd juno +rake build +``` + +### Install gem +``` +cd juno +rake install +``` + +### Execute tests +``` +cd juno +rake spec +``` + +### Execute rubocop linitng +``` +cd juno +rake lint +``` + +### Update documentation +``` +cd juno +rake yard:document +``` diff --git a/client/Ruby/docs/Juno.html b/client/Ruby/docs/Juno.html new file mode 100644 index 0000000..76931cd --- /dev/null +++ b/client/Ruby/docs/Juno.html @@ -0,0 +1,301 @@ + + + + + + + Module: Juno + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: Juno + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/constants.rb,
+ lib/juno/logger.rb,
lib/juno/version.rb,
lib/juno/Utils/utils.rb,
lib/juno/Config/config.rb,
lib/juno/server_status.rb,
lib/juno/IO/JunoMessage.rb,
lib/juno/Net/worker_pool.rb,
lib/juno/Net/io_processor.rb,
lib/juno/Net/ping_message.rb,
lib/juno/Config/properties.rb,
lib/juno/IO/ProtocolHeader.rb,
lib/juno/Net/request_queue.rb,
lib/juno/Client/cache_store.rb,
lib/juno/Client/sync_client.rb,
lib/juno/Net/base_processor.rb,
lib/juno/Net/client_handler.rb,
lib/juno/Utils/client_utils.rb,
lib/juno/Client/juno_request.rb,
lib/juno/Client/react_client.rb,
lib/juno/IO/OperationMessage.rb,
lib/juno/IO/PayloadComponent.rb,
lib/juno/Client/juno_response.rb,
lib/juno/Config/config_reader.rb,
lib/juno/IO/MetadataComponent.rb,
lib/juno/Client/operation_type.rb,
lib/juno/Client/record_context.rb,
lib/juno/Config/config_provider.rb,
lib/juno/Client/operation_status.rb,
lib/juno/Config/default_properties.rb,
lib/juno/IO/MetadataComponentTemplate.rb
+
+
+ +
+ +

Overview

+
+ +

Top module for juno client

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + Modules: Client, ClientUtils, IO, Net + + + + Classes: Config, ConfigProvider, ConfigReader, DefaultProperties, Logger, Properties, ServerStatus, Utils + + +

+ + +

+ Constant Summary + collapse +

+ +
+ +
VERSION = + +
+
'0.1.0'
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .configureObject + + + + + +

+ + + + +
+
+
+
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+
+
# File 'lib/juno/Config/config.rb', line 105
+
+def self.configure
+  if @juno_config.nil?
+    config_reader = Juno::ConfigReader.new
+    yield config_reader
+    if !config_reader.file_path.nil?
+      @juno_config = Config.new(ConfigProvider.new(config_reader.file_path, config_reader.source_format, nil),
+                                log_file: config_reader.log_file, ssl_cert_file: config_reader.ssl_cert_file,
+                                ssl_key_file: config_reader.ssl_key_file)
+      @LOGGER = Juno::Logger.instance
+    elsif !config_reader.url.nil? # URL should URI Object
+      # @juno_config = Config.new(ConfigProvider.new(@juno_config.file_path, @juno_config.source_format, nil))
+    else
+      raise 'No file or url provided'
+    end
+  else
+    Juno::Logger.instance.warn('Juno client cannot be reconfigured')
+  end
+end
+
+
+ +
+

+ + .juno_configObject + + + + + +

+ + + + +
+
+
+
+124
+125
+126
+127
+128
+
+
# File 'lib/juno/Config/config.rb', line 124
+
+def self.juno_config
+  raise 'Please configure the properties using Juno.configure' if @juno_config.nil?
+
+  @juno_config
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client.html b/client/Ruby/docs/Juno/Client.html new file mode 100644 index 0000000..5f98928 --- /dev/null +++ b/client/Ruby/docs/Juno/Client.html @@ -0,0 +1,128 @@ + + + + + + + Module: Juno::Client + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: Juno::Client + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/cache_store.rb,
+ lib/juno/Client/sync_client.rb,
lib/juno/Client/juno_request.rb,
lib/juno/Client/react_client.rb,
lib/juno/Client/juno_response.rb,
lib/juno/Client/operation_type.rb,
lib/juno/Client/record_context.rb,
lib/juno/Client/operation_status.rb
+
+
+ +
+ +

Overview

+
+ +

Module for code exposed to the developer

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: CacheStore, JunoRequest, JunoResponse, OperationStatus, OperationType, ReactClient, RecordContext, SyncClient + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client/CacheStore.html b/client/Ruby/docs/Juno/Client/CacheStore.html new file mode 100644 index 0000000..c1e16bf --- /dev/null +++ b/client/Ruby/docs/Juno/Client/CacheStore.html @@ -0,0 +1,557 @@ + + + + + + + Class: Juno::Client::CacheStore + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Client::CacheStore + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/cache_store.rb
+
+ +
+ +

Overview

+
+ +

Cache store for ruby on rails

+ + +
+
+
+ + +
+ + + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initializeCacheStore + + + + + +

+
+ +

Returns a new instance of CacheStore.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Client/cache_store.rb', line 9
+
+def initialize
+  @react_client = Juno::Client::ReactClient.new
+end
+
+
+ +
+ + +
+

Class Method Details

+ + +
+

+ + .supports_cache_versioning?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+27
+28
+29
+
+
# File 'lib/juno/Client/cache_store.rb', line 27
+
+def self.supports_cache_versioning?
+  true
+end
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #delete(key) ⇒ Object + + + + + +

+ + + + +
+
+
+
+31
+32
+33
+34
+35
+36
+
+
# File 'lib/juno/Client/cache_store.rb', line 31
+
+def delete(key)
+  future_obj = @react_client.destroy(key).wait
+  return false if future_obj.nil? || future_obj.rejected?
+
+  future_obj.value.status[:code] == Juno::Client::OperationStatus::SUCCESS[:code]
+end
+
+
+ +
+

+ + #exist?(key) ⇒ Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+38
+39
+40
+
+
# File 'lib/juno/Client/cache_store.rb', line 38
+
+def exist?(key)
+  !read(key).nil?
+end
+
+
+ +
+

+ + #read(key, options = {}) ⇒ Object + + + + + +

+ + + + +
+
+
+
+22
+23
+24
+25
+
+
# File 'lib/juno/Client/cache_store.rb', line 22
+
+def read(key, options = {})
+  future_obj = @react_client.get(key).wait
+  read_response(future_obj, options[:version])
+end
+
+
+ +
+

+ + #write(key, value, _options = {}) ⇒ Object + + + + + +

+ + + + +
+
+
+
+13
+14
+15
+16
+17
+18
+19
+20
+
+
# File 'lib/juno/Client/cache_store.rb', line 13
+
+def write(key, value, _options = {})
+  future_obj = @react_client.set(key, value).wait
+  return false if future_obj.nil?
+
+  raise future_obj.reason if future_obj.rejected?
+
+  future_obj.value.status[:txnOk]
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client/JunoRequest.html b/client/Ruby/docs/Juno/Client/JunoRequest.html new file mode 100644 index 0000000..7358430 --- /dev/null +++ b/client/Ruby/docs/Juno/Client/JunoRequest.html @@ -0,0 +1,905 @@ + + + + + + + Class: Juno::Client::JunoRequest + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Client::JunoRequest + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/juno_request.rb
+
+ +
+ +

Overview

+
+ +

Request Object created from application request

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: Type + + +

+ + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(key:, version:, type:, value: nil, time_to_live_s: nil, creation_time: nil) ⇒ JunoRequest + + + + + +

+
+ +

Constructor for JunoRequest

+ + +
+
+
+

Parameters:

+
    + +
  • + + key + + + (String) + + + + — +
    +

    key for the document (required)

    +
    + +
  • + +
  • + + version + + + (Integer) + + + + — +
    +

    value for the document (required)

    +
    + +
  • + +
  • + + version + + + (Juno::JunoRequest::Type) + + + + — +
    +

    value for the document (required)

    +
    + +
  • + +
  • + + type + + + (String) + + + + — +
    +

    value for the document (optional, default: 1 byte string: 0.chr)

    +
    + +
  • + +
  • + + type + + + (Integer) + + + + — +
    +

    Time to live for the document (optional, default: read from config file)

    +
    + +
  • + +
  • + + type + + + (Integer) + + + + — +
    +

    Time to live for the document (optional, default: initialized to Time.now in JunoMessage)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+
+
# File 'lib/juno/Client/juno_request.rb', line 25
+
+def initialize(key:, version:, type:, value: nil, time_to_live_s: nil, creation_time: nil)
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  @key = key
+  @version = version.to_i
+  @type = type
+  @value = value.to_s.empty? ? 0.chr : value.to_s
+  @time_to_live_s = time_to_live_s.to_i
+  @creation_time = creation_time
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #creation_timeObject + + + + + +

+
+ +

Returns the value of attribute creation_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+16
+17
+18
+
+
# File 'lib/juno/Client/juno_request.rb', line 16
+
+def creation_time
+  @creation_time
+end
+
+
+ + + +
+

+ + #keyObject + + + + + +

+
+ +

Returns the value of attribute key.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+16
+17
+18
+
+
# File 'lib/juno/Client/juno_request.rb', line 16
+
+def key
+  @key
+end
+
+
+ + + +
+

+ + #time_to_live_sObject + + + + + +

+
+ +

Returns the value of attribute time_to_live_s.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+16
+17
+18
+
+
# File 'lib/juno/Client/juno_request.rb', line 16
+
+def time_to_live_s
+  @time_to_live_s
+end
+
+
+ + + +
+

+ + #typeObject + + + + + +

+
+ +

Returns the value of attribute type.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+16
+17
+18
+
+
# File 'lib/juno/Client/juno_request.rb', line 16
+
+def type
+  @type
+end
+
+
+ + + +
+

+ + #valueObject + + + + + +

+
+ +

Returns the value of attribute value.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+16
+17
+18
+
+
# File 'lib/juno/Client/juno_request.rb', line 16
+
+def value
+  @value
+end
+
+
+ + + +
+

+ + #versionObject + + + + + +

+
+ +

Returns the value of attribute version.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+16
+17
+18
+
+
# File 'lib/juno/Client/juno_request.rb', line 16
+
+def version
+  @version
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #==(other) ⇒ Object + + + + + +

+ + + + +
+
+
+
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+
+
# File 'lib/juno/Client/juno_request.rb', line 36
+
+def ==(other)
+  return false unless other.is_a?(JunoRequest)
+
+  other.key == @key &&
+    other.version == @version &&
+    other.type == @type &&
+    other.value == @value &&
+    other.time_to_live_s == @time_to_live_s &&
+    other.creation_time == @creation_time
+end
+
+
+ +
+

+ + #to_sObject + + + + + +

+
+ +

Function to serialize JunoRequest

+ + +
+
+
+ + +
+ + + + +
+
+
+
+48
+49
+50
+
+
# File 'lib/juno/Client/juno_request.rb', line 48
+
+def to_s
+  "JunoRequest key:#{@key} version:#{@version} type:#{@type}, value: #{@value}, time_to_live: #{@time_to_live}, creation_time: #{@creation_time}"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client/JunoRequest/Type.html b/client/Ruby/docs/Juno/Client/JunoRequest/Type.html new file mode 100644 index 0000000..619822d --- /dev/null +++ b/client/Ruby/docs/Juno/Client/JunoRequest/Type.html @@ -0,0 +1,157 @@ + + + + + + + Class: Juno::Client::JunoRequest::Type + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Client::JunoRequest::Type + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/juno_request.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
CREATE = + +
+
1
+ +
GET = + +
+
2
+ +
UPDATE = + +
+
3
+ +
SET = + +
+
4
+ +
DESTROY = + +
+
5
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client/JunoResponse.html b/client/Ruby/docs/Juno/Client/JunoResponse.html new file mode 100644 index 0000000..3aab10d --- /dev/null +++ b/client/Ruby/docs/Juno/Client/JunoResponse.html @@ -0,0 +1,616 @@ + + + + + + + Class: Juno::Client::JunoResponse + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Client::JunoResponse + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/juno_response.rb
+
+ +
+ +

Overview

+
+ +

Response sent to the application

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(key:, value:, version:, time_to_live_s:, creation_time:, operation_status:) ⇒ JunoResponse + + + + + +

+
+ +

Returns a new instance of JunoResponse.

+ + +
+
+
+

Parameters:

+
    + +
  • + + key + + + (String) + + + + — +
    +

    (required)

    +
    + +
  • + +
  • + + status + + + (Juno::Client::OperationStatus) + + + + — +
    +

    (required)

    +
    + +
  • + +
  • + + value + + + (String) + + + + — +
    +

    (required)

    +
    + +
  • + +
  • + + version + + + (Integer) + + + + — +
    +

    (required)

    +
    + +
  • + +
  • + + creation_time + + + (Integer) + + + + — +
    +

    (required)

    +
    + +
  • + +
  • + + time_to_live_s + + + (Integer) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+15
+16
+17
+18
+19
+20
+21
+22
+23
+
+
# File 'lib/juno/Client/juno_response.rb', line 15
+
+def initialize(key:, value:, version:, time_to_live_s:, creation_time:, operation_status:)
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  @key = key
+  @status = operation_status
+  @value = value
+  @record_context = Juno::Client::RecordContext.new(key: key, version: version, creation_time: creation_time,
+                                                    time_to_live_s: time_to_live_s)
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #keyObject + + + + + +

+
+ +

Returns the value of attribute key.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/Client/juno_response.rb', line 7
+
+def key
+  @key
+end
+
+
+ + + +
+

+ + #record_contextObject + + + + + +

+
+ +

Returns the value of attribute record_context.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/Client/juno_response.rb', line 7
+
+def record_context
+  @record_context
+end
+
+
+ + + +
+

+ + #statusObject + + + + + +

+
+ +

Returns the value of attribute status.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/Client/juno_response.rb', line 7
+
+def status
+  @status
+end
+
+
+ + + +
+

+ + #valueObject + + + + + +

+
+ +

Returns the value of attribute value.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/Client/juno_response.rb', line 7
+
+def value
+  @value
+end
+
+
+ +
+ + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client/OperationStatus.html b/client/Ruby/docs/Juno/Client/OperationStatus.html new file mode 100644 index 0000000..37fb85f --- /dev/null +++ b/client/Ruby/docs/Juno/Client/OperationStatus.html @@ -0,0 +1,344 @@ + + + + + + + Class: Juno::Client::OperationStatus + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Client::OperationStatus + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/operation_status.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
SUCCESS = + +
+
{ code: 0, error_msg: 'No error', txnOk: true }.freeze
+ +
NO_KEY = + +
+
{ code: 1, error_msg: 'Key not found', txnOk: true }.freeze
+ +
BAD_PARAM = + +
+
{ code: 2, error_msg: 'Bad parameter', txnOk: false }.freeze
+ +
UNIQUE_KEY_VIOLATION = + +
+
{ code: 3, error_msg: 'Duplicate key', txnOk: true }.freeze
+ +
RECORD_LOCKED = + +
+
{ code: 4, error_msg: 'Record Locked', txnOk: true }.freeze
+ +
ILLEGAL_ARGUMENT = + +
+
{ code: 5, error_msg: 'Illegal argument', txnOk: false }.freeze
+ +
CONDITION_VIOLATION = + +
+
{ code: 6, error_msg: 'Condition in the request violated', txnOk: true }.freeze
+ +
INTERNAL_ERROR = + +
+
{ code: 7, error_msg: 'Internal error', txnOk: false }.freeze
+ +
QUEUE_FULL = + +
+
{ code: 8, error_msg: 'Outbound client queue full', txnOk: false }.freeze
+ +
NO_STORAGE = + +
+
{ code: 9, error_msg: 'No storage server running', txnOk: false }.freeze
+ +
TTL_EXTEND_FAILURE = + +
+
{ code: 10, error_msg: 'Failure to extend TTL on get', txnOk: true }.freeze
+ +
RESPONSE_TIMEOUT = + +
+
{ code: 11, error_msg: 'Response Timed out', txnOk: false }.freeze
+ +
CONNECTION_ERROR = + +
+
{ code: 12, error_msg: 'Connection Error', txnOk: false }.freeze
+ +
UNKNOWN_ERROR = + +
+
{ code: 13, error_msg: 'Unknown Error', txnOk: false }.freeze
+ +
@@status_code_map = + +
+
nil
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .get(status_code) ⇒ Object + + + + + +

+ + + + +
+
+
+
+33
+34
+35
+36
+37
+38
+
+
# File 'lib/juno/Client/operation_status.rb', line 33
+
+def self.get(status_code)
+  initialize_map if @@status_code_map.nil?
+  return @@status_code_map[status_code] if @@status_code_map.key?(status_code)
+
+  INTERNAL_ERROR
+end
+
+
+ +
+

+ + .initialize_mapObject + + + + + +

+ + + + +
+
+
+
+24
+25
+26
+27
+28
+29
+30
+31
+
+
# File 'lib/juno/Client/operation_status.rb', line 24
+
+def self.initialize_map
+  @@status_code_map = {}
+
+  constants.each do |const|
+    const_obj = const_get(const)
+    @@status_code_map[const_obj[:code]] = const_obj
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client/OperationType.html b/client/Ruby/docs/Juno/Client/OperationType.html new file mode 100644 index 0000000..a207bab --- /dev/null +++ b/client/Ruby/docs/Juno/Client/OperationType.html @@ -0,0 +1,199 @@ + + + + + + + Class: Juno::Client::OperationType + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Client::OperationType + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/operation_type.rb
+
+ +
+ +

Overview

+
+ +

Constant for JunoRequest operation type

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
Nop = + +
+
{
+  code: 0,
+  str: 'NOP'
+}.freeze
+ +
Create = + +
+
{
+  code: 1,
+  str: 'CREATE'
+}.freeze
+ +
Get = + +
+
{
+  code: 2,
+  str: 'GET'
+}.freeze
+ +
Update = + +
+
{
+  code: 3,
+  str: 'UPDATE'
+}.freeze
+ +
Set = + +
+
{
+  code: 4,
+  str: 'SET'
+}.freeze
+ +
CompareAndSet = + +
+
{
+  code: 5,
+  str: 'COMPAREANDSET'
+}.freeze
+ +
Destroy = + +
+
{
+  code: 6,
+  str: 'DESTROY'
+}.freeze
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client/ReactClient.html b/client/Ruby/docs/Juno/Client/ReactClient.html new file mode 100644 index 0000000..4599396 --- /dev/null +++ b/client/Ruby/docs/Juno/Client/ReactClient.html @@ -0,0 +1,1347 @@ + + + + + + + Class: Juno::Client::ReactClient + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Client::ReactClient + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/react_client.rb
+
+ +
+ +

Overview

+
+ +

Async Client for Juno

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
MAX_OPERATION_RETRY = +
+
+ +

Constants for operation retry

+ + +
+
+
+ + +
+
+
1
+ +
MAX_RETRY_INTERVAL = +
+
+ +

msec

+ + +
+
+
+ + +
+
+
15
+ +
MIN_RETRY_INTERVAL = +
+
+ +

msec

+ + +
+
+
+ + +
+
+
10
+ +
@@OPAQUE_GENERATOR = +
+
+ +

@ Global Opaque generator. Uses ConcurrentFixnum for thread safety

+ + +
+
+
+ + +
+
+
Concurrent::AtomicFixnum.new(-1)
+ +
@@fail_count = +
+
+ +

@ Variable to count failed requests

+ + +
+
+
+ + +
+
+
Concurrent::AtomicFixnum.new(0)
+ +
@@received = +
+
+ +

@ Variable to count responses received

+ + +
+
+
+ + +
+
+
Concurrent::AtomicFixnum.new(0)
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initializeReactClient + + + + + +

+
+ +

Returns a new instance of ReactClient.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+33
+34
+35
+36
+37
+38
+39
+
+
# File 'lib/juno/Client/react_client.rb', line 33
+
+def initialize
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  @request_queue = Juno::Net::RequestQueue.instance
+  @executor = Concurrent::ThreadPoolExecutor.new(min_threads: 4, max_threads: 16, max_queue: 10_000)
+  @count = 0
+end
+
+
+ +
+ + +
+

Class Method Details

+ + +
+

+ + .failed_countObject + + + + + +

+ + + + +
+
+
+
+25
+26
+27
+
+
# File 'lib/juno/Client/react_client.rb', line 25
+
+def self.failed_count
+  @@fail_count.value
+end
+
+
+ +
+

+ + .op_countObject + + + + + +

+ + + + +
+
+
+
+21
+22
+23
+
+
# File 'lib/juno/Client/react_client.rb', line 21
+
+def self.op_count
+  @@OPAQUE_GENERATOR.value
+end
+
+
+ +
+

+ + .recvObject + + + + + +

+ + + + +
+
+
+
+29
+30
+31
+
+
# File 'lib/juno/Client/react_client.rb', line 29
+
+def self.recv
+  @@received.value
+end
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #compare_and_set(record_context, value, ttl) ⇒ Object + + + + + +

+
+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+
+
# File 'lib/juno/Client/react_client.rb', line 86
+
+def compare_and_set(record_context, value, ttl)
+  unless record_context.is_a?(Juno::Client::RecordContext)
+    raise ArgumentError, 'recird context should be of type Juno::Client::RecordContext'
+  end
+  raise ArgumentError, 'Version cannot be less than 1' if record_context.version.to_i < 1
+
+  juno_request = Juno::Client::JunoRequest.new(key: record_context.key.to_s,
+                                               value: value,
+                                               version: record_context.version.to_i,
+                                               type: Juno::Client::JunoRequest::Type::UPDATE,
+                                               time_to_live_s: ttl,
+                                               creation_time: Time.now.to_i)
+  process_single(juno_request)
+end
+
+
+ +
+

+ + #create(key, value, ttl: nil) ⇒ Boolean + + + + + +

+
+ +

Function to create new key value pair

+ + +
+
+
+

Parameters:

+
    + +
  • + + key + + + (String) + + + + — +
    +

    key for the document (required)

    +
    + +
  • + +
  • + + value + + + (String) + + + + — +
    +

    value for the document (required)

    +
    + +
  • + +
  • + + ttl + + + (Integer) + + + (defaults to: nil) + + + — +
    +

    Time to live for the document (optional, default: read from config file)

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +
    +

    True if operation submited successfully, else false

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+56
+57
+58
+59
+60
+61
+62
+63
+64
+
+
# File 'lib/juno/Client/react_client.rb', line 56
+
+def create(key, value, ttl: nil)
+  juno_request = Juno::Client::JunoRequest.new(key: key,
+                                               value: value,
+                                               version: 0,
+                                               type: Juno::Client::JunoRequest::Type::CREATE,
+                                               time_to_live_s: ttl,
+                                               creation_time: Time.now.to_i)
+  process_single(juno_request)
+end
+
+
+ +
+

+ + #destroy(key, ttl: nil) ⇒ Object + + + + Also known as: + delete + + + + +

+ + + + +
+
+
+
+131
+132
+133
+134
+135
+136
+137
+138
+139
+
+
# File 'lib/juno/Client/react_client.rb', line 131
+
+def destroy(key, ttl: nil)
+  juno_request = Juno::Client::JunoRequest.new(key: key,
+                                               value: '',
+                                               version: 0,
+                                               type: Juno::Client::JunoRequest::Type::DESTROY,
+                                               time_to_live_s: ttl,
+                                               creation_time: Time.now.to_i)
+  process_single(juno_request)
+end
+
+
+ +
+

+ + #exist?(key) ⇒ Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+144
+
+
# File 'lib/juno/Client/react_client.rb', line 144
+
+def exist?(key); end
+
+
+ +
+

+ + #get(key, ttl: nil) ⇒ Juno::Client::JunoResponse + + + + Also known as: + read + + + + +

+
+ +

Function to get existing key value pair

+ + +
+
+
+

Parameters:

+
    + +
  • + + key + + + (String) + + + + — +
    +

    key for the document (required)

    +
    + +
  • + +
  • + + value + + + (String) + + + + — +
    +

    value for the document (required)

    +
    + +
  • + +
  • + + ttl + + + (Integer) + + + (defaults to: nil) + + + — +
    +

    Time to live for the document (optional, default: read from config file)

    +
    + +
  • + +
+ +

Returns:

+ + +

See Also:

+ + +
+ + + + +
+
+
+
+108
+109
+110
+111
+112
+113
+114
+115
+116
+
+
# File 'lib/juno/Client/react_client.rb', line 108
+
+def get(key, ttl: nil)
+  juno_request = Juno::Client::JunoRequest.new(key: key,
+                                               value: '',
+                                               version: 0,
+                                               type: Juno::Client::JunoRequest::Type::GET,
+                                               time_to_live_s: ttl,
+                                               creation_time: Time.now.to_i)
+  process_single(juno_request)
+end
+
+
+ +
+

+ + #set(key, value, ttl: nil) ⇒ Boolean + + + + Also known as: + write + + + + +

+
+ +

Function to set value for given key

+ + +
+
+
+

Parameters:

+
    + +
  • + + key + + + (String) + + + + — +
    +

    key for the document (required)

    +
    + +
  • + +
  • + + value + + + (String) + + + + — +
    +

    value for the document (required)

    +
    + +
  • + +
  • + + ttl + + + (Integer) + + + (defaults to: nil) + + + — +
    +

    Time to live for the document (optional, default: read from config file)

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +
    +

    True if operation submited successfully, else false

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+73
+74
+75
+76
+77
+78
+79
+80
+81
+
+
# File 'lib/juno/Client/react_client.rb', line 73
+
+def set(key, value, ttl: nil)
+  juno_request = Juno::Client::JunoRequest.new(key: key,
+                                               value: value,
+                                               version: 0,
+                                               type: Juno::Client::JunoRequest::Type::SET,
+                                               time_to_live_s: ttl,
+                                               creation_time: Time.now.to_i)
+  process_single(juno_request)
+end
+
+
+ +
+

+ + #stopObject + + + + + +

+ + + + +
+
+
+
+41
+42
+43
+44
+45
+46
+47
+
+
# File 'lib/juno/Client/react_client.rb', line 41
+
+def stop
+  @LOGGER.info(@PROG_NAME) { 'stop initiated by client' }
+  @request_queue.stop
+  @executor.shutdown
+  @executor.wait_for_termination
+  @executor.kill
+end
+
+
+ +
+

+ + #update(key, value, ttl: nil) ⇒ Object + + + + + +

+ + + + +
+
+
+
+121
+122
+123
+124
+125
+126
+127
+128
+129
+
+
# File 'lib/juno/Client/react_client.rb', line 121
+
+def update(key, value, ttl: nil)
+  juno_request = Juno::Client::JunoRequest.new(key: key,
+                                               value: value,
+                                               version: 0,
+                                               type: Juno::Client::JunoRequest::Type::UPDATE,
+                                               time_to_live_s: ttl,
+                                               creation_time: Time.now.to_i)
+  process_single(juno_request)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client/RecordContext.html b/client/Ruby/docs/Juno/Client/RecordContext.html new file mode 100644 index 0000000..db0d8e5 --- /dev/null +++ b/client/Ruby/docs/Juno/Client/RecordContext.html @@ -0,0 +1,579 @@ + + + + + + + Class: Juno::Client::RecordContext + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Client::RecordContext + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/record_context.rb
+
+ +
+ + + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(key:, version:, creation_time:, time_to_live_s:) ⇒ RecordContext + + + + + +

+
+ +

Returns a new instance of RecordContext.

+ + +
+
+
+

Parameters:

+
    + +
  • + + key + + + (String) + + + + — +
    +

    (required)

    +
    + +
  • + +
  • + + version + + + (Integer) + + + + — +
    +

    (required)

    +
    + +
  • + +
  • + + creation_time + + + (Integer) + + + + — +
    +

    (required)

    +
    + +
  • + +
  • + + time_to_live_s + + + (Integer) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+12
+13
+14
+15
+16
+17
+18
+19
+
+
# File 'lib/juno/Client/record_context.rb', line 12
+
+def initialize(key:, version:, creation_time:, time_to_live_s:)
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  @key = key
+  @version = version
+  @creation_time = creation_time
+  @time_to_live_s = time_to_live_s
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #creation_timeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute creation_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+6
+7
+8
+
+
# File 'lib/juno/Client/record_context.rb', line 6
+
+def creation_time
+  @creation_time
+end
+
+
+ + + +
+

+ + #keyObject (readonly) + + + + + +

+
+ +

Returns the value of attribute key.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+6
+7
+8
+
+
# File 'lib/juno/Client/record_context.rb', line 6
+
+def key
+  @key
+end
+
+
+ + + +
+

+ + #time_to_live_sObject (readonly) + + + + + +

+
+ +

Returns the value of attribute time_to_live_s.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+6
+7
+8
+
+
# File 'lib/juno/Client/record_context.rb', line 6
+
+def time_to_live_s
+  @time_to_live_s
+end
+
+
+ + + +
+

+ + #versionObject (readonly) + + + + + +

+
+ +

Returns the value of attribute version.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+6
+7
+8
+
+
# File 'lib/juno/Client/record_context.rb', line 6
+
+def version
+  @version
+end
+
+
+ +
+ + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Client/SyncClient.html b/client/Ruby/docs/Juno/Client/SyncClient.html new file mode 100644 index 0000000..1e2e052 --- /dev/null +++ b/client/Ruby/docs/Juno/Client/SyncClient.html @@ -0,0 +1,844 @@ + + + + + + + Class: Juno::Client::SyncClient + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Client::SyncClient + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Client/sync_client.rb
+
+ +
+ +

Overview

+
+ +

Async Client for Juno

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initializeSyncClient + + + + + +

+
+ +

Returns a new instance of SyncClient.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Client/sync_client.rb', line 9
+
+def initialize
+  @react_client = Juno::Client::ReactClient.new
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #compare_and_set(record_context, value, ttl: nil) ⇒ Object + + + + + +

+ + + + +
+
+
+
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+
+
# File 'lib/juno/Client/sync_client.rb', line 64
+
+def compare_and_set(record_context, value, ttl: nil)
+  juno_resp = nil
+  begin
+    juno_resp = @react_client.compare_and_set(record_context, value, ttl)
+  rescue ArgumentError => e
+    raise e.message
+  end
+
+  return nil if juno_resp.nil?
+
+  raise juno_resp.reason if juno_resp.rejected?
+
+  juno_resp.value # JunoResponse
+end
+
+
+ +
+

+ + #create(key, value, ttl: nil) ⇒ Juno::Client::JunoResponse + + + + + +

+
+ +

Function to create new key value pair

+ + +
+
+
+

Parameters:

+
    + +
  • + + key + + + (String) + + + + — +
    +

    key for the document (required)

    +
    + +
  • + +
  • + + value + + + (String) + + + + — +
    +

    value for the document (required)

    +
    + +
  • + +
  • + + ttl + + + (Integer) + + + (defaults to: nil) + + + — +
    +

    Time to live for the document (optional, default: read from config file)

    +
    + +
  • + +
+ +

Returns:

+ + +
+ + + + +
+
+
+
+18
+19
+20
+21
+22
+23
+24
+25
+
+
# File 'lib/juno/Client/sync_client.rb', line 18
+
+def create(key, value, ttl: nil)
+  juno_resp = @react_client.create(key, value, ttl: ttl).wait
+  return nil if juno_resp.nil?
+
+  raise juno_resp.reason if juno_resp.rejected?
+
+  juno_resp.value # JunoResponse
+end
+
+
+ +
+

+ + #destroy(key, ttl: nil) ⇒ Object + + + + + +

+ + + + +
+
+
+
+79
+80
+81
+82
+83
+84
+85
+86
+
+
# File 'lib/juno/Client/sync_client.rb', line 79
+
+def destroy(key, ttl: nil)
+  juno_resp = @react_client.destroy(key.to_s, ttl: ttl).wait
+  return nil if juno_resp.nil?
+
+  raise juno_resp.reason if juno_resp.rejected?
+
+  juno_resp.value # JunoResponse
+end
+
+
+ +
+

+ + #get(key, ttl: nil) ⇒ Juno::Client::JunoResponse + + + + + +

+
+ +

Function to get existing key value pair

+ + +
+
+
+

Parameters:

+
    + +
  • + + key + + + (String) + + + + — +
    +

    key for the document (required)

    +
    + +
  • + +
  • + + value + + + (String) + + + + — +
    +

    value for the document (required)

    +
    + +
  • + +
  • + + ttl + + + (Integer) + + + (defaults to: nil) + + + — +
    +

    Time to live for the document (optional, default: read from config file)

    +
    + +
  • + +
+ +

Returns:

+ + +
+ + + + +
+
+
+
+46
+47
+48
+49
+50
+51
+52
+53
+
+
# File 'lib/juno/Client/sync_client.rb', line 46
+
+def get(key, ttl: nil)
+  juno_resp = @react_client.get(key.to_s, ttl: ttl).wait
+  return nil if juno_resp.nil?
+
+  raise juno_resp.reason if juno_resp.rejected?
+
+  juno_resp.value # JunoResponse
+end
+
+
+ +
+

+ + #set(key, value, ttl: nil) ⇒ Juno::Client::JunoResponse + + + + + +

+
+ +

Function to set value for given key

+ + +
+
+
+

Parameters:

+
    + +
  • + + key + + + (String) + + + + — +
    +

    key for the document (required)

    +
    + +
  • + +
  • + + value + + + (String) + + + + — +
    +

    value for the document (required)

    +
    + +
  • + +
  • + + ttl + + + (Integer) + + + (defaults to: nil) + + + — +
    +

    Time to live for the document (optional, default: read from config file)

    +
    + +
  • + +
+ +

Returns:

+ + +
+ + + + +
+
+
+
+32
+33
+34
+35
+36
+37
+38
+39
+
+
# File 'lib/juno/Client/sync_client.rb', line 32
+
+def set(key, value, ttl: nil)
+  juno_resp = @react_client.set(key.to_s, value.to_s, ttl: ttl).wait
+  return nil if juno_resp.nil?
+
+  raise juno_resp.reason if juno_resp.rejected?
+
+  juno_resp.value # JunoResponse
+end
+
+
+ +
+

+ + #update(key, value, ttl: nil) ⇒ Object + + + + + +

+ + + + +
+
+
+
+55
+56
+57
+58
+59
+60
+61
+62
+
+
# File 'lib/juno/Client/sync_client.rb', line 55
+
+def update(key, value, ttl: nil)
+  juno_resp = @react_client.update(key.to_s, value.to_s, ttl: ttl).wait
+  return nil if juno_resp.nil?
+
+  raise juno_resp.reason if juno_resp.rejected?
+
+  juno_resp.value # JunoResponse
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/ClientUtils.html b/client/Ruby/docs/Juno/ClientUtils.html new file mode 100644 index 0000000..da69bfb --- /dev/null +++ b/client/Ruby/docs/Juno/ClientUtils.html @@ -0,0 +1,676 @@ + + + + + + + Module: Juno::ClientUtils + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: Juno::ClientUtils + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Utils/client_utils.rb
+
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .compressed_value(value) ⇒ Object + + + + + +

+ + + + +
+
+
+
+42
+43
+44
+45
+46
+47
+48
+
+
# File 'lib/juno/Utils/client_utils.rb', line 42
+
+def self.compressed_value(value)
+  compressed_value = Snappy.deflate(value)
+  compression_achieved = 100 - (compressed_value.length * 100) / value.length
+  [compressed_value, compression_achieved]
+rescue Exception
+  [value, false]
+end
+
+
+ +
+

+ + .create_operation_message(juno_message, opaque) ⇒ Object + + + + + +

+ + + + +
+
+
+
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+
+
# File 'lib/juno/Utils/client_utils.rb', line 5
+
+def self.create_operation_message(juno_message, opaque)
+  protocol_header = Juno::IO::ProtocolHeader.new
+  protocol_header.version = juno_message.version
+  protocol_header.opcode = juno_message.operation_type
+  protocol_header.opaque = opaque
+
+   = Juno::IO::MetadataComponent.new
+  if juno_message.time_to_live_s.to_i.positive?
+    .set_time_to_live(juno_message.time_to_live_s.to_i)
+  end
+  .set_version(juno_message.version)
+
+  if [Juno::IO::JunoMessage::OperationType::CREATE,
+      Juno::IO::JunoMessage::OperationType::SET].include?(juno_message.operation_type)
+    .set_creation_time(Time.now.to_i)
+  end
+
+  .set_expiration_time((Time.now + juno_message.time_to_live_s).to_i) # what ?
+  .set_request_uuid(juno_message.request_uuid)
+  .set_source_info(app_name: juno_message.app_name, ip: juno_message.ip, port: juno_message.port)
+  .set_originator_request_id # what
+
+  payload_component = Juno::IO::PayloadComponent.new
+  payload_component.namespace = juno_message.namespace
+  payload_component.payload_key = juno_message.key
+  payload_component.set_value(juno_message.value, juno_message.compression_type)
+
+  operation_message = Juno::IO::OperationMessage.new
+  operation_message.protocol_header = protocol_header
+  operation_message. = 
+  operation_message.payload_component = payload_component
+
+  juno_message.message_size = operation_message.size
+
+  operation_message
+end
+
+
+ +
+

+ + .decode_operation_message(operation_message) ⇒ Object + + + + + +

+ + + + +
+
+
+
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+
+
# File 'lib/juno/Utils/client_utils.rb', line 111
+
+def self.decode_operation_message(operation_message)
+  return nil unless operation_message.is_a?(Juno::IO::OperationMessage)
+
+  juno_message = Juno::IO::JunoMessage.new
+  opcode = operation_message.protocol_header.opcode.to_i
+  juno_message.operation_type = Juno::IO::JunoMessage::OperationType.get(opcode)
+
+  server_status = operation_message.protocol_header.status.to_i
+  juno_message.server_status = Juno::ServerStatus.get(server_status)
+
+  juno_message.message_size = operation_message.protocol_header.message_size.to_i
+
+  unless operation_message..nil?
+     = operation_message.
+    juno_message.time_to_live_s = .time_to_live.to_i
+    juno_message.ip = .ip
+    juno_message.port = .port
+    juno_message.version = .version.to_i
+    juno_message.creation_time = .creation_time.to_i
+    juno_message.expiration_time = .expiration_time.to_i
+    juno_message.request_uuid = .request_uuid
+    juno_message.app_name = .app_name
+    juno_message.last_modification = .last_modification.to_i
+    juno_message.originator_request_id = .originator_request_id.to_s
+    juno_message.correlation_id = .correlation_id
+    juno_message.request_handling_time = .request_handling_time.to_i
+    # juno_message.request_start_time = metadata_component.
+    # expiry
+  end
+
+  unless operation_message.payload_component.nil?
+    juno_message.namespace = operation_message.payload_component.namespace.to_s
+    juno_message.key = operation_message.payload_component.payload_key.to_s
+    juno_message.is_compressed = operation_message.payload_component.compressed?
+    juno_message.compression_type = operation_message.payload_component.compression_type.to_i
+    juno_message.value = if operation_message.payload_component.payload_length.to_i.zero?
+                           juno_message.compression_achieved = 0
+                           nil
+                         elsif juno_message.is_compressed
+                           compressed_value = operation_message.payload_component.value.to_s
+                           decompressed_value = decompress_value(compressed_value)
+                           juno_message.compression_achieved = 100 - (compressed_value.length / decompressed_value.length.to_f) * 100.0
+                           decompressed_value
+                         else
+                           juno_message.compression_achieved = 0
+                           operation_message.payload_component.value.to_s
+                         end
+  end
+
+  juno_message
+end
+
+
+ +
+

+ + .decompress_value(value) ⇒ Object + + + + + +

+ + + + +
+
+
+
+50
+51
+52
+53
+54
+55
+
+
# File 'lib/juno/Utils/client_utils.rb', line 50
+
+def self.decompress_value(value)
+  Snappy.inflate(value)
+rescue Exception
+  # Log failure
+  value
+end
+
+
+ +
+

+ + .validate!(juno_request) ⇒ Object + + + + + +

+
+ + +
+
+
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+
+
# File 'lib/juno/Utils/client_utils.rb', line 57
+
+def self.validate!(juno_request)
+  return false unless juno_request.is_a?(Juno::Client::JunoRequest)
+
+  raise ArgumentError, 'Juno request key cannot be empty' if juno_request.key.to_s.nil?
+
+  juno_request.time_to_live_s = Juno.juno_config.default_lifetime unless juno_request.time_to_live_s.to_i.positive?
+
+  if juno_request.time_to_live_s > Juno.juno_config.max_lifetime || juno_request.time_to_live_s.negative?
+    raise ArgumentError,
+          "Record time_to_live_s (#{juno_request.time_to_live_s}s) cannot be greater than  #{Juno.juno_config.max_lifetime}s or negative ."
+  end
+
+  if juno_request.key.to_s.size > Juno.juno_config.max_key_size
+    raise ArgumentError,
+          "Key size cannot be greater than #{Juno.juno_config.max_key_size}"
+  end
+
+  if juno_request.key.to_s.size > Juno.juno_config.max_key_size
+    raise ArgumentError,
+          "Key size cannot be greater than #{Juno.juno_config.max_key_size}"
+  end
+
+  juno_message = Juno::IO::JunoMessage.new
+  juno_message.key = juno_request.key
+  juno_message.version = juno_request.version
+  juno_message.operation_type = juno_request.type
+  juno_message.time_to_live_s = juno_request.time_to_live_s
+  juno_message.creation_time = juno_request.creation_time
+  juno_message.namespace = Juno.juno_config.record_namespace
+  juno_message.app_name = Juno.juno_config.app_name
+  juno_message.request_uuid = UUIDTools::UUID.random_create.to_s
+  juno_message.ip = IPAddr.new(Juno::Utils.local_ips[0])
+  juno_message.port = 0
+
+  unless [Juno::Client::JunoRequest::Type::GET,
+          Juno::Client::JunoRequest::Type::DESTROY].include?(juno_request.type)
+    payload_value = juno_request.value
+    is_compressed = false
+    compression_achieved = 0
+    if Juno.juno_config.use_payload_compression && value.length > 1024
+      payload_value, compression_achieved = compressed_value(value)
+      is_compressed = true if compression_achieved.positive?
+    end
+    juno_message.is_compressed = is_compressed
+    juno_message.value = payload_value
+    juno_message.compression_achieved = compression_achieved
+    juno_message.compression_type = is_compressed ? Juno::IO::CompressionType::Snappy : Juno::IO::CompressionType::None
+  end
+
+  juno_message
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Config.html b/client/Ruby/docs/Juno/Config.html new file mode 100644 index 0000000..45920a6 --- /dev/null +++ b/client/Ruby/docs/Juno/Config.html @@ -0,0 +1,2381 @@ + + + + + + + Class: Juno::Config + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Config + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Config/config.rb
+
+ +
+ +

Overview

+
+ +

Juno.configure do |config|

+ +
config.record_namespace = "kk"
+config.host = '10.138.38.83'
+config.port = 5080
+config.app_name = "TestApp"
+config.file_path = ""
+config.url = ""
+
+ +

end

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: Source + + +

+ + +

+ Constant Summary + collapse +

+ +
+ +
REQUIRED_PROPERTIES = + +
+
%i[host port app_name record_namespace log_file].freeze
+ +
+ + + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(config_provider, log_file:, ssl_cert_file: nil, ssl_key_file: nil) ⇒ Config + + + + + +

+
+ +

Returns a new instance of Config.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+22
+23
+24
+25
+26
+27
+28
+29
+30
+
+
# File 'lib/juno/Config/config.rb', line 22
+
+def initialize(config_provider, log_file:, ssl_cert_file: nil, ssl_key_file: nil)
+  @PROG_NAME = self.class.name
+  @log_file = log_file
+  @ssl_cert_file = ssl_cert_file
+  @ssl_key_file = ssl_key_file
+  @config = config_provider
+  read_all
+  validate!
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #app_nameObject (readonly) + + + + + +

+
+ +

Returns the value of attribute app_name.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def app_name
+  @app_name
+end
+
+
+ + + +
+

+ + #bypass_ltmObject (readonly) + + + + + +

+
+ +

Returns the value of attribute bypass_ltm.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def bypass_ltm
+  @bypass_ltm
+end
+
+
+ + + +
+

+ + #config_prefixObject (readonly) + + + + + +

+
+ +

Returns the value of attribute config_prefix.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def config_prefix
+  @config_prefix
+end
+
+
+ + + +
+

+ + #connection_lifetimeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute connection_lifetime.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def connection_lifetime
+  @connection_lifetime
+end
+
+
+ + + +
+

+ + #connection_pool_sizeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute connection_pool_size.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def connection_pool_size
+  @connection_pool_size
+end
+
+
+ + + +
+

+ + #connection_timeoutObject (readonly) + + + + + +

+
+ +

Returns the value of attribute connection_timeout.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def connection_timeout
+  @connection_timeout
+end
+
+
+ + + +
+

+ + #default_lifetimeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute default_lifetime.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def default_lifetime
+  @default_lifetime
+end
+
+
+ + + +
+

+ + #hostObject (readonly) + + + + + +

+
+ +

Returns the value of attribute host.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def host
+  @host
+end
+
+
+ + + +
+

+ + #log_fileObject (readonly) + + + + + +

+
+ +

Returns the value of attribute log_file.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def log_file
+  @log_file
+end
+
+
+ + + +
+

+ + #max_connection_lifetimeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute max_connection_lifetime.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def max_connection_lifetime
+  @max_connection_lifetime
+end
+
+
+ + + +
+

+ + #max_connection_pool_sizeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute max_connection_pool_size.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def max_connection_pool_size
+  @max_connection_pool_size
+end
+
+
+ + + +
+

+ + #max_connection_timeoutObject (readonly) + + + + + +

+
+ +

Returns the value of attribute max_connection_timeout.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def max_connection_timeout
+  @max_connection_timeout
+end
+
+
+ + + +
+

+ + #max_key_sizeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute max_key_size.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def max_key_size
+  @max_key_size
+end
+
+
+ + + +
+

+ + #max_lifetimeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute max_lifetime.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def max_lifetime
+  @max_lifetime
+end
+
+
+ + + +
+

+ + #max_namespace_lengthObject (readonly) + + + + + +

+
+ +

Returns the value of attribute max_namespace_length.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def max_namespace_length
+  @max_namespace_length
+end
+
+
+ + + +
+

+ + #max_response_timeoutObject (readonly) + + + + + +

+
+ +

Returns the value of attribute max_response_timeout.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def max_response_timeout
+  @max_response_timeout
+end
+
+
+ + + +
+

+ + #max_value_sizeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute max_value_size.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def max_value_size
+  @max_value_size
+end
+
+
+ + + +
+

+ + #operation_retryObject (readonly) + + + + + +

+
+ +

Returns the value of attribute operation_retry.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def operation_retry
+  @operation_retry
+end
+
+
+ + + +
+

+ + #portObject (readonly) + + + + + +

+
+ +

Returns the value of attribute port.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def port
+  @port
+end
+
+
+ + + +
+

+ + #reconnect_on_failObject (readonly) + + + + + +

+
+ +

Returns the value of attribute reconnect_on_fail.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def reconnect_on_fail
+  @reconnect_on_fail
+end
+
+
+ + + +
+

+ + #record_namespaceObject (readonly) + + + + + +

+
+ +

Returns the value of attribute record_namespace.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def record_namespace
+  @record_namespace
+end
+
+
+ + + +
+

+ + #response_timeoutObject (readonly) + + + + + +

+
+ +

Returns the value of attribute response_timeout.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def response_timeout
+  @response_timeout
+end
+
+
+ + + +
+

+ + #ssl_cert_fileObject (readonly) + + + + + +

+
+ +

Returns the value of attribute ssl_cert_file.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def ssl_cert_file
+  @ssl_cert_file
+end
+
+
+ + + +
+

+ + #ssl_key_fileObject (readonly) + + + + + +

+
+ +

Returns the value of attribute ssl_key_file.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def ssl_key_file
+  @ssl_key_file
+end
+
+
+ + + +
+

+ + #use_payload_compressionObject (readonly) + + + + + +

+
+ +

Returns the value of attribute use_payload_compression.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def use_payload_compression
+  @use_payload_compression
+end
+
+
+ + + +
+

+ + #use_sslObject (readonly) + + + + + +

+
+ +

Returns the value of attribute use_ssl.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Config/config.rb', line 14
+
+def use_ssl
+  @use_ssl
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #read_allObject + + + + + +

+
+ +

Function to map all properties read from config file to variables

+ + +
+
+
+ + +
+ + + + +
+
+
+
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+
+
# File 'lib/juno/Config/config.rb', line 33
+
+def read_all
+  @response_timeout = @config.get_property(Juno::Properties::RESPONSE_TIMEOUT,
+                                           Juno::DefaultProperties::RESPONSE_TIMEOUT_MS)
+  @connection_timeout = @config.get_property(Juno::Properties::CONNECTION_TIMEOUT,
+                                             Juno::DefaultProperties::CONNECTION_TIMEOUT_MS)
+  @connection_pool_size = @config.get_property(Juno::Properties::CONNECTION_POOLSIZE,
+                                               Juno::DefaultProperties::CONNECTION_POOLSIZE)
+  @connection_lifetime = @config.get_property(Juno::Properties::CONNECTION_LIFETIME,
+                                              Juno::DefaultProperties::CONNECTION_LIFETIME_MS)
+  @default_lifetime = @config.get_property(Juno::Properties::DEFAULT_LIFETIME,
+                                           Juno::DefaultProperties::DEFAULT_LIFETIME_S)
+  @max_response_timeout = @config.get_property(Juno::Properties::MAX_RESPONSE_TIMEOUT,
+                                               Juno::DefaultProperties::MAX_RESPONSE_TIMEOUT_MS)
+  @max_connection_timeout = @config.get_property(Juno::Properties::MAX_CONNECTION_TIMEOUT,
+                                                 Juno::DefaultProperties::MAX_CONNECTION_TIMEOUT_MS)
+  @max_connection_pool_size = @config.get_property(Juno::Properties::MAX_CONNECTION_POOL_SIZE,
+                                                   Juno::DefaultProperties::MAX_CONNECTION_POOL_SIZE)
+  @max_connection_lifetime = @config.get_property(Juno::Properties::MAX_CONNECTION_LIFETIME,
+                                                  Juno::DefaultProperties::MAX_CONNECTION_LIFETIME_MS)
+  @max_lifetime = @config.get_property(Juno::Properties::MAX_LIFETIME, Juno::DefaultProperties::MAX_LIFETIME_S)
+  @max_key_size = @config.get_property(Juno::Properties::MAX_KEY_SIZE, Juno::DefaultProperties::MAX_KEY_SIZE_B)
+  @max_value_size = @config.get_property(Juno::Properties::MAX_VALUE_SIZE,
+                                         Juno::DefaultProperties::MAX_VALUE_SIZE_B)
+  @max_namespace_length = @config.get_property(Juno::Properties::MAX_NAMESPACE_LENGTH,
+                                               Juno::DefaultProperties::MAX_NAMESPACE_LENGTH)
+  @host = @config.get_property(Juno::Properties::HOST, Juno::DefaultProperties::HOST)
+  @port = @config.get_property(Juno::Properties::PORT, Juno::DefaultProperties::PORT)
+  @app_name = @config.get_property(Juno::Properties::APP_NAME, Juno::DefaultProperties::APP_NAME)
+  @record_namespace = @config.get_property(Juno::Properties::RECORD_NAMESPACE,
+                                           Juno::DefaultProperties::RECORD_NAMESPACE)
+  @use_ssl = @config.get_property(Juno::Properties::USE_SSL, Juno::DefaultProperties::USE_SSL)
+  @use_payload_compression = @config.get_property(Juno::Properties::USE_PAYLOAD_COMPRESSION,
+                                                  Juno::DefaultProperties::USE_PAYLOAD_COMPRESSION)
+  @operation_retry = @config.get_property(Juno::Properties::ENABLE_RETRY, Juno::DefaultProperties::OPERATION_RETRY)
+  @bypass_ltm = @config.get_property(Juno::Properties::BYPASS_LTM, Juno::DefaultProperties::BYPASS_LTM)
+  @reconnect_on_fail = @config.get_property(Juno::Properties::RECONNECT_ON_FAIL,
+                                            Juno::DefaultProperties::RECONNECT_ON_FAIL)
+  @config_prefix = @config.get_property(Juno::Properties::CONFIG_PREFIX, Juno::DefaultProperties::CONFIG_PREFIX)
+  nil
+end
+
+
+ +
+

+ + #validate!Object + + + + + +

+ + + + +
+
+
+
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+
+
# File 'lib/juno/Config/config.rb', line 74
+
+def validate!
+  missing_properties = []
+  REQUIRED_PROPERTIES.each do |property|
+    missing_properties.push(property) if send(property).nil?
+  end
+
+  if @use_ssl
+    %i[ssl_cert_file ssl_key_file].each do |property|
+      missing_properties.push(property) if send(property).nil?
+    end
+  end
+
+  if missing_properties.length.positive?
+    raise "Please provide a value for the required property(s) #{missing_properties.join(', ')}."
+  end
+
+  if @use_ssl
+    raise 'SSL Certificate file not found' unless File.exist?(@ssl_cert_file)
+    raise 'SSL Key file not found' unless File.exist?(@ssl_key_file)
+  end
+
+  nil
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Config/Source.html b/client/Ruby/docs/Juno/Config/Source.html new file mode 100644 index 0000000..a8cc383 --- /dev/null +++ b/client/Ruby/docs/Juno/Config/Source.html @@ -0,0 +1,147 @@ + + + + + + + Class: Juno::Config::Source + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Config::Source + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Config/config.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
YAML_FILE = + +
+
0
+ +
JSON_FILE = + +
+
1
+ +
URL = + +
+
2
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/ConfigProvider.html b/client/Ruby/docs/Juno/ConfigProvider.html new file mode 100644 index 0000000..9115e80 --- /dev/null +++ b/client/Ruby/docs/Juno/ConfigProvider.html @@ -0,0 +1,603 @@ + + + + + + + Class: Juno::ConfigProvider + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::ConfigProvider + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Config/config_provider.rb
+
+ +
+ +

Overview

+
+ +

Class to read config from file or url

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(source_uri, source_format = nil, _http_handler = nil) ⇒ Object + + + + + +

+
+ +

Constructor

+ + +
+
+
+

Parameters:

+
    + +
  • + + source_uri + + + (URI) + + + + — +
    +

    Ruby URI Object for file or URL (required)

    +
    + +
  • + +
  • + + source_format + + + (String) + + + (defaults to: nil) + + + — +
    +

    source_format required only for url. Inferred from file extension when using file (optional)

    +
    + +
  • + +
+ + +

See Also:

+ + +
+ + + + +
+
+
+
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+
+
# File 'lib/juno/Config/config_provider.rb', line 12
+
+def initialize(source_uri, source_format = nil, _http_handler = nil)
+  begin
+    source_scheme = source_uri&.send(:scheme)
+  rescue StandardError => e
+    raise "Invalid source_uri object.\n #{e.message}"
+  end
+  if source_scheme == 'file'
+    read_from_file(source_uri)
+  elsif source_scheme =~ /^http(s)?$/
+    read_from_url(source_uri, source_format, http_handler)
+  else
+    raise 'Only local file and URL supported'
+  end
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #get_property(property_key, default_value = nil) ⇒ Object + + + + + +

+
+ +

Function to read propertied in the heirarchy define in Juno::Properties

+ + +
+
+
+

Parameters:

+
    + +
  • + + property_key + + + (String) + + + + — +
    +

    String key (required)

    +
    + +
  • + +
  • + + default_value + + + (optional) + + + (defaults to: nil) + + + — +
    +

    default value if property not found

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + + + + + +
    +

    Propert value. Returns default_value if property not found

    +
    + +
  • + +
+ +

See Also:

+ + +
+ + + + +
+
+
+
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+
+
# File 'lib/juno/Config/config_provider.rb', line 52
+
+def get_property(property_key, default_value = nil)
+  return default_value if property_key.to_s.empty?
+
+  value = configatron.to_h
+  property_key.to_s.split('.').each do |k|
+    return default_value unless value.is_a?(Hash) && value.key?(k.to_sym)
+
+    value = value[k.to_sym]
+    # puts "#{k} --- #{value}"
+  end
+
+  value.nil? || value.is_a?(Hash) ? default_value : value
+end
+
+
+ +
+

+ + #read_from_file(source_uri) ⇒ nil + + + + + +

+
+ +

Function to intialize configatron object from config file/URL

+ + +
+
+
+

Parameters:

+
    + +
  • + + source_uri + + + (URI) + + + + — +
    +

    Ruby URI Object for file or URL (required)

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (nil) + + + +
  • + +
+ +
+ + + + +
+
+
+
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+
+
# File 'lib/juno/Config/config_provider.rb', line 30
+
+def read_from_file(source_uri)
+  raise 'Config file not found' unless File.exist?(source_uri.path)
+
+  hsh = if ['.yml', '.yaml'].include?(File.extname(source_uri.path))
+          YAML.load_file(source_uri.path)
+        elsif ['.json'].inlcude?(File.extname(source_uri.path))
+          json_text = File.read(source_uri.path)
+          JSON.parse(json_text)
+        else
+          raise 'Unknown file format'
+        end
+  configatron.configure_from_hash(hsh)
+  nil
+end
+
+
+ +
+

+ + #read_from_url(source_uri, source_format, http_handler) ⇒ Object + + + + + +

+ + + + +
+
+
+
+45
+
+
# File 'lib/juno/Config/config_provider.rb', line 45
+
+def read_from_url(source_uri, source_format, http_handler); end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/ConfigReader.html b/client/Ruby/docs/Juno/ConfigReader.html new file mode 100644 index 0000000..df1a4d1 --- /dev/null +++ b/client/Ruby/docs/Juno/ConfigReader.html @@ -0,0 +1,1002 @@ + + + + + + + Class: Juno::ConfigReader + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::ConfigReader + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Config/config_reader.rb
+
+ +
+ +

Overview

+
+ +

Properties Reader - Properties to be read from the developer using Juno.configure Either file_path or url is required log device can be a filename or IO Object

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initializeConfigReader + + + + + +

+
+ +

Returns a new instance of ConfigReader.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+12
+13
+14
+15
+16
+17
+18
+
+
# File 'lib/juno/Config/config_reader.rb', line 12
+
+def initialize
+  # default values
+  @log_level = ::Logger::Severity::INFO
+  @max_log_file_bytes = 1_048_576 # default for inbuilt logger class
+  @log_device = $stdout
+  @log_rotation = 'daily' # daily, weekly, monthly
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #file_pathObject + + + + + +

+
+ +

Returns the value of attribute file_path.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def file_path
+  @file_path
+end
+
+
+ + + +
+

+ + #http_handlerObject + + + + + +

+
+ +

Returns the value of attribute http_handler.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def http_handler
+  @http_handler
+end
+
+
+ + + +
+

+ + #log_deviceObject + + + + + +

+
+ +

Returns the value of attribute log_device.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def log_device
+  @log_device
+end
+
+
+ + + +
+

+ + #log_fileObject + + + + + +

+
+ +

Returns the value of attribute log_file.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def log_file
+  @log_file
+end
+
+
+ + + +
+

+ + #log_levelObject + + + + + +

+
+ +

Returns the value of attribute log_level.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def log_level
+  @log_level
+end
+
+
+ + + +
+

+ + #log_rotationObject + + + + + +

+
+ +

Returns the value of attribute log_rotation.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def log_rotation
+  @log_rotation
+end
+
+
+ + + +
+

+ + #max_log_file_bytesObject + + + + + +

+
+ +

Returns the value of attribute max_log_file_bytes.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def max_log_file_bytes
+  @max_log_file_bytes
+end
+
+
+ + + +
+

+ + #source_formatObject + + + + + +

+
+ +

Returns the value of attribute source_format.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def source_format
+  @source_format
+end
+
+
+ + + +
+

+ + #ssl_cert_fileObject + + + + + +

+
+ +

Returns the value of attribute ssl_cert_file.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def ssl_cert_file
+  @ssl_cert_file
+end
+
+
+ + + +
+

+ + #ssl_key_fileObject + + + + + +

+
+ +

Returns the value of attribute ssl_key_file.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def ssl_key_file
+  @ssl_key_file
+end
+
+
+ + + +
+

+ + #urlObject + + + + + +

+
+ +

Returns the value of attribute url.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/Config/config_reader.rb', line 9
+
+def url
+  @url
+end
+
+
+ +
+ + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/DefaultProperties.html b/client/Ruby/docs/Juno/DefaultProperties.html new file mode 100644 index 0000000..be59348 --- /dev/null +++ b/client/Ruby/docs/Juno/DefaultProperties.html @@ -0,0 +1,291 @@ + + + + + + + Class: Juno::DefaultProperties + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::DefaultProperties + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Config/default_properties.rb
+
+ +
+ +

Overview

+
+ +

Module containing constant default values for Properties

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
RESPONSE_TIMEOUT_MS = + +
+
200
+ +
CONNECTION_TIMEOUT_MS = + +
+
200
+ +
CONNECTION_POOLSIZE = + +
+
1
+ +
CONNECTION_LIFETIME_MS = + +
+
30_000
+ +
DEFAULT_LIFETIME_S = + +
+
259_200
+ +
MAX_RESPONSE_TIMEOUT_MS = +
+
+ +

Max for all above property

+ + +
+
+
+ + +
+
+
5000
+ +
MAX_CONNECTION_LIFETIME_MS = + +
+
30_000
+ +
MAX_CONNECTION_TIMEOUT_MS = + +
+
5000
+ +
MAX_KEY_SIZE_B = + +
+
128
+ +
MAX_VALUE_SIZE_B = + +
+
204_800
+ +
MAX_NAMESPACE_LENGTH = + +
+
64
+ +
MAX_CONNECTION_POOL_SIZE = + +
+
3
+ +
MAX_LIFETIME_S = + +
+
259_200
+ +
HOST = +
+
+ +

Required Properties

+ + +
+
+
+ + +
+
+
''
+ +
PORT = + +
+
0
+ +
APP_NAME = + +
+
''
+ +
RECORD_NAMESPACE = + +
+
''
+ +
CONFIG_PREFIX = +
+
+ +

optional Properties

+ + +
+
+
+ + +
+
+
''
+ +
USE_SSL = + +
+
true
+ +
RECONNECT_ON_FAIL = + +
+
false
+ +
USE_PAYLOAD_COMPRESSION = + +
+
false
+ +
OPERATION_RETRY = + +
+
false
+ +
BYPASS_LTM = + +
+
true
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO.html b/client/Ruby/docs/Juno/IO.html new file mode 100644 index 0000000..fbc7867 --- /dev/null +++ b/client/Ruby/docs/Juno/IO.html @@ -0,0 +1,227 @@ + + + + + + + Module: Juno::IO + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: Juno::IO + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/constants.rb,
+ lib/juno/IO/JunoMessage.rb,
lib/juno/IO/ProtocolHeader.rb,
lib/juno/IO/OperationMessage.rb,
lib/juno/IO/PayloadComponent.rb,
lib/juno/IO/MetadataComponent.rb,
lib/juno/IO/MetadataComponentTemplate.rb
+
+
+ +
+ +

Overview

+
+ +

Juno wire protocol consists of a 12-byte header. Depending on the type, the appropriate message payload follows the fixed header section. Following is the header protocol:

+ +
      | 0| 1| 2| 3| 4| 5| 6| 7| 0| 1| 2| 3| 4| 5| 6| 7| 0| 1| 2| 3| 4| 5| 6| 7| 0| 1| 2| 3| 4| 5| 6| 7|
+ byte |                      0|                      1|                      2|                      3|
+------+-----------------------+-----------------------+-----------------------+-----------------------+
+    0 | magic                                         | version               | message type flag     |
+      |                                               |                       +-----------------+-----+
+      |                                               |                       | type            | RQ  |
+------+-----------------------------------------------+-----------------------+-----------------+-----+
+    4 | message size                                                                                  |
+------+-----------------------------------------------------------------------------------------------+
+    8 | opaque                                                                                        |
+------+-----------------------------------------------------------------------------------------------+
+
+ +

Following is the detailed description of each field in the header:

+ +

offset name size (bytes) meaning 0 Magic 2 Magic number, used to identify Juno message.

+ +

'0x5050'

+ +

2 Version 1 Protocol version, current version is 1. 3 Message Type flag

+ +
1 	bit 0-5
+
+ +

Message Type

+ +

0: Operational Message

+ +

1: Admin Message

+ +

2: Cluster Control Message

+ +

bit 6-7 RQ flag

+ +

0: response

+ +

1: two way request

+ +

3: one way request

+ +

4 Message size 4 Specifies the length of the message 8 Opaque 4 The Opaque data set in the request will be copied back in the response Operational Message Client Info (ip, port, type, application name) Request Type: request or response Operation Type: Create, Get, Update, Delete Request Id Request Info (key, ttl, version, namespace) Payload data size Payload Response Info (status/error code, error string) Flag Before defining the details of the protocol for operational message, we need to review, and finalize somethings at page.

+ +

Operational Message Header

+ +
operational request header
+      |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
+ byte |              0|              1|              2|              3|
+------+---------------+---------------+---------------+---------------+
+    0 | opcode        |flag           | shard Id                      |
+      |               +-+-------------+                               |
+      |               |R|             |                               |
+------+---------------+-+-------------+-------------------------------+
+
+operational response header
+      |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
+ byte |              0|              1|              2|              3|
+------+---------------+---------------+---------------+---------------+
+    0 | opcode        |flag           | reserved      | status        |
+      |               +-+-------------+               |               |
+      |               |R|             |               |               |
+------+---------------+-+-------------+---------------+---------------+
+
+opcode:
+  0x00    Nop
+  0x01    Create
+  0x02    Get
+  0x03    Update
+  0x04    Set
+  0x05    Destroy
+  0x81    PrepareCreate
+  0x82    Read
+  0x83    PrepareUpdate
+  0x84    PrepareSet
+  0x85    PrepareDelete
+  0x86    Delete
+  0xC1    Commit
+  0xC2    Abort (Rollback)
+  0xC3    Repair
+  0xC4    MarkDelete
+  0xE1    Clone
+  0xFE    MockSetParam
+  oxFF    MockReSet
+
+ +

R:

+ +
1 if it is for replication
+
+ +

shard Id:

+ +
only meaning for request to SS
+
+ +

status:

+ +
1 byte, only meaningful for response
+
+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: CompressionType, JunoMessage, MetadataComponent, MetadataComponentTemplate, OffsetWidth, OperationMessage, PayloadComponent, PayloadType, ProtocolHeader + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/CompressionType.html b/client/Ruby/docs/Juno/IO/CompressionType.html new file mode 100644 index 0000000..7ccc89e --- /dev/null +++ b/client/Ruby/docs/Juno/IO/CompressionType.html @@ -0,0 +1,250 @@ + + + + + + + Class: Juno::IO::CompressionType + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::CompressionType + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/constants.rb
+
+ +
+ +

Overview

+
+ +

Class containing constants for CompressionType

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
None = + +
+
'None'
+ +
Snappy = + +
+
'Snappy'
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .valid?(compression_type) ⇒ Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+31
+32
+33
+34
+35
+36
+
+
# File 'lib/juno/IO/constants.rb', line 31
+
+def self.valid?(compression_type)
+  constants.each do |constant|
+    return true if const_get(constant) == compression_type
+  end
+  false
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/JunoMessage.html b/client/Ruby/docs/Juno/IO/JunoMessage.html new file mode 100644 index 0000000..7994ce1 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/JunoMessage.html @@ -0,0 +1,1860 @@ + + + + + + + Class: Juno::IO::JunoMessage + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::JunoMessage + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/JunoMessage.rb
+
+ +
+ +

Overview

+
+ +

JunoMessage containing all configuration required to create an operation message

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: OperationType + + +

+ + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initializeJunoMessage + + + + + +

+
+ +

Returns a new instance of JunoMessage.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 13
+
+def initialize
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  @operation_type = Juno::IO::JunoMessage::OperationType::NOP
+  @server_status = Juno::ServerStatus::SUCCESS
+  @compression_type = Juno::IO::CompressionType::None
+  @is_compressed = false
+  @compression_achieved = 0
+  @message_size = 0
+  @value = ''
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #app_nameObject + + + + + +

+
+ +

Returns the value of attribute app_name.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def app_name
+  @app_name
+end
+
+
+ + + +
+

+ + #compression_achievedObject + + + + + +

+
+ +

Returns the value of attribute compression_achieved.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def compression_achieved
+  @compression_achieved
+end
+
+
+ + + +
+

+ + #compression_typeObject + + + + + +

+
+ +

Returns the value of attribute compression_type.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def compression_type
+  @compression_type
+end
+
+
+ + + +
+

+ + #correlation_idObject + + + + + +

+
+ +

Returns the value of attribute correlation_id.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def correlation_id
+  @correlation_id
+end
+
+
+ + + +
+

+ + #creation_timeObject + + + + + +

+
+ +

Returns the value of attribute creation_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def creation_time
+  @creation_time
+end
+
+
+ + + +
+

+ + #expiration_timeObject + + + + + +

+
+ +

Returns the value of attribute expiration_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def expiration_time
+  @expiration_time
+end
+
+
+ + + +
+

+ + #expiryObject + + + + + +

+
+ +

Returns the value of attribute expiry.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def expiry
+  @expiry
+end
+
+
+ + + +
+

+ + #ipObject + + + + + +

+
+ +

Returns the value of attribute ip.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def ip
+  @ip
+end
+
+
+ + + +
+

+ + #is_compressedObject + + + + + +

+
+ +

Returns the value of attribute is_compressed.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def is_compressed
+  @is_compressed
+end
+
+
+ + + +
+

+ + #keyObject + + + + + +

+
+ +

Returns the value of attribute key.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def key
+  @key
+end
+
+
+ + + +
+

+ + #last_modificationObject + + + + + +

+
+ +

Returns the value of attribute last_modification.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def last_modification
+  @last_modification
+end
+
+
+ + + +
+

+ + #message_sizeObject + + + + + +

+
+ +

Returns the value of attribute message_size.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def message_size
+  @message_size
+end
+
+
+ + + +
+

+ + #namespaceObject + + + + + +

+
+ +

Returns the value of attribute namespace.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def namespace
+  @namespace
+end
+
+
+ + + +
+

+ + #operation_typeObject + + + + + +

+
+ +

Returns the value of attribute operation_type.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def operation_type
+  @operation_type
+end
+
+
+ + + +
+

+ + #originator_request_idObject + + + + + +

+
+ +

Returns the value of attribute originator_request_id.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def originator_request_id
+  @originator_request_id
+end
+
+
+ + + +
+

+ + #portObject + + + + + +

+
+ +

Returns the value of attribute port.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def port
+  @port
+end
+
+
+ + + +
+

+ + #request_handling_timeObject + + + + + +

+
+ +

Returns the value of attribute request_handling_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def request_handling_time
+  @request_handling_time
+end
+
+
+ + + +
+

+ + #request_start_timeObject + + + + + +

+
+ +

Returns the value of attribute request_start_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def request_start_time
+  @request_start_time
+end
+
+
+ + + +
+

+ + #request_uuidObject + + + + + +

+
+ +

Returns the value of attribute request_uuid.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def request_uuid
+  @request_uuid
+end
+
+
+ + + +
+

+ + #server_statusObject + + + + + +

+
+ +

Returns the value of attribute server_status.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def server_status
+  @server_status
+end
+
+
+ + + +
+

+ + #time_to_live_sObject + + + + + +

+
+ +

Returns the value of attribute time_to_live_s.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def time_to_live_s
+  @time_to_live_s
+end
+
+
+ + + +
+

+ + #valueObject + + + + + +

+
+ +

Returns the value of attribute value.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def value
+  @value
+end
+
+
+ + + +
+

+ + #versionObject + + + + + +

+
+ +

Returns the value of attribute version.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 7
+
+def version
+  @version
+end
+
+
+ +
+ + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/JunoMessage/OperationType.html b/client/Ruby/docs/Juno/IO/JunoMessage/OperationType.html new file mode 100644 index 0000000..2b42550 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/JunoMessage/OperationType.html @@ -0,0 +1,304 @@ + + + + + + + Class: Juno::IO::JunoMessage::OperationType + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::JunoMessage::OperationType + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/JunoMessage.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
NOP = + +
+
0
+ +
CREATE = + +
+
1
+ +
GET = + +
+
2
+ +
UPDATE = + +
+
3
+ +
SET = + +
+
4
+ +
DESTROY = + +
+
5
+ +
@@status_code_map = + +
+
nil
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .get(status_code) ⇒ Object + + + + + +

+ + + + +
+
+
+
+44
+45
+46
+47
+48
+49
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 44
+
+def self.get(status_code)
+  initialize_map if @@status_code_map.nil?
+  return @@status_code_map[status_code.to_i] if @@status_code_map.key?(status_code)
+
+  INTERNAL_ERROR
+end
+
+
+ +
+

+ + .initialize_mapObject + + + + + +

+ + + + +
+
+
+
+35
+36
+37
+38
+39
+40
+41
+42
+
+
# File 'lib/juno/IO/JunoMessage.rb', line 35
+
+def self.initialize_map
+  @@status_code_map = {}
+
+  constants.each do |const|
+    const_obj = const_get(const)
+    @@status_code_map[const_obj.to_i] = const_obj
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/MetadataComponent.html b/client/Ruby/docs/Juno/IO/MetadataComponent.html new file mode 100644 index 0000000..affccc6 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/MetadataComponent.html @@ -0,0 +1,2518 @@ + + + + + + + Class: Juno::IO::MetadataComponent + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::MetadataComponent + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/MetadataComponent.rb
+
+ +
+ +

Overview

+
+ +

Wrapper class for MetadataComponentTemplate

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: MetadataField, TagAndType + + +

+ + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initializeMetadataComponent + + + + + +

+
+ +

Returns a new instance of MetadataComponent.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+94
+95
+96
+97
+98
+99
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 94
+
+def initialize
+  @PROG_NAME = self.class.name
+  # @LOGGER = Juno::Logger.instance
+  # @metadata_field_list [Array<MetadataField>]
+  @metadata_field_list = []
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #app_nameObject (readonly) + + + + + +

+
+ +

Returns the value of attribute app_name.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def app_name
+  @app_name
+end
+
+
+ + + +
+

+ + #correlation_idObject (readonly) + + + + + +

+
+ +

Returns the value of attribute correlation_id.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def correlation_id
+  @correlation_id
+end
+
+
+ + + +
+

+ + #creation_timeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute creation_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def creation_time
+  @creation_time
+end
+
+
+ + + +
+

+ + #expiration_timeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute expiration_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def expiration_time
+  @expiration_time
+end
+
+
+ + + +
+

+ + #ipObject (readonly) + + + + + +

+
+ +

Returns the value of attribute ip.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def ip
+  @ip
+end
+
+
+ + + +
+

+ + #last_modificationObject (readonly) + + + + + +

+
+ +

Returns the value of attribute last_modification.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def last_modification
+  @last_modification
+end
+
+
+ + + +
+

+ + #metadata_field_listObject (readonly) + + + + + +

+
+ +

Returns the value of attribute metadata_field_list.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def 
+  @metadata_field_list
+end
+
+
+ + + +
+

+ + #originator_request_idObject (readonly) + + + + + +

+
+ +

Returns the value of attribute originator_request_id.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def originator_request_id
+  @originator_request_id
+end
+
+
+ + + +
+

+ + #portObject (readonly) + + + + + +

+
+ +

Returns the value of attribute port.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def port
+  @port
+end
+
+
+ + + +
+

+ + #request_handling_timeObject (readonly) + + + + + +

+
+ +

Returns the value of attribute request_handling_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def request_handling_time
+  @request_handling_time
+end
+
+
+ + + +
+

+ + #request_uuidObject (readonly) + + + + + +

+
+ +

Returns the value of attribute request_uuid.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def request_uuid
+  @request_uuid
+end
+
+
+ + + +
+

+ + #time_to_liveObject (readonly) + + + + + +

+
+ +

Returns the value of attribute time_to_live.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def time_to_live
+  @time_to_live
+end
+
+
+ + + +
+

+ + #versionObject (readonly) + + + + + +

+
+ +

Returns the value of attribute version.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+91
+92
+93
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 91
+
+def version
+  @version
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #add_field(field) ⇒ Object + + + + + +

+
+ +

Function to add feild to the list

+ + +
+
+
+

Parameters:

+
    + +
  • + + field + + + (MetadataField) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+202
+203
+204
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 202
+
+def add_field(field)
+  .push(field)
+end
+
+
+ +
+

+ + #num_bytesObject + + + + + +

+
+ +

function to calculate size of metadata component

+ + +
+
+
+ + +
+ + + + +
+
+
+
+207
+208
+209
+210
+211
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 207
+
+def num_bytes
+  io = StringIO.new
+  write(io)
+  io.size
+end
+
+
+ +
+

+ + #read(io) ⇒ Object + + + + + +

+
+ +

Function to de-serialize Component to buffer

+ + +
+
+
+

Parameters:

+
    + +
  • + + io + + + (StringIO) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 238
+
+def read(io)
+   = MetadataComponentTemplate.new
+  .read(io)
+
+  body_buffer = StringIO.new(.body)
+
+  ..each do |field|
+    case field.field_tag
+    when TagAndType::TimeToLive[:tag]
+      ttl_byte_string = body_buffer.read(1 << (1 + TagAndType::TimeToLive[:size_type]))
+      set_time_to_live(ttl_byte_string.unpack1(OffsetWidth.UINT32))
+
+    when TagAndType::Version[:tag]
+      version_byte_string = body_buffer.read(1 << (1 + TagAndType::Version[:size_type]))
+      set_version(version_byte_string.unpack1(OffsetWidth.UINT32))
+
+    when TagAndType::CreationTime[:tag]
+      creation_time_byte_string = body_buffer.read(1 << (1 + TagAndType::CreationTime[:size_type]))
+      set_creation_time(creation_time_byte_string.unpack1(OffsetWidth.UINT32))
+
+    when TagAndType::RequestUUID[:tag]
+      request_uuid_byte_string = body_buffer.read(1 << (1 + TagAndType::RequestUUID[:size_type]))
+      set_request_uuid(request_uuid_byte_string)
+
+    when TagAndType::SourceInfo[:tag]
+      source_info = MetadataComponentTemplate::SourceInfoField.new
+      source_info.read(body_buffer)
+      set_source_info(app_name: source_info.app_name, ip: IPAddr.new_ntoh(source_info.ip), port: source_info.port)
+
+    when TagAndType::LastModification[:tag]
+      last_modification_byte_string = body_buffer.read(1 << (1 + TagAndType::LastModification[:size_type]))
+      set_last_modification(last_modification_byte_string.unpack1(OffsetWidth.UINT64))
+
+    when TagAndType::ExpirationTime[:tag]
+      expiration_time_byte_string = body_buffer.read(1 << (1 + TagAndType::ExpirationTime[:size_type]))
+      set_expiration_time(expiration_time_byte_string.unpack1(OffsetWidth.UINT32))
+
+    when TagAndType::OriginatorRequestID[:tag]
+      originator_request_id_byte_string = body_buffer.read(1 << (1 + TagAndType::OriginatorRequestID[:size_type]))
+      set_originator_request_id(originator_request_id_byte_string)
+    # when TagAndType::CorrelationID[:tag]
+
+    when TagAndType::RequestHandlingTime[:tag]
+      request_handling_time_byte_string = body_buffer.read(1 << (1 + TagAndType::RequestHandlingTime[:size_type]))
+      set_request_handling_time(request_handling_time_byte_string.unpack1(OffsetWidth.UINT32))
+    end
+  end
+end
+
+
+ +
+

+ + #set_correlation_id(input_uuid_byte_string = nil) ⇒ Object + + + + + +

+
+ +

if not provided, creates a uuid itself

+ + +
+
+
+

Parameters:

+
    + +
  • + + input_uuid_byte_string + + + (String) + + + (defaults to: nil) + + + — +
    +

    (optional)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 180
+
+def set_correlation_id(input_uuid_byte_string = nil)
+  @correlation_id = if input_uuid_byte_string.nil?
+                      UUIDTools::UUID.random_create
+                    else
+                      UUIDTools::UUID.parse_raw(input_uuid_byte_string)
+                    end
+  field = MetadataComponentTemplate::CorrelationIDField.new
+  field.correlation_id = @correlation_id.raw
+  str_io = StringIO.new
+  field.write(str_io)
+  # puts field
+  add_field(MetadataField.new(0x09, 0x0, str_io.string))
+end
+
+
+ +
+

+ + #set_creation_time(data) ⇒ Object + + + + + +

+
+ + +
+
+
+

Parameters:

+
    + +
  • + + creation_time + + + (Integer) + + + + — +
    • +

      Unix timestamp (required)

      +
    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+119
+120
+121
+122
+123
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 119
+
+def set_creation_time(data)
+  @creation_time = data
+  creation_time_bytes_string = [data].pack(OffsetWidth.UINT32)
+  add_field(MetadataField.new(0x03, 0x01, creation_time_bytes_string))
+end
+
+
+ +
+

+ + #set_expiration_time(data) ⇒ Object + + + + + +

+ + + + +
+
+
+
+125
+126
+127
+128
+129
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 125
+
+def set_expiration_time(data)
+  @expiration_time = data
+  expiration_time_bytes_string = [data].pack(OffsetWidth.UINT32)
+  add_field(MetadataField.new(0x04, 0x01, expiration_time_bytes_string))
+end
+
+
+ +
+

+ + #set_last_modification(data) ⇒ Object + + + + + +

+ + + + +
+
+
+
+160
+161
+162
+163
+164
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 160
+
+def set_last_modification(data)
+  @last_modification = data
+  last_modification_bytes_string = [data].pack(OffsetWidth.UINT64)
+  add_field(MetadataField.new(0x07, 0x02, last_modification_bytes_string))
+end
+
+
+ +
+

+ + #set_originator_request_id(input_uuid_byte_string = nil) ⇒ Object + + + + + +

+
+ +

if not provided, creates a uuid itself

+ + +
+
+
+

Parameters:

+
    + +
  • + + input_uuid_byte_string + + + (String) + + + (defaults to: nil) + + + — +
    +

    (optional)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+168
+169
+170
+171
+172
+173
+174
+175
+176
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 168
+
+def set_originator_request_id(input_uuid_byte_string = nil)
+  @originator_request_id = if input_uuid_byte_string.nil?
+                             UUIDTools::UUID.random_create
+                           else
+                             UUIDTools::UUID.parse_raw(input_uuid_byte_string)
+                           end
+  add_field(MetadataField.new(0x08, 0x03, @originator_request_id.raw))
+  @originator_request_id
+end
+
+
+ +
+

+ + #set_request_handling_time(data) ⇒ Object + + + + + +

+ + + + +
+
+
+
+194
+195
+196
+197
+198
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 194
+
+def set_request_handling_time(data)
+  @request_handling_time = data
+  request_handling_time_bytes_string = [data].pack(OffsetWidth.UINT32)
+  add_field(MetadataField.new(0x0A, 0x01, request_handling_time_bytes_string))
+end
+
+
+ +
+

+ + #set_request_uuid(input_uuid_byte_string = nil) ⇒ Object + + + + + +

+
+ +

if not provided, creates a uuid itself

+ + +
+
+
+

Parameters:

+
    + +
  • + + input_uuid_byte_string + + + (String) + + + (defaults to: nil) + + + — +
    • +

      Record Time to live (optional)

      +
    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+133
+134
+135
+136
+137
+138
+139
+140
+141
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 133
+
+def set_request_uuid(input_uuid_byte_string = nil)
+  @request_uuid = if input_uuid_byte_string.nil?
+                    UUIDTools::UUID.random_create
+                  else
+                    UUIDTools::UUID.parse_raw(input_uuid_byte_string)
+                  end
+  add_field(MetadataField.new(0x05, 0x03, @request_uuid.raw))
+  @request_uuid
+end
+
+
+ +
+

+ + #set_source_info(app_name:, ip:, port:) ⇒ Object + + + + + +

+
+ +

SourceInfoField

+ + +
+
+
+

Parameters:

+
    + +
  • + + app_name + + + (String) + + + + — +
    • +

      Record Time to live (required)

      +
    +
    + +
  • + +
  • + + ip + + + (IPAddr) + + + + — +
    • +

      ip address for component (required)

      +
    +
    + +
  • + +
  • + + port + + + (Integer) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 147
+
+def set_source_info(app_name:, ip:, port:)
+  @ip = ip
+  @port = port
+  @app_name = app_name
+  data = MetadataComponentTemplate::SourceInfoField.new
+  data.app_name = app_name
+  data.ip = ip.hton
+  data.port = port
+  str_io = StringIO.new
+  data.write(str_io)
+  add_field(MetadataField.new(0x06, 0x00, str_io.string))
+end
+
+
+ +
+

+ + #set_time_to_live(ttl) ⇒ Object + + + + + +

+
+ + +
+
+
+

Parameters:

+
    + +
  • + + ttl + + + (Integer) + + + + — +
    • +

      Record Time to live

      +
    +
    + +
  • + +
+ +

Raises:

+
    + +
  • + + + (ArgumentError) + + + +
  • + +
+ +
+ + + + +
+
+
+
+102
+103
+104
+105
+106
+107
+108
+109
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 102
+
+def set_time_to_live(ttl)
+  ttl = ttl.to_i
+  raise ArgumentError, 'TTL should be > 0' unless ttl.positive?
+
+  @time_to_live = ttl
+  ttl = [ttl].pack(OffsetWidth.UINT32)
+  add_field(MetadataField.new(0x01, 0x01, ttl))
+end
+
+
+ +
+

+ + #set_version(data) ⇒ Object + + + + + +

+
+ + +
+
+
+

Parameters:

+
    + +
  • + + version + + + (Integer) + + + + — +
    • +

      Record version

      +
    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+112
+113
+114
+115
+116
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 112
+
+def set_version(data)
+  @version = data
+  version_bytes_string = [data].pack(OffsetWidth.UINT32)
+  add_field(MetadataField.new(0x02, 0x01, version_bytes_string))
+end
+
+
+ +
+

+ + #write(io) ⇒ Object + + + + + +

+
+ +

Function to serialize Component to buffer

+ + +
+
+
+

Parameters:

+
    + +
  • + + io + + + (StringIO) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 215
+
+def write(io)
+  buffer = MetadataComponentTemplate.new
+  buffer.number_of_fields = .length
+  .each do |field|
+    f = MetadataComponentTemplate::MetadataHeaderField.new
+    f.size_type = field.size_type
+    f.field_tag = field.tag
+    buffer..push(f)
+  end
+
+  body = StringIO.new
+  .each do |field|
+    body.write(field.data)
+  end
+  padding_size = (8 - body.size % 8) % 8
+  body.write(Array.new(0, padding_size).pack(OffsetWidth.UINT8('*'))) if padding_size.positive?
+  buffer.body = body.string
+
+  buffer.write(io)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/MetadataComponent/MetadataField.html b/client/Ruby/docs/Juno/IO/MetadataComponent/MetadataField.html new file mode 100644 index 0000000..7853e2a --- /dev/null +++ b/client/Ruby/docs/Juno/IO/MetadataComponent/MetadataField.html @@ -0,0 +1,514 @@ + + + + + + + Class: Juno::IO::MetadataComponent::MetadataField + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::MetadataComponent::MetadataField + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/MetadataComponent.rb
+
+ +
+ +

Overview

+
+ +

DataType for @metadata_field_list

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: SizeType + + +

+ + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(tag, size_type, data) ⇒ MetadataField + + + + + +

+
+ +

Returns a new instance of MetadataField.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+334
+335
+336
+337
+338
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 334
+
+def initialize(tag, size_type, data)
+  @tag = tag
+  @size_type = size_type
+  @data = data
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #dataObject + + + + + +

+
+ +

Returns the value of attribute data.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+332
+333
+334
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 332
+
+def data
+  @data
+end
+
+
+ + + +
+

+ + #size_typeObject + + + + + +

+
+ +

Returns the value of attribute size_type.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+332
+333
+334
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 332
+
+def size_type
+  @size_type
+end
+
+
+ + + +
+

+ + #tagObject + + + + + +

+
+ +

Returns the value of attribute tag.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+332
+333
+334
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 332
+
+def tag
+  @tag
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #sizeObject + + + + + +

+ + + + +
+
+
+
+340
+341
+342
+343
+344
+345
+346
+
+
# File 'lib/juno/IO/MetadataComponent.rb', line 340
+
+def size
+  if size_type == SizeType::Variable
+    data.length
+  else
+    1 << (size_type + 1)
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/MetadataComponent/MetadataField/SizeType.html b/client/Ruby/docs/Juno/IO/MetadataComponent/MetadataField/SizeType.html new file mode 100644 index 0000000..a866f48 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/MetadataComponent/MetadataField/SizeType.html @@ -0,0 +1,137 @@ + + + + + + + Class: Juno::IO::MetadataComponent::MetadataField::SizeType + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::MetadataComponent::MetadataField::SizeType + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/MetadataComponent.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
Variable = + +
+
0
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/MetadataComponent/TagAndType.html b/client/Ruby/docs/Juno/IO/MetadataComponent/TagAndType.html new file mode 100644 index 0000000..bfa6938 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/MetadataComponent/TagAndType.html @@ -0,0 +1,212 @@ + + + + + + + Class: Juno::IO::MetadataComponent::TagAndType + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::MetadataComponent::TagAndType + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/MetadataComponent.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
TimeToLive = + +
+
{
+  tag: 0x01,
+  size_type: 0x01
+}.freeze
+ +
Version = + +
+
{
+  tag: 0x02,
+  size_type: 0x01
+}.freeze
+ +
CreationTime = + +
+
{
+  tag: 0x03,
+  size_type: 0x01
+}.freeze
+ +
RequestUUID = + +
+
{
+  tag: 0x05,
+  size_type: 0x03
+}.freeze
+ +
SourceInfo = + +
+
{
+  tag: 0x06,
+  size_type: 0x00
+}.freeze
+ +
ExpirationTime = + +
+
{
+  tag: 0x04,
+  size_type: 0x01
+}.freeze
+ +
LastModification = + +
+
{
+  tag: 0x07,
+  size_type: 0x02
+}.freeze
+ +
OriginatorRequestID = + +
+
{
+  tag: 0x08,
+  size_type: 0x03
+}.freeze
+ +
CorrelationID = + +
+
{
+  tag: 0x09,
+  size_type: 0x00
+}.freeze
+ +
RequestHandlingTime = + +
+
{
+  tag: 0x0A,
+  size_type: 0x01
+}.freeze
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/MetadataComponentTemplate.html b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate.html new file mode 100644 index 0000000..d1fb34e --- /dev/null +++ b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate.html @@ -0,0 +1,255 @@ + + + + + + + Class: Juno::IO::MetadataComponentTemplate + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::MetadataComponentTemplate + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/MetadataComponentTemplate.rb
+
+ +
+ +

Defined Under Namespace

+

+ + + + + Classes: CorrelationIDField, FixedLengthField, MetadataHeaderField, SourceInfoField + + +

+ + + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + +
+

Instance Method Details

+ + +
+

+ + #header_num_bytesObject + + + + + +

+ + + + +
+
+
+
+52
+53
+54
+
+
# File 'lib/juno/IO/MetadataComponentTemplate.rb', line 52
+
+def header_num_bytes
+  component_size.num_bytes + tag_id.num_bytes + number_of_fields.num_bytes + .num_bytes
+end
+
+
+ +
+

+ + #header_padding_lengthObject + + + + + +

+ + + + +
+
+
+
+56
+57
+58
+
+
# File 'lib/juno/IO/MetadataComponentTemplate.rb', line 56
+
+def header_padding_length
+  (4 - header_num_bytes % 4) % 4
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/CorrelationIDField.html b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/CorrelationIDField.html new file mode 100644 index 0000000..ea32bd9 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/CorrelationIDField.html @@ -0,0 +1,195 @@ + + + + + + + Class: Juno::IO::MetadataComponentTemplate::CorrelationIDField + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::MetadataComponentTemplate::CorrelationIDField + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/MetadataComponentTemplate.rb
+
+ +
+ + + + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + +
+

Instance Method Details

+ + +
+

+ + #padding_sizeObject + + + + + +

+ + + + +
+
+
+
+40
+41
+42
+43
+
+
# File 'lib/juno/IO/MetadataComponentTemplate.rb', line 40
+
+def padding_size
+  size = component_size.num_bytes + correlation_id_length.num_bytes + correlation_id.num_bytes
+  (4 - size % 4) % 4
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/FixedLengthField.html b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/FixedLengthField.html new file mode 100644 index 0000000..0afbca9 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/FixedLengthField.html @@ -0,0 +1,124 @@ + + + + + + + Class: Juno::IO::MetadataComponentTemplate::FixedLengthField + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::MetadataComponentTemplate::FixedLengthField + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/MetadataComponentTemplate.rb
+
+ +
+ + + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/MetadataHeaderField.html b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/MetadataHeaderField.html new file mode 100644 index 0000000..b173ae2 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/MetadataHeaderField.html @@ -0,0 +1,124 @@ + + + + + + + Class: Juno::IO::MetadataComponentTemplate::MetadataHeaderField + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::MetadataComponentTemplate::MetadataHeaderField + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/MetadataComponentTemplate.rb
+
+ +
+ + + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/SourceInfoField.html b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/SourceInfoField.html new file mode 100644 index 0000000..f1d8d8f --- /dev/null +++ b/client/Ruby/docs/Juno/IO/MetadataComponentTemplate/SourceInfoField.html @@ -0,0 +1,319 @@ + + + + + + + Class: Juno::IO::MetadataComponentTemplate::SourceInfoField + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::MetadataComponentTemplate::SourceInfoField + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/MetadataComponentTemplate.rb
+
+ +
+ + + + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + +
+

Instance Method Details

+ + +
+

+ + #field_bytesObject + + + + + +

+ + + + +
+
+
+
+18
+19
+20
+
+
# File 'lib/juno/IO/MetadataComponentTemplate.rb', line 18
+
+def field_bytes
+  field_length.num_bytes + app_name_length.num_bytes + port.num_bytes + ip.num_bytes + app_name.num_bytes
+end
+
+
+ +
+

+ + #ipv6?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+26
+27
+28
+
+
# File 'lib/juno/IO/MetadataComponentTemplate.rb', line 26
+
+def ipv6?
+  IPAddr.new_ntoh(ip).ipv6?
+end
+
+
+ +
+

+ + #padding_sizeObject + + + + + +

+ + + + +
+
+
+
+22
+23
+24
+
+
# File 'lib/juno/IO/MetadataComponentTemplate.rb', line 22
+
+def padding_size
+  (4 - field_bytes % 4) % 4
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/OffsetWidth.html b/client/Ruby/docs/Juno/IO/OffsetWidth.html new file mode 100644 index 0000000..9ac361e --- /dev/null +++ b/client/Ruby/docs/Juno/IO/OffsetWidth.html @@ -0,0 +1,359 @@ + + + + + + + Class: Juno::IO::OffsetWidth + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::OffsetWidth + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/constants.rb
+
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .UINT16(count = '') ⇒ Object + + + + + +

+ + + + +
+
+
+
+17
+18
+19
+
+
# File 'lib/juno/IO/constants.rb', line 17
+
+def self.UINT16(count = '')
+  "n#{count}"
+end
+
+
+ +
+

+ + .UINT32(count = '') ⇒ Object + + + + + +

+ + + + +
+
+
+
+13
+14
+15
+
+
# File 'lib/juno/IO/constants.rb', line 13
+
+def self.UINT32(count = '')
+  "N#{count}"
+end
+
+
+ +
+

+ + .UINT64(count = '') ⇒ Object + + + + + +

+
+ +

Count can be integer or '*'

+ + +
+
+
+ + +
+ + + + +
+
+
+
+9
+10
+11
+
+
# File 'lib/juno/IO/constants.rb', line 9
+
+def self.UINT64(count = '')
+  "Q#{count}"
+end
+
+
+ +
+

+ + .UINT8(count = '') ⇒ Object + + + + + +

+ + + + +
+
+
+
+21
+22
+23
+
+
# File 'lib/juno/IO/constants.rb', line 21
+
+def self.UINT8(count = '')
+  "C#{count}"
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/OperationMessage.html b/client/Ruby/docs/Juno/IO/OperationMessage.html new file mode 100644 index 0000000..8d770e3 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/OperationMessage.html @@ -0,0 +1,716 @@ + + + + + + + Class: Juno::IO::OperationMessage + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::OperationMessage + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/OperationMessage.rb
+
+ +
+ + + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initializeOperationMessage + + + + + +

+
+ +

Returns a new instance of OperationMessage.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+8
+9
+10
+11
+12
+
+
# File 'lib/juno/IO/OperationMessage.rb', line 8
+
+def initialize
+  @protocol_header = ProtocolHeader.new
+  @metadata_component = nil
+  @payload_component = nil
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #metadata_componentObject + + + + + +

+
+ +

Returns the value of attribute metadata_component.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+6
+7
+8
+
+
# File 'lib/juno/IO/OperationMessage.rb', line 6
+
+def 
+  @metadata_component
+end
+
+
+ + + +
+

+ + #payload_componentObject + + + + + +

+
+ +

Returns the value of attribute payload_component.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+6
+7
+8
+
+
# File 'lib/juno/IO/OperationMessage.rb', line 6
+
+def payload_component
+  @payload_component
+end
+
+
+ + + +
+

+ + #protocol_headerObject + + + + + +

+
+ +

Returns the value of attribute protocol_header.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+6
+7
+8
+
+
# File 'lib/juno/IO/OperationMessage.rb', line 6
+
+def protocol_header
+  @protocol_header
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #read(io) ⇒ Object + + + + + +

+
+ +

Function to de-serialize message to buffer

+ + +
+
+
+

Parameters:

+
    + +
  • + + io + + + (StringIO) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+
+
# File 'lib/juno/IO/OperationMessage.rb', line 35
+
+def read(io)
+  return if io.eof? || (io.size - io.pos) < 16
+
+  @protocol_header = ProtocolHeader.new
+  @metadata_component = MetadataComponent.new
+  @payload_component = PayloadComponent.new
+
+  @protocol_header.read(io)
+
+  remaining_size = protocol_header.message_size - 16
+  prev_position = io.pos
+
+  @metadata_component.read(io) if !io.eof? && (io.size - io.pos) >= remaining_size
+
+  remaining_size -= (io.pos - prev_position)
+
+  @payload_component.read(io) if !io.eof? && (io.size - io.pos) >= remaining_size
+  nil
+end
+
+
+ +
+

+ + #sizeObject + + + + + +

+
+ +

Calculates size of message

+ + +
+
+
+ + +
+ + + + +
+
+
+
+15
+16
+17
+18
+19
+20
+
+
# File 'lib/juno/IO/OperationMessage.rb', line 15
+
+def size
+  total_size = protocol_header.num_bytes
+  total_size += payload_component.num_bytes unless payload_component.nil?
+  total_size += .num_bytes unless .nil?
+  total_size
+end
+
+
+ +
+

+ + #write(io) ⇒ Object + + + + + +

+
+ +

Function to serialize message to buffer

+ + +
+
+
+

Parameters:

+
    + +
  • + + io + + + (StringIO) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+24
+25
+26
+27
+28
+29
+30
+31
+
+
# File 'lib/juno/IO/OperationMessage.rb', line 24
+
+def write(io)
+  protocol_header.message_size = size
+
+  protocol_header.write(io)
+  &.write(io)
+  payload_component&.write(io)
+  nil
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/PayloadComponent.html b/client/Ruby/docs/Juno/IO/PayloadComponent.html new file mode 100644 index 0000000..65b8466 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/PayloadComponent.html @@ -0,0 +1,648 @@ + + + + + + + Class: Juno::IO::PayloadComponent + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::PayloadComponent + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/PayloadComponent.rb
+
+ +
+ +

Overview

+
+ +

** Payload (or KeyValue) Component **

+ +

A 12-byte header followed by name, key and value

+ +
Tag/ID: 0x01
+
+
  • +

    Header *

    + +
    |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
    +|              0|              1|              2|              3|
    +
    +
+ +

——---------------—————---------------—————+

+ +
0 | Size                                                          |
+
+ +

——---------------—————-------------------------------

+ +
4 | Tag/ID (0x01) | namespace len | key length                    |
+
+ +

——---------------—————-------------------------------

+ +
8 | payload length                                                |
+
+ +

——---------------------------------------------------------------

+ +
(
+ The max namespace length: 255
+ payload length = 0 if len(payload data) = 0, otherwise,
+ payload length = 1 + len(payload data) = len(payload field)
+)
+
+
  • +

    Body *

    +
+ +

---------—–---------------————————-+ |namespace| key | payload field | Padding to align 8-byte | ---------—–---------------————————-+

+
  • +

    Payload field*

    +
+ +

---------------------————–+ | 1 byte payload type | Payload data | ---------------------————–+

+
  • +

    Payload Type

    +
+ +

0: payload data is the actual value passed from client user 1: payload data is encrypted by Juno client library, details not specified 2: payload data is encrypted by Juno proxy with AES-GCM. encryption key length is 256 bits 3: Payload data is compressed by Juno Client library.

+
  • +

    Payload data

    +
+ +

for payload type 2 --------------------------------—————----------------- | 4 bytes encryption key version | 12 bytes nonce | encrypted data | --------------------------------—————-----------------

+ +

for payload type 3 ---------------------------------——————---------------- | 1 byte size of compression type | compression type | compressed data| ---------------------------------——————----------------

+
  • +

    compression type

    +
+ +

1) snappy (default algorithm) 2) TBD

+ + +
+
+
+ + +

Defined Under Namespace

+

+ + + + + Classes: CompressedPayloadData, EncryptedPayloadData, UncompressedPayloadData + + +

+ + + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + +
+

Instance Method Details

+ + +
+

+ + #compressed?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+154
+155
+156
+157
+158
+
+
# File 'lib/juno/IO/PayloadComponent.rb', line 154
+
+def compressed?
+  return true if payload_type == PayloadType::Compressed
+
+  false
+end
+
+
+ +
+

+ + #compression_typeObject + + + + + +

+ + + + +
+
+
+
+160
+161
+162
+163
+164
+
+
# File 'lib/juno/IO/PayloadComponent.rb', line 160
+
+def compression_type
+  return payload_data.compression_type if compressed?
+
+  CompressionType::None
+end
+
+
+ +
+

+ + #custom_num_bytesObject + + + + + +

+
+ +

to prevent stack overflow

+ + +
+
+
+ + +
+ + + + +
+
+
+
+103
+104
+105
+106
+107
+
+
# File 'lib/juno/IO/PayloadComponent.rb', line 103
+
+def custom_num_bytes
+  size = component_size.num_bytes + tag_id.num_bytes + namespace_length.num_bytes + key_length.num_bytes + payload_length.num_bytes + namespace.num_bytes + payload_key.num_bytes
+  size += payload_type.num_bytes + payload_data.num_bytes if payload_length.positive?
+  size
+end
+
+
+ +
+

+ + #get_payload_data_lengthObject + + + + + +

+ + + + +
+
+
+
+98
+99
+100
+
+
# File 'lib/juno/IO/PayloadComponent.rb', line 98
+
+def get_payload_data_length
+  (payload_length.positive? ? payload_length - 1 : 0)
+end
+
+
+ +
+

+ + #padding_lengthObject + + + + + +

+ + + + +
+
+
+
+109
+110
+111
+
+
# File 'lib/juno/IO/PayloadComponent.rb', line 109
+
+def padding_length
+  (8 - custom_num_bytes % 8) % 8
+end
+
+
+ +
+

+ + #set_value(input_value, compression_type = CompressionType::None) ⇒ Object + + + + + +

+ + + + +
+
+
+
+140
+141
+142
+143
+144
+145
+146
+147
+148
+
+
# File 'lib/juno/IO/PayloadComponent.rb', line 140
+
+def set_value(input_value, compression_type = CompressionType::None)
+  if compression_type != CompressionType::None
+    self.payload_type = PayloadType::Compressed
+    payload_data.compression_type = compression_type
+  else
+    self.payload_type = PayloadType::UnCompressed
+  end
+  payload_data.data = input_value
+end
+
+
+ +
+

+ + #valueObject + + + + + +

+ + + + +
+
+
+
+150
+151
+152
+
+
# File 'lib/juno/IO/PayloadComponent.rb', line 150
+
+def value
+  payload_data.data
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/PayloadComponent/CompressedPayloadData.html b/client/Ruby/docs/Juno/IO/PayloadComponent/CompressedPayloadData.html new file mode 100644 index 0000000..8f58a9d --- /dev/null +++ b/client/Ruby/docs/Juno/IO/PayloadComponent/CompressedPayloadData.html @@ -0,0 +1,193 @@ + + + + + + + Class: Juno::IO::PayloadComponent::CompressedPayloadData + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::PayloadComponent::CompressedPayloadData + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/PayloadComponent.rb
+
+ +
+ + + + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + +
+

Instance Method Details

+ + +
+

+ + #data_lengthObject + + + + + +

+ + + + +
+
+
+
+65
+66
+67
+
+
# File 'lib/juno/IO/PayloadComponent.rb', line 65
+
+def data_length
+  eval_parameter(:payload_data_length) - 1 - compression_type
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/PayloadComponent/EncryptedPayloadData.html b/client/Ruby/docs/Juno/IO/PayloadComponent/EncryptedPayloadData.html new file mode 100644 index 0000000..f2bb7e0 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/PayloadComponent/EncryptedPayloadData.html @@ -0,0 +1,124 @@ + + + + + + + Class: Juno::IO::PayloadComponent::EncryptedPayloadData + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::PayloadComponent::EncryptedPayloadData + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/PayloadComponent.rb
+
+ +
+ + + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/PayloadComponent/UncompressedPayloadData.html b/client/Ruby/docs/Juno/IO/PayloadComponent/UncompressedPayloadData.html new file mode 100644 index 0000000..68f9f00 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/PayloadComponent/UncompressedPayloadData.html @@ -0,0 +1,142 @@ + + + + + + + Class: Juno::IO::PayloadComponent::UncompressedPayloadData + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::PayloadComponent::UncompressedPayloadData + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/PayloadComponent.rb
+
+ +
+ +

Overview

+
+ +

encrypted_payload_data PayloadType::Encrypted, payload_data_length: lambda {

+ +
                                                                        get_payload_data_length
+                                                                      }
+end
+
+ +

end

+ + +
+
+
+ + +
+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/PayloadType.html b/client/Ruby/docs/Juno/IO/PayloadType.html new file mode 100644 index 0000000..e620dfe --- /dev/null +++ b/client/Ruby/docs/Juno/IO/PayloadType.html @@ -0,0 +1,158 @@ + + + + + + + Class: Juno::IO::PayloadType + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::PayloadType + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/constants.rb
+
+ +
+ +

Overview

+
+ +

Class containing constants for PayloadType

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
UnCompressed = + +
+
0x00
+ +
Encrypted = + +
+
0x02
+ +
Compressed = + +
+
0x03
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/ProtocolHeader.html b/client/Ruby/docs/Juno/IO/ProtocolHeader.html new file mode 100644 index 0000000..5a97317 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/ProtocolHeader.html @@ -0,0 +1,329 @@ + + + + + + + Class: Juno::IO::ProtocolHeader + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::ProtocolHeader + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/ProtocolHeader.rb
+
+ +
+ +

Defined Under Namespace

+

+ + + + + Classes: MessageTypeFlag, MessageTypes, OpCodes, RequestTypes + + +

+ + + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + + +
+

Instance Method Details

+ + +
+

+ + #message_typeObject + + + + + +

+ + + + +
+
+
+
+176
+177
+178
+
+
# File 'lib/juno/IO/ProtocolHeader.rb', line 176
+
+def message_type
+  message_type_flag.message_type
+end
+
+
+ +
+

+ + #request?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+155
+156
+157
+
+
# File 'lib/juno/IO/ProtocolHeader.rb', line 155
+
+def request?
+  message_type_flag.message_request_type != RequestTypes::Response
+end
+
+
+ +
+

+ + #request_typeObject + + + + + +

+ + + + +
+
+
+
+172
+173
+174
+
+
# File 'lib/juno/IO/ProtocolHeader.rb', line 172
+
+def request_type
+  message_type_flag.message_request_type
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/ProtocolHeader/MessageTypeFlag.html b/client/Ruby/docs/Juno/IO/ProtocolHeader/MessageTypeFlag.html new file mode 100644 index 0000000..0063eb4 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/ProtocolHeader/MessageTypeFlag.html @@ -0,0 +1,124 @@ + + + + + + + Class: Juno::IO::ProtocolHeader::MessageTypeFlag + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::ProtocolHeader::MessageTypeFlag + + + +

+
+ +
+
Inherits:
+
+ BinData::Record + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/ProtocolHeader.rb
+
+ +
+ + + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/ProtocolHeader/MessageTypes.html b/client/Ruby/docs/Juno/IO/ProtocolHeader/MessageTypes.html new file mode 100644 index 0000000..8c1bf0b --- /dev/null +++ b/client/Ruby/docs/Juno/IO/ProtocolHeader/MessageTypes.html @@ -0,0 +1,147 @@ + + + + + + + Class: Juno::IO::ProtocolHeader::MessageTypes + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::ProtocolHeader::MessageTypes + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/ProtocolHeader.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
OperationalMessage = + +
+
0
+ +
AdminMessage = + +
+
1
+ +
ClusterControlMessage = + +
+
2
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/ProtocolHeader/OpCodes.html b/client/Ruby/docs/Juno/IO/ProtocolHeader/OpCodes.html new file mode 100644 index 0000000..59fe3e8 --- /dev/null +++ b/client/Ruby/docs/Juno/IO/ProtocolHeader/OpCodes.html @@ -0,0 +1,324 @@ + + + + + + + Class: Juno::IO::ProtocolHeader::OpCodes + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::ProtocolHeader::OpCodes + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/ProtocolHeader.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
Nop = + +
+
0x00
+ +
Create = + +
+
0x01
+ +
Get = + +
+
0x02
+ +
Update = + +
+
0x03
+ +
Set = + +
+
0x04
+ +
Destroy = + +
+
0x05
+ +
PrepareCreate = + +
+
0x81
+ +
Read = + +
+
0x82
+ +
PrepareUpdate = + +
+
0x83
+ +
PrepareSet = + +
+
0x84
+ +
PrepareDelete = + +
+
0x85
+ +
Delete = + +
+
0x86
+ +
Commit = + +
+
0xC1
+ +
Abort = + +
+
0xC2
+ +
Repair = + +
+
0xC3
+ +
MarkDelete = + +
+
0xC4
+ +
Clone = + +
+
0xE1
+ +
MockSetParam = + +
+
0xFE
+ +
MockReSet = + +
+
0xFF
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .valid?(opcode) ⇒ Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+142
+143
+144
+145
+146
+147
+
+
# File 'lib/juno/IO/ProtocolHeader.rb', line 142
+
+def self.valid?(opcode)
+  constants.each do |constant|
+    return true if const_get(constant) == opcode
+  end
+  false
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/IO/ProtocolHeader/RequestTypes.html b/client/Ruby/docs/Juno/IO/ProtocolHeader/RequestTypes.html new file mode 100644 index 0000000..d414bbf --- /dev/null +++ b/client/Ruby/docs/Juno/IO/ProtocolHeader/RequestTypes.html @@ -0,0 +1,147 @@ + + + + + + + Class: Juno::IO::ProtocolHeader::RequestTypes + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::IO::ProtocolHeader::RequestTypes + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/IO/ProtocolHeader.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
Response = + +
+
0
+ +
TwoWayRequest = + +
+
1
+ +
OneWayRequest = + +
+
2
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Logger.html b/client/Ruby/docs/Juno/Logger.html new file mode 100644 index 0000000..fee0785 --- /dev/null +++ b/client/Ruby/docs/Juno/Logger.html @@ -0,0 +1,307 @@ + + + + + + + Class: Juno::Logger + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Logger + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/logger.rb
+
+ +
+ +

Overview

+
+ +

DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
@@mutex = + +
+
Mutex.new
+ +
@@instance = +
+
+ +

Singleton instance

+ + +
+
+
+ + +
+
+
nil
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .instanceObject + + + + + +

+ + + + +
+
+
+
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+
+
# File 'lib/juno/logger.rb', line 12
+
+def self.instance
+  return @@instance unless @@instance.nil?
+
+  @@mutex.synchronize do
+    if @@instance.nil?
+      raise 'log file not configured' if Juno.juno_config.log_file.to_s.empty?
+
+      @@instance = ::Logger.new(Juno.juno_config.log_file, 'daily', progname: 'JunoRubyClient')
+
+      @@instance.level = ::Logger::INFO
+    end
+  end
+  @@instance
+end
+
+
+ +
+

+ + .level=(log_level) ⇒ Object + + + + + +

+ + + + +
+
+
+
+27
+28
+29
+
+
# File 'lib/juno/logger.rb', line 27
+
+def self.level=(log_level)
+  @@instance.level = log_level unless @@instance.nil?
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Net.html b/client/Ruby/docs/Juno/Net.html new file mode 100644 index 0000000..d9786d6 --- /dev/null +++ b/client/Ruby/docs/Juno/Net.html @@ -0,0 +1,117 @@ + + + + + + + Module: Juno::Net + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Module: Juno::Net + + + +

+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Net/worker_pool.rb,
+ lib/juno/Net/io_processor.rb,
lib/juno/Net/ping_message.rb,
lib/juno/Net/request_queue.rb,
lib/juno/Net/base_processor.rb,
lib/juno/Net/client_handler.rb
+
+
+ +
+ +

Defined Under Namespace

+

+ + + + + Classes: BaseProcessor, ClientHandler, IOProcessor, PingMessage, QueueEntry, RequestQueue, WorkerPool + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Net/BaseProcessor.html b/client/Ruby/docs/Juno/Net/BaseProcessor.html new file mode 100644 index 0000000..f7a608b --- /dev/null +++ b/client/Ruby/docs/Juno/Net/BaseProcessor.html @@ -0,0 +1,404 @@ + + + + + + + Class: Juno::Net::BaseProcessor + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Net::BaseProcessor + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Net/base_processor.rb
+
+ +
+ +

Overview

+
+ +

BaseProcessor - base class for IOProcessor Handles logic for reading and writing ping_ip for bypass ltm

+ + +
+
+
+ + +
+

Direct Known Subclasses

+

IOProcessor

+
+ + + + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(_ = nil) ⇒ BaseProcessor + + + + + +

+
+ +

Returns a new instance of BaseProcessor.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+8
+9
+10
+
+
# File 'lib/juno/Net/base_processor.rb', line 8
+
+def initialize(_ = nil)
+  @ping_queue = SizedQueue.new(1)
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #clear_ping_queueObject + + + + + +

+ + + + +
+
+
+
+32
+33
+34
+
+
# File 'lib/juno/Net/base_processor.rb', line 32
+
+def clear_ping_queue
+  @ping_queue.clear
+end
+
+
+ +
+

+ + #ping_ipObject + + + + + +

+ + + + +
+
+
+
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+
+
# File 'lib/juno/Net/base_processor.rb', line 16
+
+def ping_ip
+  begin
+    ip = @ping_queue.pop(true)
+  rescue ThreadError
+    return nil
+  end
+
+  return nil if ip.to_s.empty?
+
+  begin
+    IPAddr.new(ip)
+  rescue StandardError
+    nil
+  end
+end
+
+
+ +
+

+ + #ping_ip=(ip) ⇒ Object + + + + + +

+ + + + +
+
+
+
+12
+13
+14
+
+
# File 'lib/juno/Net/base_processor.rb', line 12
+
+def ping_ip=(ip)
+  @ping_queue.push(ip)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Net/ClientHandler.html b/client/Ruby/docs/Juno/Net/ClientHandler.html new file mode 100644 index 0000000..bebd369 --- /dev/null +++ b/client/Ruby/docs/Juno/Net/ClientHandler.html @@ -0,0 +1,1143 @@ + + + + + + + Class: Juno::Net::ClientHandler + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Net::ClientHandler + + + +

+
+ +
+
Inherits:
+
+ EventMachine::Connection + +
    +
  • Object
  • + + + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Net/client_handler.rb
+
+ +
+ +

Overview

+
+ +

Hanldes connection creation and receiving data asynchronously Managed by EventMachine::Connection

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
@@recv_count = +
+
+ +

Constant to count messages received

+ + +
+
+
+ + +
+
+
Concurrent::AtomicFixnum.new(0)
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + + +
+

Constructor Details

+ +
+

+ + #initialize(io_processor) ⇒ ClientHandler + + + + + +

+
+ +

Constructor

+ + +
+
+
+

Parameters:

+ + + +
+ + + + +
+
+
+
+17
+18
+19
+20
+21
+22
+23
+24
+25
+
+
# File 'lib/juno/Net/client_handler.rb', line 17
+
+def initialize(io_processor)
+  super
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  @io_processor = io_processor
+  @channel = self
+  @connected = Concurrent::AtomicBoolean.new(false)
+  @ssl_connected = Concurrent::AtomicBoolean.new(false)
+end
+
+
+ +
+ + +
+

Class Method Details

+ + +
+

+ + .received_messagesObject + + + + + +

+ + + + +
+
+
+
+11
+12
+13
+
+
# File 'lib/juno/Net/client_handler.rb', line 11
+
+def self.received_messages
+  @@recv_count.value
+end
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #connection_completedObject + + + + + +

+
+ +

Called by EventMachine after TCP Connection estabilished

+ + +
+
+
+ + +
+ + + + +
+
+
+
+92
+93
+94
+95
+
+
# File 'lib/juno/Net/client_handler.rb', line 92
+
+def connection_completed
+  @connected.value = true
+  on_connection_completed unless use_ssl?
+end
+
+
+ +
+

+ + #is_connected?Boolean + + + + + +

+
+ +

method to check if channel is connected

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+
+
# File 'lib/juno/Net/client_handler.rb', line 55
+
+def is_connected?
+  if use_ssl?
+    return false if @ssl_connected.false?
+  elsif @connected.false?
+    return false
+  end
+
+  # get ip and port of server
+  # Socket.unpack_sockaddr_in(@channel.get_peername)
+  true
+rescue Exception => e
+  @LOGGER.error(@PROG_NAME) { e.message }
+  false
+end
+
+
+ +
+

+ + #on_connection_completedObject + + + + + +

+
+ +

Method called when TCP connection estabilished. If useSSL is true, it is called after a successfull ssl handshake

+ + +
+
+
+ + +
+ + + + +
+
+
+
+50
+51
+52
+
+
# File 'lib/juno/Net/client_handler.rb', line 50
+
+def on_connection_completed
+  # puts "completed #{Time.now}"
+end
+
+
+ +
+

+ + #post_initObject + + + + + +

+
+ +

Method called once for each instance of Juno::Net::ClientHandler at initialization

+ + +
+
+
+ + +
+ + + + +
+
+
+
+28
+29
+30
+
+
# File 'lib/juno/Net/client_handler.rb', line 28
+
+def post_init
+  start_tls_connection if use_ssl?
+end
+
+
+ +
+

+ + #receive_data(data) ⇒ Object + + + + + +

+
+ +

method called by EventMachine when data is received from server

+ + +
+
+
+

Parameters:

+
    + +
  • + + data + + + (String) + + + + — +
    • +

      byte data received from server

      +
    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+
+
# File 'lib/juno/Net/client_handler.rb', line 80
+
+def receive_data(data)
+  @@recv_count.increment
+  # puts @@recv_count
+
+  EventMachine.defer do
+    operation_message = Juno::IO::OperationMessage.new
+    operation_message.read(StringIO.new(data))
+    @io_processor.put_response(operation_message)
+  end
+end
+
+
+ +
+

+ + #ssl_handshake_completedObject + + + + + +

+
+ +

Called by EventMachine after ssl handshake

+ + +
+
+
+ + +
+ + + + +
+
+
+
+106
+107
+108
+109
+110
+111
+112
+113
+
+
# File 'lib/juno/Net/client_handler.rb', line 106
+
+def ssl_handshake_completed
+  @ssl_connected.value = true
+  on_connection_completed if use_ssl?
+
+  # puts get_cipher_name
+  # puts get_cipher_protocol
+  @server_handshake_completed = true
+end
+
+
+ +
+

+ + #start_tls_connectionObject + + + + + +

+
+ +

starts tls connection once TCP connection is estabilished

+ + +
+
+
+ + +
+ + + + +
+
+
+
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+
+
# File 'lib/juno/Net/client_handler.rb', line 33
+
+def start_tls_connection
+  raise 'SSL Cert file not found' unless File.exist?(Juno.juno_config.ssl_cert_file)
+  raise 'SSL Key file not found' unless File.exist?(Juno.juno_config.ssl_key_file)
+
+  @channel.start_tls(
+    private_key_file: Juno.juno_config.ssl_key_file, cert: File.read(Juno.juno_config.ssl_cert_file)
+  )
+  # Timer to check if SSL Handshake was successful
+  EventMachine::Timer.new(Juno.juno_config.max_connection_timeout.to_f / 1000) do
+    if @ssl_connected.false?
+      puts 'SLL Handshake timeout'
+      close_connection
+    end
+  end
+end
+
+
+ +
+

+ + #unbind(error) ⇒ Object + + + + + +

+
+ +

Called by EventMachine after connection disconnected

+ + +
+
+
+

Parameters:

+
    + +
  • + + m + + + + + + + — +
    • +

      Error if disconnected due to an error

      +
    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+99
+100
+101
+102
+103
+
+
# File 'lib/juno/Net/client_handler.rb', line 99
+
+def unbind(error)
+  @connected.value = false
+  @ssl_connected.value = false
+  puts error unless error.nil?
+end
+
+
+ +
+

+ + #use_ltm?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+74
+75
+76
+
+
# File 'lib/juno/Net/client_handler.rb', line 74
+
+def use_ltm?
+  Juno.juno_config.bypass_ltm
+end
+
+
+ +
+

+ + #use_ssl?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+70
+71
+72
+
+
# File 'lib/juno/Net/client_handler.rb', line 70
+
+def use_ssl?
+  Juno.juno_config.use_ssl
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Net/IOProcessor.html b/client/Ruby/docs/Juno/Net/IOProcessor.html new file mode 100644 index 0000000..8201fc6 --- /dev/null +++ b/client/Ruby/docs/Juno/Net/IOProcessor.html @@ -0,0 +1,1536 @@ + + + + + + + Class: Juno::Net::IOProcessor + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Net::IOProcessor + + + +

+
+ +
+
Inherits:
+
+ BaseProcessor + + + show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Net/io_processor.rb
+
+ +
+ +

Overview

+
+ +

Module to handle connections to server, reading/writing requests from request queue

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
INITIAL_BYPASSLTM_RETRY_INTERVAL = + +
+
337_500
+ +
MAX_BYPASSLTM_RETRY_INTERVAL = + +
+
86_400_000
+ +
INIT_WAIT_TIME = + +
+
200
+ +
MAX_WAIT_TIME = + +
+
60_000
+ +
@@counter = +
+
+ +

class variable to count messages sent using send_data

+ + +
+
+
+ + +
+
+
Concurrent::AtomicFixnum.new(0)
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + + + + + + + + + + +

Methods inherited from BaseProcessor

+

#clear_ping_queue, #ping_ip, #ping_ip=

+
+

Constructor Details

+ +
+

+ + #initialize(request_queue, opaque_resp_queue_map) ⇒ IOProcessor + + + + + +

+
+ +

Returns a new instance of IOProcessor.

+ + +
+
+
+

Parameters:

+
    + +
  • + + request_queue + + + (Juno::Net::RequestQueue) + + + +
  • + +
  • + + opaque_resp_queue_map + + + (Concurrent::Map) + + + + — +
    • +

      map containing opaque as key and value as Response queue corresponding to opaque

      +
    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+
+
# File 'lib/juno/Net/io_processor.rb', line 20
+
+def initialize(request_queue, opaque_resp_queue_map)
+  super()
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  @stop = false
+  @request_queue = request_queue
+  @opaque_resp_queue_map = opaque_resp_queue_map
+  @ctx = nil ## changed
+  @handshake_failed_attempts = 0
+  @reconnect_wait_time = INIT_WAIT_TIME
+  @shift = 5 # seconds
+  @next_bypass_ltm_check_time = Time.now
+  @bypass_ltm_retry_interval = INITIAL_BYPASSLTM_RETRY_INTERVAL
+  # @config = config
+  @channel = nil
+  @next_reconnect_due = Float::INFINITY
+end
+
+
+ +
+ + +
+

Class Method Details

+ + +
+

+ + .send_countObject + + + + + +

+ + + + +
+
+
+
+14
+15
+16
+
+
# File 'lib/juno/Net/io_processor.rb', line 14
+
+def self.send_count
+  @@counter.value
+end
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #bypass_ltm_disabled?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+202
+203
+204
+205
+206
+207
+208
+
+
# File 'lib/juno/Net/io_processor.rb', line 202
+
+def bypass_ltm_disabled?
+  if Time.now > @next_bypass_ltm_check_time && @bypass_ltm_retry_interval < MAX_BYPASSLTM_RETRY_INTERVAL
+    return false
+  end
+
+  true
+end
+
+
+ +
+

+ + #connection_lifetimeObject + + + + + +

+ + + + +
+
+
+
+38
+39
+40
+
+
# File 'lib/juno/Net/io_processor.rb', line 38
+
+def connection_lifetime
+  Juno.juno_config.connection_lifetime
+end
+
+
+ +
+

+ + #disconnect_channel(channel) ⇒ Object + + + + + +

+ + + + +
+
+
+
+63
+64
+65
+66
+67
+
+
# File 'lib/juno/Net/io_processor.rb', line 63
+
+def disconnect_channel(channel)
+  EventMachine::Timer.new(2 * Juno.juno_config.max_response_timeout.to_f / 1000) do
+    channel&.close_connection_after_writing if !channel.nil? && channel.is_connected?
+  end
+end
+
+
+ +
+

+ + #hostObject + + + + + +

+ + + + +
+
+
+
+190
+191
+192
+
+
# File 'lib/juno/Net/io_processor.rb', line 190
+
+def host
+  Juno.juno_config.host
+end
+
+
+ +
+

+ + #initiate_bypass_ltmObject + + + + + +

+ + + + +
+
+
+
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+
+
# File 'lib/juno/Net/io_processor.rb', line 75
+
+def initiate_bypass_ltm
+  send_ping_message
+  EventMachine::Timer.new(Juno.juno_config.response_timeout.to_f / 1000) do
+    ip = ping_ip
+    unless ip.nil?
+      new_channel = EventMachine.connect(ip.to_s, Juno.juno_config.port, ClientHandler, self)
+      EventMachine::Timer.new(Juno.juno_config.connection_timeout.to_f / 1000) do
+        if new_channel.is_connected?
+          @LOGGER.info(@PROG_NAME) { "conncected to Proxy #{ip}:#{Juno.juno_config.port} " }
+          old_channel = @channel
+          @channel = new_channel
+          disconnect_channel(old_channel)
+        else
+          @LOGGER.info(@PROG_NAME) { "could not conncect to Proxy #{ip}:#{Juno.juno_config.port} " }
+        end
+      end
+    end
+  end
+end
+
+
+ +
+

+ + #juno_connect(recycle = false) ⇒ Object + + + + + +

+
+ +

Method to handle connections creation, re-attempts on failure, initiates connection refresh and connection to Proxy

+ + +
+
+
+

Parameters:

+
    + +
  • + + recycle + + + (Boolean) + + + (defaults to: false) + + + — +
    • +

      True if connection refresh request (optional, default: false)

      +
    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+
+
# File 'lib/juno/Net/io_processor.rb', line 107
+
+def juno_connect(recycle = false)
+  return if !recycle && !@channel.nil? && @channel.is_connected?
+
+  new_channel = EventMachine.connect(Juno.juno_config.host, Juno.juno_config.port, ClientHandler, self)
+  new_channel.pending_connect_timeout = Juno.juno_config.connection_lifetime
+  EventMachine::Timer.new(Juno.juno_config.connection_timeout.to_f / 1000) do
+    if new_channel.is_connected?
+      @LOGGER.info(@PROG_NAME) { "conncected to #{Juno.juno_config.host}:#{Juno.juno_config.port} " }
+      if recycle
+        old_channel = @channel
+        @channel = new_channel
+        disconnect_channel(old_channel)
+      else
+        @channel = new_channel
+      end
+      initiate_bypass_ltm if use_ltm?
+      set_recycle_timer
+    else
+      @recycle_timer&.cancel
+      new_channel&.close_connection if !new_channel.nil? && new_channel.is_connected?
+      @LOGGER.info(@PROG_NAME) do
+        "Could not conncect to #{Juno.juno_config.host}:#{Juno.juno_config.port}\n Retrying in #{@reconnect_wait_time.to_f / 1000}ms "
+      end
+      EventMachine::Timer.new(@reconnect_wait_time.to_f / 1000) do
+        @reconnect_wait_time *= 2
+        @reconnect_wait_time = MAX_WAIT_TIME if @reconnect_wait_time > MAX_WAIT_TIME
+        @reconnect_wait_time *= (1 + 0.3 * rand)
+        juno_connect(recycle)
+      end
+    end
+  end
+end
+
+
+ +
+

+ + #portObject + + + + + +

+ + + + +
+
+
+
+194
+195
+196
+
+
# File 'lib/juno/Net/io_processor.rb', line 194
+
+def port
+  Juno.juno_config.port
+end
+
+
+ +
+

+ + #put_response(operation_message) ⇒ Object + + + + + +

+ + + + +
+
+
+
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+
+
# File 'lib/juno/Net/io_processor.rb', line 42
+
+def put_response(operation_message)
+  return if operation_message.nil?
+
+  unless Juno::Net::PingMessage.ping_response?(operation_message, self)
+    opaque = operation_message&.protocol_header&.opaque
+    return if opaque.nil?
+
+    resp_queue = @opaque_resp_queue_map.get_and_set(opaque.to_i, nil)
+    if !resp_queue.nil?
+      begin
+        resp_queue.push(operation_message)
+      rescue ThreadError
+        @LOGGER.debug(@PROG_NAME) { "response queue for #{opaque.to_i} is full" }
+      end
+    else
+      @LOGGER.debug(@PROG_NAME) { "resp_queue nil for #{opaque.to_i}" }
+    end
+  end
+  nil
+end
+
+
+ +
+

+ + #reset_connectionsObject + + + + + +

+ + + + +
+
+
+
+181
+182
+183
+184
+
+
# File 'lib/juno/Net/io_processor.rb', line 181
+
+def reset_connections
+  @recycle_timer&.cancel
+  disconnect_channel(@channel)
+end
+
+
+ +
+

+ + #runObject + + + + + +

+
+ +

Event loop to continously check for requests in @request_queue

+ + +
+
+
+ + +
+ + + + +
+
+
+
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+
+
# File 'lib/juno/Net/io_processor.rb', line 145
+
+def run
+  EventMachine.run do
+    juno_connect
+    EventMachine.tick_loop do
+      if !@channel.nil? && @channel.is_connected?
+        # key = "19key#{rand(100) + rand(1_000_000)}"
+        item = @request_queue.pop
+        unless item.nil?
+          @@counter.increment
+          @channel.send_data(item.msg_buffer)
+        end
+      end
+      :stop if @stop == true
+    rescue Exception => e
+      @LOGGER.error(@PROG_NAME) do
+        "Error in tick_loop: #{e.message}. Stopping tick_loop"
+      end
+      :stop
+    end.on_stop do
+      @LOGGER.debug(@PROG_NAME) do
+        "tick loop stopped. Stop initiated by client #{@stop}"
+      end
+      reset_connections
+      EventMachine::Timer.new(2 * Juno.juno_config.connection_timeout.to_f / 1000) do
+        EventMachine.stop
+      end
+    end
+  rescue Exception => e
+    @LOGGER.debug(@PROG_NAME) do
+      "EventMachine Fatal Exception #{e.message}"
+    end
+    reset_connections
+    EventMachine.stop
+  end
+end
+
+
+ +
+

+ + #send_ping_messageObject + + + + + +

+
+ +

Sends ping message to LoadBalancer to get ProxyIP

+ + +
+
+
+ + +

See Also:

+ + +
+ + + + +
+
+
+
+97
+98
+99
+100
+101
+102
+103
+
+
# File 'lib/juno/Net/io_processor.rb', line 97
+
+def send_ping_message
+  ping_message = Juno::Net::PingMessage.new
+  buff = StringIO.new
+  ping_message.write(buff)
+  request_uuid = ping_message&.operation_message&.&.request_uuid.to_s
+  @request_queue.push(buff.string, request_uuid)
+end
+
+
+ +
+

+ + #set_recycle_timerObject + + + + + +

+ + + + +
+
+
+
+69
+70
+71
+72
+73
+
+
# File 'lib/juno/Net/io_processor.rb', line 69
+
+def set_recycle_timer
+  @recycle_timer = EventMachine::Timer.new(Juno.juno_config.connection_lifetime.to_f / 1000) do
+    juno_connect(true)
+  end
+end
+
+
+ +
+

+ + #stopObject + + + + + +

+ + + + +
+
+
+
+140
+141
+142
+
+
# File 'lib/juno/Net/io_processor.rb', line 140
+
+def stop
+  @stop = true
+end
+
+
+ +
+

+ + #use_ltm?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+198
+199
+200
+
+
# File 'lib/juno/Net/io_processor.rb', line 198
+
+def use_ltm?
+  host != '127.0.0.1' && Juno.juno_config.bypass_ltm # boolean
+end
+
+
+ +
+

+ + #use_ssl?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+186
+187
+188
+
+
# File 'lib/juno/Net/io_processor.rb', line 186
+
+def use_ssl?
+  Juno.juno_config.use_ssl
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Net/PingMessage.html b/client/Ruby/docs/Juno/Net/PingMessage.html new file mode 100644 index 0000000..13ea337 --- /dev/null +++ b/client/Ruby/docs/Juno/Net/PingMessage.html @@ -0,0 +1,864 @@ + + + + + + + Class: Juno::Net::PingMessage + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Net::PingMessage + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Net/ping_message.rb
+
+ +
+ +

Overview

+
+ +

Module to Create/Decode Ping messages

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
JUNO_INTERNAL_APPNAME = +
+
+ +

Constant Internal app name to check for ping messages

+ + +
+
+
+ + +
+
+
'JunoInternal'
+ +
+ + + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(app_name = nil, opaque = 0) ⇒ PingMessage + + + + + +

+
+ +

Returns a new instance of PingMessage.

+ + +
+
+
+

Parameters:

+
    + +
  • + + operation_message + + + (Juno::IO::OperationMessage) + + + + — +
    +

    (optional, default: Juno::Net::PingMessage::JUNO_INTERNAL_APPNAME)

    +
    + +
  • + +
  • + + opaque + + + (Integer) + + + (defaults to: 0) + + + — +
    +

    (optional, default: 0)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+
+
# File 'lib/juno/Net/ping_message.rb', line 15
+
+def initialize(app_name = nil, opaque = 0)
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  app_name = JUNO_INTERNAL_APPNAME if app_name.to_s.empty?
+
+   = Juno::IO::MetadataComponent.new
+  .set_request_uuid
+  .set_source_info(app_name: app_name, ip: IPAddr.new(Juno::Utils.local_ips[0]), port: 0)
+
+  protocol_header = Juno::IO::ProtocolHeader.new
+  protocol_header.opcode = Juno::IO::ProtocolHeader::OpCodes::Nop
+  protocol_header.opaque = opaque
+
+  @operation_message = Juno::IO::OperationMessage.new
+  @operation_message. = 
+  @operation_message.protocol_header = protocol_header
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #operation_messageObject (readonly) + + + + + +

+
+ +

method to read the operation message

+ + +
+
+
+ + +
+ + + + +
+
+
+
+11
+12
+13
+
+
# File 'lib/juno/Net/ping_message.rb', line 11
+
+def operation_message
+  @operation_message
+end
+
+
+ +
+ + +
+

Class Method Details

+ + +
+

+ + .ping_response?(operation_message, processor) ⇒ Boolean + + + + + +

+
+ +

method to check if given operation message is a Ping response Updates ping_ip in processor if it is a ping response

+ + +
+
+
+

Parameters:

+ + +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+
+
# File 'lib/juno/Net/ping_message.rb', line 37
+
+def self.ping_response?(operation_message, processor)
+  return false unless processor.use_ltm?
+
+  opcode = operation_message&.protocol_header&.opcode
+  raise 'missing protocol header' if opcode.nil?
+  return false if opcode != Juno::IO::ProtocolHeader::OpCodes::Nop
+  return false if operation_message&..nil?
+  return false if operation_message&.&.ip.to_s.empty?
+  return false if operation_message&.&.app_name != JUNO_INTERNAL_APPNAME
+
+  ping_ip = operation_message..ip.to_s
+  if ping_ip.split('.')[0] == '127'
+    processor.ping_ip = ''
+    return true
+  end
+  if Juno::Utils.local_ips.include?(ping_ip)
+    processor.ping_ip = ''
+    return true
+  end
+  processor.ping_ip = ping_ip
+  true
+end
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #ipObject + + + + + +

+
+ +

Function to read the ping ip

+ + +
+
+
+ + +
+ + + + +
+
+
+
+74
+75
+76
+
+
# File 'lib/juno/Net/ping_message.rb', line 74
+
+def ip
+  @operation_message&.&.ip
+end
+
+
+ +
+

+ + #portObject + + + + + +

+
+ +

Function to read the port from metadata component

+ + +
+
+
+ + +
+ + + + +
+
+
+
+79
+80
+81
+
+
# File 'lib/juno/Net/ping_message.rb', line 79
+
+def port
+  @operation_message&.&.port
+end
+
+
+ +
+

+ + #read(buf) ⇒ Object + + + + + +

+
+ +

Function to de-serialize Component from buffer

+ + +
+
+
+

Parameters:

+
    + +
  • + + buff + + + (StringIO) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+68
+69
+70
+71
+
+
# File 'lib/juno/Net/ping_message.rb', line 68
+
+def read(buf)
+  @operation_message = Juno::IO::OperationMessage.new
+  @operation_message.read(buf)
+end
+
+
+ +
+

+ + #write(buf) ⇒ Object + + + + + +

+
+ +

Function to serialize Component to buffer

+ + +
+
+
+

Parameters:

+
    + +
  • + + buff + + + (StringIO) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+62
+63
+64
+
+
# File 'lib/juno/Net/ping_message.rb', line 62
+
+def write(buf)
+  @operation_message.write(buf)
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Net/QueueEntry.html b/client/Ruby/docs/Juno/Net/QueueEntry.html new file mode 100644 index 0000000..849f02e --- /dev/null +++ b/client/Ruby/docs/Juno/Net/QueueEntry.html @@ -0,0 +1,475 @@ + + + + + + + Class: Juno::Net::QueueEntry + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Net::QueueEntry + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Net/request_queue.rb
+
+ +
+ +

Overview

+
+ +

DataType of each item in RequestQueue

+ + +
+
+
+ + +
+ + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(msg_buffer, id) ⇒ QueueEntry + + + + + +

+
+ +

Returns a new instance of QueueEntry.

+ + +
+
+
+

Parameters:

+
    + +
  • + + msg_bugger + + + (StringIO) + + + + — +
    +

    (required)

    +
    + +
  • + +
  • + + id + + + (String) + + + + — +
    • +

      request UUID (required)

      +
    +
    + +
  • + +
+ + +
+ + + + +
+
+
+
+11
+12
+13
+14
+15
+
+
# File 'lib/juno/Net/request_queue.rb', line 11
+
+def initialize(msg_buffer, id)
+  @msg_buffer = msg_buffer
+  @req_id = id
+  @enqueue_time = Time.now
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #enqueue_timeObject + + + + + +

+
+ +

Returns the value of attribute enqueue_time.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/Net/request_queue.rb', line 7
+
+def enqueue_time
+  @enqueue_time
+end
+
+
+ + + +
+

+ + #msg_bufferObject + + + + + +

+
+ +

Returns the value of attribute msg_buffer.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/Net/request_queue.rb', line 7
+
+def msg_buffer
+  @msg_buffer
+end
+
+
+ + + +
+

+ + #req_idObject + + + + + +

+
+ +

Returns the value of attribute req_id.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+7
+8
+9
+
+
# File 'lib/juno/Net/request_queue.rb', line 7
+
+def req_id
+  @req_id
+end
+
+
+ +
+ + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Net/RequestQueue.html b/client/Ruby/docs/Juno/Net/RequestQueue.html new file mode 100644 index 0000000..8bec365 --- /dev/null +++ b/client/Ruby/docs/Juno/Net/RequestQueue.html @@ -0,0 +1,826 @@ + + + + + + + Class: Juno::Net::RequestQueue + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Net::RequestQueue + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Net/request_queue.rb
+
+ +
+ +

Overview

+
+ +

Request queue - Singleton

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
@@mutex = +
+
+ +

mutex to synchronize creation of RequestQueue instance

+ + +
+
+
+ + +
+
+
Mutex.new
+ +
@@instance = +
+
+ +

Singleton instance

+ + +
+
+
+ + +
+
+
nil
+ +
+ + + + + +

Instance Attribute Summary collapse

+ + + + + + +

+ Class Method Summary + collapse +

+ + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initializeRequestQueue + + + + + +

+
+ +

Returns a new instance of RequestQueue.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+38
+39
+40
+41
+42
+43
+44
+45
+
+
# File 'lib/juno/Net/request_queue.rb', line 38
+
+def initialize
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  @size = 13_000 # Default request queue size
+  @request_queue = SizedQueue.new(@size)
+  @opaque_resp_queue_map = Concurrent::Map.new
+  @worker_pool = Juno::Net::WorkerPool.new(self)
+end
+
+
+ +
+ +
+

Instance Attribute Details

+ + + +
+

+ + #opaque_resp_queue_mapObject (readonly) + + + + + +

+
+ +

Returns the value of attribute opaque_resp_queue_map.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+36
+37
+38
+
+
# File 'lib/juno/Net/request_queue.rb', line 36
+
+def opaque_resp_queue_map
+  @opaque_resp_queue_map
+end
+
+
+ +
+ + +
+

Class Method Details

+ + +
+

+ + .instanceObject + + + + + +

+ + + + +
+
+
+
+26
+27
+28
+29
+30
+31
+32
+
+
# File 'lib/juno/Net/request_queue.rb', line 26
+
+def self.instance
+  return @@instance unless @@instance.nil?
+
+  @@mutex.synchronize do
+    @@instance ||= new
+  end
+end
+
+
+ +
+ +
+

Instance Method Details

+ + +
+

+ + #full?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+47
+48
+49
+
+
# File 'lib/juno/Net/request_queue.rb', line 47
+
+def full?
+  @request_queue.size == @size
+end
+
+
+ +
+

+ + #popQueueEntry + + + + + +

+
+ +

Returns - nil if queue empty.

+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (QueueEntry) + + + + — +
    • +

      nil if queue empty

      +
    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+77
+78
+79
+80
+81
+82
+
+
# File 'lib/juno/Net/request_queue.rb', line 77
+
+def pop
+  @request_queue.pop(true)
+rescue ThreadError
+  # queue empty
+  nil
+end
+
+
+ +
+

+ + #push(msg_buffer, request_uuid) ⇒ Boolean + + + + + +

+
+ +

Returns - true if successfully pushed item to queue. Else false.

+ + +
+
+
+

Parameters:

+
    + +
  • + + operation_message + + + (Juno::IO::OperatioinMessage) + + + + — +
    +

    (required)

    +
    + +
  • + +
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + + — +
    • +

      true if successfully pushed item to queue. Else false

      +
    +
    + +
  • + +
+ +
+ + + + +
+
+
+
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+
+
# File 'lib/juno/Net/request_queue.rb', line 62
+
+def push(msg_buffer, request_uuid)
+  # buffer = StringIO.new
+  # operation_message.write(buffer)
+  # request_uuid = operation_message&.metadata_component&.request_uuid.to_s
+  request_uuid = 'not_set' if request_uuid.to_s.empty?
+
+  begin
+    @request_queue.push(QueueEntry.new(msg_buffer, request_uuid), true)
+  rescue ThreadError
+    return false
+  end
+  true
+end
+
+
+ +
+

+ + #sizeObject + + + + + +

+ + + + +
+
+
+
+51
+52
+53
+
+
# File 'lib/juno/Net/request_queue.rb', line 51
+
+def size
+  @request_queue.size
+end
+
+
+ +
+

+ + #stopObject + + + + + +

+ + + + +
+
+
+
+55
+56
+57
+58
+
+
# File 'lib/juno/Net/request_queue.rb', line 55
+
+def stop
+  @worker_pool.stop
+  @request_queue.clear
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Net/WorkerPool.html b/client/Ruby/docs/Juno/Net/WorkerPool.html new file mode 100644 index 0000000..7c85a5a --- /dev/null +++ b/client/Ruby/docs/Juno/Net/WorkerPool.html @@ -0,0 +1,405 @@ + + + + + + + Class: Juno::Net::WorkerPool + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Net::WorkerPool + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Net/worker_pool.rb
+
+ +
+ + + + + + + + + +

+ Instance Method Summary + collapse +

+ + + + +
+

Constructor Details

+ +
+

+ + #initialize(request_queue) ⇒ WorkerPool + + + + + +

+
+ +

Returns a new instance of WorkerPool.

+ + +
+
+
+ + +
+ + + + +
+
+
+
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+
+
# File 'lib/juno/Net/worker_pool.rb', line 6
+
+def initialize(request_queue)
+  raise 'Request queue cannot be nil' if request_queue.nil?
+
+  @PROG_NAME = self.class.name
+  @LOGGER = Juno::Logger.instance
+  @request_queue = request_queue
+  EventMachine.threadpool_size = 200
+  @io_processor = Juno::Net::IOProcessor.new(@request_queue, @request_queue.opaque_resp_queue_map)
+  init
+end
+
+
+ +
+ + +
+

Instance Method Details

+ + +
+

+ + #active?Boolean + + + + + +

+
+ + +
+
+
+ +

Returns:

+
    + +
  • + + + (Boolean) + + + +
  • + +
+ +
+ + + + +
+
+
+
+23
+24
+25
+
+
# File 'lib/juno/Net/worker_pool.rb', line 23
+
+def active?
+  @worker.alive?
+end
+
+
+ +
+

+ + #initObject + + + + + +

+ + + + +
+
+
+
+17
+18
+19
+20
+21
+
+
# File 'lib/juno/Net/worker_pool.rb', line 17
+
+def init
+  @worker = Thread.new do
+    @io_processor.run
+  end
+end
+
+
+ +
+

+ + #stopObject + + + + + +

+ + + + +
+
+
+
+27
+28
+29
+
+
# File 'lib/juno/Net/worker_pool.rb', line 27
+
+def stop
+  @io_processor.stop
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Properties.html b/client/Ruby/docs/Juno/Properties.html new file mode 100644 index 0000000..96f382d --- /dev/null +++ b/client/Ruby/docs/Juno/Properties.html @@ -0,0 +1,269 @@ + + + + + + + Class: Juno::Properties + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Properties + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Config/properties.rb
+
+ +
+ +

Overview

+
+ +

Module for properties key (config file)

+ + +
+
+
+ + +
+ +

+ Constant Summary + collapse +

+ +
+ +
RESPONSE_TIMEOUT = + +
+
'juno.response.timeout_msec'
+ +
CONNECTION_TIMEOUT = + +
+
'juno.connection.timeout_msec'
+ +
DEFAULT_LIFETIME = + +
+
'juno.default_record_lifetime_sec'
+ +
CONNECTION_LIFETIME = + +
+
'juno.connection.recycle_duration_msec'
+ +
CONNECTION_POOLSIZE = + +
+
'juno.connection.pool_size'
+ +
RECONNECT_ON_FAIL = + +
+
'juno.connection.reconnect_on_fail'
+ +
HOST = + +
+
'juno.server.host'
+ +
PORT = + +
+
'juno.server.port'
+ +
APP_NAME = + +
+
'juno.application_name'
+ +
RECORD_NAMESPACE = + +
+
'juno.record_namespace'
+ +
USE_SSL = + +
+
'juno.useSSL'
+ +
USE_PAYLOAD_COMPRESSION = + +
+
'juno.usePayloadCompression'
+ +
ENABLE_RETRY = + +
+
'juno.operation.retry'
+ +
BYPASS_LTM = + +
+
'juno.connection.byPassLTM'
+ +
CONFIG_PREFIX = + +
+
'prefix'
+ +
MAX_LIFETIME = +
+
+ +

Max for each property

+ + +
+
+
+ + +
+
+
'juno.max_record_lifetime_sec'
+ +
MAX_KEY_SIZE = + +
+
'juno.max_key_size'
+ +
MAX_VALUE_SIZE = + +
+
'juno.max_value_size'
+ +
MAX_RESPONSE_TIMEOUT = + +
+
'juno.response.max_timeout_msec'
+ +
MAX_CONNECTION_TIMEOUT = + +
+
'juno.connection.max_timeout_msec'
+ +
MAX_CONNECTION_LIFETIME = + +
+
'juno.connection.max_recycle_duration_msec'
+ +
MAX_CONNECTION_POOL_SIZE = + +
+
'juno.connection.max_pool_size'
+ +
MAX_NAMESPACE_LENGTH = + +
+
'juno.max_record_namespace_length'
+ +
+ + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/ServerStatus.html b/client/Ruby/docs/Juno/ServerStatus.html new file mode 100644 index 0000000..d5da961 --- /dev/null +++ b/client/Ruby/docs/Juno/ServerStatus.html @@ -0,0 +1,351 @@ + + + + + + + Class: Juno::ServerStatus + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::ServerStatus + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/server_status.rb
+
+ +
+ + + +

+ Constant Summary + collapse +

+ +
+ +
SUCCESS = + +
+
{ code: 0, error_msg: 'no error', client_operation_status: Juno::Client::OperationStatus::SUCCESS }.freeze
+ +
BAD_MSG = + +
+
{ code: 1, error_msg: 'bad message',
+client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze
+ +
NO_KEY = + +
+
{ code: 3, error_msg: 'key not found',
+client_operation_status: Juno::Client::OperationStatus::NO_KEY }.freeze
+ +
DUP_KEY = + +
+
{ code: 4, error_msg: 'dup key',
+client_operation_status: Juno::Client::OperationStatus::UNIQUE_KEY_VIOLATION }.freeze
+ +
BAD_PARAM = + +
+
{ code: 7,  error_msg: 'bad parameter',
+client_operation_status: Juno::Client::OperationStatus::BAD_PARAM }.freeze
+ +
RECORD_LOCKED = + +
+
{ code: 8, error_msg: 'record locked',
+client_operation_status: Juno::Client::OperationStatus::RECORD_LOCKED }.freeze
+ +
NO_STORAGE_SERVER = + +
+
{ code: 12, error_msg: 'no active storage server',
+client_operation_status: Juno::Client::OperationStatus::NO_STORAGE }.freeze
+ +
SERVER_BUSY = + +
+
{ code: 14, error_msg: 'Server busy',
+client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze
+ +
VERSION_CONFLICT = + +
+
{ code: 19, error_msg:  'version conflict',
+client_operation_status: Juno::Client::OperationStatus::CONDITION_VIOLATION }.freeze
+ +
OP_STATUS_SS_READ_TTL_EXTENDERR = + +
+
{ code: 23, error_msg: 'Error extending TTL by SS',
+client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze
+ +
COMMIT_FAILURE = + +
+
{ code: 25, error_msg: 'Commit Failure',
+client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze
+ +
INCONSISTENT_STATE = + +
+
{ code: 26, error_msg: 'Inconsistent State',
+client_operation_status: Juno::Client::OperationStatus::SUCCESS }.freeze
+ +
INTERNAL = + +
+
{ code: 255, error_msg: 'Internal error',
+client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze
+ +
@@status_code_map = + +
+
nil
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .get(status_code) ⇒ Object + + + + + +

+ + + + +
+
+
+
+42
+43
+44
+45
+46
+47
+
+
# File 'lib/juno/server_status.rb', line 42
+
+def self.get(status_code)
+  initialize_map if @@status_code_map.nil?
+  return @@status_code_map[status_code] if @@status_code_map.key?(status_code.to_i)
+
+  INTERNAL
+end
+
+
+ +
+

+ + .initialize_mapObject + + + + + +

+ + + + +
+
+
+
+33
+34
+35
+36
+37
+38
+39
+40
+
+
# File 'lib/juno/server_status.rb', line 33
+
+def self.initialize_map
+  @@status_code_map = {}
+
+  constants.each do |const|
+    const_obj = const_get(const)
+    @@status_code_map[const_obj[:code].to_i] = const_obj
+  end
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/Juno/Utils.html b/client/Ruby/docs/Juno/Utils.html new file mode 100644 index 0000000..35fced5 --- /dev/null +++ b/client/Ruby/docs/Juno/Utils.html @@ -0,0 +1,640 @@ + + + + + + + Class: Juno::Utils + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Class: Juno::Utils + + + +

+
+ +
+
Inherits:
+
+ Object + +
    +
  • Object
  • + + + +
+ show all + +
+
+ + + + + + + + + + + +
+
Defined in:
+
lib/juno/Utils/utils.rb
+
+ +
+ + + + + + + + + +

+ Class Method Summary + collapse +

+ + + + + + +
+

Class Method Details

+ + +
+

+ + .create_and_send_ping_messageObject + + + + + +

+ + + + +
+
+
+
+110
+111
+112
+113
+114
+115
+116
+117
+118
+
+
# File 'lib/juno/Utils/utils.rb', line 110
+
+def self.create_and_send_ping_message
+  ping_message = Juno::Net::PingMessage.new
+  ping_buffer = StringIO.new
+  ping_message.write(ping_buffer)
+  response = ssl_request(ping_buffer)
+  ping_message = Juno::Net::PingMessage.new
+  ping_message.read(response)
+  ping_message
+end
+
+
+ +
+

+ + .create_message(key, op_type, value = '') ⇒ Object + + + + + +

+ + + + +
+
+
+
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+
+
# File 'lib/juno/Utils/utils.rb', line 15
+
+def self.create_message(key, op_type, value = '')
+   = Juno::IO::MetadataComponent.new
+  # ip = IPAddr.new(Socket.ip_address_list.detect(&:ipv4_private?).ip_address)
+  .set_time_to_live(Juno.juno_config.default_lifetime)
+  .set_version(1)
+  .set_creation_time(1000)
+  .set_request_uuid
+  .set_correlation_id
+  .set_originator_request_id
+  .set_source_info(app_name: Juno.juno_config.app_name, ip: IPAddr.new(Juno::Utils.local_ips[0]),
+                                      port: Juno.juno_config.port)
+
+  payload_component = Juno::IO::PayloadComponent.new
+  payload_component.namespace = Juno.juno_config.record_namespace
+  payload_component.payload_key = key
+  if op_type == Juno::IO::ProtocolHeader::OpCodes::Create && !value.to_s.empty?
+    is_compressed = false
+    if Juno.juno_config.use_payload_compression && value.length > 1024
+      value, compression_achieved = compressed_value(value)
+      is_compressed = true if compression_achieved.positive?
+    end
+    if is_compressed
+      puts 'using compression'
+      payload_component.set_value(value, Juno::IO::CompressionType::Snappy)
+    else
+      payload_component.set_value(value)
+    end
+  end
+
+  protocol_header = Juno::IO::ProtocolHeader.new
+  protocol_header.opcode = op_type
+
+  operation_message = Juno::IO::OperationMessage.new
+  operation_message. = 
+  operation_message.protocol_header = protocol_header
+  operation_message.payload_component = payload_component
+  buffer = StringIO.new
+  operation_message.write(buffer)
+  buffer
+end
+
+
+ +
+

+ + .local_ipsObject + + + + + +

+ + + + +
+
+
+
+5
+6
+7
+8
+9
+10
+11
+12
+13
+
+
# File 'lib/juno/Utils/utils.rb', line 5
+
+def self.local_ips
+  ip_addresses = Socket.ip_address_list.select do |addr|
+    addr.ipv4? && !addr.ipv4_loopback? # && !addr.ipv4_private?
+  end
+  ip_addresses.map!(&:ip_address)
+rescue StandardError => e
+  puts e.message
+  ['127.0.0.1']
+end
+
+
+ +
+

+ + .ssl_contextObject + + + + + +

+ + + + +
+
+
+
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+
+
# File 'lib/juno/Utils/utils.rb', line 56
+
+def self.ssl_context
+  ssl_context = OpenSSL::SSL::SSLContext.new
+  ssl_context.ssl_version = :TLSv1_1
+  cert = OpenSSL::X509::Certificate.new(File.open(File.expand_path(File.join(
+                                                                     __dir__, '..', '..', 'server.crt'
+                                                                   ))))
+  key = OpenSSL::PKey::RSA.new(File.open(File.expand_path(File.join(
+                                                            __dir__, '..', '..', 'server.pem'
+                                                          ))))
+  ca_file = OpenSSL::X509::Certificate.new(File.open(File.expand_path(File.join(
+                                                                        __dir__, '..', '..', 'myca.crt'
+                                                                      ))))
+  ssl_context.add_certificate(cert, key, [ca_file])
+  # ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
+  ssl_context.ssl_timeout = 10
+  ssl_context.timeout = 10
+  ssl_context
+end
+
+
+ +
+

+ + .ssl_request(buffer) ⇒ Object + + + + + +

+ + + + +
+
+
+
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+
+
# File 'lib/juno/Utils/utils.rb', line 75
+
+def self.ssl_request(buffer)
+  socket = TCPSocket.open(Juno.juno_config.host, Juno.juno_config.port)
+  if Juno.juno_config.use_ssl
+    ctx = ssl_context
+    socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
+    socket.sync_close = true
+    # socket.post_connection_check(Juno.juno_config.host)
+    socket.connect
+  end
+
+  # puts socket.peer_finished_message.bytes.join(', ')
+  # puts socket.verify_result
+
+  socket.write(buffer.string)
+  res_buffer = StringIO.new
+  header = true
+
+  size = 0
+  while (line = socket.sysread(1024 * 16)) # buffer size of OpenSSL library
+    if header
+      p = Juno::IO::ProtocolHeader.new
+      p.read(StringIO.new(line))
+      header = false
+      size = p.message_size
+    end
+    res_buffer.write(line)
+    break if res_buffer.length == size
+  end
+  socket.close
+
+  res_buffer.rewind
+
+  res_buffer
+end
+
+
+ +
+

+ + .time_diff_ms(a, b) ⇒ Object + + + + + +

+ + + + +
+
+
+
+120
+121
+122
+
+
# File 'lib/juno/Utils/utils.rb', line 120
+
+def self.time_diff_ms(a, b)
+  (b - a).abs * 1000
+end
+
+
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/_index.html b/client/Ruby/docs/_index.html new file mode 100644 index 0000000..2c8e152 --- /dev/null +++ b/client/Ruby/docs/_index.html @@ -0,0 +1,620 @@ + + + + + + + Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Documentation by YARD 0.9.34

+
+

Alphabetic Index

+ +

File Listing

+ + +
+

Namespace Listing A-Z

+ + + + + + + + +
+ + + + + + + + + + + + + + +
    +
  • F
  • + +
+ + +
    +
  • I
  • +
      + +
    • + IO + + (Juno) + +
    • + +
    • + IOProcessor + + (Juno::Net) + +
    • + +
    +
+ + + + + +
+ + +
    +
  • L
  • +
      + +
    • + Logger + + (Juno) + +
    • + +
    +
+ + + + + +
    +
  • N
  • +
      + +
    • + Net + + (Juno) + +
    • + +
    +
+ + + + + + + + +
    +
  • Q
  • + +
+ + + + + +
    +
  • S
  • + +
+ + +
+ + +
    +
  • T
  • +
      + +
    • + TagAndType + + (Juno::IO::MetadataComponent) + +
    • + +
    • + Type + + (Juno::Client::JunoRequest) + +
    • + +
    +
+ + + + + +
    +
  • W
  • + +
+ +
+ +
+ +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/docs/class_list.html b/client/Ruby/docs/class_list.html new file mode 100644 index 0000000..aac651f --- /dev/null +++ b/client/Ruby/docs/class_list.html @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + Class List + + + +
+
+

Class List

+ + + +
+ + +
+ + diff --git a/client/Ruby/docs/css/common.css b/client/Ruby/docs/css/common.css new file mode 100644 index 0000000..cf25c45 --- /dev/null +++ b/client/Ruby/docs/css/common.css @@ -0,0 +1 @@ +/* Override this file with custom rules */ \ No newline at end of file diff --git a/client/Ruby/docs/css/full_list.css b/client/Ruby/docs/css/full_list.css new file mode 100644 index 0000000..fa35982 --- /dev/null +++ b/client/Ruby/docs/css/full_list.css @@ -0,0 +1,58 @@ +body { + margin: 0; + font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; + font-size: 13px; + height: 101%; + overflow-x: hidden; + background: #fafafa; +} + +h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; } +.clear { clear: both; } +.fixed_header { position: fixed; background: #fff; width: 100%; padding-bottom: 10px; margin-top: 0; top: 0; z-index: 9999; height: 70px; } +#search { position: absolute; right: 5px; top: 9px; padding-left: 24px; } +#content.insearch #search, #content.insearch #noresults { background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat center left; } +#full_list { padding: 0; list-style: none; margin-left: 0; margin-top: 80px; font-size: 1.1em; } +#full_list ul { padding: 0; } +#full_list li { padding: 0; margin: 0; list-style: none; } +#full_list li .item { padding: 5px 5px 5px 12px; } +#noresults { padding: 7px 12px; background: #fff; } +#content.insearch #noresults { margin-left: 7px; } +li.collapsed ul { display: none; } +li a.toggle { cursor: default; position: relative; left: -5px; top: 4px; text-indent: -999px; width: 10px; height: 9px; margin-left: -10px; display: block; float: left; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; } +li.collapsed a.toggle { opacity: 0.5; cursor: default; background-position: top left; } +li { color: #888; cursor: pointer; } +li.deprecated { text-decoration: line-through; font-style: italic; } +li.odd { background: #f0f0f0; } +li.even { background: #fafafa; } +.item:hover { background: #ddd; } +li small:before { content: "("; } +li small:after { content: ")"; } +li small.search_info { display: none; } +a, a:visited { text-decoration: none; color: #05a; } +li.clicked > .item { background: #05a; color: #ccc; } +li.clicked > .item a, li.clicked > .item a:visited { color: #eee; } +li.clicked > .item a.toggle { opacity: 0.5; background-position: bottom right; } +li.collapsed.clicked a.toggle { background-position: top right; } +#search input { border: 1px solid #bbb; border-radius: 3px; } +#full_list_nav { margin-left: 10px; font-size: 0.9em; display: block; color: #aaa; } +#full_list_nav a, #nav a:visited { color: #358; } +#full_list_nav a:hover { background: transparent; color: #5af; } +#full_list_nav span:after { content: ' | '; } +#full_list_nav span:last-child:after { content: ''; } + +#content h1 { margin-top: 0; } +li { white-space: nowrap; cursor: normal; } +li small { display: block; font-size: 0.8em; } +li small:before { content: ""; } +li small:after { content: ""; } +li small.search_info { display: none; } +#search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #888; padding-left: 0; padding-right: 24px; } +#content.insearch #search { background-position: center right; } +#search input { width: 110px; } + +#full_list.insearch ul { display: block; } +#full_list.insearch .item { display: none; } +#full_list.insearch .found { display: block; padding-left: 11px !important; } +#full_list.insearch li a.toggle { display: none; } +#full_list.insearch li small.search_info { display: block; } diff --git a/client/Ruby/docs/css/style.css b/client/Ruby/docs/css/style.css new file mode 100644 index 0000000..eb0dbc8 --- /dev/null +++ b/client/Ruby/docs/css/style.css @@ -0,0 +1,497 @@ +html { + width: 100%; + height: 100%; +} +body { + font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; + font-size: 13px; + width: 100%; + margin: 0; + padding: 0; + display: flex; + display: -webkit-flex; + display: -ms-flexbox; +} + +#nav { + position: relative; + width: 100%; + height: 100%; + border: 0; + border-right: 1px dotted #eee; + overflow: auto; +} +.nav_wrap { + margin: 0; + padding: 0; + width: 20%; + height: 100%; + position: relative; + display: flex; + display: -webkit-flex; + display: -ms-flexbox; + flex-shrink: 0; + -webkit-flex-shrink: 0; + -ms-flex: 1 0; +} +#resizer { + position: absolute; + right: -5px; + top: 0; + width: 10px; + height: 100%; + cursor: col-resize; + z-index: 9999; +} +#main { + flex: 5 1; + -webkit-flex: 5 1; + -ms-flex: 5 1; + outline: none; + position: relative; + background: #fff; + padding: 1.2em; + padding-top: 0.2em; + box-sizing: border-box; +} + +@media (max-width: 920px) { + .nav_wrap { width: 100%; top: 0; right: 0; overflow: visible; position: absolute; } + #resizer { display: none; } + #nav { + z-index: 9999; + background: #fff; + display: none; + position: absolute; + top: 40px; + right: 12px; + width: 500px; + max-width: 80%; + height: 80%; + overflow-y: scroll; + border: 1px solid #999; + border-collapse: collapse; + box-shadow: -7px 5px 25px #aaa; + border-radius: 2px; + } +} + +@media (min-width: 920px) { + body { height: 100%; overflow: hidden; } + #main { height: 100%; overflow: auto; } + #search { display: none; } +} + +#main img { max-width: 100%; } +h1 { font-size: 25px; margin: 1em 0 0.5em; padding-top: 4px; border-top: 1px dotted #d5d5d5; } +h1.noborder { border-top: 0px; margin-top: 0; padding-top: 4px; } +h1.title { margin-bottom: 10px; } +h1.alphaindex { margin-top: 0; font-size: 22px; } +h2 { + padding: 0; + padding-bottom: 3px; + border-bottom: 1px #aaa solid; + font-size: 1.4em; + margin: 1.8em 0 0.5em; + position: relative; +} +h2 small { font-weight: normal; font-size: 0.7em; display: inline; position: absolute; right: 0; } +h2 small a { + display: block; + height: 20px; + border: 1px solid #aaa; + border-bottom: 0; + border-top-left-radius: 5px; + background: #f8f8f8; + position: relative; + padding: 2px 7px; +} +.clear { clear: both; } +.inline { display: inline; } +.inline p:first-child { display: inline; } +.docstring, .tags, #filecontents { font-size: 15px; line-height: 1.5145em; } +.docstring p > code, .docstring p > tt, .tags p > code, .tags p > tt { + color: #c7254e; background: #f9f2f4; padding: 2px 4px; font-size: 1em; + border-radius: 4px; +} +.docstring h1, .docstring h2, .docstring h3, .docstring h4 { padding: 0; border: 0; border-bottom: 1px dotted #bbb; } +.docstring h1 { font-size: 1.2em; } +.docstring h2 { font-size: 1.1em; } +.docstring h3, .docstring h4 { font-size: 1em; border-bottom: 0; padding-top: 10px; } +.summary_desc .object_link a, .docstring .object_link a { + font-family: monospace; font-size: 1.05em; + color: #05a; background: #EDF4FA; padding: 2px 4px; font-size: 1em; + border-radius: 4px; +} +.rdoc-term { padding-right: 25px; font-weight: bold; } +.rdoc-list p { margin: 0; padding: 0; margin-bottom: 4px; } +.summary_desc pre.code .object_link a, .docstring pre.code .object_link a { + padding: 0px; background: inherit; color: inherit; border-radius: inherit; +} + +/* style for */ +#filecontents table, .docstring table { border-collapse: collapse; } +#filecontents table th, #filecontents table td, +.docstring table th, .docstring table td { border: 1px solid #ccc; padding: 8px; padding-right: 17px; } +#filecontents table tr:nth-child(odd), +.docstring table tr:nth-child(odd) { background: #eee; } +#filecontents table tr:nth-child(even), +.docstring table tr:nth-child(even) { background: #fff; } +#filecontents table th, .docstring table th { background: #fff; } + +/* style for
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; +f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() +{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file diff --git a/client/Ruby/docs/method_list.html b/client/Ruby/docs/method_list.html new file mode 100644 index 0000000..4332e85 --- /dev/null +++ b/client/Ruby/docs/method_list.html @@ -0,0 +1,2075 @@ + + + + + + + + + + + + + + + + + + Method List + + + +
+
+

Method List

+ + + +
+ + +
+ + diff --git a/client/Ruby/docs/top-level-namespace.html b/client/Ruby/docs/top-level-namespace.html new file mode 100644 index 0000000..469ccbb --- /dev/null +++ b/client/Ruby/docs/top-level-namespace.html @@ -0,0 +1,110 @@ + + + + + + + Top Level Namespace + + — Documentation by YARD 0.9.34 + + + + + + + + + + + + + + + + + + + +
+ + +

Top Level Namespace + + + +

+
+ + + + + + + + + + + +
+ +

Defined Under Namespace

+

+ + + Modules: Juno + + + + +

+ + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/client/Ruby/juno.yml b/client/Ruby/juno.yml new file mode 100644 index 0000000..d2fdf12 --- /dev/null +++ b/client/Ruby/juno.yml @@ -0,0 +1,26 @@ +juno: + useSSL: true + default_record_lifetime_sec: 1800 + max_record_lifetime_sec: 259200 + max_record_namespace_length: 256 + max_key_size: 128 + application_name: TestApp + record_namespace: TestNamespace + usePayloadCompression: false + operation: + retry: true + response: + timeout_msec: 2000 + max_timeout_msec: 5000 + connection: + timeout_msec: 300 + recycle_duration_msec: 30000 + pool_size: 10 + reconnect_on_fail: false + byPassLTM: true + max_timeout_msec: 3000 + max_recycle_duration_msec: 50000 + max_pool_size: 20 + server: + host: "127.0.0.1" + port: 8080 diff --git a/client/Ruby/juno/.rspec b/client/Ruby/juno/.rspec new file mode 100644 index 0000000..c99d2e7 --- /dev/null +++ b/client/Ruby/juno/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/client/Ruby/juno/CODE_OF_CONDUCT.md b/client/Ruby/juno/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..7fed206 --- /dev/null +++ b/client/Ruby/juno/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at TODO: Write your email address. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/client/Ruby/juno/Gemfile b/client/Ruby/juno/Gemfile new file mode 100644 index 0000000..30277c7 --- /dev/null +++ b/client/Ruby/juno/Gemfile @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# Gemfile + +source 'http://rubygems.org' + +git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } + +# Specify your gem's dependencies in juno.gemspec +gemspec diff --git a/client/Ruby/juno/Gemfile.lock b/client/Ruby/juno/Gemfile.lock new file mode 100644 index 0000000..9bf1e71 --- /dev/null +++ b/client/Ruby/juno/Gemfile.lock @@ -0,0 +1,95 @@ +PATH + remote: . + specs: + juno (1.0.0) + bindata (~> 2.4.15) + concurrent-ruby (~> 1.2.2) + configatron (~> 4.5.1) + eventmachine (~> 1.2.7) + json (~> 2.5.1) + logger (~> 1.2.7) + openssl (~> 2.2.0) + snappy (~> 0.3.0) + uri (~> 0.12.2) + uuidtools (~> 2.2.0) + yaml (~> 0.1.1) + +GEM + remote: http://rubygems.org/ + specs: + ast (2.4.2) + bindata (2.4.15) + concurrent-ruby (1.2.2) + configatron (4.5.1) + diff-lcs (1.5.0) + eventmachine (1.2.7) + ffi (1.15.5) + get_process_mem (0.2.7) + ffi (~> 1.0) + ipaddr (1.2.5) + json (2.5.1) + language_server-protocol (3.17.0.3) + logger (1.2.8.1) + openssl (2.2.3) + ipaddr + parallel (1.23.0) + parser (3.2.2.3) + ast (~> 2.4.1) + racc + racc (1.7.1) + rainbow (3.1.1) + rake (13.0.6) + regexp_parser (2.8.1) + rexml (3.2.6) + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-html-formatter (0.0.1) + rspec-mocks (3.12.6) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-support (3.12.1) + rubocop (1.55.0) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.2.2.3) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.28.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.29.0) + parser (>= 3.2.1.0) + ruby-prof (1.6.3) + ruby-progressbar (1.13.0) + snappy (0.3.0) + unicode-display_width (2.4.2) + uri (0.12.2) + uuidtools (2.2.0) + yaml (0.1.1) + yard (0.9.34) + +PLATFORMS + arm64-darwin-21 + +DEPENDENCIES + bundler + get_process_mem + juno! + rake + rspec + rspec-html-formatter + rubocop + ruby-prof + yard + +BUNDLED WITH + 2.2.3 diff --git a/client/Ruby/juno/LICENSE.txt b/client/Ruby/juno/LICENSE.txt new file mode 100644 index 0000000..1c7e4b6 --- /dev/null +++ b/client/Ruby/juno/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 TODO: Write your name + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/client/Ruby/juno/Rakefile b/client/Ruby/juno/Rakefile new file mode 100644 index 0000000..bcab8af --- /dev/null +++ b/client/Ruby/juno/Rakefile @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'bundler/gem_tasks' +require 'rspec/core/rake_task' +require 'rubocop/rake_task' +require 'yard' + +task default: :spec + +RSpec::Core::RakeTask.new(:spec) do |t| + t.pattern = Dir.glob('spec/**/*_spec.rb') + t.rspec_opts = ['--format html', '--out juno_spec_results.html'] +end + +RuboCop::RakeTask.new(:lint) do |task| + task.patterns = ['lib/**/*.rb'] + task.options = ['--autocorrect', '--fail-level', 'error'] +end + +namespace :yard do + task :before_yard do + FileUtils.rm_rf('../docs') if Dir.exist?('../docs') + FileUtils.rm_rf('doc') if Dir.exist?('doc') + end + + task :after_yard do + FileUtils.mv('doc', '../docs') + FileUtils.rm_rf('.yardoc') + end + + YARD::Rake::YardocTask.new(:document) do |task| + task.files = ['lib/**/*.rb'] + task.before = -> { Rake::Task['yard:before_yard'].invoke } + task.after = -> { Rake::Task['yard:after_yard'].invoke } + end +end diff --git a/client/Ruby/juno/bin/console b/client/Ruby/juno/bin/console new file mode 100755 index 0000000..1224dca --- /dev/null +++ b/client/Ruby/juno/bin/console @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'bundler/setup' +require 'juno' + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# (If you use this, don't forget to add pry to your Gemfile!) +# require "pry" +# Pry.start + +require 'irb' +IRB.start(__FILE__) diff --git a/client/Ruby/juno/bin/setup b/client/Ruby/juno/bin/setup new file mode 100755 index 0000000..dce67d8 --- /dev/null +++ b/client/Ruby/juno/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/client/Ruby/juno/juno.gemspec b/client/Ruby/juno/juno.gemspec new file mode 100644 index 0000000..46425d7 --- /dev/null +++ b/client/Ruby/juno/juno.gemspec @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +lib = File.expand_path('lib', __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'juno/version' + +Gem::Specification.new do |spec| + spec.name = 'juno' + spec.version = Juno::VERSION + spec.authors = ['PayPal Inc'] + spec.email = ['paypal.com'] + + spec.summary = 'Ruby gem for Juno client' + spec.description = 'Ruby gem for Juno client' + spec.homepage = 'https://github.com/paypal/junodb' + spec.license = 'MIT' + + if spec.respond_to?(:metadata) + spec.metadata['allowed_push_host'] = 'https://github.com/paypal/junodb' + + spec.metadata['homepage_uri'] = spec.homepage + spec.metadata['source_code_uri'] = 'https://github.com/paypal/junodb' + spec.metadata['changelog_uri'] = 'https://github.com/paypal/junodb' + else + raise 'RubyGems 2.0 or newer is required to protect against ' \ + 'public gem pushes.' + end + + spec.files = Dir.chdir(File.expand_path(__dir__)) do + `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + end + spec.bindir = 'exe' + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ['lib'] + + spec.add_development_dependency 'bundler' + spec.add_development_dependency 'get_process_mem' + spec.add_development_dependency 'rake' + spec.add_development_dependency 'rspec' + spec.add_development_dependency 'rspec-html-formatter' + spec.add_development_dependency 'rubocop' + spec.add_development_dependency 'ruby-prof' + spec.add_development_dependency 'yard' + + spec.add_runtime_dependency 'bindata', '~> 2.4.15' + spec.add_runtime_dependency 'concurrent-ruby', '~> 1.2.2' + spec.add_runtime_dependency 'configatron', '~> 4.5.1' + spec.add_runtime_dependency 'eventmachine', '~> 1.2.7' + spec.add_runtime_dependency 'json', '~> 2.5.1' + spec.add_runtime_dependency 'logger', '~> 1.2.7' + spec.add_runtime_dependency 'openssl', '~> 2.2.0' + spec.add_runtime_dependency 'snappy', '~> 0.3.0' + spec.add_runtime_dependency 'uri', '~> 0.12.2' + spec.add_runtime_dependency 'uuidtools', '~> 2.2.0' + spec.add_runtime_dependency 'yaml', '~> 0.1.1' +end diff --git a/client/Ruby/juno/lib/juno.rb b/client/Ruby/juno/lib/juno.rb new file mode 100644 index 0000000..22739d3 --- /dev/null +++ b/client/Ruby/juno/lib/juno.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'timeout' +require 'uuidtools' +require 'bindata' +require 'uri' +require 'json' +require 'yaml' +require 'logger' +require 'snappy' +require 'eventmachine' +require 'concurrent' +require 'configatron' + +require_relative 'juno/version' + +require_relative 'juno/Utils/utils' +require_relative 'juno/Utils/client_utils' + +require_relative 'juno/IO/constants' +require_relative 'juno/IO/JunoMessage' +require_relative 'juno/IO/MetadataComponentTemplate' +require_relative 'juno/IO/MetadataComponent' +require_relative 'juno/IO/PayloadComponent' +require_relative 'juno/IO/ProtocolHeader' +require_relative 'juno/IO/OperationMessage' + +require_relative 'juno/Net/base_processor' +require_relative 'juno/Net/ping_message' +require_relative 'juno/Net/request_queue' +require_relative 'juno/Net/client_handler' +require_relative 'juno/Net/io_processor' +require_relative 'juno/Net/worker_pool' + +require_relative 'juno/Config/config_reader' +require_relative 'juno/Config/config_provider' +require_relative 'juno/Config/properties' +require_relative 'juno/Config/default_properties' +require_relative 'juno/Config/config' + +require_relative 'juno/Client/operation_status' +require_relative 'juno/Client/operation_type' +require_relative 'juno/Client/juno_request' +require_relative 'juno/Client/record_context' +require_relative 'juno/Client/juno_response' +require_relative 'juno/Client/react_client' +require_relative 'juno/Client/cache_store' +require_relative 'juno/Client/sync_client' + +require_relative 'juno/server_status' +require_relative 'juno/logger' diff --git a/client/Ruby/juno/lib/juno/Client/cache_store.rb b/client/Ruby/juno/lib/juno/Client/cache_store.rb new file mode 100755 index 0000000..dadfbef --- /dev/null +++ b/client/Ruby/juno/lib/juno/Client/cache_store.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + # Module for code exposed to the developer + module Client + # Cache store for ruby on rails + class CacheStore + def initialize + @react_client = Juno::Client::ReactClient.new + end + + def write(key, value, _options = {}) + future_obj = @react_client.set(key, value).wait + return false if future_obj.nil? + + raise future_obj.reason if future_obj.rejected? + + future_obj.value.status[:txnOk] + end + + def read(key, options = {}) + future_obj = @react_client.get(key).wait + read_response(future_obj, options[:version]) + end + + def self.supports_cache_versioning? + true + end + + def delete(key) + future_obj = @react_client.destroy(key).wait + return false if future_obj.nil? || future_obj.rejected? + + future_obj.value.status[:code] == Juno::Client::OperationStatus::SUCCESS[:code] + end + + def exist?(key) + !read(key).nil? + end + + private + + def read_response(future_obj, version) + return nil if future_obj.nil? || future_obj.rejected? + + return future_obj.value.value if version.nil? + + return future_obj.value.value if future_obj.record_context.version == version + + nil + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Client/juno_request.rb b/client/Ruby/juno/lib/juno/Client/juno_request.rb new file mode 100644 index 0000000..c2f2cf6 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Client/juno_request.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + module Client + # Request Object created from application request + class JunoRequest + class Type + CREATE = 1 + GET = 2 + UPDATE = 3 + SET = 4 + DESTROY = 5 + end + + attr_accessor :key, :version, :type, :value, :time_to_live_s, :creation_time + + # Constructor for JunoRequest + # @param key [String] key for the document (required) + # @param version [Integer] value for the document (required) + # @param version [Juno::JunoRequest::Type] value for the document (required) + # @param type [String] value for the document (optional, default: 1 byte string: 0.chr) + # @param type [Integer] Time to live for the document (optional, default: read from config file) + # @param type [Integer] Time to live for the document (optional, default: initialized to Time.now in JunoMessage) + def initialize(key:, version:, type:, value: nil, time_to_live_s: nil, creation_time: nil) + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + @key = key + @version = version.to_i + @type = type + @value = value.to_s.empty? ? 0.chr : value.to_s + @time_to_live_s = time_to_live_s.to_i + @creation_time = creation_time + end + + def ==(other) + return false unless other.is_a?(JunoRequest) + + other.key == @key && + other.version == @version && + other.type == @type && + other.value == @value && + other.time_to_live_s == @time_to_live_s && + other.creation_time == @creation_time + end + + # Function to serialize JunoRequest + def to_s + "JunoRequest key:#{@key} version:#{@version} type:#{@type}, value: #{@value}, time_to_live: #{@time_to_live}, creation_time: #{@creation_time}" + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Client/juno_response.rb b/client/Ruby/juno/lib/juno/Client/juno_response.rb new file mode 100644 index 0000000..8c56732 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Client/juno_response.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Juno + module Client + # Response sent to the application + class JunoResponse + attr_accessor :key, :status, :value, :record_context + + # @param key [String] (required) + # @param status [Juno::Client::OperationStatus] (required) + # @param value [String] (required) + # @param version [Integer] (required) + # @param creation_time [Integer] (required) + # @param time_to_live_s [Integer] (required) + def initialize(key:, value:, version:, time_to_live_s:, creation_time:, operation_status:) + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + @key = key + @status = operation_status + @value = value + @record_context = Juno::Client::RecordContext.new(key: key, version: version, creation_time: creation_time, + time_to_live_s: time_to_live_s) + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Client/operation_status.rb b/client/Ruby/juno/lib/juno/Client/operation_status.rb new file mode 100644 index 0000000..538cf5a --- /dev/null +++ b/client/Ruby/juno/lib/juno/Client/operation_status.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Constant for Operation Status in JunoResponse +module Juno + module Client + class OperationStatus + SUCCESS = { code: 0, error_msg: 'No error', txnOk: true }.freeze + NO_KEY = { code: 1, error_msg: 'Key not found', txnOk: true }.freeze + BAD_PARAM = { code: 2, error_msg: 'Bad parameter', txnOk: false }.freeze + UNIQUE_KEY_VIOLATION = { code: 3, error_msg: 'Duplicate key', txnOk: true }.freeze + RECORD_LOCKED = { code: 4, error_msg: 'Record Locked', txnOk: true }.freeze + ILLEGAL_ARGUMENT = { code: 5, error_msg: 'Illegal argument', txnOk: false }.freeze + CONDITION_VIOLATION = { code: 6, error_msg: 'Condition in the request violated', txnOk: true }.freeze + INTERNAL_ERROR = { code: 7, error_msg: 'Internal error', txnOk: false }.freeze + QUEUE_FULL = { code: 8, error_msg: 'Outbound client queue full', txnOk: false }.freeze + NO_STORAGE = { code: 9, error_msg: 'No storage server running', txnOk: false }.freeze + TTL_EXTEND_FAILURE = { code: 10, error_msg: 'Failure to extend TTL on get', txnOk: true }.freeze + RESPONSE_TIMEOUT = { code: 11, error_msg: 'Response Timed out', txnOk: false }.freeze + CONNECTION_ERROR = { code: 12, error_msg: 'Connection Error', txnOk: false }.freeze + UNKNOWN_ERROR = { code: 13, error_msg: 'Unknown Error', txnOk: false }.freeze + + @@status_code_map = nil + + def self.initialize_map + @@status_code_map = {} + + constants.each do |const| + const_obj = const_get(const) + @@status_code_map[const_obj[:code]] = const_obj + end + end + + def self.get(status_code) + initialize_map if @@status_code_map.nil? + return @@status_code_map[status_code] if @@status_code_map.key?(status_code) + + INTERNAL_ERROR + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Client/operation_type.rb b/client/Ruby/juno/lib/juno/Client/operation_type.rb new file mode 100644 index 0000000..3f14f86 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Client/operation_type.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + module Client + # Constant for JunoRequest operation type + class OperationType + Nop = { + code: 0, + str: 'NOP' + }.freeze + Create = { + code: 1, + str: 'CREATE' + }.freeze + Get = { + code: 2, + str: 'GET' + }.freeze + Update = { + code: 3, + str: 'UPDATE' + }.freeze + Set = { + code: 4, + str: 'SET' + }.freeze + CompareAndSet = { + code: 5, + str: 'COMPAREANDSET' + }.freeze + Destroy = { + code: 6, + str: 'DESTROY' + }.freeze + end + end +end diff --git a/client/Ruby/juno/lib/juno/Client/react_client.rb b/client/Ruby/juno/lib/juno/Client/react_client.rb new file mode 100644 index 0000000..b7e1a0b --- /dev/null +++ b/client/Ruby/juno/lib/juno/Client/react_client.rb @@ -0,0 +1,233 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + # Module for code exposed to the developer + module Client + # Async Client for Juno + class ReactClient + # @ Global Opaque generator. Uses ConcurrentFixnum for thread safety + @@OPAQUE_GENERATOR = Concurrent::AtomicFixnum.new(-1) + # @ Variable to count failed requests + @@fail_count = Concurrent::AtomicFixnum.new(0) + # @ Variable to count responses received + @@received = Concurrent::AtomicFixnum.new(0) + + # Constants for operation retry + MAX_OPERATION_RETRY = 1 + MAX_RETRY_INTERVAL = 15 # msec + MIN_RETRY_INTERVAL = 10 # msec + + def self.op_count + @@OPAQUE_GENERATOR.value + end + + def self.failed_count + @@fail_count.value + end + + def self.recv + @@received.value + end + + def initialize + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + @request_queue = Juno::Net::RequestQueue.instance + @executor = Concurrent::ThreadPoolExecutor.new(min_threads: 4, max_threads: 16, max_queue: 10_000) + @count = 0 + end + + def stop + @LOGGER.info(@PROG_NAME) { 'stop initiated by client' } + @request_queue.stop + @executor.shutdown + @executor.wait_for_termination + @executor.kill + end + + # Function to create new key value pair + # @param key [String] key for the document (required) + # @param value [String] value for the document (required) + # @param ttl [Integer] Time to live for the document (optional, default: read from config file) + # @return [Boolean] True if operation submited successfully, else false + # @see #process_single + # @see Juno::DefaultProperties::DEFAULT_LIFETIME_S + def create(key, value, ttl: nil) + juno_request = Juno::Client::JunoRequest.new(key: key, + value: value, + version: 0, + type: Juno::Client::JunoRequest::Type::CREATE, + time_to_live_s: ttl, + creation_time: Time.now.to_i) + process_single(juno_request) + end + + # Function to set value for given key + # @param key [String] key for the document (required) + # @param value [String] value for the document (required) + # @param ttl [Integer] Time to live for the document (optional, default: read from config file) + # @return [Boolean] True if operation submited successfully, else false + # @see #process_single + # @see Juno::DefaultProperties::DEFAULT_LIFETIME_S + def set(key, value, ttl: nil) + juno_request = Juno::Client::JunoRequest.new(key: key, + value: value, + version: 0, + type: Juno::Client::JunoRequest::Type::SET, + time_to_live_s: ttl, + creation_time: Time.now.to_i) + process_single(juno_request) + end + # @!method write + # @see #create + alias write set + + def compare_and_set(record_context, value, ttl) + unless record_context.is_a?(Juno::Client::RecordContext) + raise ArgumentError, 'recird context should be of type Juno::Client::RecordContext' + end + raise ArgumentError, 'Version cannot be less than 1' if record_context.version.to_i < 1 + + juno_request = Juno::Client::JunoRequest.new(key: record_context.key.to_s, + value: value, + version: record_context.version.to_i, + type: Juno::Client::JunoRequest::Type::UPDATE, + time_to_live_s: ttl, + creation_time: Time.now.to_i) + process_single(juno_request) + end + + # Function to get existing key value pair + # @param key [String] key for the document (required) + # @param value [String] value for the document (required) + # @param ttl [Integer] Time to live for the document (optional, default: read from config file) + # @return [Juno::Client::JunoResponse] + # @see Juno::Client#process_single + # @see Juno::DefaultProperties::DEFAULT_LIFETIME_S + def get(key, ttl: nil) + juno_request = Juno::Client::JunoRequest.new(key: key, + value: '', + version: 0, + type: Juno::Client::JunoRequest::Type::GET, + time_to_live_s: ttl, + creation_time: Time.now.to_i) + process_single(juno_request) + end + # @!method read + # @see #get + alias read get + + def update(key, value, ttl: nil) + juno_request = Juno::Client::JunoRequest.new(key: key, + value: value, + version: 0, + type: Juno::Client::JunoRequest::Type::UPDATE, + time_to_live_s: ttl, + creation_time: Time.now.to_i) + process_single(juno_request) + end + + def destroy(key, ttl: nil) + juno_request = Juno::Client::JunoRequest.new(key: key, + value: '', + version: 0, + type: Juno::Client::JunoRequest::Type::DESTROY, + time_to_live_s: ttl, + creation_time: Time.now.to_i) + process_single(juno_request) + end + # @!method delete + # @see #destroy + alias delete destroy + + def exist?(key); end + + private + + # Function to process a request. Set operation retry true in config file + # @param ttl [Juno::Client::JunoRequest] + # @return [Boolean] True if operation submited successfully, else false + # @see Juno::ClientUtils#validate + # @see Juno::DefaultProperties::DEFAULT_LIFETIME_S + # @see Juno::Net::RequestQueue#opaque_resp_queue_map + def process_single(juno_request) + # rubocop:disable Style/SignalException + # Concurrent::Future object to execute asynchronously + Concurrent::Future.execute(executor: @executor) do + begin + begin + juno_message = Juno::ClientUtils.validate!(juno_request) + rescue ArgumentError => e + fail(e.message) + end + operation_retry = Juno.juno_config.operation_retry + juno_resp = nil + opaque = nil + opaque_resp_queue_map = @request_queue.opaque_resp_queue_map + (MAX_OPERATION_RETRY + 1).times do + opaque = @@OPAQUE_GENERATOR.increment + operation_message = Juno::ClientUtils.create_operation_message(juno_message, opaque) + + resp_queue = SizedQueue.new(1) + opaque_resp_queue_map[opaque] = resp_queue + + # map to compute response times for requests + msg_buffer = StringIO.new + operation_message.write(msg_buffer) + + fail('Queue full') unless @request_queue.push(msg_buffer.string, + operation_message&.metadata_component&.request_uuid.to_s) + + resp = nil + begin + Timeout.timeout(Juno.juno_config.response_timeout.to_f / 1000) do + resp = resp_queue.pop + end + rescue Timeout::Error + resp = nil + end + + if resp.nil? + fail('Request Timeout') unless operation_retry + + @LOGGER.debug(@PROG_NAME) { "Retrying #{opaque} " } + operation_retry = false + # Backoff time for request retry + sec = rand(MAX_RETRY_INTERVAL - MIN_RETRY_INTERVAL) + MIN_RETRY_INTERVAL + @LOGGER.debug(@PROG_NAME) { "Backoff time #{sec.to_f / 1000}ms " } + sleep(sec.to_f / 1000) + next + end + juno_resp_msg = Juno::ClientUtils.decode_operation_message(resp) + fail('Could not fetch valid response') if juno_resp_msg.nil? + + juno_resp = Juno::Client::JunoResponse.new(key: juno_resp_msg.key, value: juno_resp_msg.value, + version: juno_resp_msg.version, time_to_live_s: juno_resp_msg.time_to_live_s, + creation_time: juno_resp_msg.creation_time, + operation_status: juno_resp_msg.server_status[:client_operation_status]) + + fail(juno_resp.status[:error_msg]) unless [Juno::Client::OperationStatus::SUCCESS[:code], Juno::Client::OperationStatus::CONDITION_VIOLATION[:code], + Juno::Client::OperationStatus::NO_KEY[:code], Juno::Client::OperationStatus::RECORD_LOCKED[:code], + Juno::Client::OperationStatus::UNIQUE_KEY_VIOLATION[:code], Juno::Client::OperationStatus::TTL_EXTEND_FAILURE[:code]].include?(juno_resp.status[:code]) + + break + end + rescue StandardError => e + puts e.backtrace + fail(e) + ensure + opaque_resp_queue_map.delete(opaque) + @@fail_count.increment if juno_resp.nil? + @@received.increment unless juno_resp.nil? + # rubocop:enable Style/SignalException + end + juno_resp + end + rescue Concurrent::RejectedExecutionError + @LOGGER.error(@PROG_NAME) { 'Too many requests Concurrent::Future' } + nil + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Client/record_context.rb b/client/Ruby/juno/lib/juno/Client/record_context.rb new file mode 100644 index 0000000..1f2c50a --- /dev/null +++ b/client/Ruby/juno/lib/juno/Client/record_context.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Juno + module Client + class RecordContext + attr_reader :key, :version, :creation_time, :time_to_live_s + + # @param key [String] (required) + # @param version [Integer] (required) + # @param creation_time [Integer] (required) + # @param time_to_live_s [Integer] (required) + def initialize(key:, version:, creation_time:, time_to_live_s:) + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + @key = key + @version = version + @creation_time = creation_time + @time_to_live_s = time_to_live_s + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Client/sync_client.rb b/client/Ruby/juno/lib/juno/Client/sync_client.rb new file mode 100644 index 0000000..f7afc7c --- /dev/null +++ b/client/Ruby/juno/lib/juno/Client/sync_client.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + # Module for code exposed to the developer + module Client + # Async Client for Juno + class SyncClient + def initialize + @react_client = Juno::Client::ReactClient.new + end + + # Function to create new key value pair + # @param key [String] key for the document (required) + # @param value [String] value for the document (required) + # @param ttl [Integer] Time to live for the document (optional, default: read from config file) + # @return [Juno::Client::JunoResponse] + def create(key, value, ttl: nil) + juno_resp = @react_client.create(key, value, ttl: ttl).wait + return nil if juno_resp.nil? + + raise juno_resp.reason if juno_resp.rejected? + + juno_resp.value # JunoResponse + end + + # Function to set value for given key + # @param key [String] key for the document (required) + # @param value [String] value for the document (required) + # @param ttl [Integer] Time to live for the document (optional, default: read from config file) + # @return [Juno::Client::JunoResponse] + def set(key, value, ttl: nil) + juno_resp = @react_client.set(key.to_s, value.to_s, ttl: ttl).wait + return nil if juno_resp.nil? + + raise juno_resp.reason if juno_resp.rejected? + + juno_resp.value # JunoResponse + end + + # Function to get existing key value pair + # @param key [String] key for the document (required) + # @param value [String] value for the document (required) + # @param ttl [Integer] Time to live for the document (optional, default: read from config file) + # @return [Juno::Client::JunoResponse] + def get(key, ttl: nil) + juno_resp = @react_client.get(key.to_s, ttl: ttl).wait + return nil if juno_resp.nil? + + raise juno_resp.reason if juno_resp.rejected? + + juno_resp.value # JunoResponse + end + + def update(key, value, ttl: nil) + juno_resp = @react_client.update(key.to_s, value.to_s, ttl: ttl).wait + return nil if juno_resp.nil? + + raise juno_resp.reason if juno_resp.rejected? + + juno_resp.value # JunoResponse + end + + def compare_and_set(record_context, value, ttl: nil) + juno_resp = nil + begin + juno_resp = @react_client.compare_and_set(record_context, value, ttl) + rescue ArgumentError => e + raise e.message + end + + return nil if juno_resp.nil? + + raise juno_resp.reason if juno_resp.rejected? + + juno_resp.value # JunoResponse + end + + def destroy(key, ttl: nil) + juno_resp = @react_client.destroy(key.to_s, ttl: ttl).wait + return nil if juno_resp.nil? + + raise juno_resp.reason if juno_resp.rejected? + + juno_resp.value # JunoResponse + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Config/config.rb b/client/Ruby/juno/lib/juno/Config/config.rb new file mode 100644 index 0000000..d0254cb --- /dev/null +++ b/client/Ruby/juno/lib/juno/Config/config.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + # Juno.configure do |config| + # config.record_namespace = "kk" + # config.host = '10.138.38.83' + # config.port = 5080 + # config.app_name = "TestApp" + # config.file_path = "" + # config.url = "" + # end + class Config + attr_reader :response_timeout, :connection_timeout, :connection_pool_size, :connection_lifetime, :default_lifetime, + :max_response_timeout, :max_connection_timeout, :max_connection_pool_size, :max_connection_lifetime, :max_lifetime, :max_key_size, :max_value_size, :max_namespace_length, + :host, :port, :app_name, :record_namespace, + :use_ssl, :use_payload_compression, :operation_retry, :bypass_ltm, :reconnect_on_fail, :config_prefix, + :log_file, :ssl_cert_file, :ssl_key_file + + REQUIRED_PROPERTIES = %i[host port app_name record_namespace log_file].freeze + + def initialize(config_provider, log_file:, ssl_cert_file: nil, ssl_key_file: nil) + @PROG_NAME = self.class.name + @log_file = log_file + @ssl_cert_file = ssl_cert_file + @ssl_key_file = ssl_key_file + @config = config_provider + read_all + validate! + end + + # Function to map all properties read from config file to variables + def read_all + @response_timeout = @config.get_property(Juno::Properties::RESPONSE_TIMEOUT, + Juno::DefaultProperties::RESPONSE_TIMEOUT_MS) + @connection_timeout = @config.get_property(Juno::Properties::CONNECTION_TIMEOUT, + Juno::DefaultProperties::CONNECTION_TIMEOUT_MS) + @connection_pool_size = @config.get_property(Juno::Properties::CONNECTION_POOLSIZE, + Juno::DefaultProperties::CONNECTION_POOLSIZE) + @connection_lifetime = @config.get_property(Juno::Properties::CONNECTION_LIFETIME, + Juno::DefaultProperties::CONNECTION_LIFETIME_MS) + @default_lifetime = @config.get_property(Juno::Properties::DEFAULT_LIFETIME, + Juno::DefaultProperties::DEFAULT_LIFETIME_S) + @max_response_timeout = @config.get_property(Juno::Properties::MAX_RESPONSE_TIMEOUT, + Juno::DefaultProperties::MAX_RESPONSE_TIMEOUT_MS) + @max_connection_timeout = @config.get_property(Juno::Properties::MAX_CONNECTION_TIMEOUT, + Juno::DefaultProperties::MAX_CONNECTION_TIMEOUT_MS) + @max_connection_pool_size = @config.get_property(Juno::Properties::MAX_CONNECTION_POOL_SIZE, + Juno::DefaultProperties::MAX_CONNECTION_POOL_SIZE) + @max_connection_lifetime = @config.get_property(Juno::Properties::MAX_CONNECTION_LIFETIME, + Juno::DefaultProperties::MAX_CONNECTION_LIFETIME_MS) + @max_lifetime = @config.get_property(Juno::Properties::MAX_LIFETIME, Juno::DefaultProperties::MAX_LIFETIME_S) + @max_key_size = @config.get_property(Juno::Properties::MAX_KEY_SIZE, Juno::DefaultProperties::MAX_KEY_SIZE_B) + @max_value_size = @config.get_property(Juno::Properties::MAX_VALUE_SIZE, + Juno::DefaultProperties::MAX_VALUE_SIZE_B) + @max_namespace_length = @config.get_property(Juno::Properties::MAX_NAMESPACE_LENGTH, + Juno::DefaultProperties::MAX_NAMESPACE_LENGTH) + @host = @config.get_property(Juno::Properties::HOST, Juno::DefaultProperties::HOST) + @port = @config.get_property(Juno::Properties::PORT, Juno::DefaultProperties::PORT) + @app_name = @config.get_property(Juno::Properties::APP_NAME, Juno::DefaultProperties::APP_NAME) + @record_namespace = @config.get_property(Juno::Properties::RECORD_NAMESPACE, + Juno::DefaultProperties::RECORD_NAMESPACE) + @use_ssl = @config.get_property(Juno::Properties::USE_SSL, Juno::DefaultProperties::USE_SSL) + @use_payload_compression = @config.get_property(Juno::Properties::USE_PAYLOAD_COMPRESSION, + Juno::DefaultProperties::USE_PAYLOAD_COMPRESSION) + @operation_retry = @config.get_property(Juno::Properties::ENABLE_RETRY, Juno::DefaultProperties::OPERATION_RETRY) + @bypass_ltm = @config.get_property(Juno::Properties::BYPASS_LTM, Juno::DefaultProperties::BYPASS_LTM) + @reconnect_on_fail = @config.get_property(Juno::Properties::RECONNECT_ON_FAIL, + Juno::DefaultProperties::RECONNECT_ON_FAIL) + @config_prefix = @config.get_property(Juno::Properties::CONFIG_PREFIX, Juno::DefaultProperties::CONFIG_PREFIX) + nil + end + + def validate! + missing_properties = [] + REQUIRED_PROPERTIES.each do |property| + missing_properties.push(property) if send(property).nil? + end + + if @use_ssl + %i[ssl_cert_file ssl_key_file].each do |property| + missing_properties.push(property) if send(property).nil? + end + end + + if missing_properties.length.positive? + raise "Please provide a value for the required property(s) #{missing_properties.join(', ')}." + end + + if @use_ssl + raise 'SSL Certificate file not found' unless File.exist?(@ssl_cert_file) + raise 'SSL Key file not found' unless File.exist?(@ssl_key_file) + end + + nil + end + + class Source + YAML_FILE = 0 + JSON_FILE = 1 + URL = 2 + end + end + + def self.configure + if @juno_config.nil? + config_reader = Juno::ConfigReader.new + yield config_reader + if !config_reader.file_path.nil? + @juno_config = Config.new(ConfigProvider.new(config_reader.file_path, config_reader.source_format, nil), + log_file: config_reader.log_file, ssl_cert_file: config_reader.ssl_cert_file, + ssl_key_file: config_reader.ssl_key_file) + @LOGGER = Juno::Logger.instance + elsif !config_reader.url.nil? # URL should URI Object + # @juno_config = Config.new(ConfigProvider.new(@juno_config.file_path, @juno_config.source_format, nil)) + else + raise 'No file or url provided' + end + else + Juno::Logger.instance.warn('Juno client cannot be reconfigured') + end + end + + def self.juno_config + raise 'Please configure the properties using Juno.configure' if @juno_config.nil? + + @juno_config + end +end diff --git a/client/Ruby/juno/lib/juno/Config/config_provider.rb b/client/Ruby/juno/lib/juno/Config/config_provider.rb new file mode 100644 index 0000000..3f5d937 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Config/config_provider.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + # Class to read config from file or url + class ConfigProvider + # Constructor + # @param source_uri [URI] Ruby URI Object for file or URL (required) + # @param source_format [String] source_format required only for url. Inferred from file extension when using file (optional) + # @return Propert value. Return default_value if property not found + # @see Juno::Properties + def initialize(source_uri, source_format = nil, _http_handler = nil) + begin + source_scheme = source_uri&.send(:scheme) + rescue StandardError => e + raise "Invalid source_uri object.\n #{e.message}" + end + if source_scheme == 'file' + read_from_file(source_uri) + elsif source_scheme =~ /^http(s)?$/ + read_from_url(source_uri, source_format, http_handler) + else + raise 'Only local file and URL supported' + end + end + + # Function to intialize configatron object from config file/URL + # @param source_uri [URI] Ruby URI Object for file or URL (required) + # @return [nil] + def read_from_file(source_uri) + raise 'Config file not found' unless File.exist?(source_uri.path) + + hsh = if ['.yml', '.yaml'].include?(File.extname(source_uri.path)) + YAML.load_file(source_uri.path) + elsif ['.json'].inlcude?(File.extname(source_uri.path)) + json_text = File.read(source_uri.path) + JSON.parse(json_text) + else + raise 'Unknown file format' + end + configatron.configure_from_hash(hsh) + nil + end + + def read_from_url(source_uri, source_format, http_handler); end + + # Function to read propertied in the heirarchy define in Juno::Properties + # @param property_key [String] String key (required) + # @param default_value (optional) default value if property not found + # @return Propert value. Returns default_value if property not found + # @see Juno::Properties + def get_property(property_key, default_value = nil) + return default_value if property_key.to_s.empty? + + value = configatron.to_h + property_key.to_s.split('.').each do |k| + return default_value unless value.is_a?(Hash) && value.key?(k.to_sym) + + value = value[k.to_sym] + # puts "#{k} --- #{value}" + end + + value.nil? || value.is_a?(Hash) ? default_value : value + end + end +end diff --git a/client/Ruby/juno/lib/juno/Config/config_reader.rb b/client/Ruby/juno/lib/juno/Config/config_reader.rb new file mode 100644 index 0000000..4f8d3e6 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Config/config_reader.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + # Properties Reader - Properties to be read from the developer using Juno.configure + # Either file_path or url is required + # log device can be a filename or IO Object + class ConfigReader + attr_accessor :file_path, :url, :source_format, :http_handler, :log_level, :log_device, + :max_log_file_bytes, :log_rotation, :log_file, :ssl_cert_file, :ssl_key_file + + def initialize + # default values + @log_level = ::Logger::Severity::INFO + @max_log_file_bytes = 1_048_576 # default for inbuilt logger class + @log_device = $stdout + @log_rotation = 'daily' # daily, weekly, monthly + end + end +end diff --git a/client/Ruby/juno/lib/juno/Config/default_properties.rb b/client/Ruby/juno/lib/juno/Config/default_properties.rb new file mode 100644 index 0000000..fee4232 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Config/default_properties.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + # Module containing constant default values for Properties + class DefaultProperties + RESPONSE_TIMEOUT_MS = 200 + CONNECTION_TIMEOUT_MS = 200 + CONNECTION_POOLSIZE = 1 + CONNECTION_LIFETIME_MS = 30_000 + DEFAULT_LIFETIME_S = 259_200 + + # Max for all above property + MAX_RESPONSE_TIMEOUT_MS = 5000 + MAX_CONNECTION_LIFETIME_MS = 30_000 + MAX_CONNECTION_TIMEOUT_MS = 5000 + MAX_KEY_SIZE_B = 128 + MAX_VALUE_SIZE_B = 204_800 + MAX_NAMESPACE_LENGTH = 64 + MAX_CONNECTION_POOL_SIZE = 3 + MAX_LIFETIME_S = 259_200 + + # Required Properties + HOST = '' + PORT = 0 + APP_NAME = '' + RECORD_NAMESPACE = '' + + # optional Properties + CONFIG_PREFIX = '' + USE_SSL = true + RECONNECT_ON_FAIL = false + USE_PAYLOAD_COMPRESSION = false + OPERATION_RETRY = false + BYPASS_LTM = true + end +end diff --git a/client/Ruby/juno/lib/juno/Config/properties.rb b/client/Ruby/juno/lib/juno/Config/properties.rb new file mode 100644 index 0000000..488d12a --- /dev/null +++ b/client/Ruby/juno/lib/juno/Config/properties.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + # Module for properties key (config file) + class Properties + RESPONSE_TIMEOUT = 'juno.response.timeout_msec' + CONNECTION_TIMEOUT = 'juno.connection.timeout_msec' + DEFAULT_LIFETIME = 'juno.default_record_lifetime_sec' + CONNECTION_LIFETIME = 'juno.connection.recycle_duration_msec' + CONNECTION_POOLSIZE = 'juno.connection.pool_size' + RECONNECT_ON_FAIL = 'juno.connection.reconnect_on_fail' + HOST = 'juno.server.host' + PORT = 'juno.server.port' + APP_NAME = 'juno.application_name' + RECORD_NAMESPACE = 'juno.record_namespace' + USE_SSL = 'juno.useSSL' + USE_PAYLOAD_COMPRESSION = 'juno.usePayloadCompression' + ENABLE_RETRY = 'juno.operation.retry' + BYPASS_LTM = 'juno.connection.byPassLTM' + CONFIG_PREFIX = 'prefix' + + # Max for each property + MAX_LIFETIME = 'juno.max_record_lifetime_sec' + MAX_KEY_SIZE = 'juno.max_key_size' + MAX_VALUE_SIZE = 'juno.max_value_size' + MAX_RESPONSE_TIMEOUT = 'juno.response.max_timeout_msec' + MAX_CONNECTION_TIMEOUT = 'juno.connection.max_timeout_msec' + MAX_CONNECTION_LIFETIME = 'juno.connection.max_recycle_duration_msec' + MAX_CONNECTION_POOL_SIZE = 'juno.connection.max_pool_size' + MAX_NAMESPACE_LENGTH = 'juno.max_record_namespace_length' + end +end diff --git a/client/Ruby/juno/lib/juno/IO/JunoMessage.rb b/client/Ruby/juno/lib/juno/IO/JunoMessage.rb new file mode 100644 index 0000000..7678fcf --- /dev/null +++ b/client/Ruby/juno/lib/juno/IO/JunoMessage.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Juno + module IO + # JunoMessage containing all configuration required to create an operation message + class JunoMessage + attr_accessor :operation_type, :server_status, + :namespace, :key, :value, :is_compressed, :compression_type, + :time_to_live_s, :version, :creation_time, :expiration_time, :request_uuid, + :ip, :app_name, :port, :last_modification, :originator_request_id, :correlation_id, + :request_handling_time, :request_start_time, :message_size, :compression_achieved, :expiry + + def initialize + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + @operation_type = Juno::IO::JunoMessage::OperationType::NOP + @server_status = Juno::ServerStatus::SUCCESS + @compression_type = Juno::IO::CompressionType::None + @is_compressed = false + @compression_achieved = 0 + @message_size = 0 + @value = '' + end + + class OperationType + NOP = 0 + CREATE = 1 + GET = 2 + UPDATE = 3 + SET = 4 + DESTROY = 5 + + @@status_code_map = nil + + def self.initialize_map + @@status_code_map = {} + + constants.each do |const| + const_obj = const_get(const) + @@status_code_map[const_obj.to_i] = const_obj + end + end + + def self.get(status_code) + initialize_map if @@status_code_map.nil? + return @@status_code_map[status_code.to_i] if @@status_code_map.key?(status_code) + + INTERNAL_ERROR + end + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/IO/MetadataComponent.rb b/client/Ruby/juno/lib/juno/IO/MetadataComponent.rb new file mode 100644 index 0000000..9b8c3c9 --- /dev/null +++ b/client/Ruby/juno/lib/juno/IO/MetadataComponent.rb @@ -0,0 +1,354 @@ +# frozen_string_literal: true + +module Juno + module IO + # + # ** MetaData Component ** + # A variable length header followed by a set of meta data fields + # Tag/ID: 0x02 + # * Header * + # + # | 0| 1| 2| 3| 4| 5| 6| 7| + # 0 | size | 4 bytes + # ----+-----------------------+--------- + # 4 | Tag/ID (0x02) | 1 byte + # ----+-----------------------+--------- + # 5 | Number of fields | 1 byte + # ----+--------------+--------+--------- + # 6 | Field tag |SizeType| 1 byte + # ----+--------------+--------+--------- + # | ... | + # ----+-----------------------+--------- + # | padding to 4 | + # ----+-----------------------+--------- + # (Don't think we need a header size. ) + # + # SizeType: + # 0 variable length field, for that case, + # the first 1 byte of the field MUST be + # the size of the field(padding to 4 byte). + # The max is 255. + # n Fixed length: 2 ^ (n+1) bytes + # + # + # + # * Body * + # ----+-----------------------+--------- + # | Field data | defined by Field tag + # ----+-----------------------+--------- + # | ... | + # ----+-----------------------+--------- + # | padding to 8 | + # ----+-----------------------+--------- + # + # * Predefined Field Types * + # + # TimeToLive Field + # Tag : 0x01 + # SizeType : 0x01 + # Version Field + # Tag : 0x02 + # SizeType : 0x01 + # Creation Time Field + # Tag : 0x03 + # SizeType : 0x01 + # Expiration Time Field + # Tag : 0x04 + # SizeType : 0x01 + # RequestID/UUID Field + # Tag : 0x05 + # SizeType : 0x03 + # Source Info Field + # Tag : 0x06 + # SizeType : 0 + # Last Modification time (nano second) + # Tag : 0x07 + # SizeType : 0x02 + # Originator RequestID Field + # Tag : 0x08 + # SizeType : 0x03 + # Correlation ID field + # Tag : 0x09 + # SizeType : 0x0 + # Request Handling Time Field + # Tag : 0x0a + # SizeType : 0x01 + # + # Tag: 0x06 + # + # | 0| 1| 2| 3| 4| 5| 6| 7| 0| 1| 2| 3| 4| 5| 6| 7| 0| 1| 2| 3| 4| 5| 6| 7| 0| 1| 2| 3| 4| 5| 6| 7| + # | 0| 1| 2| 3| + # +-----------+-----------+--------------------+--+-----------------------+-----------------------+ + # | size (include padding)| app name length | T| Port | + # +-----------------------+--------------------+--+-----------------------------------------------+ + # | IPv4 address if T is 0 or IPv6 address if T is 1 | + # +-----------------------------------------------------------------------------------------------+ + # | application name, padding to 4-bytes aligned | + # +-----------------------------------------------------------------------------------------------+ + + # Wrapper class for MetadataComponentTemplate + class MetadataComponent + attr_reader :metadata_field_list, :time_to_live, :version, :creation_time, :expiration_time, :request_uuid, + :ip, :app_name, :port, :last_modification, :originator_request_id, :correlation_id, :request_handling_time + + def initialize + @PROG_NAME = self.class.name + # @LOGGER = Juno::Logger.instance + # @metadata_field_list [Array] + @metadata_field_list = [] + end + + # @param ttl [Integer] - Record Time to live + def set_time_to_live(ttl) + ttl = ttl.to_i + raise ArgumentError, 'TTL should be > 0' unless ttl.positive? + + @time_to_live = ttl + ttl = [ttl].pack(OffsetWidth.UINT32) + add_field(MetadataField.new(0x01, 0x01, ttl)) + end + + # @param version [Integer] - Record version + def set_version(data) + @version = data + version_bytes_string = [data].pack(OffsetWidth.UINT32) + add_field(MetadataField.new(0x02, 0x01, version_bytes_string)) + end + + # @param creation_time [Integer] - Unix timestamp (required) + def set_creation_time(data) + @creation_time = data + creation_time_bytes_string = [data].pack(OffsetWidth.UINT32) + add_field(MetadataField.new(0x03, 0x01, creation_time_bytes_string)) + end + + def set_expiration_time(data) + @expiration_time = data + expiration_time_bytes_string = [data].pack(OffsetWidth.UINT32) + add_field(MetadataField.new(0x04, 0x01, expiration_time_bytes_string)) + end + + # @param input_uuid_byte_string [String] - Record Time to live (optional) + # if not provided, creates a uuid itself + def set_request_uuid(input_uuid_byte_string = nil) + @request_uuid = if input_uuid_byte_string.nil? + UUIDTools::UUID.random_create + else + UUIDTools::UUID.parse_raw(input_uuid_byte_string) + end + add_field(MetadataField.new(0x05, 0x03, @request_uuid.raw)) + @request_uuid + end + + # SourceInfoField + # @param app_name [String] - Record Time to live (required) + # @param ip [IPAddr] - ip address for component (required) + # @param port [Integer] (required) + def set_source_info(app_name:, ip:, port:) + @ip = ip + @port = port + @app_name = app_name + data = MetadataComponentTemplate::SourceInfoField.new + data.app_name = app_name + data.ip = ip.hton + data.port = port + str_io = StringIO.new + data.write(str_io) + add_field(MetadataField.new(0x06, 0x00, str_io.string)) + end + + def set_last_modification(data) + @last_modification = data + last_modification_bytes_string = [data].pack(OffsetWidth.UINT64) + add_field(MetadataField.new(0x07, 0x02, last_modification_bytes_string)) + end + + # @param input_uuid_byte_string [String] (optional) + # if not provided, creates a uuid itself + def set_originator_request_id(input_uuid_byte_string = nil) + @originator_request_id = if input_uuid_byte_string.nil? + UUIDTools::UUID.random_create + else + UUIDTools::UUID.parse_raw(input_uuid_byte_string) + end + add_field(MetadataField.new(0x08, 0x03, @originator_request_id.raw)) + @originator_request_id + end + + # @param input_uuid_byte_string [String] (optional) + # if not provided, creates a uuid itself + def set_correlation_id(input_uuid_byte_string = nil) + @correlation_id = if input_uuid_byte_string.nil? + UUIDTools::UUID.random_create + else + UUIDTools::UUID.parse_raw(input_uuid_byte_string) + end + field = MetadataComponentTemplate::CorrelationIDField.new + field.correlation_id = @correlation_id.raw + str_io = StringIO.new + field.write(str_io) + # puts field + add_field(MetadataField.new(0x09, 0x0, str_io.string)) + end + + def set_request_handling_time(data) + @request_handling_time = data + request_handling_time_bytes_string = [data].pack(OffsetWidth.UINT32) + add_field(MetadataField.new(0x0A, 0x01, request_handling_time_bytes_string)) + end + + # Function to add feild to the list + # @param field [MetadataField] (required) + def add_field(field) + metadata_field_list.push(field) + end + + # function to calculate size of metadata component + def num_bytes + io = StringIO.new + write(io) + io.size + end + + # Function to serialize Component to buffer + # @param io [StringIO] (required) + def write(io) + buffer = MetadataComponentTemplate.new + buffer.number_of_fields = metadata_field_list.length + metadata_field_list.each do |field| + f = MetadataComponentTemplate::MetadataHeaderField.new + f.size_type = field.size_type + f.field_tag = field.tag + buffer.metadata_fields.push(f) + end + + body = StringIO.new + metadata_field_list.each do |field| + body.write(field.data) + end + padding_size = (8 - body.size % 8) % 8 + body.write(Array.new(0, padding_size).pack(OffsetWidth.UINT8('*'))) if padding_size.positive? + buffer.body = body.string + + buffer.write(io) + end + + # Function to de-serialize Component to buffer + # @param io [StringIO] (required) + def read(io) + metadata_component = MetadataComponentTemplate.new + metadata_component.read(io) + + body_buffer = StringIO.new(metadata_component.body) + + metadata_component.metadata_fields.each do |field| + case field.field_tag + when TagAndType::TimeToLive[:tag] + ttl_byte_string = body_buffer.read(1 << (1 + TagAndType::TimeToLive[:size_type])) + set_time_to_live(ttl_byte_string.unpack1(OffsetWidth.UINT32)) + + when TagAndType::Version[:tag] + version_byte_string = body_buffer.read(1 << (1 + TagAndType::Version[:size_type])) + set_version(version_byte_string.unpack1(OffsetWidth.UINT32)) + + when TagAndType::CreationTime[:tag] + creation_time_byte_string = body_buffer.read(1 << (1 + TagAndType::CreationTime[:size_type])) + set_creation_time(creation_time_byte_string.unpack1(OffsetWidth.UINT32)) + + when TagAndType::RequestUUID[:tag] + request_uuid_byte_string = body_buffer.read(1 << (1 + TagAndType::RequestUUID[:size_type])) + set_request_uuid(request_uuid_byte_string) + + when TagAndType::SourceInfo[:tag] + source_info = MetadataComponentTemplate::SourceInfoField.new + source_info.read(body_buffer) + set_source_info(app_name: source_info.app_name, ip: IPAddr.new_ntoh(source_info.ip), port: source_info.port) + + when TagAndType::LastModification[:tag] + last_modification_byte_string = body_buffer.read(1 << (1 + TagAndType::LastModification[:size_type])) + set_last_modification(last_modification_byte_string.unpack1(OffsetWidth.UINT64)) + + when TagAndType::ExpirationTime[:tag] + expiration_time_byte_string = body_buffer.read(1 << (1 + TagAndType::ExpirationTime[:size_type])) + set_expiration_time(expiration_time_byte_string.unpack1(OffsetWidth.UINT32)) + + when TagAndType::OriginatorRequestID[:tag] + originator_request_id_byte_string = body_buffer.read(1 << (1 + TagAndType::OriginatorRequestID[:size_type])) + set_originator_request_id(originator_request_id_byte_string) + # when TagAndType::CorrelationID[:tag] + + when TagAndType::RequestHandlingTime[:tag] + request_handling_time_byte_string = body_buffer.read(1 << (1 + TagAndType::RequestHandlingTime[:size_type])) + set_request_handling_time(request_handling_time_byte_string.unpack1(OffsetWidth.UINT32)) + end + end + end + + class TagAndType + TimeToLive = { + tag: 0x01, + size_type: 0x01 + }.freeze + Version = { + tag: 0x02, + size_type: 0x01 + }.freeze + CreationTime = { + tag: 0x03, + size_type: 0x01 + }.freeze + RequestUUID = { + tag: 0x05, + size_type: 0x03 + }.freeze + SourceInfo = { + tag: 0x06, + size_type: 0x00 + }.freeze + ExpirationTime = { + tag: 0x04, + size_type: 0x01 + }.freeze + LastModification = { + tag: 0x07, + size_type: 0x02 + }.freeze + OriginatorRequestID = { + tag: 0x08, + size_type: 0x03 + }.freeze + CorrelationID = { + tag: 0x09, + size_type: 0x00 + }.freeze + RequestHandlingTime = { + tag: 0x0A, + size_type: 0x01 + }.freeze + end + + # DataType for @metadata_field_list + class MetadataField + attr_accessor :tag, :size_type, :data + + def initialize(tag, size_type, data) + @tag = tag + @size_type = size_type + @data = data + end + + def size + if size_type == SizeType::Variable + data.length + else + 1 << (size_type + 1) + end + end + + class SizeType + Variable = 0 + end + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/IO/MetadataComponentTemplate.rb b/client/Ruby/juno/lib/juno/IO/MetadataComponentTemplate.rb new file mode 100644 index 0000000..95d1948 --- /dev/null +++ b/client/Ruby/juno/lib/juno/IO/MetadataComponentTemplate.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +module Juno + module IO + class MetadataComponentTemplate < BinData::Record + class MetadataHeaderField < BinData::Record + bit3 :size_type + bit5 :field_tag + end + + class FixedLengthField < BinData::Record + mandatory_parameter :field_length + + string :data, read_length: :field_length + end + + class SourceInfoField < BinData::Record + def field_bytes + field_length.num_bytes + app_name_length.num_bytes + port.num_bytes + ip.num_bytes + app_name.num_bytes + end + + def padding_size + (4 - field_bytes % 4) % 4 + end + + def ipv6? + IPAddr.new_ntoh(ip).ipv6? + end + + endian :big + uint8 :field_length, value: -> { field_bytes + padding.num_bytes } + uint8 :app_name_length, value: -> { ipv6? ? app_name.length | 128 : app_name.length } + uint16 :port + string :ip, read_length: -> { app_name_length & 128 == 1 ? 16 : 4 } + string :app_name, read_length: :app_name_length + string :padding, length: :padding_size + end + + class CorrelationIDField < BinData::Record + def padding_size + size = component_size.num_bytes + correlation_id_length.num_bytes + correlation_id.num_bytes + (4 - size % 4) % 4 + end + + endian :big + uint8 :component_size, value: -> { num_bytes } + uint8 :correlation_id_length, value: -> { correlation_id.length } + string :correlation_id + string :padding, length: :padding_size + end + + def header_num_bytes + component_size.num_bytes + tag_id.num_bytes + number_of_fields.num_bytes + metadata_fields.num_bytes + end + + def header_padding_length + (4 - header_num_bytes % 4) % 4 + end + + endian :big + uint32 :component_size, value: -> { num_bytes } + uint8 :tag_id, value: 0x02 + uint8 :number_of_fields, value: -> { metadata_fields.length } + array :metadata_fields, initial_length: :number_of_fields, type: :metadata_header_field + string :header_padding, length: :header_padding_length # implement padding length + + string :body, read_length: lambda { + component_size - 4 - 1 - 1 - number_of_fields - header_padding.num_bytes + } + end + end +end diff --git a/client/Ruby/juno/lib/juno/IO/OperationMessage.rb b/client/Ruby/juno/lib/juno/IO/OperationMessage.rb new file mode 100644 index 0000000..4eba9f0 --- /dev/null +++ b/client/Ruby/juno/lib/juno/IO/OperationMessage.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module Juno + module IO + class OperationMessage + attr_accessor :protocol_header, :metadata_component, :payload_component + + def initialize + @protocol_header = ProtocolHeader.new + @metadata_component = nil + @payload_component = nil + end + + # Calculates size of message + def size + total_size = protocol_header.num_bytes + total_size += payload_component.num_bytes unless payload_component.nil? + total_size += metadata_component.num_bytes unless metadata_component.nil? + total_size + end + + # Function to serialize message to buffer + # @param io [StringIO] (required) + def write(io) + protocol_header.message_size = size + + protocol_header.write(io) + metadata_component&.write(io) + payload_component&.write(io) + nil + end + + # Function to de-serialize message to buffer + # @param io [StringIO] (required) + def read(io) + return if io.eof? || (io.size - io.pos) < 16 + + @protocol_header = ProtocolHeader.new + @metadata_component = MetadataComponent.new + @payload_component = PayloadComponent.new + + @protocol_header.read(io) + + remaining_size = protocol_header.message_size - 16 + prev_position = io.pos + + @metadata_component.read(io) if !io.eof? && (io.size - io.pos) >= remaining_size + + remaining_size -= (io.pos - prev_position) + + @payload_component.read(io) if !io.eof? && (io.size - io.pos) >= remaining_size + nil + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/IO/PayloadComponent.rb b/client/Ruby/juno/lib/juno/IO/PayloadComponent.rb new file mode 100644 index 0000000..4c2e426 --- /dev/null +++ b/client/Ruby/juno/lib/juno/IO/PayloadComponent.rb @@ -0,0 +1,167 @@ +# frozen_string_literal: true + +module Juno + module IO + # ** Payload (or KeyValue) Component ** + # + # A 12-byte header followed by name, key and value + # Tag/ID: 0x01 + # * Header * + # + # |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7| + # | 0| 1| 2| 3| + # ------+---------------+---------------+---------------+---------------+ + # 0 | Size | + # ------+---------------+---------------+-------------------------------+ + # 4 | Tag/ID (0x01) | namespace len | key length | + # ------+---------------+---------------+-------------------------------+ + # 8 | payload length | + # ------+---------------------------------------------------------------+ + # + # ( + # The max namespace length: 255 + # payload length = 0 if len(payload data) = 0, otherwise, + # payload length = 1 + len(payload data) = len(payload field) + # ) + # + # + # * Body * + # +---------+-----+---------------+-------------------------+ + # |namespace| key | payload field | Padding to align 8-byte | + # +---------+-----+---------------+-------------------------+ + # + # * Payload field* + # +---------------------+--------------+ + # | 1 byte payload type | Payload data | + # +---------------------+--------------+ + # + # * Payload Type + # 0: payload data is the actual value passed from client user + # 1: payload data is encrypted by Juno client library, details not specified + # 2: payload data is encrypted by Juno proxy with AES-GCM. encryption key length is 256 bits + # 3: Payload data is compressed by Juno Client library. + # + # * Payload data + # for payload type 2 + # +--------------------------------+----------------+----------------+ + # | 4 bytes encryption key version | 12 bytes nonce | encrypted data | + # +--------------------------------+----------------+----------------+ + # + # for payload type 3 + # +---------------------------------+------------------+----------------+ + # | 1 byte size of compression type | compression type | compressed data| + # +---------------------------------+------------------+----------------+ + # + # * compression type + # 1) snappy (default algorithm) + # 2) TBD + class PayloadComponent < BinData::Record + class EncryptedPayloadData < BinData::Record + mandatory_parameter :payload_data_length + end + + class CompressedPayloadData < BinData::Record + mandatory_parameter :payload_data_length + def data_length + eval_parameter(:payload_data_length) - 1 - compression_type + end + + uint8 :compression_type_size, value: -> { :compression_type.length } + string :compression_type, read_length: :compression_type_size, initial_value: CompressionType::None + string :data, read_length: :data_length + end + + # class PayloadBody < BinData::Record + # mandatory_parameter :payload_length + # uint8 :payload_type, initial_value: PayloadType::UnCompressed, only_if: -> { :payload_length.positive? } # optional + + # choice :payload_data, selection: :payload_type, only_if: -> { :payload_length.positive? } do + # compressed_payload_data PayloadType::Compressed, payload_data_length: lambda { + # get_payload_data_length + # } + + # uncompressed_payload_data PayloadType::UnCompressed, payload_data_length: lambda { + # get_payload_data_length + # } + + # encrypted_payload_data PayloadType::Encrypted, payload_data_length: lambda { + # get_payload_data_length + # } + # end + # end + + class UncompressedPayloadData < BinData::Record + mandatory_parameter :payload_data_length + string :data, read_length: :payload_data_length + end + + def get_payload_data_length + (payload_length.positive? ? payload_length - 1 : 0) + end + + # to prevent stack overflow + def custom_num_bytes + size = component_size.num_bytes + tag_id.num_bytes + namespace_length.num_bytes + key_length.num_bytes + payload_length.num_bytes + namespace.num_bytes + payload_key.num_bytes + size += payload_type.num_bytes + payload_data.num_bytes if payload_length.positive? + size + end + + def padding_length + (8 - custom_num_bytes % 8) % 8 + end + + endian :big + uint32 :component_size, value: -> { num_bytes } + uint8 :tag_id, value: 0x01 + uint8 :namespace_length, value: -> { namespace.length } + uint16 :key_length, value: -> { payload_key.length } + uint32 :payload_length, value: -> { payload_data.num_bytes.zero? ? 0 : payload_data.num_bytes + 1 } + string :namespace, read_length: :namespace_length # required + string :payload_key, read_length: :key_length # required + uint8 :payload_type, onlyif: lambda { + payload_length.positive? + }, initial_value: PayloadType::UnCompressed # optional + + choice :payload_data, selection: :payload_type, onlyif: -> { payload_length.positive? } do + compressed_payload_data PayloadType::Compressed, payload_data_length: lambda { + get_payload_data_length + } + + uncompressed_payload_data PayloadType::UnCompressed, payload_data_length: lambda { + get_payload_data_length + } + + encrypted_payload_data PayloadType::Encrypted, payload_data_length: lambda { + get_payload_data_length + } + end + string :padding, length: :padding_length + + def set_value(input_value, compression_type = CompressionType::None) + if compression_type != CompressionType::None + self.payload_type = PayloadType::Compressed + payload_data.compression_type = compression_type + else + self.payload_type = PayloadType::UnCompressed + end + payload_data.data = input_value + end + + def value + payload_data.data + end + + def compressed? + return true if payload_type == PayloadType::Compressed + + false + end + + def compression_type + return payload_data.compression_type if compressed? + + CompressionType::None + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/IO/ProtocolHeader.rb b/client/Ruby/juno/lib/juno/IO/ProtocolHeader.rb new file mode 100644 index 0000000..8229797 --- /dev/null +++ b/client/Ruby/juno/lib/juno/IO/ProtocolHeader.rb @@ -0,0 +1,181 @@ +# frozen_string_literal: true + +module Juno + # Juno wire protocol consists of a 12-byte header. Depending on the type, the appropriate message payload follows the fixed header section. Following is the header protocol: + # + # | 0| 1| 2| 3| 4| 5| 6| 7| 0| 1| 2| 3| 4| 5| 6| 7| 0| 1| 2| 3| 4| 5| 6| 7| 0| 1| 2| 3| 4| 5| 6| 7| + # byte | 0| 1| 2| 3| + # ------+-----------------------+-----------------------+-----------------------+-----------------------+ + # 0 | magic | version | message type flag | + # | | +-----------------+-----+ + # | | | type | RQ | + # ------+-----------------------------------------------+-----------------------+-----------------+-----+ + # 4 | message size | + # ------+-----------------------------------------------------------------------------------------------+ + # 8 | opaque | + # ------+-----------------------------------------------------------------------------------------------+ + # + # Following is the detailed description of each field in the header: + # + # offset name size (bytes) meaning + # 0 Magic 2 + # Magic number, used to identify Juno message. + # + # '0x5050' + # + # 2 Version 1 Protocol version, current version is 1. + # 3 Message Type flag + # 1 bit 0-5 + # Message Type + # + # 0: Operational Message + # + # 1: Admin Message + # + # 2: Cluster Control Message + # + # bit 6-7 + # RQ flag + # + # 0: response + # + # 1: two way request + # + # 3: one way request + # + # 4 Message size 4 Specifies the length of the message + # 8 Opaque 4 The Opaque data set in the request will be copied back in the response + # Operational Message + # Client Info (ip, port, type, application name) + # Request Type: request or response + # Operation Type: Create, Get, Update, Delete + # Request Id + # Request Info (key, ttl, version, namespace) + # Payload data size + # Payload + # Response Info (status/error code, error string) + # Flag + # Before defining the details of the protocol for operational message, we need to review, and finalize somethings at page. + # + # Operational Message Header + # + # operational request header + # |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7| + # byte | 0| 1| 2| 3| + # ------+---------------+---------------+---------------+---------------+ + # 0 | opcode |flag | shard Id | + # | +-+-------------+ | + # | |R| | | + # ------+---------------+-+-------------+-------------------------------+ + # + # operational response header + # |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7| + # byte | 0| 1| 2| 3| + # ------+---------------+---------------+---------------+---------------+ + # 0 | opcode |flag | reserved | status | + # | +-+-------------+ | | + # | |R| | | | + # ------+---------------+-+-------------+---------------+---------------+ + # + # opcode: + # 0x00 Nop + # 0x01 Create + # 0x02 Get + # 0x03 Update + # 0x04 Set + # 0x05 Destroy + # 0x81 PrepareCreate + # 0x82 Read + # 0x83 PrepareUpdate + # 0x84 PrepareSet + # 0x85 PrepareDelete + # 0x86 Delete + # 0xC1 Commit + # 0xC2 Abort (Rollback) + # 0xC3 Repair + # 0xC4 MarkDelete + # 0xE1 Clone + # 0xFE MockSetParam + # oxFF MockReSet + # R: + # 1 if it is for replication + # shard Id: + # only meaning for request to SS + # status: + # 1 byte, only meaningful for response + # + module IO + class ProtocolHeader < BinData::Record + class MessageTypes + OperationalMessage = 0 + AdminMessage = 1 + ClusterControlMessage = 2 + end + + class RequestTypes + Response = 0 + TwoWayRequest = 1 + OneWayRequest = 2 + end + + class OpCodes + Nop = 0x00 + Create = 0x01 + Get = 0x02 + Update = 0x03 + Set = 0x04 + Destroy = 0x05 + PrepareCreate = 0x81 + Read = 0x82 + PrepareUpdate = 0x83 + PrepareSet = 0x84 + PrepareDelete = 0x85 + Delete = 0x86 + Commit = 0xC1 + Abort = 0xC2 + Repair = 0xC3 + MarkDelete = 0xC4 + Clone = 0xE1 + MockSetParam = 0xFE + MockReSet = 0xFF + + def self.valid?(opcode) + constants.each do |constant| + return true if const_get(constant) == opcode + end + false + end + end + + class MessageTypeFlag < BinData::Record + bit2 :message_request_type, initial_value: ProtocolHeader::RequestTypes::TwoWayRequest + bit6 :message_type, initial_value: ProtocolHeader::MessageTypes::OperationalMessage + end + + def request? + message_type_flag.message_request_type != RequestTypes::Response + end + + endian :big + uint16 :magic, value: 0x5050 + uint8 :version, value: 1 + message_type_flag :message_type_flag + uint32 :message_size + uint32 :opaque, initial_value: 0 + uint8 :opcode, initial_value: OpCodes::Nop + uint8 :flag, value: 0 + + uint16 :shard_id, value: 0, onlyif: -> { request? } + uint8 :reserved, onlyif: -> { !request? } + uint8 :status, onlyif: -> { !request? } + + def request_type + message_type_flag.message_request_type + end + + def message_type + message_type_flag.message_type + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/IO/constants.rb b/client/Ruby/juno/lib/juno/IO/constants.rb new file mode 100644 index 0000000..543f24e --- /dev/null +++ b/client/Ruby/juno/lib/juno/IO/constants.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Top module for juno client +module Juno + # Submodule containing modules related to WireProtocol + module IO + class OffsetWidth + # Count can be integer or '*' + def self.UINT64(count = '') + "Q#{count}" + end + + def self.UINT32(count = '') + "N#{count}" + end + + def self.UINT16(count = '') + "n#{count}" + end + + def self.UINT8(count = '') + "C#{count}" + end + end + + # Class containing constants for CompressionType + class CompressionType + None = 'None' + Snappy = 'Snappy' + + def self.valid?(compression_type) + constants.each do |constant| + return true if const_get(constant) == compression_type + end + false + end + end + + # Class containing constants for PayloadType + class PayloadType + UnCompressed = 0x00 + Encrypted = 0x02 + Compressed = 0x03 + end + end +end diff --git a/client/Ruby/juno/lib/juno/Net/base_processor.rb b/client/Ruby/juno/lib/juno/Net/base_processor.rb new file mode 100644 index 0000000..79c7171 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Net/base_processor.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Juno + module Net + # BaseProcessor - base class for IOProcessor + # Handles logic for reading and writing ping_ip for bypass ltm + class BaseProcessor + def initialize(_ = nil) + @ping_queue = SizedQueue.new(1) + end + + def ping_ip=(ip) + @ping_queue.push(ip) + end + + def ping_ip + begin + ip = @ping_queue.pop(true) + rescue ThreadError + return nil + end + + return nil if ip.to_s.empty? + + begin + IPAddr.new(ip) + rescue StandardError + nil + end + end + + def clear_ping_queue + @ping_queue.clear + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Net/client_handler.rb b/client/Ruby/juno/lib/juno/Net/client_handler.rb new file mode 100644 index 0000000..22ecc32 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Net/client_handler.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +module Juno + module Net + # Hanldes connection creation and receiving data asynchronously + # Managed by EventMachine::Connection + class ClientHandler < EventMachine::Connection + # Constant to count messages received + @@recv_count = Concurrent::AtomicFixnum.new(0) + + def self.received_messages + @@recv_count.value + end + + # Constructor + # @param io_processor (Juno::Net::IOProcessor) + def initialize(io_processor) + super + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + @io_processor = io_processor + @channel = self + @connected = Concurrent::AtomicBoolean.new(false) + @ssl_connected = Concurrent::AtomicBoolean.new(false) + end + + # Method called once for each instance of Juno::Net::ClientHandler at initialization + def post_init + start_tls_connection if use_ssl? + end + + # starts tls connection once TCP connection is estabilished + def start_tls_connection + raise 'SSL Cert file not found' unless File.exist?(Juno.juno_config.ssl_cert_file) + raise 'SSL Key file not found' unless File.exist?(Juno.juno_config.ssl_key_file) + + @channel.start_tls( + private_key_file: Juno.juno_config.ssl_key_file, cert: File.read(Juno.juno_config.ssl_cert_file) + ) + # Timer to check if SSL Handshake was successful + EventMachine::Timer.new(Juno.juno_config.max_connection_timeout.to_f / 1000) do + if @ssl_connected.false? + puts 'SLL Handshake timeout' + close_connection + end + end + end + + # Method called when TCP connection estabilished. If useSSL is true, it is called after a successfull ssl handshake + def on_connection_completed + # puts "completed #{Time.now}" + end + + # method to check if channel is connected + def is_connected? + if use_ssl? + return false if @ssl_connected.false? + elsif @connected.false? + return false + end + + # get ip and port of server + # Socket.unpack_sockaddr_in(@channel.get_peername) + true + rescue Exception => e + @LOGGER.error(@PROG_NAME) { e.message } + false + end + + def use_ssl? + Juno.juno_config.use_ssl + end + + def use_ltm? + Juno.juno_config.bypass_ltm + end + + # method called by EventMachine when data is received from server + # @param data [String] - byte data received from server + def receive_data(data) + @@recv_count.increment + # puts @@recv_count + + EventMachine.defer do + operation_message = Juno::IO::OperationMessage.new + operation_message.read(StringIO.new(data)) + @io_processor.put_response(operation_message) + end + end + + # Called by EventMachine after TCP Connection estabilished + def connection_completed + @connected.value = true + on_connection_completed unless use_ssl? + end + + # Called by EventMachine after connection disconnected + # @param m - Error if disconnected due to an error + def unbind(error) + @connected.value = false + @ssl_connected.value = false + puts error unless error.nil? + end + + # Called by EventMachine after ssl handshake + def ssl_handshake_completed + @ssl_connected.value = true + on_connection_completed if use_ssl? + + # puts get_cipher_name + # puts get_cipher_protocol + @server_handshake_completed = true + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Net/io_processor.rb b/client/Ruby/juno/lib/juno/Net/io_processor.rb new file mode 100644 index 0000000..436fc9b --- /dev/null +++ b/client/Ruby/juno/lib/juno/Net/io_processor.rb @@ -0,0 +1,211 @@ +# frozen_string_literal: true + +require 'concurrent' +module Juno + module Net + # Module to handle connections to server, reading/writing requests from request queue + class IOProcessor < BaseProcessor + INITIAL_BYPASSLTM_RETRY_INTERVAL = 337_500 + MAX_BYPASSLTM_RETRY_INTERVAL = 86_400_000 + INIT_WAIT_TIME = 200 + MAX_WAIT_TIME = 60_000 + # class variable to count messages sent using send_data + @@counter = Concurrent::AtomicFixnum.new(0) + def self.send_count + @@counter.value + end + + # @param request_queue [Juno::Net::RequestQueue] + # @param opaque_resp_queue_map [Concurrent::Map] - map containing opaque as key and value as Response queue corresponding to opaque + def initialize(request_queue, opaque_resp_queue_map) + super() + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + @stop = false + @request_queue = request_queue + @opaque_resp_queue_map = opaque_resp_queue_map + @ctx = nil ## changed + @handshake_failed_attempts = 0 + @reconnect_wait_time = INIT_WAIT_TIME + @shift = 5 # seconds + @next_bypass_ltm_check_time = Time.now + @bypass_ltm_retry_interval = INITIAL_BYPASSLTM_RETRY_INTERVAL + # @config = config + @channel = nil + @next_reconnect_due = Float::INFINITY + end + + def connection_lifetime + Juno.juno_config.connection_lifetime + end + + def put_response(operation_message) + return if operation_message.nil? + + unless Juno::Net::PingMessage.ping_response?(operation_message, self) + opaque = operation_message&.protocol_header&.opaque + return if opaque.nil? + + resp_queue = @opaque_resp_queue_map.get_and_set(opaque.to_i, nil) + if !resp_queue.nil? + begin + resp_queue.push(operation_message) + rescue ThreadError + @LOGGER.debug(@PROG_NAME) { "response queue for #{opaque.to_i} is full" } + end + else + @LOGGER.debug(@PROG_NAME) { "resp_queue nil for #{opaque.to_i}" } + end + end + nil + end + + def disconnect_channel(channel) + EventMachine::Timer.new(2 * Juno.juno_config.max_response_timeout.to_f / 1000) do + channel&.close_connection_after_writing if !channel.nil? && channel.is_connected? + end + end + + def set_recycle_timer + @recycle_timer = EventMachine::Timer.new(Juno.juno_config.connection_lifetime.to_f / 1000) do + juno_connect(true) + end + end + + def initiate_bypass_ltm + send_ping_message + EventMachine::Timer.new(Juno.juno_config.response_timeout.to_f / 1000) do + ip = ping_ip + unless ip.nil? + new_channel = EventMachine.connect(ip.to_s, Juno.juno_config.port, ClientHandler, self) + EventMachine::Timer.new(Juno.juno_config.connection_timeout.to_f / 1000) do + if new_channel.is_connected? + @LOGGER.info(@PROG_NAME) { "conncected to Proxy #{ip}:#{Juno.juno_config.port} " } + old_channel = @channel + @channel = new_channel + disconnect_channel(old_channel) + else + @LOGGER.info(@PROG_NAME) { "could not conncect to Proxy #{ip}:#{Juno.juno_config.port} " } + end + end + end + end + end + + # Sends ping message to LoadBalancer to get ProxyIP + # @see Juno::Net::PingMessage + def send_ping_message + ping_message = Juno::Net::PingMessage.new + buff = StringIO.new + ping_message.write(buff) + request_uuid = ping_message&.operation_message&.metadata_component&.request_uuid.to_s + @request_queue.push(buff.string, request_uuid) + end + + # Method to handle connections creation, re-attempts on failure, initiates connection refresh and connection to Proxy + # @param recycle [Boolean] - True if connection refresh request (optional, default: false) + def juno_connect(recycle = false) + return if !recycle && !@channel.nil? && @channel.is_connected? + + new_channel = EventMachine.connect(Juno.juno_config.host, Juno.juno_config.port, ClientHandler, self) + new_channel.pending_connect_timeout = Juno.juno_config.connection_lifetime + EventMachine::Timer.new(Juno.juno_config.connection_timeout.to_f / 1000) do + if new_channel.is_connected? + @LOGGER.info(@PROG_NAME) { "conncected to #{Juno.juno_config.host}:#{Juno.juno_config.port} " } + if recycle + old_channel = @channel + @channel = new_channel + disconnect_channel(old_channel) + else + @channel = new_channel + end + initiate_bypass_ltm if use_ltm? + set_recycle_timer + else + @recycle_timer&.cancel + new_channel&.close_connection if !new_channel.nil? && new_channel.is_connected? + @LOGGER.info(@PROG_NAME) do + "Could not conncect to #{Juno.juno_config.host}:#{Juno.juno_config.port}\n Retrying in #{@reconnect_wait_time.to_f / 1000}ms " + end + EventMachine::Timer.new(@reconnect_wait_time.to_f / 1000) do + @reconnect_wait_time *= 2 + @reconnect_wait_time = MAX_WAIT_TIME if @reconnect_wait_time > MAX_WAIT_TIME + @reconnect_wait_time *= (1 + 0.3 * rand) + juno_connect(recycle) + end + end + end + end + + def stop + @stop = true + end + + # Event loop to continously check for requests in @request_queue + def run + EventMachine.run do + juno_connect + EventMachine.tick_loop do + if !@channel.nil? && @channel.is_connected? + # key = "19key#{rand(100) + rand(1_000_000)}" + item = @request_queue.pop + unless item.nil? + @@counter.increment + @channel.send_data(item.msg_buffer) + end + end + :stop if @stop == true + rescue Exception => e + @LOGGER.error(@PROG_NAME) do + "Error in tick_loop: #{e.message}. Stopping tick_loop" + end + :stop + end.on_stop do + @LOGGER.debug(@PROG_NAME) do + "tick loop stopped. Stop initiated by client #{@stop}" + end + reset_connections + EventMachine::Timer.new(2 * Juno.juno_config.connection_timeout.to_f / 1000) do + EventMachine.stop + end + end + rescue Exception => e + @LOGGER.debug(@PROG_NAME) do + "EventMachine Fatal Exception #{e.message}" + end + reset_connections + EventMachine.stop + end + end + + def reset_connections + @recycle_timer&.cancel + disconnect_channel(@channel) + end + + def use_ssl? + Juno.juno_config.use_ssl + end + + def host + Juno.juno_config.host + end + + def port + Juno.juno_config.port + end + + def use_ltm? + host != '127.0.0.1' && Juno.juno_config.bypass_ltm # boolean + end + + def bypass_ltm_disabled? + if Time.now > @next_bypass_ltm_check_time && @bypass_ltm_retry_interval < MAX_BYPASSLTM_RETRY_INTERVAL + return false + end + + true + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Net/ping_message.rb b/client/Ruby/juno/lib/juno/Net/ping_message.rb new file mode 100644 index 0000000..6d06060 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Net/ping_message.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +module Juno + module Net + # Module to Create/Decode Ping messages + class PingMessage + # Constant Internal app name to check for ping messages + JUNO_INTERNAL_APPNAME = 'JunoInternal' + + # method to read the operation message + attr_reader :operation_message + + # @param operation_message [Juno::IO::OperationMessage] (optional, default: Juno::Net::PingMessage::JUNO_INTERNAL_APPNAME) + # @param opaque [Integer] (optional, default: 0) + def initialize(app_name = nil, opaque = 0) + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + app_name = JUNO_INTERNAL_APPNAME if app_name.to_s.empty? + + meta_data_component = Juno::IO::MetadataComponent.new + meta_data_component.set_request_uuid + meta_data_component.set_source_info(app_name: app_name, ip: IPAddr.new(Juno::Utils.local_ips[0]), port: 0) + + protocol_header = Juno::IO::ProtocolHeader.new + protocol_header.opcode = Juno::IO::ProtocolHeader::OpCodes::Nop + protocol_header.opaque = opaque + + @operation_message = Juno::IO::OperationMessage.new + @operation_message.metadata_component = meta_data_component + @operation_message.protocol_header = protocol_header + end + + # method to check if given operation message is a Ping response + # Updates ping_ip in processor if it is a ping response + # @param operation_message [Juno::IO::OperationMessage] (required) + # @param operation_message [Juno::Net::IOProcessor] (required) + def self.ping_response?(operation_message, processor) + return false unless processor.use_ltm? + + opcode = operation_message&.protocol_header&.opcode + raise 'missing protocol header' if opcode.nil? + return false if opcode != Juno::IO::ProtocolHeader::OpCodes::Nop + return false if operation_message&.metadata_component.nil? + return false if operation_message&.metadata_component&.ip.to_s.empty? + return false if operation_message&.metadata_component&.app_name != JUNO_INTERNAL_APPNAME + + ping_ip = operation_message.metadata_component.ip.to_s + if ping_ip.split('.')[0] == '127' + processor.ping_ip = '' + return true + end + if Juno::Utils.local_ips.include?(ping_ip) + processor.ping_ip = '' + return true + end + processor.ping_ip = ping_ip + true + end + + # Function to serialize Component to buffer + # @param buff [StringIO] (required) + def write(buf) + @operation_message.write(buf) + end + + # Function to de-serialize Component from buffer + # @param buff [StringIO] (required) + def read(buf) + @operation_message = Juno::IO::OperationMessage.new + @operation_message.read(buf) + end + + # Function to read the ping ip + def ip + @operation_message&.metadata_component&.ip + end + + # Function to read the port from metadata component + def port + @operation_message&.metadata_component&.port + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Net/request_queue.rb b/client/Ruby/juno/lib/juno/Net/request_queue.rb new file mode 100644 index 0000000..4b62093 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Net/request_queue.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module Juno + module Net + # DataType of each item in RequestQueue + class QueueEntry + attr_accessor :msg_buffer, :req_id, :enqueue_time + + # @param msg_bugger [StringIO] (required) + # @param id [String] - request UUID (required) + def initialize(msg_buffer, id) + @msg_buffer = msg_buffer + @req_id = id + @enqueue_time = Time.now + end + end + + # Request queue - Singleton + class RequestQueue + # mutex to synchronize creation of RequestQueue instance + @@mutex = Mutex.new + + # Singleton instance + @@instance = nil + + def self.instance + return @@instance unless @@instance.nil? + + @@mutex.synchronize do + @@instance ||= new + end + end + + private_class_method :new + + attr_reader :opaque_resp_queue_map + + def initialize + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + @size = 13_000 # Default request queue size + @request_queue = SizedQueue.new(@size) + @opaque_resp_queue_map = Concurrent::Map.new + @worker_pool = Juno::Net::WorkerPool.new(self) + end + + def full? + @request_queue.size == @size + end + + def size + @request_queue.size + end + + def stop + @worker_pool.stop + @request_queue.clear + end + + # @param operation_message [Juno::IO::OperatioinMessage] (required) + # @return [Boolean] - true if successfully pushed item to queue. Else false + def push(msg_buffer, request_uuid) + # buffer = StringIO.new + # operation_message.write(buffer) + # request_uuid = operation_message&.metadata_component&.request_uuid.to_s + request_uuid = 'not_set' if request_uuid.to_s.empty? + + begin + @request_queue.push(QueueEntry.new(msg_buffer, request_uuid), true) + rescue ThreadError + return false + end + true + end + + # @return [QueueEntry] - nil if queue empty + def pop + @request_queue.pop(true) + rescue ThreadError + # queue empty + nil + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Net/worker_pool.rb b/client/Ruby/juno/lib/juno/Net/worker_pool.rb new file mode 100644 index 0000000..a94c692 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Net/worker_pool.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Juno + module Net + class WorkerPool + def initialize(request_queue) + raise 'Request queue cannot be nil' if request_queue.nil? + + @PROG_NAME = self.class.name + @LOGGER = Juno::Logger.instance + @request_queue = request_queue + EventMachine.threadpool_size = 200 + @io_processor = Juno::Net::IOProcessor.new(@request_queue, @request_queue.opaque_resp_queue_map) + init + end + + def init + @worker = Thread.new do + @io_processor.run + end + end + + def active? + @worker.alive? + end + + def stop + @io_processor.stop + end + end + end +end diff --git a/client/Ruby/juno/lib/juno/Utils/client_utils.rb b/client/Ruby/juno/lib/juno/Utils/client_utils.rb new file mode 100644 index 0000000..ae10f05 --- /dev/null +++ b/client/Ruby/juno/lib/juno/Utils/client_utils.rb @@ -0,0 +1,163 @@ +# frozen_string_literal: true + +module Juno + module ClientUtils + def self.create_operation_message(juno_message, opaque) + protocol_header = Juno::IO::ProtocolHeader.new + protocol_header.version = juno_message.version + protocol_header.opcode = juno_message.operation_type + protocol_header.opaque = opaque + + metadata_component = Juno::IO::MetadataComponent.new + if juno_message.time_to_live_s.to_i.positive? + metadata_component.set_time_to_live(juno_message.time_to_live_s.to_i) + end + metadata_component.set_version(juno_message.version) + + if [Juno::IO::JunoMessage::OperationType::CREATE, + Juno::IO::JunoMessage::OperationType::SET].include?(juno_message.operation_type) + metadata_component.set_creation_time(Time.now.to_i) + end + + metadata_component.set_expiration_time((Time.now + juno_message.time_to_live_s).to_i) # what ? + metadata_component.set_request_uuid(juno_message.request_uuid) + metadata_component.set_source_info(app_name: juno_message.app_name, ip: juno_message.ip, port: juno_message.port) + metadata_component.set_originator_request_id # what + + payload_component = Juno::IO::PayloadComponent.new + payload_component.namespace = juno_message.namespace + payload_component.payload_key = juno_message.key + payload_component.set_value(juno_message.value, juno_message.compression_type) + + operation_message = Juno::IO::OperationMessage.new + operation_message.protocol_header = protocol_header + operation_message.metadata_component = metadata_component + operation_message.payload_component = payload_component + + juno_message.message_size = operation_message.size + + operation_message + end + + def self.compressed_value(value) + compressed_value = Snappy.deflate(value) + compression_achieved = 100 - (compressed_value.length * 100) / value.length + [compressed_value, compression_achieved] + rescue Exception + [value, false] + end + + def self.decompress_value(value) + Snappy.inflate(value) + rescue Exception + # Log failure + value + end + + def self.validate!(juno_request) + return false unless juno_request.is_a?(Juno::Client::JunoRequest) + + raise ArgumentError, 'Juno request key cannot be empty' if juno_request.key.to_s.nil? + + juno_request.time_to_live_s = Juno.juno_config.default_lifetime unless juno_request.time_to_live_s.to_i.positive? + + if juno_request.time_to_live_s > Juno.juno_config.max_lifetime || juno_request.time_to_live_s.negative? + raise ArgumentError, + "Record time_to_live_s (#{juno_request.time_to_live_s}s) cannot be greater than #{Juno.juno_config.max_lifetime}s or negative ." + end + + if juno_request.key.to_s.size > Juno.juno_config.max_key_size + raise ArgumentError, + "Key size cannot be greater than #{Juno.juno_config.max_key_size}" + end + + if juno_request.key.to_s.size > Juno.juno_config.max_key_size + raise ArgumentError, + "Key size cannot be greater than #{Juno.juno_config.max_key_size}" + end + + juno_message = Juno::IO::JunoMessage.new + juno_message.key = juno_request.key + juno_message.version = juno_request.version + juno_message.operation_type = juno_request.type + juno_message.time_to_live_s = juno_request.time_to_live_s + juno_message.creation_time = juno_request.creation_time + juno_message.namespace = Juno.juno_config.record_namespace + juno_message.app_name = Juno.juno_config.app_name + juno_message.request_uuid = UUIDTools::UUID.random_create.to_s + juno_message.ip = IPAddr.new(Juno::Utils.local_ips[0]) + juno_message.port = 0 + + unless [Juno::Client::JunoRequest::Type::GET, + Juno::Client::JunoRequest::Type::DESTROY].include?(juno_request.type) + payload_value = juno_request.value + is_compressed = false + compression_achieved = 0 + if Juno.juno_config.use_payload_compression && value.length > 1024 + payload_value, compression_achieved = compressed_value(value) + is_compressed = true if compression_achieved.positive? + end + juno_message.is_compressed = is_compressed + juno_message.value = payload_value + juno_message.compression_achieved = compression_achieved + juno_message.compression_type = is_compressed ? Juno::IO::CompressionType::Snappy : Juno::IO::CompressionType::None + end + + juno_message + end + + # @params operation_message [Juno::IO::OperationMessage] (required) + # @returns [Juno::IO::JunoMessage] + def self.decode_operation_message(operation_message) + return nil unless operation_message.is_a?(Juno::IO::OperationMessage) + + juno_message = Juno::IO::JunoMessage.new + opcode = operation_message.protocol_header.opcode.to_i + juno_message.operation_type = Juno::IO::JunoMessage::OperationType.get(opcode) + + server_status = operation_message.protocol_header.status.to_i + juno_message.server_status = Juno::ServerStatus.get(server_status) + + juno_message.message_size = operation_message.protocol_header.message_size.to_i + + unless operation_message.metadata_component.nil? + metadata_component = operation_message.metadata_component + juno_message.time_to_live_s = metadata_component.time_to_live.to_i + juno_message.ip = metadata_component.ip + juno_message.port = metadata_component.port + juno_message.version = metadata_component.version.to_i + juno_message.creation_time = metadata_component.creation_time.to_i + juno_message.expiration_time = metadata_component.expiration_time.to_i + juno_message.request_uuid = metadata_component.request_uuid + juno_message.app_name = metadata_component.app_name + juno_message.last_modification = metadata_component.last_modification.to_i + juno_message.originator_request_id = metadata_component.originator_request_id.to_s + juno_message.correlation_id = metadata_component.correlation_id + juno_message.request_handling_time = metadata_component.request_handling_time.to_i + # juno_message.request_start_time = metadata_component. + # expiry + end + + unless operation_message.payload_component.nil? + juno_message.namespace = operation_message.payload_component.namespace.to_s + juno_message.key = operation_message.payload_component.payload_key.to_s + juno_message.is_compressed = operation_message.payload_component.compressed? + juno_message.compression_type = operation_message.payload_component.compression_type.to_i + juno_message.value = if operation_message.payload_component.payload_length.to_i.zero? + juno_message.compression_achieved = 0 + nil + elsif juno_message.is_compressed + compressed_value = operation_message.payload_component.value.to_s + decompressed_value = decompress_value(compressed_value) + juno_message.compression_achieved = 100 - (compressed_value.length / decompressed_value.length.to_f) * 100.0 + decompressed_value + else + juno_message.compression_achieved = 0 + operation_message.payload_component.value.to_s + end + end + + juno_message + end + end +end diff --git a/client/Ruby/juno/lib/juno/Utils/utils.rb b/client/Ruby/juno/lib/juno/Utils/utils.rb new file mode 100644 index 0000000..f9da34d --- /dev/null +++ b/client/Ruby/juno/lib/juno/Utils/utils.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +module Juno + class Utils + def self.local_ips + ip_addresses = Socket.ip_address_list.select do |addr| + addr.ipv4? && !addr.ipv4_loopback? # && !addr.ipv4_private? + end + ip_addresses.map!(&:ip_address) + rescue StandardError => e + puts e.message + ['127.0.0.1'] + end + + def self.create_message(key, op_type, value = '') + meta_data_component = Juno::IO::MetadataComponent.new + # ip = IPAddr.new(Socket.ip_address_list.detect(&:ipv4_private?).ip_address) + meta_data_component.set_time_to_live(Juno.juno_config.default_lifetime) + meta_data_component.set_version(1) + meta_data_component.set_creation_time(1000) + meta_data_component.set_request_uuid + meta_data_component.set_correlation_id + meta_data_component.set_originator_request_id + meta_data_component.set_source_info(app_name: Juno.juno_config.app_name, ip: IPAddr.new(Juno::Utils.local_ips[0]), + port: Juno.juno_config.port) + + payload_component = Juno::IO::PayloadComponent.new + payload_component.namespace = Juno.juno_config.record_namespace + payload_component.payload_key = key + if op_type == Juno::IO::ProtocolHeader::OpCodes::Create && !value.to_s.empty? + is_compressed = false + if Juno.juno_config.use_payload_compression && value.length > 1024 + value, compression_achieved = compressed_value(value) + is_compressed = true if compression_achieved.positive? + end + if is_compressed + puts 'using compression' + payload_component.set_value(value, Juno::IO::CompressionType::Snappy) + else + payload_component.set_value(value) + end + end + + protocol_header = Juno::IO::ProtocolHeader.new + protocol_header.opcode = op_type + + operation_message = Juno::IO::OperationMessage.new + operation_message.metadata_component = meta_data_component + operation_message.protocol_header = protocol_header + operation_message.payload_component = payload_component + buffer = StringIO.new + operation_message.write(buffer) + buffer + end + + def self.ssl_context + ssl_context = OpenSSL::SSL::SSLContext.new + ssl_context.ssl_version = :TLSv1_1 + cert = OpenSSL::X509::Certificate.new(File.open(File.expand_path(File.join( + __dir__, '..', '..', 'server.crt' + )))) + key = OpenSSL::PKey::RSA.new(File.open(File.expand_path(File.join( + __dir__, '..', '..', 'server.pem' + )))) + ca_file = OpenSSL::X509::Certificate.new(File.open(File.expand_path(File.join( + __dir__, '..', '..', 'myca.crt' + )))) + ssl_context.add_certificate(cert, key, [ca_file]) + # ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER + ssl_context.ssl_timeout = 10 + ssl_context.timeout = 10 + ssl_context + end + + def self.ssl_request(buffer) + socket = TCPSocket.open(Juno.juno_config.host, Juno.juno_config.port) + if Juno.juno_config.use_ssl + ctx = ssl_context + socket = OpenSSL::SSL::SSLSocket.new(socket, ctx) + socket.sync_close = true + # socket.post_connection_check(Juno.juno_config.host) + socket.connect + end + + # puts socket.peer_finished_message.bytes.join(', ') + # puts socket.verify_result + + socket.write(buffer.string) + res_buffer = StringIO.new + header = true + + size = 0 + while (line = socket.sysread(1024 * 16)) # buffer size of OpenSSL library + if header + p = Juno::IO::ProtocolHeader.new + p.read(StringIO.new(line)) + header = false + size = p.message_size + end + res_buffer.write(line) + break if res_buffer.length == size + end + socket.close + + res_buffer.rewind + + res_buffer + end + + def self.create_and_send_ping_message + ping_message = Juno::Net::PingMessage.new + ping_buffer = StringIO.new + ping_message.write(ping_buffer) + response = ssl_request(ping_buffer) + ping_message = Juno::Net::PingMessage.new + ping_message.read(response) + ping_message + end + + def self.time_diff_ms(a, b) + (b - a).abs * 1000 + end + end +end diff --git a/client/Ruby/juno/lib/juno/logger.rb b/client/Ruby/juno/lib/juno/logger.rb new file mode 100644 index 0000000..6e0ef7e --- /dev/null +++ b/client/Ruby/juno/lib/juno/logger.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Juno + # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN + + class Logger + @@mutex = Mutex.new + + # Singleton instance + @@instance = nil + + def self.instance + return @@instance unless @@instance.nil? + + @@mutex.synchronize do + if @@instance.nil? + raise 'log file not configured' if Juno.juno_config.log_file.to_s.empty? + + @@instance = ::Logger.new(Juno.juno_config.log_file, 'daily', progname: 'JunoRubyClient') + + @@instance.level = ::Logger::INFO + end + end + @@instance + end + + def self.level=(log_level) + @@instance.level = log_level unless @@instance.nil? + end + + private_class_method :new + end +end diff --git a/client/Ruby/juno/lib/juno/server_status.rb b/client/Ruby/juno/lib/juno/server_status.rb new file mode 100644 index 0000000..a5af05d --- /dev/null +++ b/client/Ruby/juno/lib/juno/server_status.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module Juno + class ServerStatus + SUCCESS = { code: 0, error_msg: 'no error', client_operation_status: Juno::Client::OperationStatus::SUCCESS }.freeze + BAD_MSG = { code: 1, error_msg: 'bad message', + client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze + NO_KEY = { code: 3, error_msg: 'key not found', + client_operation_status: Juno::Client::OperationStatus::NO_KEY }.freeze + DUP_KEY = { code: 4, error_msg: 'dup key', + client_operation_status: Juno::Client::OperationStatus::UNIQUE_KEY_VIOLATION }.freeze + BAD_PARAM = { code: 7, error_msg: 'bad parameter', + client_operation_status: Juno::Client::OperationStatus::BAD_PARAM }.freeze + RECORD_LOCKED = { code: 8, error_msg: 'record locked', + client_operation_status: Juno::Client::OperationStatus::RECORD_LOCKED }.freeze + NO_STORAGE_SERVER = { code: 12, error_msg: 'no active storage server', + client_operation_status: Juno::Client::OperationStatus::NO_STORAGE }.freeze + SERVER_BUSY = { code: 14, error_msg: 'Server busy', + client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze + VERSION_CONFLICT = { code: 19, error_msg: 'version conflict', + client_operation_status: Juno::Client::OperationStatus::CONDITION_VIOLATION }.freeze + OP_STATUS_SS_READ_TTL_EXTENDERR = { code: 23, error_msg: 'Error extending TTL by SS', + client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze + COMMIT_FAILURE = { code: 25, error_msg: 'Commit Failure', + client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze + INCONSISTENT_STATE = { code: 26, error_msg: 'Inconsistent State', + client_operation_status: Juno::Client::OperationStatus::SUCCESS }.freeze + INTERNAL = { code: 255, error_msg: 'Internal error', + client_operation_status: Juno::Client::OperationStatus::INTERNAL_ERROR }.freeze + + @@status_code_map = nil + + def self.initialize_map + @@status_code_map = {} + + constants.each do |const| + const_obj = const_get(const) + @@status_code_map[const_obj[:code].to_i] = const_obj + end + end + + def self.get(status_code) + initialize_map if @@status_code_map.nil? + return @@status_code_map[status_code] if @@status_code_map.key?(status_code.to_i) + + INTERNAL + end + end +end diff --git a/client/Ruby/juno/lib/juno/version.rb b/client/Ruby/juno/lib/juno/version.rb new file mode 100644 index 0000000..e9bf587 --- /dev/null +++ b/client/Ruby/juno/lib/juno/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Juno + VERSION = '1.0.0' +end diff --git a/client/Ruby/juno/pkg/juno-0.1.0.gem b/client/Ruby/juno/pkg/juno-0.1.0.gem new file mode 100644 index 0000000..90a4f1c Binary files /dev/null and b/client/Ruby/juno/pkg/juno-0.1.0.gem differ diff --git a/client/Ruby/juno/pkg/juno-1.0.0.gem b/client/Ruby/juno/pkg/juno-1.0.0.gem new file mode 100644 index 0000000..06f0399 Binary files /dev/null and b/client/Ruby/juno/pkg/juno-1.0.0.gem differ diff --git a/client/Ruby/juno/spec/Client/sync_client.rb b/client/Ruby/juno/spec/Client/sync_client.rb new file mode 100644 index 0000000..aaf3846 --- /dev/null +++ b/client/Ruby/juno/spec/Client/sync_client.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'juno' + +describe 'Sync client tests' do + before(:context) do + Juno.configure do |config| + config.file_path = URI.join('file:///', File.expand_path('./../../../juno.yml').to_s) + config.log_file = 'juno.log' + config.ssl_cert_file = File.expand_path('./../../lib/server.crt') + config.ssl_key_file = File.expand_path('./../../lib/server.pem') + end + + @juno_client = Juno::Client::SyncClient.new + @key = "mykey#{rand(1000)}" + @value = 'myvalue' + end + + it 'create test' do + juno_resp = @juno_client.create(@key, @value, ttl: 12_000) + expect(juno_resp.status[:code]).to eq(Juno::ServerStatus::SUCCESS[:code]) + expect(juno_resp.record_context.time_to_live_s).to eq(12_000) + end + + it 'get request test' do + juno_resp = @juno_client.get(@key) + expect(juno_resp.status[:code]).to eq(Juno::ServerStatus::SUCCESS[:code]) + expect(juno_resp.value).to eq(@value) + expect(juno_resp.record_context.version).to eq(1) + end + + it 'update request test' do + juno_resp = @juno_client.update(@key, 'newvalue') + @record_context = juno_resp.record_context + expect(juno_resp.status[:code]).to eq(Juno::ServerStatus::SUCCESS[:code]) + expect(juno_resp.value).to eq(@value) + expect(juno_resp.record_context.version).to eq(1) + end + + it 'compare_and_set request test' do + juno_resp = @juno_client.compare_and_set(@record_context, 'value99') + expect(juno_resp.status[:code]).to eq(Juno::ServerStatus::SUCCESS[:code]) + expect(juno_resp.value).to eq(@value) + expect(juno_resp.record_context.version).to eq(1) + end +end diff --git a/client/Ruby/juno/spec/IO/metadata_component.rb b/client/Ruby/juno/spec/IO/metadata_component.rb new file mode 100644 index 0000000..16f4080 --- /dev/null +++ b/client/Ruby/juno/spec/IO/metadata_component.rb @@ -0,0 +1,139 @@ +# frozen_string_literal: true + +require 'bindata' +require_relative '../../lib/juno/IO/constants' +require_relative '../../lib/juno/IO/MetadataComponentTemplate' +require_relative '../../lib/juno/IO/MetadataComponent' + +describe 'Juno::IO::PayloadComponent buffer write' do + before(:context) do + @payload = Juno::IO::MetadataComponent.new + @NAMESPACE = 'testnamespace123' + @KEY = 'testkey123' + @VALUE = 'testvalue456' + + @payload.payload_key = @KEY # length: 10 + @payload.namespace = @NAMESPACE # length: 16 + @payload.set_value(@VALUE) # length: 12 + # size = 13 + 10 + 16 + 12 + 5 = 56 + buff = StringIO.new + @payload.write(buff) + + @bytes_arr = buff.string.bytes + end + + it 'component size should be 56' do + expect(@bytes_arr.length).to eq(56) + size = @bytes_arr.shift(4).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT32) + expect(@payload.component_size).to eq(56) + expect(size).to eq(56) + end + + it 'tag_id should be 1' do + expect(@payload.tag_id).to eq(1) + expect(@bytes_arr.shift).to eq(1) + end + + it 'namspace_length should be 16' do + expect(@payload.namespace_length).to eq(16) + expect(@bytes_arr.shift).to eq(16) + end + + it 'key_length should be 10' do + key_length = @bytes_arr.shift(2).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT16) + expect(@payload.key_length).to eq(10) + expect(key_length).to eq(10) + end + + it 'payload_length should be 13' do + payload_length = @bytes_arr.shift(4).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT32) + expect(@payload.payload_length).to eq(13) + expect(payload_length).to eq(13) + end + + it 'namespace as expected' do + namespace = @bytes_arr.shift(@NAMESPACE.length).pack(Juno::IO::OffsetWidth.UINT8('*')) + expect(@payload.namespace).to eq(@NAMESPACE) + expect(namespace).to eq(@NAMESPACE) + end + + it 'key as expected' do + key = @bytes_arr.shift(@KEY.length).pack(Juno::IO::OffsetWidth.UINT8('*')) + expect(@payload.payload_key).to eq(@KEY) + expect(key).to eq(@KEY) + end + + it 'payload_type should be Juno::IO::PayloadType::UnCompressed' do + ptype = @bytes_arr.shift + expect(@payload.payload_type).to eq(Juno::IO::PayloadType::UnCompressed) + expect(ptype).to eq(Juno::IO::PayloadType::UnCompressed) + end + + it 'payload value expected' do + value = @bytes_arr.shift(@VALUE.length).pack(Juno::IO::OffsetWidth.UINT8('*')) + expect(@payload.value).to eq(@VALUE) + expect(value).to eq(@VALUE) + end + + it 'payload length' do + padding = @bytes_arr.shift(5).pack(Juno::IO::OffsetWidth.UINT8('*')) + expect(padding.length).to eq(5) + expect(@payload.padding.length).to eq(5) + expect(padding).to eq([0, 0, 0, 0, 0].pack(Juno::IO::OffsetWidth.UINT8('*'))) + expect(@payload.padding).to eq([0, 0, 0, 0, 0].pack(Juno::IO::OffsetWidth.UINT8('*'))) + end +end + +describe 'Juno::IO::PayloadComponent buffer read' do + before(:context) do + @payload = Juno::IO::PayloadComponent.new + @NAMESPACE = 'testnamespace123' # length: 16 + @KEY = 'testkey123' # length: 10 + @VALUE = 'testvalue456' # length: 12 + + # size = 13 + 10 + 16 + 12 + 5 = 56 + buff = StringIO.new("\x00\x00\x008\x01\x10\x00\n\x00\x00\x00\rtestnamespace123testkey123\x00testvalue456\x00\x00\x00\x00\x00") + @payload.read(buff) + end + + it 'component size should be 56' do + expect(@payload.component_size).to eq(56) + end + + it 'tag_id should be 1' do + expect(@payload.tag_id).to eq(1) + end + + it 'namspace_length should be 16' do + expect(@payload.namespace_length).to eq(16) + end + + it 'key_length should be 10' do + expect(@payload.key_length).to eq(10) + end + + it 'payload_length should be 13' do + expect(@payload.payload_length).to eq(13) + end + + it 'namespace as expected' do + expect(@payload.namespace).to eq(@NAMESPACE) + end + + it 'key as expected' do + expect(@payload.payload_key).to eq(@KEY) + end + + it 'payload_type should be Juno::IO::PayloadType::UnCompressed' do + expect(@payload.payload_type).to eq(Juno::IO::PayloadType::UnCompressed) + end + + it 'payload value expected' do + expect(@payload.value).to eq(@VALUE) + end + + it 'payload length' do + expect(@payload.padding.length).to eq(5) + expect(@payload.padding).to eq([0, 0, 0, 0, 0].pack(Juno::IO::OffsetWidth.UINT8('*'))) + end +end diff --git a/client/Ruby/juno/spec/IO/payload_component_spec.rb b/client/Ruby/juno/spec/IO/payload_component_spec.rb new file mode 100644 index 0000000..d064f78 --- /dev/null +++ b/client/Ruby/juno/spec/IO/payload_component_spec.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true + +require 'juno' + +describe 'Juno::IO::PayloadComponent buffer write' do + before(:context) do + @payload = Juno::IO::PayloadComponent.new + @NAMESPACE = 'testnamespace123' + @KEY = 'testkey123' + @VALUE = 'testvalue456' + + @payload.payload_key = @KEY # length: 10 + @payload.namespace = @NAMESPACE # length: 16 + @payload.set_value(@VALUE) # length: 12 + # size = 13 + 10 + 16 + 12 + 5 = 56 + buff = StringIO.new + @payload.write(buff) + + @bytes_arr = buff.string.bytes + end + + it 'component size should be 56' do + expect(@bytes_arr.length).to eq(56) + size = @bytes_arr.shift(4).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT32) + expect(@payload.component_size).to eq(56) + expect(size).to eq(56) + end + + it 'tag_id should be 1' do + expect(@payload.tag_id).to eq(1) + expect(@bytes_arr.shift).to eq(1) + end + + it 'namspace_length should be 16' do + expect(@payload.namespace_length).to eq(16) + expect(@bytes_arr.shift).to eq(16) + end + + it 'key_length should be 10' do + key_length = @bytes_arr.shift(2).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT16) + expect(@payload.key_length).to eq(10) + expect(key_length).to eq(10) + end + + it 'payload_length should be 13' do + payload_length = @bytes_arr.shift(4).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT32) + expect(@payload.payload_length).to eq(13) + expect(payload_length).to eq(13) + end + + it 'namespace as expected' do + namespace = @bytes_arr.shift(@NAMESPACE.length).pack(Juno::IO::OffsetWidth.UINT8('*')) + expect(@payload.namespace).to eq(@NAMESPACE) + expect(namespace).to eq(@NAMESPACE) + end + + it 'key as expected' do + key = @bytes_arr.shift(@KEY.length).pack(Juno::IO::OffsetWidth.UINT8('*')) + expect(@payload.payload_key).to eq(@KEY) + expect(key).to eq(@KEY) + end + + it 'payload_type should be Juno::IO::PayloadType::UnCompressed' do + ptype = @bytes_arr.shift + expect(@payload.payload_type).to eq(Juno::IO::PayloadType::UnCompressed) + expect(ptype).to eq(Juno::IO::PayloadType::UnCompressed) + end + + it 'payload value expected' do + value = @bytes_arr.shift(@VALUE.length).pack(Juno::IO::OffsetWidth.UINT8('*')) + expect(@payload.value).to eq(@VALUE) + expect(value).to eq(@VALUE) + end + + it 'payload length' do + padding = @bytes_arr.shift(5).pack(Juno::IO::OffsetWidth.UINT8('*')) + expect(padding.length).to eq(5) + expect(@payload.padding.length).to eq(5) + expect(padding).to eq([0, 0, 0, 0, 0].pack(Juno::IO::OffsetWidth.UINT8('*'))) + expect(@payload.padding).to eq([0, 0, 0, 0, 0].pack(Juno::IO::OffsetWidth.UINT8('*'))) + end +end + +describe 'Juno::IO::PayloadComponent buffer read' do + before(:context) do + @payload = Juno::IO::PayloadComponent.new + @NAMESPACE = 'testnamespace123' # length: 16 + @KEY = 'testkey123' # length: 10 + @VALUE = 'testvalue456' # length: 12 + + # size = 13 + 10 + 16 + 12 + 5 = 56 + buff = StringIO.new("\x00\x00\x008\x01\x10\x00\n\x00\x00\x00\rtestnamespace123testkey123\x00testvalue456\x00\x00\x00\x00\x00") + @payload.read(buff) + end + + it 'component size should be 56' do + expect(@payload.component_size).to eq(56) + end + + it 'tag_id should be 1' do + expect(@payload.tag_id).to eq(1) + end + + it 'namspace_length should be 16' do + expect(@payload.namespace_length).to eq(16) + end + + it 'key_length should be 10' do + expect(@payload.key_length).to eq(10) + end + + it 'payload_length should be 13' do + expect(@payload.payload_length).to eq(13) + end + + it 'namespace as expected' do + expect(@payload.namespace).to eq(@NAMESPACE) + end + + it 'key as expected' do + expect(@payload.payload_key).to eq(@KEY) + end + + it 'payload_type should be Juno::IO::PayloadType::UnCompressed' do + expect(@payload.payload_type).to eq(Juno::IO::PayloadType::UnCompressed) + end + + it 'payload value expected' do + expect(@payload.value).to eq(@VALUE) + end + + it 'payload length' do + expect(@payload.padding.length).to eq(5) + expect(@payload.padding).to eq([0, 0, 0, 0, 0].pack(Juno::IO::OffsetWidth.UINT8('*'))) + end +end diff --git a/client/Ruby/juno/spec/IO/protocol_header_spec.rb b/client/Ruby/juno/spec/IO/protocol_header_spec.rb new file mode 100644 index 0000000..b64a02e --- /dev/null +++ b/client/Ruby/juno/spec/IO/protocol_header_spec.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require 'juno' + +describe 'Juno::IO::ProtocolHeader buffer write' do + before(:context) do + @header = Juno::IO::ProtocolHeader.new + @header.message_size = 16 + @header.opaque = 12 + buff = StringIO.new + @header.write(buff) + @bytes_arr = buff.string.bytes + end + + it 'number of bytes should be 16' do + expect(@bytes_arr.size).to eq(16) + end + + it 'magic should be 0x5050' do + magic = @bytes_arr.shift(2).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT16) + expect(magic).to eq(0x5050) + expect(@header.magic).to eq(0x5050) + end + + it 'version should be 1' do + expect(@bytes_arr.shift).to eq(1) + end + + # by default it is an operation message and RequestType is a TwoWayRequest + it 'message_type_flag should be 64' do + expect(@bytes_arr.shift).to eq(64) + end + + it 'message_size should be 16' do + message_size = @bytes_arr.shift(4).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT32) + expect(message_size).to eq(16) + expect(@header.message_size).to eq(16) + end + + it 'opaque should be 12' do + opaque = @bytes_arr.shift(4).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT32) + expect(opaque).to eq(12) + expect(@header.opaque).to eq(12) + end + + it 'opcode should be 0' do + expect(@bytes_arr.shift).to eq(Juno::IO::ProtocolHeader::OpCodes::Nop) + expect(@header.opcode).to eq(Juno::IO::ProtocolHeader::OpCodes::Nop) + end + + it 'flag should be 0' do + expect(@bytes_arr.shift).to eq(0) + expect(@header.flag).to eq(0) + end + + it 'shard_id should be 0' do + shard_id = @bytes_arr.shift(4).pack(Juno::IO::OffsetWidth.UINT8('*')).unpack1(Juno::IO::OffsetWidth.UINT16) + expect(shard_id).to eq(0) + expect(@header.shard_id).to eq(0) + end +end + +describe 'Juno::IO::ProtocolHeader buffer read' do + before do + @header = Juno::IO::ProtocolHeader.new + buff = StringIO.new("PP\x01@\x00\x00\x00\x10\x00\x00\x00\f\x00\x00\x00\x00") + @header.read(buff) + end + + it 'number of bytes should be 16' do + expect(@header.message_size).to eq(16) + end + + it 'magic should be 0x5050' do + expect(@header.magic).to eq(0x5050) + end + + it 'version should be 1' do + expect(@header.version).to eq(1) + end + + # by default it is an operation message and RequestType is a TwoWayRequest + it 'message_type_flag should be 64' do + expect(@header.message_type_flag.message_request_type).to eq(Juno::IO::ProtocolHeader::RequestTypes::TwoWayRequest) + expect(@header.message_type_flag.message_type).to eq(Juno::IO::ProtocolHeader::MessageTypes::OperationalMessage) + end + + it 'message_size should be 16' do + expect(@header.message_size).to eq(16) + end + + it 'opaque should be 12' do + expect(@header.opaque).to eq(12) + end + + it 'opcode should be 0' do + expect(@header.opcode).to eq(Juno::IO::ProtocolHeader::OpCodes::Nop) + end + + it 'flag should be 0' do + expect(@header.flag).to eq(Juno::IO::ProtocolHeader::OpCodes::Nop) + end + + it 'shard_id should be 0' do + expect(@header.shard_id).to eq(0) + end +end diff --git a/client/Ruby/juno/spec/spec_helper.rb b/client/Ruby/juno/spec/spec_helper.rb new file mode 100644 index 0000000..253df0f --- /dev/null +++ b/client/Ruby/juno/spec/spec_helper.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +RSpec.configure do |config| + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + end + config.shared_context_metadata_behavior = :apply_to_host_groups +end diff --git a/client/Ruby/sample.rb b/client/Ruby/sample.rb new file mode 100644 index 0000000..09e4125 --- /dev/null +++ b/client/Ruby/sample.rb @@ -0,0 +1,41 @@ +require 'juno' + +Juno.configure do |config| + config.file_path = URI.join('file:///', '') + config.log_file = '' + config.ssl_cert_file = '' + config.ssl_key_file = '' +end + +# Rails cache store +juno_client = Juno::Client::CacheStore.new +juno_client.write('key', 'value') + +# Synchronous Client +juno_client = Juno::Client::SyncClient.new +resp = juno_client.create('key', 'value') +resp = juno_client.get('key') +resp = juno_client.update('key', 'newvalue') + + +# Return Juno::Client::JunoResponse +resp = juno_client.create('15', '99') +resp = juno_client.get('15') +resp = juno_client.update('15', '100') + + +# Asyn Client +class Callback + def update(time, value, reason) + puts time + if reason.to_s.empty? + puts value + else + puts "failed: #{reason}" + end + end +end + +juno_client = Juno::Client::ReactClient.new +juno_client.create('mykey', 'myvalue') +juno_client.add_observer(Callback.new)