Class: Universa::UMI
- Inherits:
-
Object
- Object
- Universa::UMI
- Defined in:
- lib/universa/umi.rb
Overview
Universa Method Invocation remote interface.
By default, it creates UMI interface to the included UMI server which gives almost full access to the Universa Java API:
Uasge:
>> umi = Universa::UMI.new()
>> # create a new key and new contract with this key as creator:
>> contract = umi.instantiate "Contract", umi.instantiate("PrivateKey", 2048)
Use #instantiate to create new instances of remote classes, which return Ref instances, and just call their methods as if these are usual ruby methods. For example in the example above:
address = contract.getKeysToSignWith()[0].getPublicKey().getShortAddress().toString()
In the sample above all the methods are called on the remote side, returning links to remote objects which are all Ref instances, and the last ‘toString()` call return a string, which is converted to ruby string and saved into variable. This sentence, therefore, get the first signer key and transofrms it to the string short address.
Having several ‘UMI` interfaces.
It is possible to have several UMI instances, by default, it will create separate process with isolated data space, which is perfectly safe to use in various scenarios.
It still means the object from different interfaces can’t be interchanged. Ref instances created by one interface should be used with this interface only, or the InterchangeError will be raised.
Remote exceptions
If remote part will thow an Exception performing a method, it will be raised as an instance of Farcall::RemoteError class which carries remote exception information.
Transport level
UMI uses Farcall transport in woth JSON adapter and “n” as separator.
Constant Summary collapse
- @@session_log_path =
nil
Class Method Summary collapse
-
.session_log_path=(path) ⇒ Object
Set the detault UMI session log path (including file) that will be used if no log parameter will be passed to the UMI constructor.
Instance Method Summary collapse
-
#close ⇒ Object
Close child process.
-
#core_version ⇒ Object
Universa network library core version.
-
#find_by_remote_id(remote_id) ⇒ Object
debug use only.
- #get_field(remote_object, name) ⇒ Object
-
#initialize(path = nil, version_check: /./, system: "UMI", log: nil, convert_case: true, factory: nil) ⇒ UMI
constructor
Create UMI instance.
-
#inspect ⇒ Object
short data label for UMI interface.
-
#instantiate(object_class_name, *args, adapter: nil) ⇒ Ref
Create instance of some Universa Java API class, for example ‘Contract’, passing any arguments to its constructor.
-
#invoke(ref, method, *args) ⇒ Object
Invoke method by name.
- #invoke_static(class_name, method, *args) ⇒ Object
- #set_field(remote_object, name, value) ⇒ Object
-
#version ⇒ Object
Version of the connected UMI server.
-
#with_trace(&block) ⇒ Object
Execute the block with trace mode on.
Constructor Details
#initialize(path = nil, version_check: /./, system: "UMI", log: nil, convert_case: true, factory: nil) ⇒ UMI
Create UMI instance. It starts the private child process wit UMI server and securely connects to it so no other connection could occur.
# create UNI interface
umi = Universa::UMI.new()
# create a new key and new contract with this key as creator:
contract = umi.instantiate "Contract", umi.instantiate("PrivateKey", 2048)
contract.seal() # binary packed string returned
contract.check() #=> true
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/universa/umi.rb', line 76 def initialize(path = nil, version_check: /./, system: "UMI", log: nil, convert_case: true, factory: nil) log ||= @@session_log_path path ||= File.(File.split(__FILE__)[0] + "/../../bin/umi/bin/umi") @in, @out, @err, @wtr = Open3.popen3("#{path} #{log ? "-log #{log}" : ''}") @endpoint = Farcall::Endpoint.new( Farcall::JsonTransport.create(delimiter: "\n", input: @out, output: @in) ) @lock = Monitor.new @cache = {} @closed = false @convert_case, @factory = convert_case, factory @references = {} start_cleanup_queue @version = call("version") raise Error, "Unsupported system: #{@version}" if @version.system != "UMI" raise Error, "Unsupported version: #{@version}" if @version.version !~ /0\.8\.\d+/ rescue Errno::ENOENT @err and STDERR.puts @err.read raise Error, "missing java binaries" end |
Class Method Details
.session_log_path=(path) ⇒ Object
Set the detault UMI session log path (including file) that will be used if no log parameter will be passed to the UMI constructor
56 57 58 |
# File 'lib/universa/umi.rb', line 56 def self.session_log_path= path @@session_log_path = path end |
Instance Method Details
#close ⇒ Object
Close child process. No remote calls should occur after it.
144 145 146 147 148 149 150 151 152 |
# File 'lib/universa/umi.rb', line 144 def close @queue.push :poison_pill @cleanup_thread.join @closed = true @endpoint.close @in.close @out.close @wtr.value.exited? end |
#core_version ⇒ Object
Returns Universa network library core version.
103 104 105 106 107 |
# File 'lib/universa/umi.rb', line 103 def core_version @core_version ||= begin invoke_static "Core", "getVersion" end end |
#find_by_remote_id(remote_id) ⇒ Object
debug use only. Looks for the cached e.g. (alive) remote object. Does not check the remote side.
161 162 163 |
# File 'lib/universa/umi.rb', line 161 def find_by_remote_id remote_id @lock.synchronize {@cache[remote_id]&.get} end |
#get_field(remote_object, name) ⇒ Object
130 131 132 |
# File 'lib/universa/umi.rb', line 130 def get_field(remote_object, name) encode_result call("get_field", remote_object._remote_id, name) end |
#inspect ⇒ Object
short data label for UMI interface
155 156 157 |
# File 'lib/universa/umi.rb', line 155 def inspect "<UMI:#{__id__}:#{version}>" end |
#instantiate(object_class_name, *args, adapter: nil) ⇒ Ref
Create instance of some Universa Java API class, for example ‘Contract’, passing any arguments to its constructor. The returned reference could be used much like local instance, nu the actual work will happen in the child process. Use references as much as possible as they take all the housekeeping required, like memory leaks prevention and direct method calling.
115 116 117 118 |
# File 'lib/universa/umi.rb', line 115 def instantiate(object_class_name, *args, adapter: nil) ensure_open create_reference call("instantiate", object_class_name, *prepare_args(args)), adapter end |
#invoke(ref, method, *args) ⇒ Object
Invoke method by name. Should not be used directly; use Ref instance to call its methods.
121 122 123 124 125 126 127 128 |
# File 'lib/universa/umi.rb', line 121 def invoke(ref, method, *args) ensure_open ref._umi == self or raise InterchangeError @convert_case and method = method.to_s.camelize_lower # p ["invoke", ref._remote_id, method, *prepare_args(args)] result = call("invoke", ref._remote_id, method, *prepare_args(args)) encode_result result end |
#invoke_static(class_name, method, *args) ⇒ Object
139 140 141 |
# File 'lib/universa/umi.rb', line 139 def invoke_static(class_name, method, *args) encode_result call("invoke", class_name, method.to_s.camelize_lower, *prepare_args(args)) end |
#set_field(remote_object, name, value) ⇒ Object
134 135 136 137 |
# File 'lib/universa/umi.rb', line 134 def set_field(remote_object, name, value) call("set_field", remote_object._remote_id, name, prepare(value)) value end |
#version ⇒ Object
Returns version of the connected UMI server. It is different from the gem version.
98 99 100 |
# File 'lib/universa/umi.rb', line 98 def version @version.version end |
#with_trace(&block) ⇒ Object
Execute the block with trace mode on. Will spam the output with protocol information. These calls could be nested, on exit it restores previous trace state
167 168 169 170 171 172 |
# File 'lib/universa/umi.rb', line 167 def with_trace &block current_state, @trace = @trace, true result = block.call() @trace = current_state result end |