Skip to content

Commit 6a9c966

Browse files
authored
Merge pull request #32 from davide-scola/0.x-add_grenache_request
[0.x] Request
2 parents 3fec502 + a16573b commit 6a9c966

6 files changed

Lines changed: 281 additions & 2 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ grenache-get
3737
grenache-put
3838
grenache-keygen
3939
grenache-lookup
40+
grenache-request
4041
grenache-announce
4142

4243
#

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* [Retreive items from the DHT](#retreive-items-from-the-dht)
2121
* [Lookup peers](#lookup-peers)
2222
* [Announce services](#announce-services)
23+
* [Query services](#query-services)
2324
* [Maintainers](#maintainers)
2425

2526

@@ -184,6 +185,55 @@ grenache-announce --help
184185
to retrieve the complete options list.
185186

186187

188+
## Query services
189+
190+
The `grenache-request` command sends a request to a service in the DHT. To query the [rest:ext:helpdesk:foo](https://github.com/bitfinexcom/bfx-ext-helpdesk-js) service, simply run something like this:
191+
192+
```bash
193+
grenache-request 'rest:ext:helpdesk:foo' 'getDepartments'
194+
```
195+
196+
Action arguments are optional and can be omitted altogether. However, to pass an argument to an action, use the `-a` switch or its long form `--arg`; to query the [rest:net:util](https://github.com/bitfinexcom/bfx-util-net-js) service in order to get information about IP _208.67.222.222_, simply run something like this:
197+
198+
```bash
199+
grenache-request -a '"208.67.222.222"' 'rest:util:net' 'getIpInfo'
200+
```
201+
202+
To send multiple arguments, simply repeat the `-a` switch or its long form `--arg` as many times as needed; arguments will be passed to the service action in the same order as they were supplied on the command line. To query the [rest:ext:gpg](https://github.com/bitfinexcom/bfx-ext-gpg-js) service in order to get a signature for the _hello_ message, simply run something like this:
203+
204+
```bash
205+
grenache-request -a '"68656c6c6f"' -a '{"userId":1}' 'rest:ext:gpg' 'getDigitalSignature'
206+
```
207+
208+
Arguments are treated as _JSON_-encoded text; sometimes, when dealing with plain strings, this can be somewhat cumbersome. In such cases, the `-s` switch or its long form `--string` can be used to pass a string as-is or `-n` or its long form `--numeric` when accepting an option that is intended to be treated as a numeric value.
209+
210+
Typically, the output is a _JSON_-encoded text. Sometimes, filtering this text can be useful; in such cases, output can be selected using the `-q` switch or its long form `--query`, as shown below:
211+
212+
```bash
213+
grenache-request -q 'map(select(.active_members > 3))' 'rest:ext:helpdesk:bar' 'getTeams'
214+
```
215+
216+
The query is passed as-is to [jq](https://jqlang.github.io/jq/) and will be applied directly to the third position of the response array; refer to the official [filter documentation](https://jqlang.github.io/jq/manual/#basic-filters) for more details on the syntax to be used. However, there are cases where a plain string written directly to the standard output is preferable rather than formatted as a _JSON_ string with quotes, perhaps when pipe the output to another command; in such cases, the `-r` switch or its long form `--raw` can be used, as shown below:
217+
218+
```bash
219+
grenache-request -q '.[1].timezone' -r -s '208.67.222.222' 'rest:util:net' 'getIpGeo'
220+
```
221+
222+
Under normal circumstances, workflow is to look up the service via [grenache-lookup](#lookup-peers) and then send the request to the worker. There might be cases, perhaps when dealing with a system without a running [grape](https://github.com/bitfinexcom/grenache-grape), where it would be useful to query a service without looking it up first; in such cases, the `-w` switch or its long form `--worker` can be used, as shown below:
223+
224+
```bash
225+
grenache-request -r -s '776f726c64' -a '{"userId":8}' -w '10.0.0.1:1337' 'rest:ext:gpg' 'getDigitalSignature'
226+
```
227+
228+
Those are the main options; see
229+
230+
```bash
231+
grenache-request --help
232+
```
233+
234+
to retrieve the complete options list.
235+
236+
187237
## Maintainers
188238

189239
Current maintainers:

configure.ac

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ dnl implied. See the License for the specific language governing permissions
1515
dnl and limitations under the License.
1616

1717
AC_PREREQ([2.69])
18-
AC_INIT([grenache-cli],[0.7.1],[davide@bitfinex.com])
18+
AC_INIT([grenache-cli],[0.8.0],[davide@bitfinex.com])
1919

20-
AC_SUBST([VERSION], [0.7.1])
20+
AC_SUBST([VERSION], [0.8.0])
2121
AC_SUBST([SB], [`$srcdir/shtool echo -n -e %B`])
2222
AC_SUBST([EB], [`$srcdir/shtool echo -n -e %b`])
2323

@@ -190,6 +190,7 @@ AC_CONFIG_FILES([ \
190190
src/grenache-get \
191191
src/grenache-keygen \
192192
src/grenache-lookup \
193+
src/grenache-request \
193194
src/grenache-announce \
194195
tests/Makefile \
195196
tests/sign-test-vector-1.sh \

doc/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ grenache-get.1 \
2121
grenache-put.1 \
2222
grenache-keygen.1 \
2323
grenache-lookup.1 \
24+
grenache-request.1 \
2425
grenache-announce.1
2526

2627
MAINTAINERCLEANFILES = \

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ grenache-put \
3131
grenache-get \
3232
grenache-keygen \
3333
grenache-lookup \
34+
grenache-request \
3435
grenache-announce
3536

3637
noinst_LTLIBRARIES = \

src/grenache-request.in

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
#!/bin/bash
2+
############################################################################
3+
# This file is part of Grenache Command Line Interface. #
4+
# #
5+
# Copyright (C) 2017-2025 Davide Scola <davide@bitfinex.com> #
6+
# #
7+
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
8+
# not use this file except in compliance with the License. You may obtain #
9+
# a copy of the License at #
10+
# #
11+
# http://www.apache.org/licenses/LICENSE-2.0 #
12+
# #
13+
# Unless required by applicable law or agreed to in writing, software #
14+
# distributed under the License is distributed on an "AS IS" BASIS, #
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or #
16+
# implied. See the License for the specific language governing permissions #
17+
# and limitations under the License. #
18+
############################################################################
19+
20+
readonly ME="${BASH_SOURCE[0]}"
21+
readonly WHOAMI="$(@READLINK@ -snf "${ME}")"
22+
readonly ARGV=$(@GETOPT@ -o 'a:cg:hn:p:q:rs:tVw:' --long 'arg:,color,grape:,help,numeric:,port:,query:,raw,string:,tls,version,worker:' -n "${ME##*/}" -- "$@") || exit 1
23+
24+
TLS=''
25+
COLOR=''
26+
EXIT_CODE=1
27+
REQUEST_ARGC=0
28+
RESPONSE_ARGV=()
29+
REQUEST_WORKER=''
30+
REQUEST_QUERY='.'
31+
RESPONSE_QUERY='.'
32+
REQUEST_ARGUMENTS='[]'
33+
LOOKUP_ARGV=(--random)
34+
REQUEST_ARGV=(--compact-output --monochrome-output)
35+
36+
37+
# Show program's help.
38+
function show_help {
39+
@CAT@ <<_EOF
40+
${ME##*/} sends a request to a service in the DHT
41+
42+
Usage: ${ME##*/} [OPTION]... SERVICE ACTION
43+
44+
Options:
45+
-a, --arg Add an argument, JSON encoded
46+
-c, --color Pretty print
47+
-g, --grape Set the Grape hostname
48+
-n, --numeric Add a numeric argument
49+
-p, --port Set the Grape port number
50+
-q, --query Filter response against query
51+
-r, --raw Print string output as-is
52+
-s, --string Add a string argument
53+
-t, --tls Enable TLS
54+
-w, --worker Don't lookup, use this worker
55+
56+
-h, --help Show help message
57+
-V, --version Show version information
58+
59+
The \`--arg', \`--numeric' and \`--string' options can be repeated several times
60+
to add multiple arguments, which will be passed in the same order as they were
61+
supplied on the command line.
62+
63+
Examples:
64+
${ME##*/} 'foo' 'bar' Call the bar action of the foo service
65+
${ME##*/} -n 1 'foo' 'bar' The same thing, but passing a numeric argument
66+
67+
Report bugs to <@PACKAGE_BUGREPORT@>.
68+
_EOF
69+
70+
exit 1
71+
}
72+
73+
# Show program's version.
74+
function show_version {
75+
@CAT@ <<_EOF
76+
${WHOAMI##*/} @PACKAGE_VERSION@
77+
78+
Copyright (C) 2017-2025 Davide Scola <@PACKAGE_BUGREPORT@>
79+
This is free software; see the source for copying conditions. There is
80+
NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
81+
PURPOSE.
82+
83+
Written by Davide Scola.
84+
_EOF
85+
86+
exit 1
87+
}
88+
89+
90+
while true; do
91+
case "$1" in
92+
-a | --arg )
93+
REQUEST_ARGV+=(--arg "a$((++REQUEST_ARGC))" "${2}")
94+
REQUEST_QUERY+=' += [ $a'"${REQUEST_ARGC}"' | fromjson ] | .'; shift 2
95+
;;
96+
-c | --color )
97+
COLOR='yes'; shift 1
98+
;;
99+
-g | --grape )
100+
[[ -z "${2}" ]] && {
101+
echo "${ME##*/}: error: empty Grape hostname." >&2
102+
exit 1
103+
}
104+
105+
LOOKUP_ARGV+=(--grape "${2}"); shift 2
106+
;;
107+
-h | --help )
108+
show_help; shift 1
109+
;;
110+
-n | --numeric )
111+
REQUEST_ARGV+=(--arg "n$((++REQUEST_ARGC))" "${2}")
112+
REQUEST_QUERY+=' += [ $n'"${REQUEST_ARGC}"' | tonumber ] | .'; shift 2
113+
;;
114+
-p | --port )
115+
[[ -z "${2}" ]] && {
116+
echo "${ME##*/}: error: empty Grape port." >&2
117+
exit 1
118+
}
119+
120+
LOOKUP_ARGV+=(--port "${2}"); shift 2
121+
;;
122+
-q | --query )
123+
[[ -z "${2}" ]] && {
124+
echo "${ME##*/}: error: empty response query." >&2
125+
exit 1
126+
}
127+
128+
RESPONSE_QUERY="${2}"; shift 2
129+
;;
130+
-r | --raw )
131+
RESPONSE_ARGV+=(--raw-output); shift 1
132+
;;
133+
-s | --string )
134+
REQUEST_ARGV+=(--arg "s$((++REQUEST_ARGC))" "${2}")
135+
REQUEST_QUERY+=' += [ $s'"${REQUEST_ARGC}"' | tostring ] | .'; shift 2
136+
;;
137+
-t | --tls )
138+
TLS='yes'; LOOKUP_ARGV+=(--tls); shift 1
139+
;;
140+
-V | --version )
141+
show_version; shift 1
142+
;;
143+
-w | --worker )
144+
[[ -z "${2}" ]] && {
145+
echo "${ME##*/}: error: empty worker address." >&2
146+
exit 1
147+
}
148+
149+
[[ "${2##*:}" =~ ^[0-9]+$ ]] || {
150+
echo "${ME##*/}: error: invalid worker port number." >&2
151+
exit 1
152+
}
153+
154+
[[ "$((${2##*:} & 0xFFFF))" -eq 0 ]] && {
155+
echo "${ME##*/}: error: worker port number must be greater than zero." >&2
156+
exit 1
157+
}
158+
159+
[[ "${2##*:}" -ne "$((${2##*:} & 0xFFFF))" ]] && {
160+
echo "${ME##*/}: error: worker port number too big." >&2
161+
exit 1
162+
}
163+
164+
REQUEST_WORKER="${2%:*}:$((${2##*:} & 0xFFFF))"; shift 2
165+
;;
166+
-- ) shift; break ;;
167+
* ) break ;;
168+
esac
169+
done
170+
171+
[[ -z "${COLOR}" ]] && {
172+
RESPONSE_ARGV+=(--compact-output --monochrome-output)
173+
}
174+
175+
[[ "${#}" -lt 2 ]] && {
176+
show_help
177+
}
178+
179+
[[ -f "${HOME}/.grenache-cli/grenache-cli.conf" ]] || {
180+
echo "${ME##*/}: error: you need to run \`grenache-keygen' first." >&2
181+
exit "${EXIT_CODE}"
182+
}
183+
184+
exec {stderr}>&2
185+
186+
[[ x"${GRENACHE_CLI_DEBUG:+set}" != xset ]] && {
187+
exec 2>/dev/null
188+
}
189+
190+
[[ "${REQUEST_ARGC}" -gt 0 ]] && {
191+
REQUEST_ARGUMENTS="$(@JQ@ "${REQUEST_ARGV[@]}" --from-file <(echo "${REQUEST_QUERY}") <<<"${REQUEST_ARGUMENTS}")"
192+
193+
[[ "${?}" -ne 0 ]] && {
194+
echo "${ME##*/}: error: provided arguments are invalid." >&"${stderr}"
195+
196+
exec {stderr}>&-
197+
exit "${EXIT_CODE}"
198+
}
199+
}
200+
201+
JSON="$(@CURL@ -qK "${HOME}/.grenache-cli/grenache-cli.conf" -A '@PACKAGE@/@PACKAGE_VERSION@' "http${TLS:+s}://${REQUEST_WORKER:-$(grenache-lookup "${LOOKUP_ARGV[@]}" "${1}")}" < <( \
202+
@JQ@ --null-input --compact-output --monochrome-output \
203+
--arg 'action' "${2}" \
204+
--arg 'service' "${1}" \
205+
--arg 'rid' "$(@UUIDGEN@)" \
206+
--arg 'args' "${REQUEST_ARGUMENTS}" \
207+
'[ $rid, $service, { "action": $action, "args": $args | fromjson } ]' \
208+
))"
209+
210+
[[ -z "${JSON}" ]] && {
211+
echo "${ME##*/}: error: service ${1} cannot be queried." >&"${stderr}"
212+
213+
exec {stderr}>&-
214+
exit "${EXIT_CODE}"
215+
}
216+
217+
@JQ@ --exit-status '.[1]' >/dev/null <<<"${JSON}" && {
218+
@JQ@ --raw-output '.[1]' <<<"${JSON}" >&"${stderr}"
219+
} || {
220+
EXIT_CODE=0
221+
@JQ@ "${RESPONSE_ARGV[@]}" --from-file <(printf '.[2] | %s' "${RESPONSE_QUERY}") <<<"${JSON}"
222+
}
223+
224+
exec {stderr}>&-
225+
exit "${EXIT_CODE}"

0 commit comments

Comments
 (0)