universa 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +23 -3
- data/bin/refresh_umi +20 -0
- data/bin/umi/bin/umi +355 -0
- data/bin/umi/bin/umi.bat +180 -0
- data/bin/umi/lib/com.fasterxml.jackson.core.jackson-annotations-2.8.11.jar +0 -0
- data/bin/umi/lib/com.fasterxml.jackson.core.jackson-core-2.8.11.jar +0 -0
- data/bin/umi/lib/com.fasterxml.jackson.core.jackson-databind-2.8.11.1.jar +0 -0
- data/bin/umi/lib/com.fasterxml.jackson.datatype.jackson-datatype-jdk8-2.8.11.jar +0 -0
- data/bin/umi/lib/com.fasterxml.jackson.datatype.jackson-datatype-jsr310-2.8.11.jar +0 -0
- data/bin/umi/lib/com.icodici.common_tools-3.8.3.jar +0 -0
- data/bin/umi/lib/com.icodici.crypto-3.8.3.jar +0 -0
- data/bin/umi/lib/com.icodici.nanohttpd-2.1.0.jar +0 -0
- data/bin/umi/lib/com.icodici.umi-0.8.7.jar +0 -0
- data/bin/umi/lib/com.icodici.universa_core-3.8.3.jar +0 -0
- data/bin/umi/lib/com.madgag.spongycastle.core-1.58.0.0.jar +0 -0
- data/bin/umi/lib/com.squareup.jnagmp.jnagmp-2.0.0.jar +0 -0
- data/bin/umi/lib/com.typesafe.play.play-functional_2.12-2.6.10.jar +0 -0
- data/bin/umi/lib/com.typesafe.play.play-json_2.12-2.6.10.jar +0 -0
- data/bin/umi/lib/net.java.dev.jna.jna-4.5.1.jar +0 -0
- data/bin/umi/lib/net.java.dev.jna.jna-platform-4.5.0.jar +0 -0
- data/bin/umi/lib/net.sf.jopt-simple.jopt-simple-4.9.jar +0 -0
- data/bin/umi/lib/org.scala-lang.scala-library-2.12.7.jar +0 -0
- data/bin/umi/lib/org.scala-lang.scala-reflect-2.12.7.jar +0 -0
- data/bin/umi/lib/org.scala-sbt.ipcsocket.ipcsocket-1.0.0.jar +0 -0
- data/bin/umi/lib/org.typelevel.macro-compat_2.12-1.1.1.jar +0 -0
- data/bin/umi/lib/org.yaml.snakeyaml-1.18.jar +0 -0
- data/exe/universa +6 -0
- data/lib/universa/errors.rb +25 -0
- data/lib/universa/umi.rb +373 -0
- data/lib/universa/version.rb +2 -1
- data/lib/universa/weak_reference.rb +60 -0
- data/lib/universa.rb +10 -1
- data/universa.gemspec +3 -1
- metadata +45 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b0550e986188ea0c6777ed4e08112e5cbf3605b7247b11ee939a5c8b3944fcf
|
4
|
+
data.tar.gz: 56278bf8d1271447de7acde7cf85c98086c994f3635b966c104d00cb5cbb1fa6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f1b071d7ae76fed9b9879ed03e4a106f614f1a4c420e58c8b7e3e23b84b9f3b87688c9eece8a4c7485e411f49388e23d9c76da90579721f00c5bff98f6f67dc
|
7
|
+
data.tar.gz: 4da0d67c5ada6d480fa3868294993a55c2db072f29e1982f57d26c1402c59a3099967cc3d006ba097fa5e72bdc775d580a4c8869cfe8dcff5085f483b60f3715
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Universa
|
2
2
|
|
3
|
-
>
|
3
|
+
> Alfa state: direct access to Java API ready for test.
|
4
4
|
|
5
5
|
This is an under-construction official gem from [Universa][universa] that will facilitate access to the
|
6
|
-
Java library using Universa's
|
6
|
+
Java library using Universa's UMI protocol.
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
@@ -29,7 +29,27 @@ Or install it yourself as:
|
|
29
29
|
|
30
30
|
## Usage
|
31
31
|
|
32
|
-
|
32
|
+
So far, you can only get direct access the the Java API functions. To get it:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
require 'universa'
|
36
|
+
|
37
|
+
umi = Universa::UMI.new
|
38
|
+
|
39
|
+
p umi.version #=> "0.8.7"
|
40
|
+
key = umi.instantiate "PrivateKey", 2048
|
41
|
+
contract = umi.instantiate "Contract", key
|
42
|
+
sealed = contract.seal()
|
43
|
+
puts "Contract is ok: #{contract.check()}" #=> contract is ok: true"
|
44
|
+
puts "Contract id: #{contract.getId.toBase64String}" #=> contract id: x9Ey+q...
|
45
|
+
```
|
46
|
+
|
47
|
+
for more information see:
|
48
|
+
|
49
|
+
- [Universa gem page](https://kb.universa.io/universa_ruby_gem/131) in the Universa Knowledge Base.
|
50
|
+
- Universa Java API: https://kb.universa.io/general_java_api/5
|
51
|
+
- Universa UMI server: https://kb.universa.io/umi_protocol/98
|
52
|
+
- Farcall [gem](https://github.com/sergeych/farcall) and [protocol](https://github.com/sergeych/farcall/wiki).
|
33
53
|
|
34
54
|
## Development
|
35
55
|
|
data/bin/refresh_umi
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
rm download > /dev/null
|
4
|
+
|
5
|
+
wget https://files.universa.io/s/ecz6fDT7ny634Xj/download
|
6
|
+
|
7
|
+
rm -rd -f ./bin/umi >/dev/null 2>&1
|
8
|
+
rm -rd -f ./bin/umi-* >/dev/null 2>&1
|
9
|
+
|
10
|
+
echo "preparing..."
|
11
|
+
|
12
|
+
unzip download -d ./bin >/dev/null
|
13
|
+
|
14
|
+
mv ./bin/umi-* ./bin/umi >/dev/null
|
15
|
+
rm -rd ./bin/__MACOSX >/dev/null 2>&1
|
16
|
+
|
17
|
+
rm download
|
18
|
+
|
19
|
+
echo "done!"
|
20
|
+
|
data/bin/umi/bin/umi
ADDED
@@ -0,0 +1,355 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
### ------------------------------- ###
|
4
|
+
### Helper methods for BASH scripts ###
|
5
|
+
### ------------------------------- ###
|
6
|
+
|
7
|
+
die() {
|
8
|
+
echo "$@" 1>&2
|
9
|
+
exit 1
|
10
|
+
}
|
11
|
+
|
12
|
+
realpath () {
|
13
|
+
(
|
14
|
+
TARGET_FILE="$1"
|
15
|
+
CHECK_CYGWIN="$2"
|
16
|
+
|
17
|
+
cd "$(dirname "$TARGET_FILE")"
|
18
|
+
TARGET_FILE=$(basename "$TARGET_FILE")
|
19
|
+
|
20
|
+
COUNT=0
|
21
|
+
while [ -L "$TARGET_FILE" -a $COUNT -lt 100 ]
|
22
|
+
do
|
23
|
+
TARGET_FILE=$(readlink "$TARGET_FILE")
|
24
|
+
cd "$(dirname "$TARGET_FILE")"
|
25
|
+
TARGET_FILE=$(basename "$TARGET_FILE")
|
26
|
+
COUNT=$(($COUNT + 1))
|
27
|
+
done
|
28
|
+
|
29
|
+
if [ "$TARGET_FILE" == "." -o "$TARGET_FILE" == ".." ]; then
|
30
|
+
cd "$TARGET_FILE"
|
31
|
+
TARGET_FILEPATH=
|
32
|
+
else
|
33
|
+
TARGET_FILEPATH=/$TARGET_FILE
|
34
|
+
fi
|
35
|
+
|
36
|
+
# make sure we grab the actual windows path, instead of cygwin's path.
|
37
|
+
if [[ "x$CHECK_CYGWIN" == "x" ]]; then
|
38
|
+
echo "$(pwd -P)/$TARGET_FILE"
|
39
|
+
else
|
40
|
+
echo $(cygwinpath "$(pwd -P)/$TARGET_FILE")
|
41
|
+
fi
|
42
|
+
)
|
43
|
+
}
|
44
|
+
|
45
|
+
# TODO - Do we need to detect msys?
|
46
|
+
|
47
|
+
# Uses uname to detect if we're in the odd cygwin environment.
|
48
|
+
is_cygwin() {
|
49
|
+
local os=$(uname -s)
|
50
|
+
case "$os" in
|
51
|
+
CYGWIN*) return 0 ;;
|
52
|
+
*) return 1 ;;
|
53
|
+
esac
|
54
|
+
}
|
55
|
+
|
56
|
+
# This can fix cygwin style /cygdrive paths so we get the
|
57
|
+
# windows style paths.
|
58
|
+
cygwinpath() {
|
59
|
+
local file="$1"
|
60
|
+
if is_cygwin; then
|
61
|
+
echo $(cygpath -w $file)
|
62
|
+
else
|
63
|
+
echo $file
|
64
|
+
fi
|
65
|
+
}
|
66
|
+
|
67
|
+
# Make something URI friendly
|
68
|
+
make_url() {
|
69
|
+
url="$1"
|
70
|
+
local nospaces=${url// /%20}
|
71
|
+
if is_cygwin; then
|
72
|
+
echo "/${nospaces//\\//}"
|
73
|
+
else
|
74
|
+
echo "$nospaces"
|
75
|
+
fi
|
76
|
+
}
|
77
|
+
|
78
|
+
# This crazy function reads in a vanilla "linux" classpath string (only : are separators, and all /),
|
79
|
+
# and returns a classpath with windows style paths, and ; separators.
|
80
|
+
fixCygwinClasspath() {
|
81
|
+
OLDIFS=$IFS
|
82
|
+
IFS=":"
|
83
|
+
read -a classpath_members <<< "$1"
|
84
|
+
declare -a fixed_members
|
85
|
+
IFS=$OLDIFS
|
86
|
+
for i in "${!classpath_members[@]}"
|
87
|
+
do
|
88
|
+
fixed_members[i]=$(realpath "${classpath_members[i]}" "fix")
|
89
|
+
done
|
90
|
+
IFS=";"
|
91
|
+
echo "${fixed_members[*]}"
|
92
|
+
IFS=$OLDIFS
|
93
|
+
}
|
94
|
+
|
95
|
+
# Fix the classpath we use for cygwin.
|
96
|
+
fix_classpath() {
|
97
|
+
cp="$1"
|
98
|
+
if is_cygwin; then
|
99
|
+
echo "$(fixCygwinClasspath "$cp")"
|
100
|
+
else
|
101
|
+
echo "$cp"
|
102
|
+
fi
|
103
|
+
}
|
104
|
+
# Detect if we should use JAVA_HOME or just try PATH.
|
105
|
+
get_java_cmd() {
|
106
|
+
if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
|
107
|
+
echo "$JAVA_HOME/bin/java"
|
108
|
+
else
|
109
|
+
echo "java"
|
110
|
+
fi
|
111
|
+
}
|
112
|
+
|
113
|
+
echoerr () {
|
114
|
+
echo 1>&2 "$@"
|
115
|
+
}
|
116
|
+
vlog () {
|
117
|
+
[[ $verbose || $debug ]] && echoerr "$@"
|
118
|
+
}
|
119
|
+
dlog () {
|
120
|
+
[[ $debug ]] && echoerr "$@"
|
121
|
+
}
|
122
|
+
execRunner () {
|
123
|
+
# print the arguments one to a line, quoting any containing spaces
|
124
|
+
[[ $verbose || $debug ]] && echo "# Executing command line:" && {
|
125
|
+
for arg; do
|
126
|
+
if printf "%s\n" "$arg" | grep -q ' '; then
|
127
|
+
printf "\"%s\"\n" "$arg"
|
128
|
+
else
|
129
|
+
printf "%s\n" "$arg"
|
130
|
+
fi
|
131
|
+
done
|
132
|
+
echo ""
|
133
|
+
}
|
134
|
+
|
135
|
+
# we use "exec" here for our pids to be accurate.
|
136
|
+
exec "$@"
|
137
|
+
}
|
138
|
+
addJava () {
|
139
|
+
dlog "[addJava] arg = '$1'"
|
140
|
+
java_args+=( "$1" )
|
141
|
+
}
|
142
|
+
addApp () {
|
143
|
+
dlog "[addApp] arg = '$1'"
|
144
|
+
app_commands+=( "$1" )
|
145
|
+
}
|
146
|
+
addResidual () {
|
147
|
+
dlog "[residual] arg = '$1'"
|
148
|
+
residual_args+=( "$1" )
|
149
|
+
}
|
150
|
+
addDebugger () {
|
151
|
+
addJava "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$1"
|
152
|
+
}
|
153
|
+
|
154
|
+
require_arg () {
|
155
|
+
local type="$1"
|
156
|
+
local opt="$2"
|
157
|
+
local arg="$3"
|
158
|
+
if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then
|
159
|
+
die "$opt requires <$type> argument"
|
160
|
+
fi
|
161
|
+
}
|
162
|
+
is_function_defined() {
|
163
|
+
declare -f "$1" > /dev/null
|
164
|
+
}
|
165
|
+
|
166
|
+
# Attempt to detect if the script is running via a GUI or not
|
167
|
+
# TODO - Determine where/how we use this generically
|
168
|
+
detect_terminal_for_ui() {
|
169
|
+
[[ ! -t 0 ]] && [[ "${#residual_args}" == "0" ]] && {
|
170
|
+
echo "true"
|
171
|
+
}
|
172
|
+
# SPECIAL TEST FOR MAC
|
173
|
+
[[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]] && [[ "${#residual_args}" == "0" ]] && {
|
174
|
+
echo "true"
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
# Processes incoming arguments and places them in appropriate global variables. called by the run method.
|
179
|
+
process_args () {
|
180
|
+
local no_more_snp_opts=0
|
181
|
+
while [[ $# -gt 0 ]]; do
|
182
|
+
case "$1" in
|
183
|
+
--) shift && no_more_snp_opts=1 && break ;;
|
184
|
+
-h|-help) usage; exit 1 ;;
|
185
|
+
-v|-verbose) verbose=1 && shift ;;
|
186
|
+
-d|-debug) debug=1 && shift ;;
|
187
|
+
|
188
|
+
-no-version-check) no_version_check=1 && shift ;;
|
189
|
+
|
190
|
+
-mem) echo "!! WARNING !! -mem option is ignored. Please use -J-Xmx and -J-Xms" && shift 2 ;;
|
191
|
+
-jvm-debug) require_arg port "$1" "$2" && addDebugger $2 && shift 2 ;;
|
192
|
+
|
193
|
+
-main) custom_mainclass="$2" && shift 2 ;;
|
194
|
+
|
195
|
+
-java-home) require_arg path "$1" "$2" && jre=`eval echo $2` && java_cmd="$jre/bin/java" && shift 2 ;;
|
196
|
+
|
197
|
+
-D*|-agentlib*|-XX*) addJava "$1" && shift ;;
|
198
|
+
-J*) addJava "${1:2}" && shift ;;
|
199
|
+
*) addResidual "$1" && shift ;;
|
200
|
+
esac
|
201
|
+
done
|
202
|
+
|
203
|
+
if [[ no_more_snp_opts ]]; then
|
204
|
+
while [[ $# -gt 0 ]]; do
|
205
|
+
addResidual "$1" && shift
|
206
|
+
done
|
207
|
+
fi
|
208
|
+
|
209
|
+
is_function_defined process_my_args && {
|
210
|
+
myargs=("${residual_args[@]}")
|
211
|
+
residual_args=()
|
212
|
+
process_my_args "${myargs[@]}"
|
213
|
+
}
|
214
|
+
}
|
215
|
+
|
216
|
+
# Actually runs the script.
|
217
|
+
run() {
|
218
|
+
# TODO - check for sane environment
|
219
|
+
|
220
|
+
# process the combined args, then reset "$@" to the residuals
|
221
|
+
process_args "$@"
|
222
|
+
set -- "${residual_args[@]}"
|
223
|
+
argumentCount=$#
|
224
|
+
|
225
|
+
#check for jline terminal fixes on cygwin
|
226
|
+
if is_cygwin; then
|
227
|
+
stty -icanon min 1 -echo > /dev/null 2>&1
|
228
|
+
addJava "-Djline.terminal=jline.UnixTerminal"
|
229
|
+
addJava "-Dsbt.cygwin=true"
|
230
|
+
fi
|
231
|
+
|
232
|
+
# check java version
|
233
|
+
if [[ ! $no_version_check ]]; then
|
234
|
+
java_version_check
|
235
|
+
fi
|
236
|
+
|
237
|
+
if [ -n "$custom_mainclass" ]; then
|
238
|
+
mainclass=("$custom_mainclass")
|
239
|
+
else
|
240
|
+
mainclass=("${app_mainclass[@]}")
|
241
|
+
fi
|
242
|
+
|
243
|
+
# Now we check to see if there are any java opts on the environment. These get listed first, with the script able to override them.
|
244
|
+
if [[ "$JAVA_OPTS" != "" ]]; then
|
245
|
+
java_opts="${JAVA_OPTS}"
|
246
|
+
fi
|
247
|
+
|
248
|
+
# run sbt
|
249
|
+
execRunner "$java_cmd" \
|
250
|
+
${java_opts[@]} \
|
251
|
+
"${java_args[@]}" \
|
252
|
+
-cp "$(fix_classpath "$app_classpath")" \
|
253
|
+
"${mainclass[@]}" \
|
254
|
+
"${app_commands[@]}" \
|
255
|
+
"${residual_args[@]}"
|
256
|
+
|
257
|
+
local exit_code=$?
|
258
|
+
if is_cygwin; then
|
259
|
+
stty icanon echo > /dev/null 2>&1
|
260
|
+
fi
|
261
|
+
exit $exit_code
|
262
|
+
}
|
263
|
+
|
264
|
+
# Loads a configuration file full of default command line options for this script.
|
265
|
+
loadConfigFile() {
|
266
|
+
cat "$1" | sed $'/^\#/d;s/\r$//'
|
267
|
+
}
|
268
|
+
|
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
|
271
|
+
java_version_check() {
|
272
|
+
readonly java_version=$("$java_cmd" -version 2>&1 | awk -F '"' '/version/ {print $2}')
|
273
|
+
if [[ "$java_version" == "" ]]; then
|
274
|
+
echo
|
275
|
+
echo No java installations was detected.
|
276
|
+
echo Please go to http://www.java.com/getjava/ and download
|
277
|
+
echo
|
278
|
+
exit 1
|
279
|
+
else
|
280
|
+
local major=$(echo "$java_version" | cut -d'.' -f1)
|
281
|
+
if [[ "$major" -eq "1" ]]; then
|
282
|
+
local major=$(echo "$java_version" | cut -d'.' -f2)
|
283
|
+
fi
|
284
|
+
if [[ "$major" -lt "6" ]]; then
|
285
|
+
echo
|
286
|
+
echo The java installation you have is not up to date
|
287
|
+
echo $app_name requires at least version 1.6+, you have
|
288
|
+
echo version $java_version
|
289
|
+
echo
|
290
|
+
echo Please go to http://www.java.com/getjava/ and download
|
291
|
+
echo a valid Java Runtime and install before running $app_name.
|
292
|
+
echo
|
293
|
+
exit 1
|
294
|
+
fi
|
295
|
+
fi
|
296
|
+
}
|
297
|
+
|
298
|
+
### ------------------------------- ###
|
299
|
+
### Start of customized settings ###
|
300
|
+
### ------------------------------- ###
|
301
|
+
usage() {
|
302
|
+
cat <<EOM
|
303
|
+
Usage: $script_name [options]
|
304
|
+
|
305
|
+
-h | -help print this message
|
306
|
+
-v | -verbose this runner is chattier
|
307
|
+
-d | -debug set sbt log level to debug
|
308
|
+
-no-version-check Don't run the java version check.
|
309
|
+
-main <classname> Define a custom main class
|
310
|
+
-jvm-debug <port> Turn on JVM debugging, open at the given port.
|
311
|
+
|
312
|
+
# java version (default: java from PATH, currently $(java -version 2>&1 | grep version))
|
313
|
+
-java-home <path> alternate JAVA_HOME
|
314
|
+
|
315
|
+
# jvm options and output control
|
316
|
+
JAVA_OPTS environment variable, if unset uses "$java_opts"
|
317
|
+
-Dkey=val pass -Dkey=val directly to the java runtime
|
318
|
+
-J-X pass option -X directly to the java runtime
|
319
|
+
(-J is stripped)
|
320
|
+
|
321
|
+
# special option
|
322
|
+
-- To stop parsing built-in commands from the rest of the command-line.
|
323
|
+
e.g.) enabling debug and sending -d as app argument
|
324
|
+
\$ ./start-script -d -- -d
|
325
|
+
|
326
|
+
In the case of duplicated or conflicting options, basically the order above
|
327
|
+
shows precedence: JAVA_OPTS lowest, command line options highest except "--".
|
328
|
+
Available main classes:
|
329
|
+
com.icodici.farcallscala.Main
|
330
|
+
EOM
|
331
|
+
}
|
332
|
+
|
333
|
+
### ------------------------------- ###
|
334
|
+
### Main script ###
|
335
|
+
### ------------------------------- ###
|
336
|
+
|
337
|
+
declare -a residual_args
|
338
|
+
declare -a java_args
|
339
|
+
declare -a app_commands
|
340
|
+
declare -r real_script_path="$(realpath "$0")"
|
341
|
+
declare -r app_home="$(realpath "$(dirname "$real_script_path")")"
|
342
|
+
# TODO - Check whether this is ok in cygwin...
|
343
|
+
declare -r lib_dir="$(realpath "${app_home}/../lib")"
|
344
|
+
declare -a app_mainclass=(com.icodici.farcallscala.Main)
|
345
|
+
|
346
|
+
declare -r script_conf_file="${app_home}/../conf/application.ini"
|
347
|
+
declare -r app_classpath="$lib_dir/com.icodici.umi-0.8.7.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
|
+
|
349
|
+
# java_cmd is overrode in process_args when -java-home is used
|
350
|
+
declare java_cmd=$(get_java_cmd)
|
351
|
+
|
352
|
+
# if configuration files exist, prepend their contents to $@ so it can be processed by this runner
|
353
|
+
[[ -f "$script_conf_file" ]] && set -- $(loadConfigFile "$script_conf_file") "$@"
|
354
|
+
|
355
|
+
run "$@"
|
data/bin/umi/bin/umi.bat
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
@REM umi launcher script
|
2
|
+
@REM
|
3
|
+
@REM Environment:
|
4
|
+
@REM JAVA_HOME - location of a JDK home dir (optional if java on path)
|
5
|
+
@REM CFG_OPTS - JVM options (optional)
|
6
|
+
@REM Configuration:
|
7
|
+
@REM UMI_config.txt found in the UMI_HOME.
|
8
|
+
@setlocal enabledelayedexpansion
|
9
|
+
|
10
|
+
@echo off
|
11
|
+
|
12
|
+
|
13
|
+
if "%UMI_HOME%"=="" (
|
14
|
+
set "APP_HOME=%~dp0\\.."
|
15
|
+
|
16
|
+
rem Also set the old env name for backwards compatibility
|
17
|
+
set "UMI_HOME=%~dp0\\.."
|
18
|
+
) else (
|
19
|
+
set "APP_HOME=%UMI_HOME%"
|
20
|
+
)
|
21
|
+
|
22
|
+
set "APP_LIB_DIR=%APP_HOME%\lib\"
|
23
|
+
|
24
|
+
rem Detect if we were double clicked, although theoretically A user could
|
25
|
+
rem manually run cmd /c
|
26
|
+
for %%x in (!cmdcmdline!) do if %%~x==/c set DOUBLECLICKED=1
|
27
|
+
|
28
|
+
rem FIRST we load the config file of extra options.
|
29
|
+
set "CFG_FILE=%APP_HOME%\UMI_config.txt"
|
30
|
+
set CFG_OPTS=
|
31
|
+
call :parse_config "%CFG_FILE%" CFG_OPTS
|
32
|
+
|
33
|
+
rem We use the value of the JAVACMD environment variable if defined
|
34
|
+
set _JAVACMD=%JAVACMD%
|
35
|
+
|
36
|
+
if "%_JAVACMD%"=="" (
|
37
|
+
if not "%JAVA_HOME%"=="" (
|
38
|
+
if exist "%JAVA_HOME%\bin\java.exe" set "_JAVACMD=%JAVA_HOME%\bin\java.exe"
|
39
|
+
)
|
40
|
+
)
|
41
|
+
|
42
|
+
if "%_JAVACMD%"=="" set _JAVACMD=java
|
43
|
+
|
44
|
+
rem Detect if this java is ok to use.
|
45
|
+
for /F %%j in ('"%_JAVACMD%" -version 2^>^&1') do (
|
46
|
+
if %%~j==java set JAVAINSTALLED=1
|
47
|
+
if %%~j==openjdk set JAVAINSTALLED=1
|
48
|
+
)
|
49
|
+
|
50
|
+
rem BAT has no logical or, so we do it OLD SCHOOL! Oppan Redmond Style
|
51
|
+
set JAVAOK=true
|
52
|
+
if not defined JAVAINSTALLED set JAVAOK=false
|
53
|
+
|
54
|
+
if "%JAVAOK%"=="false" (
|
55
|
+
echo.
|
56
|
+
echo A Java JDK is not installed or can't be found.
|
57
|
+
if not "%JAVA_HOME%"=="" (
|
58
|
+
echo JAVA_HOME = "%JAVA_HOME%"
|
59
|
+
)
|
60
|
+
echo.
|
61
|
+
echo Please go to
|
62
|
+
echo http://www.oracle.com/technetwork/java/javase/downloads/index.html
|
63
|
+
echo and download a valid Java JDK and install before running umi.
|
64
|
+
echo.
|
65
|
+
echo If you think this message is in error, please check
|
66
|
+
echo your environment variables to see if "java.exe" and "javac.exe" are
|
67
|
+
echo available via JAVA_HOME or PATH.
|
68
|
+
echo.
|
69
|
+
if defined DOUBLECLICKED pause
|
70
|
+
exit /B 1
|
71
|
+
)
|
72
|
+
|
73
|
+
|
74
|
+
rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config.
|
75
|
+
set _JAVA_OPTS=%JAVA_OPTS%
|
76
|
+
if "!_JAVA_OPTS!"=="" set _JAVA_OPTS=!CFG_OPTS!
|
77
|
+
|
78
|
+
rem We keep in _JAVA_PARAMS all -J-prefixed and -D-prefixed arguments
|
79
|
+
rem "-J" is stripped, "-D" is left as is, and everything is appended to JAVA_OPTS
|
80
|
+
set _JAVA_PARAMS=
|
81
|
+
set _APP_ARGS=
|
82
|
+
|
83
|
+
set "APP_CLASSPATH=%APP_LIB_DIR%\com.icodici.umi-0.8.7.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
|
+
set "APP_MAIN_CLASS=com.icodici.farcallscala.Main"
|
85
|
+
set "SCRIPT_CONF_FILE=%APP_HOME%\conf\application.ini"
|
86
|
+
|
87
|
+
rem if configuration files exist, prepend their contents to the script arguments so it can be processed by this runner
|
88
|
+
call :parse_config "%SCRIPT_CONF_FILE%" SCRIPT_CONF_ARGS
|
89
|
+
|
90
|
+
call :process_args %SCRIPT_CONF_ARGS% %%*
|
91
|
+
|
92
|
+
set _JAVA_OPTS=!_JAVA_OPTS! !_JAVA_PARAMS!
|
93
|
+
|
94
|
+
if defined CUSTOM_MAIN_CLASS (
|
95
|
+
set MAIN_CLASS=!CUSTOM_MAIN_CLASS!
|
96
|
+
) else (
|
97
|
+
set MAIN_CLASS=!APP_MAIN_CLASS!
|
98
|
+
)
|
99
|
+
|
100
|
+
rem Call the application and pass all arguments unchanged.
|
101
|
+
"%_JAVACMD%" !_JAVA_OPTS! !UMI_OPTS! -cp "%APP_CLASSPATH%" %MAIN_CLASS% !_APP_ARGS!
|
102
|
+
|
103
|
+
@endlocal
|
104
|
+
|
105
|
+
exit /B %ERRORLEVEL%
|
106
|
+
|
107
|
+
|
108
|
+
rem Loads a configuration file full of default command line options for this script.
|
109
|
+
rem First argument is the path to the config file.
|
110
|
+
rem Second argument is the name of the environment variable to write to.
|
111
|
+
:parse_config
|
112
|
+
set _PARSE_FILE=%~1
|
113
|
+
set _PARSE_OUT=
|
114
|
+
if exist "%_PARSE_FILE%" (
|
115
|
+
FOR /F "tokens=* eol=# usebackq delims=" %%i IN ("%_PARSE_FILE%") DO (
|
116
|
+
set _PARSE_OUT=!_PARSE_OUT! %%i
|
117
|
+
)
|
118
|
+
)
|
119
|
+
set %2=!_PARSE_OUT!
|
120
|
+
exit /B 0
|
121
|
+
|
122
|
+
|
123
|
+
:add_java
|
124
|
+
set _JAVA_PARAMS=!_JAVA_PARAMS! %*
|
125
|
+
exit /B 0
|
126
|
+
|
127
|
+
|
128
|
+
:add_app
|
129
|
+
set _APP_ARGS=!_APP_ARGS! %*
|
130
|
+
exit /B 0
|
131
|
+
|
132
|
+
|
133
|
+
rem Processes incoming arguments and places them in appropriate global variables
|
134
|
+
:process_args
|
135
|
+
:param_loop
|
136
|
+
call set _PARAM1=%%1
|
137
|
+
set "_TEST_PARAM=%~1"
|
138
|
+
|
139
|
+
if ["!_PARAM1!"]==[""] goto param_afterloop
|
140
|
+
|
141
|
+
|
142
|
+
rem ignore arguments that do not start with '-'
|
143
|
+
if "%_TEST_PARAM:~0,1%"=="-" goto param_java_check
|
144
|
+
set _APP_ARGS=!_APP_ARGS! !_PARAM1!
|
145
|
+
shift
|
146
|
+
goto param_loop
|
147
|
+
|
148
|
+
:param_java_check
|
149
|
+
if "!_TEST_PARAM:~0,2!"=="-J" (
|
150
|
+
rem strip -J prefix
|
151
|
+
set _JAVA_PARAMS=!_JAVA_PARAMS! !_TEST_PARAM:~2!
|
152
|
+
shift
|
153
|
+
goto param_loop
|
154
|
+
)
|
155
|
+
|
156
|
+
if "!_TEST_PARAM:~0,2!"=="-D" (
|
157
|
+
rem test if this was double-quoted property "-Dprop=42"
|
158
|
+
for /F "delims== tokens=1,*" %%G in ("!_TEST_PARAM!") DO (
|
159
|
+
if not ["%%H"] == [""] (
|
160
|
+
set _JAVA_PARAMS=!_JAVA_PARAMS! !_PARAM1!
|
161
|
+
) else if [%2] neq [] (
|
162
|
+
rem it was a normal property: -Dprop=42 or -Drop="42"
|
163
|
+
call set _PARAM1=%%1=%%2
|
164
|
+
set _JAVA_PARAMS=!_JAVA_PARAMS! !_PARAM1!
|
165
|
+
shift
|
166
|
+
)
|
167
|
+
)
|
168
|
+
) else (
|
169
|
+
if "!_TEST_PARAM!"=="-main" (
|
170
|
+
call set CUSTOM_MAIN_CLASS=%%2
|
171
|
+
shift
|
172
|
+
) else (
|
173
|
+
set _APP_ARGS=!_APP_ARGS! !_PARAM1!
|
174
|
+
)
|
175
|
+
)
|
176
|
+
shift
|
177
|
+
goto param_loop
|
178
|
+
:param_afterloop
|
179
|
+
|
180
|
+
exit /B 0
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/exe/universa
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Universa
|
2
|
+
|
3
|
+
# Basic error reported by Universa library.
|
4
|
+
class Error < IOError
|
5
|
+
end
|
6
|
+
|
7
|
+
# references from different {UMI} instances are mixed together
|
8
|
+
class InterchangeError < Error
|
9
|
+
# create instance optionally overriding message
|
10
|
+
def initialize(text = "objects can't be interchanged between different UMI interfaces")
|
11
|
+
super(text)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Easy print stack trace refinement
|
16
|
+
refine Exception do
|
17
|
+
|
18
|
+
# syntax sugar: print exception class, message and stack trace (with line feeds) to
|
19
|
+
# the stderr.
|
20
|
+
def print_stack_trace
|
21
|
+
STDERR.puts "Error (#{self.class.name}): #{self}"
|
22
|
+
STDERR.puts self.backtrace.join("\n")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/universa/umi.rb
ADDED
@@ -0,0 +1,373 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'farcall'
|
3
|
+
require 'base64'
|
4
|
+
require 'weakref'
|
5
|
+
require_relative 'weak_reference'
|
6
|
+
|
7
|
+
using Universa
|
8
|
+
|
9
|
+
module Universa
|
10
|
+
|
11
|
+
# Universa Method Invocation remote interface.
|
12
|
+
#
|
13
|
+
# By default, it creates UMI interface to the included UMI server which gives almost full access
|
14
|
+
# to the Universa Java API:
|
15
|
+
#
|
16
|
+
# Uasge:
|
17
|
+
# >> umi = Universa::UMI.new()
|
18
|
+
# >> # create a new key and new contract with this key as creator:
|
19
|
+
# >> contract = umi.instantiate "Contract", umi.instantiate("PrivateKey", 2048)
|
20
|
+
#
|
21
|
+
# Use {#instantiate} to create new instances of remote classes, which return {Ref} instances,
|
22
|
+
# and just call their methods as if these are usual ruby methods. For example in the example above:
|
23
|
+
#
|
24
|
+
# address = contract.getKeysToSignWith()[0].getPublicKey().getShortAddress().toString()
|
25
|
+
#
|
26
|
+
# In the sample above all the methods are called on the remote side, returning links to remote objects
|
27
|
+
# which are all {Ref} instances, and the last `toString()` call return a string, which is converted to
|
28
|
+
# ruby string and saved into variable. This sentence, therefore, get the first signer key and transofrms it
|
29
|
+
# to the string short address.
|
30
|
+
#
|
31
|
+
# == Having several `UMI` interfaces.
|
32
|
+
#
|
33
|
+
# It is possible to have several UMI instances, by default, it will create separate process with isolated
|
34
|
+
# data space, which is perfectly safe to use in various scenarios.
|
35
|
+
#
|
36
|
+
# It still means the object from different interfaces can't be interchanged. {Ref} instances created
|
37
|
+
# by one interface should be used with this interface only, or the {InterchangeError} will be raised.
|
38
|
+
#
|
39
|
+
# == Remote exceptions
|
40
|
+
#
|
41
|
+
# If remote part will thow an Exception performing a method, it will be raised as an instance of
|
42
|
+
# {https://www.rubydoc.info/gems/farcall/Farcall/RemoteError Farcall::RemoteError} class which carries remote
|
43
|
+
# exception information.
|
44
|
+
#
|
45
|
+
# == Transport level
|
46
|
+
#
|
47
|
+
# UMI uses {https://github.com/sergeych/farcall/wiki Farcall} transport in woth JSON adapter and "\n" as separator.
|
48
|
+
#
|
49
|
+
class UMI
|
50
|
+
|
51
|
+
##
|
52
|
+
# Create UMI instance. It starts the private child process wit UMI server and securely connects to
|
53
|
+
# it so no other connection could occur.
|
54
|
+
#
|
55
|
+
# # create UNI interface
|
56
|
+
# umi = Universa::UMI.new()
|
57
|
+
# # create a new key and new contract with this key as creator:
|
58
|
+
# contract = umi.instantiate "Contract", umi.instantiate("PrivateKey", 2048)
|
59
|
+
# contract.seal() # binary packed string returned
|
60
|
+
# contract.check() #=> true
|
61
|
+
#
|
62
|
+
# @param [String] path to custom UMI server build. Use bundled one (leave as nil)
|
63
|
+
# @param [Regexp] version_check check version against
|
64
|
+
# @param [String] system expected on the remote side. 'UMI' us a universa umi server.
|
65
|
+
def initialize(path = nil, version_check: /./, system: "UMI", log: 'sessionlog.txt')
|
66
|
+
path ||= File.expand_path(File.split(__FILE__)[0] + "/../../bin/umi/bin/umi")
|
67
|
+
@in, @out, @err, @wtr = Open3.popen3("#{path} #{log ? "-log #{log}" : ''}")
|
68
|
+
@endpoint = Farcall::Endpoint.new(
|
69
|
+
Farcall::JsonTransport.create(delimiter: "\n", input: @out, output: @in)
|
70
|
+
)
|
71
|
+
@lock = Monitor.new
|
72
|
+
@cache = {}
|
73
|
+
@closed = false
|
74
|
+
@references = {}
|
75
|
+
start_cleanup_queue
|
76
|
+
@version = call("version")
|
77
|
+
raise Error, "Unsupported system: #{@version}" if @version.system != "UMI"
|
78
|
+
raise Error, "Unsupported version: #{@version}" if @version.version !~ /0\.8\.\d+/
|
79
|
+
rescue Errno::ENOENT
|
80
|
+
@err and STDERR.puts @err.read
|
81
|
+
raise Error, "missing java binaries"
|
82
|
+
end
|
83
|
+
|
84
|
+
def version
|
85
|
+
@version.version
|
86
|
+
end
|
87
|
+
|
88
|
+
# Create instance of some Universa Java API class, for example 'Contract', passing any arguments
|
89
|
+
# to its constructor. The returned reference could be used much like local instance, nu the actual
|
90
|
+
# work will happen in the child process. Use references as much as possible as they take all the
|
91
|
+
# housekeeping required, like memory leaks prevention and direct method calling.
|
92
|
+
#
|
93
|
+
# @return [Ref] reference to the remotely created object. See {Ref}.
|
94
|
+
def instantiate(object_class_name, *args)
|
95
|
+
ensure_open
|
96
|
+
create_reference call("instantiate", object_class_name, *prepare_args(args))
|
97
|
+
end
|
98
|
+
|
99
|
+
# Invoke method by name. Should not be used directly; use {Ref} instance to call its methods.
|
100
|
+
def invoke(ref, method, *args)
|
101
|
+
ensure_open
|
102
|
+
ref._umi == self or raise InterchangeError
|
103
|
+
result = call("invoke", ref._remote_id, method, *prepare_args(args))
|
104
|
+
encode_result result
|
105
|
+
rescue
|
106
|
+
$!.print_stack_trace
|
107
|
+
end
|
108
|
+
|
109
|
+
# Close child process. No remote calls should occur after it.
|
110
|
+
def close
|
111
|
+
@queue.push :poison_pill
|
112
|
+
@cleanup_thread.join
|
113
|
+
@closed = true
|
114
|
+
@endpoint.close
|
115
|
+
@in.close
|
116
|
+
@out.close
|
117
|
+
@wtr.value.exited?
|
118
|
+
end
|
119
|
+
|
120
|
+
# short data label for UMI interface
|
121
|
+
def inspect
|
122
|
+
"<UniMI:#{__id__}:#{version}>"
|
123
|
+
end
|
124
|
+
|
125
|
+
# debug use only. Looks for the cached e.g. (alive) remote object. Does not check
|
126
|
+
# the remote side.
|
127
|
+
def find_by_remote_id remote_id
|
128
|
+
@lock.synchronize {@cache[remote_id]&.get}
|
129
|
+
end
|
130
|
+
|
131
|
+
# Execute the block with trace mode on. Will spam the output with protocol information.
|
132
|
+
# These calls could be nested, on exit it restores previous trace state
|
133
|
+
def with_trace &block
|
134
|
+
current_state, @trace = @trace, true
|
135
|
+
block.call()
|
136
|
+
@trace = current_state
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
# create a finalizer that will drop remote object
|
142
|
+
def create_finalizer(remote_id)
|
143
|
+
-> (id) {
|
144
|
+
begin
|
145
|
+
@lock.synchronize {
|
146
|
+
@cache.delete(remote_id)
|
147
|
+
# log "=== removing remote ref #{id} -> #{remote_id}"
|
148
|
+
@queue.push(remote_id)
|
149
|
+
}
|
150
|
+
rescue ThreadError
|
151
|
+
# can't be called from trap contect - life is life ;)
|
152
|
+
# silently ignore
|
153
|
+
rescue
|
154
|
+
$!.print_stack_trace
|
155
|
+
end
|
156
|
+
}
|
157
|
+
end
|
158
|
+
|
159
|
+
# Create a reference correcting adapting remote types to ruby ecosystem, for example loads
|
160
|
+
# remote Java Set to a local ruby Set.
|
161
|
+
def create_reference reference_record
|
162
|
+
r = build_reference reference_record
|
163
|
+
case reference_record.className
|
164
|
+
when 'java.util.HashSet'
|
165
|
+
r.toArray()
|
166
|
+
else
|
167
|
+
r
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Create a reference from UMI remote object reference structure. Returns existing object if any. Takes care
|
172
|
+
# of dropping remote object when ruby object gets collected.
|
173
|
+
def build_reference reference_record
|
174
|
+
@lock.synchronize {
|
175
|
+
remote_id = reference_record.id
|
176
|
+
ref = @cache[remote_id]&.get
|
177
|
+
if !ref
|
178
|
+
# log "Creating new reference to remote #{remote_id}"
|
179
|
+
ref = Ref.new(self, reference_record)
|
180
|
+
ObjectSpace.define_finalizer(ref, create_finalizer(remote_id))
|
181
|
+
@cache[remote_id] = WeakReference.new(ref)
|
182
|
+
end
|
183
|
+
ref
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
# Start the remote object drop queue processing.
|
188
|
+
def start_cleanup_queue
|
189
|
+
return if @queue
|
190
|
+
@queue = Queue.new
|
191
|
+
@cleanup_thread = Thread.start {
|
192
|
+
while (!@closed)
|
193
|
+
id = @queue.pop()
|
194
|
+
if id == :poison_pill
|
195
|
+
# log "leaving cleanup queue"
|
196
|
+
break
|
197
|
+
else
|
198
|
+
begin
|
199
|
+
call("drop_objects", id)
|
200
|
+
# log "remote object dropped: #{id}"
|
201
|
+
rescue
|
202
|
+
$!.print_stack_trace
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
}
|
207
|
+
end
|
208
|
+
|
209
|
+
# convert ruby arguments array to corresponding UMI values
|
210
|
+
def prepare_args args
|
211
|
+
args.map {|x|
|
212
|
+
if x.respond_to?(:_as_umi_arg)
|
213
|
+
x._as_umi_arg(self)
|
214
|
+
else
|
215
|
+
case x
|
216
|
+
when String
|
217
|
+
x.encoding == Encoding::BINARY ? {__type: 'binary', base64: Base64.encode64(x)} : x
|
218
|
+
else
|
219
|
+
x
|
220
|
+
end
|
221
|
+
end
|
222
|
+
}
|
223
|
+
end
|
224
|
+
|
225
|
+
# Convert remote call result from UMI structures to ruby types
|
226
|
+
def encode_result value
|
227
|
+
case value
|
228
|
+
when Hashie::Mash
|
229
|
+
type = value.__type
|
230
|
+
case type
|
231
|
+
when 'RemoteObject';
|
232
|
+
create_reference value
|
233
|
+
when 'binary';
|
234
|
+
Base64.decode64(value.base64)
|
235
|
+
when 'unixtime';
|
236
|
+
Time.at(value.seconds)
|
237
|
+
else
|
238
|
+
value
|
239
|
+
end
|
240
|
+
when Hashie::Array
|
241
|
+
value.map {|x| encode_result x}
|
242
|
+
else
|
243
|
+
value
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# @raise Error if interface is closed
|
248
|
+
def ensure_open
|
249
|
+
raise Error, "UMI interface is closed" if @closed
|
250
|
+
end
|
251
|
+
|
252
|
+
EMPTY_KWARGS = {}
|
253
|
+
|
254
|
+
# perform UMI remote call
|
255
|
+
def call(command, *args)
|
256
|
+
log ">> #{command}(#{args})"
|
257
|
+
result = @endpoint.sync_call(command, *args, **EMPTY_KWARGS)
|
258
|
+
log "<< #{result}"
|
259
|
+
result
|
260
|
+
end
|
261
|
+
|
262
|
+
def log msg
|
263
|
+
@trace and puts "UNIMI #{msg}"
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# A reference to any Java-object that can call its methods like usual methods:
|
270
|
+
#
|
271
|
+
# key = umi.instantiate "PrivateKey", 2048 # this returns Ref
|
272
|
+
# address = key.getPublicKey().getShortAddress().toString()
|
273
|
+
#
|
274
|
+
# Notice that all methods called after +key+ are java methods of +PrivateKey+, +PublicKey+ and +KeyAddress+
|
275
|
+
# Java classes, whose references are created on-the-fly automatically (and will be reclaimed by GC on both
|
276
|
+
# ends soon).
|
277
|
+
#
|
278
|
+
# == Instances are uniqie
|
279
|
+
#
|
280
|
+
# What means, if some calls will return the same Java object instance, it will be returned as the same {Ref}
|
281
|
+
# instance.
|
282
|
+
#
|
283
|
+
# == Reference equality (== and !=)
|
284
|
+
#
|
285
|
+
# References are equal if they refer the same objects OR their are +equals+ - the java.equals() is called
|
286
|
+
# to compare different referenced objects. Therefore, to compare two references use:
|
287
|
+
#
|
288
|
+
# - `==`: returns true if referencs are to the same object or different objects that where left.equals(right)
|
289
|
+
# returns true.
|
290
|
+
# - `!=`: same as !(left == right)
|
291
|
+
# - `===`: thest that references refer to exactly same object instance. E.g. it is possible that
|
292
|
+
# `left == right && !()left === right) - different objects which `equals()`.
|
293
|
+
#
|
294
|
+
# Reference lifespan
|
295
|
+
#
|
296
|
+
# Each {Ref} has an allocated object in the remote side which is retained until explicetly freed by the proper
|
297
|
+
# UMI call. {Ref} class rakes care of it: when the ruby +Ref+ instance is garbage collected, its remote counterpart
|
298
|
+
# will shortly receive drop command preventing memory leakage.
|
299
|
+
#
|
300
|
+
# == Arguments
|
301
|
+
#
|
302
|
+
# you can use basic ruby objects as arguments: strings, numbers, arrays, hashes, and {Ref} instances too. Note
|
303
|
+
# that:
|
304
|
+
#
|
305
|
+
# - binary string (Encoding::Binary) are converted to byte[] iin Java side
|
306
|
+
# - utf8 strings are passed as strings.
|
307
|
+
#
|
308
|
+
# == Return value
|
309
|
+
#
|
310
|
+
# Will be deep-converted to corresponding ruby objects: hashes, arrays, sets, numbers, strings and {Ref} instances
|
311
|
+
# as need. It is, generally, inverse of converting arguments covered above.
|
312
|
+
#
|
313
|
+
class Ref
|
314
|
+
# Create new reference. Do not call it directly: the {UMI} instance will do it in a correct order.
|
315
|
+
# @param [UMI] umi instance to bind to
|
316
|
+
# @param [Hash] ref UMI reference structure
|
317
|
+
def initialize(umi, ref)
|
318
|
+
@umi, @ref = umi, ref
|
319
|
+
@id = ref.id
|
320
|
+
end
|
321
|
+
|
322
|
+
# @return [UMI] interface that this reference is bound to (and created by)
|
323
|
+
def _umi
|
324
|
+
@umi
|
325
|
+
end
|
326
|
+
|
327
|
+
# @return [Object] remote object id. Could be of any type actually.
|
328
|
+
def _remote_id
|
329
|
+
@id
|
330
|
+
end
|
331
|
+
|
332
|
+
# Internal use only. Allow processing remote commands as local calls
|
333
|
+
def respond_to_missing?(method_name, include_private = false)
|
334
|
+
method_name[0] == '_' ? super : true
|
335
|
+
end
|
336
|
+
|
337
|
+
#Internal use only. Call remote method as needed. This is where all the magick comes from: it call remote method instead of the
|
338
|
+
# local one, exactly like it is local.
|
339
|
+
def method_missing(method_name, *args, &block)
|
340
|
+
if method_name[0] == '_'
|
341
|
+
super
|
342
|
+
else
|
343
|
+
@umi.invoke self, method_name, *args
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
# Internal use only. This allow Ref instance to be an argument to the remote call. Convert it to proper UMI structure.
|
348
|
+
def _as_umi_arg(umi)
|
349
|
+
umi == @umi or raise InterchangeError
|
350
|
+
@ref
|
351
|
+
end
|
352
|
+
|
353
|
+
# short data label for instance
|
354
|
+
def inspect
|
355
|
+
"<UMI:Ref:#{@umi.__id__}:#{@ref.className}:#{@id})>"
|
356
|
+
end
|
357
|
+
|
358
|
+
# Checks that references are euqal: either both point to the same remote object or respective remote objects
|
359
|
+
# are reported equals by the remote +equals()+ call.
|
360
|
+
def ==(other)
|
361
|
+
other.is_a?(Ref) && other._umi == @umi &&
|
362
|
+
(other._remote_id == @id || other.equals(self))
|
363
|
+
end
|
364
|
+
|
365
|
+
# Equal references. Both point to the same remote object. Note that it should never happen with {UMI} class
|
366
|
+
# as it do cache non-recycled references and share them between calls.
|
367
|
+
def ===(other)
|
368
|
+
other.is_a?(Ref) && other._umi == @umi && other._remote_id == @id
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
end
|
data/lib/universa/version.rb
CHANGED
@@ -0,0 +1,60 @@
|
|
1
|
+
module Universa
|
2
|
+
|
3
|
+
# The smarter and safer weak reference than a standard one.
|
4
|
+
# It keeps object_id even if it is GC'd and can create a hard
|
5
|
+
# reference when possible. Some code borrowed from
|
6
|
+
# https://github.com/ruby-concurrency/ref.
|
7
|
+
#
|
8
|
+
# Note there is no +alive?+ method because it is not thread safe.
|
9
|
+
# Use the safe approach:
|
10
|
+
#
|
11
|
+
# weak = WeakReference.new(something)
|
12
|
+
# hard = weak.get
|
13
|
+
# if hard
|
14
|
+
# # we got safe reference in +hard+
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# or, scala/kotlin-style:
|
18
|
+
#
|
19
|
+
# weak.let { |object|
|
20
|
+
# object.do_somethinf
|
21
|
+
# }
|
22
|
+
#
|
23
|
+
class WeakReference
|
24
|
+
|
25
|
+
# ruby object it of the referenced object. Available also after object is recycled.
|
26
|
+
attr :referenced_object_id
|
27
|
+
|
28
|
+
# Create weak reference for a given object
|
29
|
+
def initialize(object)
|
30
|
+
@referenced_object_id = object.__id__
|
31
|
+
@weakref = WeakRef.new(object)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Call the block passing it hard ref to the object if it is not yet recycled
|
35
|
+
#
|
36
|
+
# @return what the block returned or nil
|
37
|
+
# @yield object if it is not recycled
|
38
|
+
def let
|
39
|
+
if (hardref = object.get)
|
40
|
+
yield hardref
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get the strong reference unless it is already reclaimed.
|
47
|
+
#
|
48
|
+
# @return [Object] har reference to the source object or nil
|
49
|
+
def get
|
50
|
+
@weakref.__getobj__
|
51
|
+
rescue => e
|
52
|
+
# Jruby implementation uses RefError while MRI uses WeakRef::RefError
|
53
|
+
if (defined?(RefError) && e.is_a?(RefError)) || (defined?(::WeakRef::RefError) && e.is_a?(::WeakRef::RefError))
|
54
|
+
nil
|
55
|
+
else
|
56
|
+
raise e
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/universa.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
require "universa/version"
|
2
|
+
require "universa/errors"
|
3
|
+
require "universa/umi"
|
2
4
|
|
5
|
+
# The Universa gem
|
6
|
+
#
|
7
|
+
# Currently, only direct access to the Java API is available:
|
8
|
+
#
|
9
|
+
# - class {UMI}. Use it to get direct access to the Java API
|
10
|
+
#
|
11
|
+
# Ruby-wrappers and tools are not yet available. Still direct access could be all you need at the time.
|
12
|
+
#
|
3
13
|
module Universa
|
4
|
-
# Your code goes here...
|
5
14
|
end
|
data/universa.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["real.sergeych@gmail.com"]
|
11
11
|
|
12
12
|
spec.summary = %q{Expose Universa Java API to ruby}
|
13
|
-
spec.description = %q{Uses
|
13
|
+
spec.description = %q{Uses UMI Universa client}
|
14
14
|
# spec.homepage = "TODO: Put your gem's website or public repo URL here."
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
@@ -30,6 +30,8 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
31
|
spec.require_paths = ["lib"]
|
32
32
|
|
33
|
+
spec.add_dependency "farcall", ">= 0.4.6"
|
34
|
+
|
33
35
|
spec.add_development_dependency "bundler", "~> 1.16"
|
34
36
|
spec.add_development_dependency "rake", "~> 10.0"
|
35
37
|
spec.add_development_dependency "rspec", "~> 3.8"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: universa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
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
|
+
date: 2018-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: farcall
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.4.6
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.4.6
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,7 +66,7 @@ dependencies:
|
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '3.8'
|
55
|
-
description: Uses
|
69
|
+
description: Uses UMI Universa client
|
56
70
|
email:
|
57
71
|
- real.sergeych@gmail.com
|
58
72
|
executables:
|
@@ -69,10 +83,38 @@ files:
|
|
69
83
|
- README.md
|
70
84
|
- Rakefile
|
71
85
|
- bin/console
|
86
|
+
- bin/refresh_umi
|
72
87
|
- bin/setup
|
88
|
+
- bin/umi/bin/umi
|
89
|
+
- bin/umi/bin/umi.bat
|
90
|
+
- bin/umi/lib/com.fasterxml.jackson.core.jackson-annotations-2.8.11.jar
|
91
|
+
- bin/umi/lib/com.fasterxml.jackson.core.jackson-core-2.8.11.jar
|
92
|
+
- bin/umi/lib/com.fasterxml.jackson.core.jackson-databind-2.8.11.1.jar
|
93
|
+
- bin/umi/lib/com.fasterxml.jackson.datatype.jackson-datatype-jdk8-2.8.11.jar
|
94
|
+
- bin/umi/lib/com.fasterxml.jackson.datatype.jackson-datatype-jsr310-2.8.11.jar
|
95
|
+
- bin/umi/lib/com.icodici.common_tools-3.8.3.jar
|
96
|
+
- bin/umi/lib/com.icodici.crypto-3.8.3.jar
|
97
|
+
- bin/umi/lib/com.icodici.nanohttpd-2.1.0.jar
|
98
|
+
- bin/umi/lib/com.icodici.umi-0.8.7.jar
|
99
|
+
- bin/umi/lib/com.icodici.universa_core-3.8.3.jar
|
100
|
+
- bin/umi/lib/com.madgag.spongycastle.core-1.58.0.0.jar
|
101
|
+
- bin/umi/lib/com.squareup.jnagmp.jnagmp-2.0.0.jar
|
102
|
+
- bin/umi/lib/com.typesafe.play.play-functional_2.12-2.6.10.jar
|
103
|
+
- bin/umi/lib/com.typesafe.play.play-json_2.12-2.6.10.jar
|
104
|
+
- bin/umi/lib/net.java.dev.jna.jna-4.5.1.jar
|
105
|
+
- bin/umi/lib/net.java.dev.jna.jna-platform-4.5.0.jar
|
106
|
+
- bin/umi/lib/net.sf.jopt-simple.jopt-simple-4.9.jar
|
107
|
+
- bin/umi/lib/org.scala-lang.scala-library-2.12.7.jar
|
108
|
+
- bin/umi/lib/org.scala-lang.scala-reflect-2.12.7.jar
|
109
|
+
- bin/umi/lib/org.scala-sbt.ipcsocket.ipcsocket-1.0.0.jar
|
110
|
+
- bin/umi/lib/org.typelevel.macro-compat_2.12-1.1.1.jar
|
111
|
+
- bin/umi/lib/org.yaml.snakeyaml-1.18.jar
|
73
112
|
- exe/universa
|
74
113
|
- lib/universa.rb
|
114
|
+
- lib/universa/errors.rb
|
115
|
+
- lib/universa/umi.rb
|
75
116
|
- lib/universa/version.rb
|
117
|
+
- lib/universa/weak_reference.rb
|
76
118
|
- universa.gemspec
|
77
119
|
homepage:
|
78
120
|
licenses:
|