universa 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|