universa 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed104de6164cf27de489c0876518ee3394a9fb9c99a0914e6583a4f39f571942
4
- data.tar.gz: b86327d0d5177c6f0f1d9d49e02f2689da2315a15f844458420104427200915b
3
+ metadata.gz: 61a9637495cf67d3ac90b3447038b6b224646cd4f36a2db7619aae13274232af
4
+ data.tar.gz: 2b6b963df5082f420ab80bf3bd47c509846ddb4d3085cc9eb19939e4c906c9ed
5
5
  SHA512:
6
- metadata.gz: 0335ca25f8c9e002f15b482bf0e0bc96c10cb6f77343dae4df2101ade54855e63a8ef407a0021a95c84dfa0f4bebaca21141881922071967bca7747b60a9a276
7
- data.tar.gz: e8e54f3825441507640af2ce38dea63aa6ac25bc770be5f11f5f2b908215f3e066d6759c5ea02afa5a61c3153d3002b00c22affe1d49a57308997f61026b1729
6
+ metadata.gz: 973eb722475a35230ce1c595faab7c47e730eb7573f737d113475d5cb4405f4d5fc6c1a3f02393e7e177e5a384d838acf53aa65641a5b5f76172ee42e60bc88b
7
+ data.tar.gz: a901518e1151a239f43f309512d1e9e8bf6f87e40a31f111b994c6f9086aad9e41cd31cb5fae7c6370d80309f6d37c6c522b7b14c347baaed12f5f09bcc56c49
data/README.md CHANGED
@@ -29,6 +29,8 @@ Or install it yourself as:
29
29
 
30
30
  ## Usage
31
31
 
32
+ ### Direct access to UMI
33
+
32
34
  So far, you can only get direct access the the Java API functions. To get it:
33
35
 
34
36
  ```ruby
@@ -55,6 +57,22 @@ for more information see:
55
57
  - Universa UMI server: https://kb.universa.io/umi_protocol/98
56
58
  - Farcall [gem](https://github.com/sergeych/farcall) and [protocol](https://github.com/sergeych/farcall/wiki).
57
59
 
60
+ ### Use UMI service (alfa state)
61
+
62
+ The Universa::Service greatly simplify work taking all boilerplate. Just create objects almost as usual and use them
63
+ as is they are local:
64
+
65
+ ```ruby
66
+ key = PrivateKey,new(open('mykey.private.unikey', 'rb').read)
67
+ contract = Contract.new(key)
68
+
69
+ contract.seal()
70
+ p contract.check()
71
+ ```
72
+
73
+ The system will create UMI server and do all the work for you. Look at the RemoteAdapter class to see how does it
74
+ work. Soon we'll add adapters for all frequently used Universa classes.
75
+
58
76
  ## Development
59
77
 
60
78
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -267,7 +267,7 @@ loadConfigFile() {
267
267
  }
268
268
 
269
269
  # Now check to see if it's a good enough version
270
- # TODO - Check to see if we have a configured default java version, otherwise use 1.6
270
+ # TODO - Check to see if we have a configured default java version, otherwise use 1.8
271
271
  java_version_check() {
272
272
  readonly java_version=$("$java_cmd" -version 2>&1 | awk -F '"' '/version/ {print $2}')
273
273
  if [[ "$java_version" == "" ]]; then
@@ -344,7 +344,7 @@ declare -r lib_dir="$(realpath "${app_home}/../lib")"
344
344
  declare -a app_mainclass=(com.icodici.farcallscala.Main)
345
345
 
346
346
  declare -r script_conf_file="${app_home}/../conf/application.ini"
347
- declare -r app_classpath="$lib_dir/com.icodici.umi-0.8.8.jar:$lib_dir/org.scala-lang.scala-library-2.12.7.jar:$lib_dir/com.icodici.universa_core-3.8.3.jar:$lib_dir/org.yaml.snakeyaml-1.18.jar:$lib_dir/net.sf.jopt-simple.jopt-simple-4.9.jar:$lib_dir/org.postgresql.postgresql-42.1.4.jar:$lib_dir/org.xerial.sqlite-jdbc-3.8.9.1.jar:$lib_dir/com.icodici.nanohttpd-2.1.0.jar:$lib_dir/com.icodici.common_tools-3.8.3.jar:$lib_dir/com.eclipsesource.minimal-json.minimal-json-0.9.4.jar:$lib_dir/net.java.dev.jna.jna-4.5.1.jar:$lib_dir/org.checkerframework.checker-qual-2.3.2.jar:$lib_dir/com.icodici.crypto-3.8.3.jar:$lib_dir/com.madgag.spongycastle.core-1.58.0.0.jar:$lib_dir/com.squareup.jnagmp.jnagmp-2.0.0.jar:$lib_dir/com.typesafe.play.play-json_2.12-2.6.10.jar:$lib_dir/com.typesafe.play.play-functional_2.12-2.6.10.jar:$lib_dir/org.scala-lang.scala-reflect-2.12.7.jar:$lib_dir/org.typelevel.macro-compat_2.12-1.1.1.jar:$lib_dir/joda-time.joda-time-2.9.9.jar:$lib_dir/com.fasterxml.jackson.core.jackson-core-2.8.11.jar:$lib_dir/com.fasterxml.jackson.core.jackson-annotations-2.8.11.jar:$lib_dir/com.fasterxml.jackson.datatype.jackson-datatype-jdk8-2.8.11.jar:$lib_dir/com.fasterxml.jackson.core.jackson-databind-2.8.11.1.jar:$lib_dir/com.fasterxml.jackson.datatype.jackson-datatype-jsr310-2.8.11.jar:$lib_dir/org.scala-sbt.ipcsocket.ipcsocket-1.0.0.jar:$lib_dir/net.java.dev.jna.jna-platform-4.5.0.jar"
347
+ declare -r app_classpath="$lib_dir/com.icodici.umi-0.8.10.jar:$lib_dir/org.scala-lang.scala-library-2.12.7.jar:$lib_dir/com.icodici.universa_core-3.8.3.jar:$lib_dir/org.yaml.snakeyaml-1.18.jar:$lib_dir/net.sf.jopt-simple.jopt-simple-4.9.jar:$lib_dir/org.postgresql.postgresql-42.1.4.jar:$lib_dir/org.xerial.sqlite-jdbc-3.8.9.1.jar:$lib_dir/com.icodici.nanohttpd-2.1.0.jar:$lib_dir/com.icodici.common_tools-3.8.3.jar:$lib_dir/com.eclipsesource.minimal-json.minimal-json-0.9.4.jar:$lib_dir/net.java.dev.jna.jna-4.5.1.jar:$lib_dir/org.checkerframework.checker-qual-2.3.2.jar:$lib_dir/com.icodici.crypto-3.8.3.jar:$lib_dir/com.madgag.spongycastle.core-1.58.0.0.jar:$lib_dir/com.squareup.jnagmp.jnagmp-2.0.0.jar:$lib_dir/com.typesafe.play.play-json_2.12-2.6.10.jar:$lib_dir/com.typesafe.play.play-functional_2.12-2.6.10.jar:$lib_dir/org.scala-lang.scala-reflect-2.12.7.jar:$lib_dir/org.typelevel.macro-compat_2.12-1.1.1.jar:$lib_dir/joda-time.joda-time-2.9.9.jar:$lib_dir/com.fasterxml.jackson.core.jackson-core-2.8.11.jar:$lib_dir/com.fasterxml.jackson.core.jackson-annotations-2.8.11.jar:$lib_dir/com.fasterxml.jackson.datatype.jackson-datatype-jdk8-2.8.11.jar:$lib_dir/com.fasterxml.jackson.core.jackson-databind-2.8.11.1.jar:$lib_dir/com.fasterxml.jackson.datatype.jackson-datatype-jsr310-2.8.11.jar:$lib_dir/org.scala-sbt.ipcsocket.ipcsocket-1.0.0.jar:$lib_dir/net.java.dev.jna.jna-platform-4.5.0.jar"
348
348
 
349
349
  # java_cmd is overrode in process_args when -java-home is used
350
350
  declare java_cmd=$(get_java_cmd)
@@ -80,7 +80,7 @@ rem "-J" is stripped, "-D" is left as is, and everything is appended to JAVA_OPT
80
80
  set _JAVA_PARAMS=
81
81
  set _APP_ARGS=
82
82
 
83
- set "APP_CLASSPATH=%APP_LIB_DIR%\com.icodici.umi-0.8.8.jar;%APP_LIB_DIR%\org.scala-lang.scala-library-2.12.7.jar;%APP_LIB_DIR%\com.icodici.universa_core-3.8.3.jar;%APP_LIB_DIR%\org.yaml.snakeyaml-1.18.jar;%APP_LIB_DIR%\net.sf.jopt-simple.jopt-simple-4.9.jar;%APP_LIB_DIR%\org.postgresql.postgresql-42.1.4.jar;%APP_LIB_DIR%\org.xerial.sqlite-jdbc-3.8.9.1.jar;%APP_LIB_DIR%\com.icodici.nanohttpd-2.1.0.jar;%APP_LIB_DIR%\com.icodici.common_tools-3.8.3.jar;%APP_LIB_DIR%\com.eclipsesource.minimal-json.minimal-json-0.9.4.jar;%APP_LIB_DIR%\net.java.dev.jna.jna-4.5.1.jar;%APP_LIB_DIR%\org.checkerframework.checker-qual-2.3.2.jar;%APP_LIB_DIR%\com.icodici.crypto-3.8.3.jar;%APP_LIB_DIR%\com.madgag.spongycastle.core-1.58.0.0.jar;%APP_LIB_DIR%\com.squareup.jnagmp.jnagmp-2.0.0.jar;%APP_LIB_DIR%\com.typesafe.play.play-json_2.12-2.6.10.jar;%APP_LIB_DIR%\com.typesafe.play.play-functional_2.12-2.6.10.jar;%APP_LIB_DIR%\org.scala-lang.scala-reflect-2.12.7.jar;%APP_LIB_DIR%\org.typelevel.macro-compat_2.12-1.1.1.jar;%APP_LIB_DIR%\joda-time.joda-time-2.9.9.jar;%APP_LIB_DIR%\com.fasterxml.jackson.core.jackson-core-2.8.11.jar;%APP_LIB_DIR%\com.fasterxml.jackson.core.jackson-annotations-2.8.11.jar;%APP_LIB_DIR%\com.fasterxml.jackson.datatype.jackson-datatype-jdk8-2.8.11.jar;%APP_LIB_DIR%\com.fasterxml.jackson.core.jackson-databind-2.8.11.1.jar;%APP_LIB_DIR%\com.fasterxml.jackson.datatype.jackson-datatype-jsr310-2.8.11.jar;%APP_LIB_DIR%\org.scala-sbt.ipcsocket.ipcsocket-1.0.0.jar;%APP_LIB_DIR%\net.java.dev.jna.jna-platform-4.5.0.jar"
83
+ set "APP_CLASSPATH=%APP_LIB_DIR%\com.icodici.umi-0.8.10.jar;%APP_LIB_DIR%\org.scala-lang.scala-library-2.12.7.jar;%APP_LIB_DIR%\com.icodici.universa_core-3.8.3.jar;%APP_LIB_DIR%\org.yaml.snakeyaml-1.18.jar;%APP_LIB_DIR%\net.sf.jopt-simple.jopt-simple-4.9.jar;%APP_LIB_DIR%\org.postgresql.postgresql-42.1.4.jar;%APP_LIB_DIR%\org.xerial.sqlite-jdbc-3.8.9.1.jar;%APP_LIB_DIR%\com.icodici.nanohttpd-2.1.0.jar;%APP_LIB_DIR%\com.icodici.common_tools-3.8.3.jar;%APP_LIB_DIR%\com.eclipsesource.minimal-json.minimal-json-0.9.4.jar;%APP_LIB_DIR%\net.java.dev.jna.jna-4.5.1.jar;%APP_LIB_DIR%\org.checkerframework.checker-qual-2.3.2.jar;%APP_LIB_DIR%\com.icodici.crypto-3.8.3.jar;%APP_LIB_DIR%\com.madgag.spongycastle.core-1.58.0.0.jar;%APP_LIB_DIR%\com.squareup.jnagmp.jnagmp-2.0.0.jar;%APP_LIB_DIR%\com.typesafe.play.play-json_2.12-2.6.10.jar;%APP_LIB_DIR%\com.typesafe.play.play-functional_2.12-2.6.10.jar;%APP_LIB_DIR%\org.scala-lang.scala-reflect-2.12.7.jar;%APP_LIB_DIR%\org.typelevel.macro-compat_2.12-1.1.1.jar;%APP_LIB_DIR%\joda-time.joda-time-2.9.9.jar;%APP_LIB_DIR%\com.fasterxml.jackson.core.jackson-core-2.8.11.jar;%APP_LIB_DIR%\com.fasterxml.jackson.core.jackson-annotations-2.8.11.jar;%APP_LIB_DIR%\com.fasterxml.jackson.datatype.jackson-datatype-jdk8-2.8.11.jar;%APP_LIB_DIR%\com.fasterxml.jackson.core.jackson-databind-2.8.11.1.jar;%APP_LIB_DIR%\com.fasterxml.jackson.datatype.jackson-datatype-jsr310-2.8.11.jar;%APP_LIB_DIR%\org.scala-sbt.ipcsocket.ipcsocket-1.0.0.jar;%APP_LIB_DIR%\net.java.dev.jna.jna-platform-4.5.0.jar"
84
84
  set "APP_MAIN_CLASS=com.icodici.farcallscala.Main"
85
85
  set "SCRIPT_CONF_FILE=%APP_HOME%\conf\application.ini"
86
86
 
@@ -1,7 +1,11 @@
1
1
  require "universa/version"
2
2
  require "universa/string_utils"
3
3
  require "universa/errors"
4
+ require "universa/tools"
4
5
  require "universa/umi"
6
+ require "universa/service"
7
+ require "universa/keys"
8
+ require "universa/contract"
5
9
 
6
10
  # The Universa gem
7
11
  #
@@ -0,0 +1,20 @@
1
+ module Universa
2
+
3
+ # Universa contract adapter.
4
+ class Contract < RemoteAdapter
5
+ remote_class "com.icodici.universa.contract.Contract"
6
+
7
+ # seal the contract
8
+ # @return [String] contract packed to the binary string
9
+ def seal
10
+ @proxy.seal()
11
+ end
12
+
13
+ # returns keys that will be used to sign this contract on next {seal}.
14
+ # @return [Set<PrivateKey>] set of private keys
15
+ def signing_keys
16
+ get_keys_to_sign_with
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,52 @@
1
+ module Universa
2
+
3
+ # A +com.icodici.crypto.PrivateKey+ extension. As the key is immutable,
4
+ # caching is used to avoid innecessary UMI calls.
5
+ class PrivateKey < RemoteAdapter
6
+ remote_class 'com.icodici.crypto.PrivateKey'
7
+
8
+ # @return [KeyAddress] short address of the corresponding public key
9
+ def short_address
10
+ @short_address ||= public_key.short_address
11
+ end
12
+
13
+ # @return [KeyAddress] long address of the corresponding public key
14
+ def long_address
15
+ @long_address ||= public_key.long_address
16
+ end
17
+
18
+ # @return [PublicKey] public key that matches this
19
+ def public_key
20
+ @public_key ||= get_public_key
21
+ end
22
+ end
23
+
24
+ # A +com.icodici.crypto.PublicKey+ extension. As the key is immutable,
25
+ # caching is used to avoid innecessary UMI calls.
26
+ class PublicKey < RemoteAdapter
27
+ remote_class 'com.icodici.crypto.PublicKey'
28
+
29
+ # @return [KeyAddress] short address
30
+ def short_address
31
+ @short_address ||= get_short_address()
32
+ end
33
+
34
+ # @return [KeyAddress] long address
35
+ def long_address
36
+ @long_address ||= get_long_address()
37
+ end
38
+ end
39
+
40
+ # The +com.icodici.crypto.KeyAddress+ extension. As it is immutable, caching is
41
+ # used to avoid unnecessary UMI calls.
42
+ class KeyAddress < RemoteAdapter
43
+ remote_class 'com.icodici.crypto.KeyAddress'
44
+
45
+ # String form of the key which could be used to unpack it back
46
+ # @return [String] packed string representation
47
+ def to_s
48
+ @string ||= toString()
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,143 @@
1
+ require 'singleton'
2
+
3
+ module Universa
4
+
5
+ # The service is a singleton to provide porcess-wide objects and methods. For example,
6
+ # the {UMI} interface and reference class factory are unique per-process for Universa
7
+ # library. It uses exactly one lazy created {UMI} connection which is shared among all threads.
8
+ # As UMI server is multithreaded by nature, is will not block ruby threads waiting for remote
9
+ # invocation.
10
+ class Service
11
+ include Singleton
12
+
13
+ # Setup service initial parameters
14
+ def initialize
15
+ @config = SmartHash.new path: nil
16
+ @known_proxies = {}
17
+ [Contract, PrivateKey, PublicKey, KeyAddress].each {|klass| register_proxy klass}
18
+ end
19
+
20
+ # Implementation of {Service.configure}
21
+ def configure &block
22
+ raise Error, "config call must happen before interface creation" if @umi
23
+ block.call @config
24
+ end
25
+
26
+ # Implementation of {Service.umi}
27
+ def umi
28
+ c = @config.to_h.transform_keys(&:to_sym).update(convert_case: true)
29
+ c[:factory] = -> (ref) {create_proxy(ref)}
30
+ @umi ||= UMI.new(c.delete(:path), **c)
31
+ end
32
+
33
+
34
+ # push string to service log
35
+ def log msg
36
+ puts "U:Service: #{msg}"
37
+ end
38
+
39
+ # Create objectproxy for known types
40
+ # @param [Ref] ref to transform
41
+ # @return [RemoteAdapter | Ref] transformed or source reference
42
+ def create_proxy ref
43
+ proxy_class = @known_proxies[ref._remote_class_name]
44
+ return ref unless proxy_class
45
+ proxy_class.new(ReferenceCreationData.new(ref))
46
+ end
47
+
48
+ class << self
49
+
50
+ # Call it before everything to update UMI interface parameters before is is created.
51
+ # Calling it when UMI is already constructed raises Error.
52
+ def configure &block
53
+ instance.configure &block
54
+ end
55
+
56
+ # Get the global UMI interface, creating it if need.
57
+ # @return [UMI] ready interface
58
+ def umi
59
+ instance.umi
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def register_proxy klass
66
+ remote_class_name = klass.remote_class_name
67
+ raise Error, "#{remote_class_name} is already registered in Service" if @known_proxies.include?(remote_class_name)
68
+ @known_proxies[remote_class_name] = klass
69
+ end
70
+ end
71
+
72
+ # The basic class to write remote class adapters (extensions). Delegates contained {Ref} instance therefore behaves
73
+ # like remote interface with some extensions.
74
+ #
75
+ # Key feature of RemoteAdapter class is the cross-call persistence. It means once created instances of the
76
+ # RemoteAdapter descendants are cached just like (in fact, instead of) {Ref} instances, so when the remote party
77
+ # returns the reference to the object once wrapped by this instance, the instance will be returned unless it is
78
+ # already garbage collected. instance will be returned, what means sort of cross-platform calls persistence.
79
+ #
80
+ # Extending this class normally should not implement the constructor, By defaul the constructor is passed to
81
+ # the remote to create remote instance.
82
+ class RemoteAdapter < Delegator
83
+
84
+ # Instantiate new proxy object passing arguments to the remote constructor. The UMO host will try
85
+ # ot find overloaded constructor that matches the arguments.
86
+ #
87
+ # @param [*Any] args any arguments that remote constructor may accept.
88
+ def initialize(*args)
89
+ if args.length == 1 && args[0].is_a?(ReferenceCreationData)
90
+ @remote = args[0].ref
91
+ else
92
+ # User called constructor
93
+ remote_class_name = self.class.remote_class_name
94
+ remote_class_name&.length or raise Error, "provide remote_class_name"
95
+ @remote = Service.umi.instantiate remote_class_name.split('.')[-1], *args, adapter: self
96
+ end
97
+ end
98
+
99
+ # Delegated object
100
+ # @return [Ref] the wrapped instance whose methpds are delegated by this
101
+ def __getobj__
102
+ @remote
103
+ end
104
+
105
+ # Updating proxied object is not allowed. Raises error.
106
+ def __setobj__
107
+ raise "ObectProxy does not support changing referenced object"
108
+ end
109
+
110
+ # Returns remote class name. There is no need to override it, when inheriting it use +remote_class+ helper:
111
+ #
112
+ # class MyKeyAddress < ObjectProxy
113
+ # remote_class 'com.icodici.crypto.KeyAddress'
114
+ #
115
+ # #...
116
+ # end
117
+ #
118
+ # Notice: remote_class will do allnecessary work for you.
119
+ #
120
+ # @return [String] remote class name
121
+ def self.remote_class_name
122
+ raise Error, "provde remote class name"
123
+ end
124
+
125
+ # Registers remote class name to be used with this adapted. Call it early in descendant class
126
+ # declaration.
127
+ def self.remote_class name
128
+ class_eval "def self.remote_class_name; '#{name}'; end"
129
+ end
130
+
131
+ # debugging label
132
+ def inspect
133
+ "<#{self.class.name}:#{__id__}:#{@remote._remote_class_name}:#{@remote._remote_id}}>"
134
+ end
135
+
136
+ # call the remote toString(). Does not cache it.
137
+ # @return [String]
138
+ def to_s
139
+ toString()
140
+ end
141
+ end
142
+
143
+ end
@@ -0,0 +1,8 @@
1
+ require 'farcall/smart_hash'
2
+
3
+ module Universa
4
+
5
+ # The Hashie::Mash without warnings, just copied from Farcall to not to copy it again
6
+ class SmartHash < Farcall::SmartHash
7
+ end
8
+ end
@@ -64,7 +64,7 @@ module Universa
64
64
  # @param [String] system expected on the remote side. 'UMI' us a universa umi server.
65
65
  # @param [Boolean] convert_case it true, convert ruby style snake case `get_some_stuff()` to java style lower camel
66
66
  # case `getSomeStuff()` while calling methods. Does not affect class names on {instantiate}.
67
- def initialize(path = nil, version_check: /./, system: "UMI", log: 'sessionlog.txt', convert_case: true)
67
+ def initialize(path = nil, version_check: /./, system: "UMI", log: 'sessionlog.txt', convert_case: true, factory: nil)
68
68
  path ||= File.expand_path(File.split(__FILE__)[0] + "/../../bin/umi/bin/umi")
69
69
  @in, @out, @err, @wtr = Open3.popen3("#{path} #{log ? "-log #{log}" : ''}")
70
70
  @endpoint = Farcall::Endpoint.new(
@@ -73,7 +73,7 @@ module Universa
73
73
  @lock = Monitor.new
74
74
  @cache = {}
75
75
  @closed = false
76
- @convert_case = convert_case
76
+ @convert_case, @factory = convert_case, factory
77
77
  @references = {}
78
78
  start_cleanup_queue
79
79
  @version = call("version")
@@ -95,9 +95,9 @@ module Universa
95
95
  # housekeeping required, like memory leaks prevention and direct method calling.
96
96
  #
97
97
  # @return [Ref] reference to the remotely created object. See {Ref}.
98
- def instantiate(object_class_name, *args)
98
+ def instantiate(object_class_name, *args, adapter: nil)
99
99
  ensure_open
100
- create_reference call("instantiate", object_class_name, *prepare_args(args))
100
+ create_reference call("instantiate", object_class_name, *prepare_args(args)), adapter
101
101
  end
102
102
 
103
103
  # Invoke method by name. Should not be used directly; use {Ref} instance to call its methods.
@@ -163,8 +163,9 @@ module Universa
163
163
 
164
164
  # Create a reference correcting adapting remote types to ruby ecosystem, for example loads
165
165
  # remote Java Set to a local ruby Set.
166
- def create_reference reference_record
167
- r = build_reference reference_record
166
+ def create_reference(reference_record, adapter = nil)
167
+ r = build_reference reference_record, adapter
168
+ return r if adapter
168
169
  case reference_record.className
169
170
  when 'java.util.HashSet'
170
171
  r.toArray()
@@ -175,16 +176,31 @@ module Universa
175
176
 
176
177
  # Create a reference from UMI remote object reference structure. Returns existing object if any. Takes care
177
178
  # of dropping remote object when ruby object gets collected.
178
- def build_reference reference_record
179
+ def build_reference(reference_record, proxy)
179
180
  @lock.synchronize {
180
181
  remote_id = reference_record.id
181
182
  ref = @cache[remote_id]&.get
182
183
  if !ref
183
184
  # log "Creating new reference to remote #{remote_id}"
184
185
  ref = Ref.new(self, reference_record)
185
- ObjectSpace.define_finalizer(ref, create_finalizer(remote_id))
186
- @cache[remote_id] = WeakReference.new(ref)
186
+ # IF we provide proxy that will consume the ref, we'll cache the proxy object,
187
+ # otherwise we run factory and cahce whatever it returns or the ref itself
188
+ obj = if proxy
189
+ # Proxy object will delegate the ref we return from there
190
+ # no action need
191
+ proxy
192
+ else
193
+ # new object: factory may create proxy for us and we'll cache it for later
194
+ # use:
195
+ @factory and ref = @factory.call(ref)
196
+ ref
197
+ end
198
+ # Important: we set finalizer fot the target object
199
+ ObjectSpace.define_finalizer(obj, create_finalizer(remote_id))
200
+ # and we cache target object
201
+ @cache[remote_id] = WeakReference.new(obj)
187
202
  end
203
+ # but we return reference: it the proxy constructor calls us, it'll need the ref:
188
204
  ref
189
205
  }
190
206
  end
@@ -334,9 +350,14 @@ module Universa
334
350
  @id
335
351
  end
336
352
 
353
+ # name of the remote class (provided by remote)
354
+ def _remote_class_name
355
+ @ref.className
356
+ end
357
+
337
358
  # Internal use only. Allow processing remote commands as local calls
338
359
  def respond_to_missing?(method_name, include_private = false)
339
- method_name[0] == '_' ? super : true
360
+ method_name[0] == '_' || LOCAL_METHODS.include?(method_name) ? super : true
340
361
  end
341
362
 
342
363
  #Internal use only. Call remote method as needed. This is where all the magick comes from: it call remote method instead of the
@@ -357,13 +378,13 @@ module Universa
357
378
 
358
379
  # short data label for instance
359
380
  def inspect
360
- "<UMI:Ref:#{@umi.__id__}:#{@ref.className}:#{@id})>"
381
+ "<UMI:Ref:#{@umi.__id__}:#{@ref.className}:#{@id}>"
361
382
  end
362
383
 
363
384
  # Checks that references are euqal: either both point to the same remote object or respective remote objects
364
385
  # are reported equals by the remote +equals()+ call.
365
386
  def ==(other)
366
- other.is_a?(Ref) && other._umi == @umi &&
387
+ (other.is_a?(Ref) || other.is_a?(RemoteAdapter)) && other._umi == @umi &&
367
388
  (other._remote_id == @id || other.equals(self))
368
389
  end
369
390
 
@@ -373,6 +394,24 @@ module Universa
373
394
  other.is_a?(Ref) && other._umi == @umi && other._remote_id == @id
374
395
  end
375
396
 
397
+ private
398
+
399
+ LOCAL_METHODS = Set.new(%i[i_respond_to_everything_so_im_not_really_a_matcher to_hash to_ary description])
400
+ end
401
+
402
+ # Service uses this class to contruct {RemoteAdapter} pointing to the existing remote object instead
403
+ # of instantiating new one.
404
+ #
405
+ class ReferenceCreationData
406
+ # reference to create proxy for
407
+ # @return [Ref]
408
+ attr :ref
409
+
410
+ # we need to wrap this ref
411
+ # @param [Ref] ref to wrap in {RemoteAdapter}
412
+ def initialize ref
413
+ @ref = ref
414
+ end
376
415
  end
377
416
 
378
417
  end
@@ -1,4 +1,4 @@
1
1
  module Universa
2
2
  # Current gem version
3
- VERSION = "0.1.2"
3
+ VERSION = "0.1.3"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: universa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - sergeych
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-02 00:00:00.000000000 Z
11
+ date: 2018-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: farcall
@@ -95,7 +95,6 @@ files:
95
95
  - bin/umi/lib/com.icodici.common_tools-3.8.3.jar
96
96
  - bin/umi/lib/com.icodici.crypto-3.8.3.jar
97
97
  - bin/umi/lib/com.icodici.nanohttpd-2.1.0.jar
98
- - bin/umi/lib/com.icodici.umi-0.8.8.jar
99
98
  - bin/umi/lib/com.icodici.universa_core-3.8.3.jar
100
99
  - bin/umi/lib/com.madgag.spongycastle.core-1.58.0.0.jar
101
100
  - bin/umi/lib/com.squareup.jnagmp.jnagmp-2.0.0.jar
@@ -111,8 +110,12 @@ files:
111
110
  - bin/umi/lib/org.yaml.snakeyaml-1.18.jar
112
111
  - exe/universa
113
112
  - lib/universa.rb
113
+ - lib/universa/contract.rb
114
114
  - lib/universa/errors.rb
115
+ - lib/universa/keys.rb
116
+ - lib/universa/service.rb
115
117
  - lib/universa/string_utils.rb
118
+ - lib/universa/tools.rb
116
119
  - lib/universa/umi.rb
117
120
  - lib/universa/version.rb
118
121
  - lib/universa/weak_reference.rb