diff --git a/.gitignore b/.gitignore index e65eb08..bce5b5c 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ grenache-get grenache-put grenache-keygen grenache-lookup +grenache-announce # # Distribution diff --git a/README.md b/README.md index aa97a4b..699a9b3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ # Grenache CLI -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +![license](https://img.shields.io/github/license/bitfinexcom/grenache-cli.svg) +![GitHub (pre-)release](https://img.shields.io/github/release/bitfinexcom/grenache-cli/all.svg) +![GitHub (Pre-)Release Date](https://img.shields.io/github/release-date-pre/bitfinexcom/grenache-cli.svg) +![GitHub last commit](https://img.shields.io/github/last-commit/bitfinexcom/grenache-cli.svg) +![GitHub pull requests](https://img.shields.io/github/issues-pr/bitfinexcom/grenache-cli.svg) +![stability-wip](https://img.shields.io/badge/stability-work_in_progress-lightgrey.svg) + + * [Introduction](#introduction) * [Prerequisites](#prerequisites) @@ -17,7 +24,7 @@ ## Introduction -The **Grenache** **C**ommand **L**ine **I**nterface is a set of tools to use the [grenache-grape](https://github.com/bitfinexcom/grenache-grape) suite directly from your command line. Using this set of tools you can create fancy scripts that communicate directly with the DHT. +The [**Grenache**](https://github.com/bitfinexcom/grenache) **C**ommand **L**ine **I**nterface is a set of tools to use the [grenache-grape](https://github.com/bitfinexcom/grenache-grape) suite directly from your command line. Using this set of tools you can create fancy scripts that communicate directly with the DHT. ## Prerequisites @@ -135,7 +142,38 @@ to retrieve the complete options list. ## Announce services -Coming soon... +The `grenache-announce` command announces the given services in order to be stored in the DHT. To announce the [rest:net:util](https://github.com/bitfinexcom/bfx-util-net-js) service on port _31337_, simply run something like this: + +```bash +grenache-announce 'rest:net:util,31337' +``` + +If no services are specified, `grenache-announce` enters the _streaming_ mode, reading the standard input. All comments (marked by a **#** or **;**) and blank lines are ignored. For example, a list of services can be announced using something like this: + +```bash +grenache-announce /run/grape/announce +``` + +Storing a service in the DHT now simply requires something like this: + +```bash +echo 'rest:net:util,31337' >/run/grape/announce +``` + +A JSON stream can also be required (perhaps to implement a network service with something like [tcpserver](https://cr.yp.to/ucspi-tcp/tcpserver.html)) using the `-j` switch or its long form `--json`. The JSON document must contain a `data` array in which the _first position_ is the service name while the _second_ is the port number. Another useful option is `-d` or `--delimiter` which allows you to set the delimiter string between the _service name_ and _port number_ when not using JSON mode. See + +```bash +grenache-announce --help +``` + +to retrieve the complete options list. ## Maintainers diff --git a/configure.ac b/configure.ac index 8e6b48e..2d8c12e 100644 --- a/configure.ac +++ b/configure.ac @@ -15,9 +15,9 @@ dnl implied. See the License for the specific language governing permissions dnl and limitations under the License. AC_PREREQ(2.69) -AC_INIT([grenache-cli], [0.5.0], [davide@bitfinex.com]) +AC_INIT([grenache-cli], [0.6.0], [davide@bitfinex.com]) -AC_SUBST([VERSION], [0.5.0]) +AC_SUBST([VERSION], [0.6.0]) AC_SUBST([SB], [`$srcdir/shtool echo -n -e %B`]) AC_SUBST([EB], [`$srcdir/shtool echo -n -e %b`]) @@ -151,7 +151,7 @@ AC_MSG_CHECKING([whether you want to enable the x86 features check]) if test "x${ax_cv_enable_x86_features}" = 'xyes'; then AC_MSG_RESULT([yes]) - case "${target}" in + case "${host}" in i?86-* | amd64-* | x86_64-*) AX_CHECK_X86_FEATURES ;; @@ -187,6 +187,7 @@ AC_CONFIG_FILES([ \ src/grenache-get \ src/grenache-keygen \ src/grenache-lookup \ + src/grenache-announce \ tests/Makefile \ tests/sign-test-vector-1.sh \ tests/sign-test-vector-2.sh \ diff --git a/src/Makefile.am b/src/Makefile.am index 56b5201..31bc212 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,7 +30,8 @@ bin_SCRIPTS = \ grenache-put \ grenache-get \ grenache-keygen \ -grenache-lookup +grenache-lookup \ +grenache-announce noinst_LTLIBRARIES = \ libed25519.la \ diff --git a/src/grenache-announce.in b/src/grenache-announce.in new file mode 100644 index 0000000..f767996 --- /dev/null +++ b/src/grenache-announce.in @@ -0,0 +1,182 @@ +#!/bin/bash +############################################################################ +# This file is part of Grenache Command Line Interface. # +# # +# Copyright (C) 2017, 2018 Davide Scola # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # +# implied. See the License for the specific language governing permissions # +# and limitations under the License. # +############################################################################ + +readonly ME="${BASH_SOURCE[0]}" +readonly WHOAMI="$(@READLINK@ -snf "${ME}")" +readonly ARGV=$(@GETOPT@ -o 'd:g:hjp:tV' --long 'delimiter:,grape:,help,json,port:,tls,version' -n "${ME##*/}" -- "$@") || exit 1 + +TLS='' +PORT=30002 +JQ_QUERY='' +EXIT_CODE=1 +DELIMITER=',' +HOSTNAME='127.0.0.1' +JQ_ARGV=(--unbuffered -r) + + +# Show program's help. +function show_help { + @CAT@ <<_EOF +Usage: + ${ME##*/} [OPTIONS] ... -- announce a service on the DHT. + + Options: + + -d, --delimiter Set the service/port delimiter + -g, --grape Set the Grape hostname + -j, --json Use JSON as data serializer + -p, --port Set the Grape port number + -t, --tls Enable TLS + + -h, --help Show this message + -V, --version Show version information + + The order of the specified options is not relevant. +_EOF + + exit 1 +} + +# Show program's version. +function show_version { + @CAT@ <<_EOF +${WHOAMI##*/} (@host_cpu@-@host_os@) @PACKAGE_NAME@/@PACKAGE_VERSION@ +Copyright (C) 2017, 2018 Davide Scola <@PACKAGE_BUGREPORT@> +This is free software; see the source for copying conditions. There is +NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. + +_EOF + + exit 1 +} + + +while true; do + case "$1" in + -d | --delimiter ) + [[ -z "${2}" ]] && { + echo "${ME##*/}: error: empty delimiter." >&2 + exit 1 + } + + DELIMITER="${2}"; shift 2 + ;; + -g | --grape ) + [[ -z "${2}" ]] && { + echo "${ME##*/}: error: empty Grape hostname." >&2 + exit 1 + } + + HOSTNAME="${2}"; shift 2 + ;; + -h | --help ) + show_help; shift 1 + ;; + -j | --json ) + JQ_QUERY='select(.data) | (.data[0] + "\t" + (.data[1] | tostring))'; shift 1 + ;; + -p | --port ) + [[ "${2}" =~ ^[0-9]+$ ]] || { + echo "${ME##*/}: error: invalid Grape port number." >&2 + exit 1 + } + + [[ "$((${2} & 0xFFFF))" -eq 0 ]] && { + echo "${ME##*/}: error: Grape port number must be greater than zero." >&2 + exit 1 + } + + [[ "${2}" -ne "$((${2} & 0xFFFF))" ]] && { + echo "${ME##*/}: error: Grape port number too big." >&2 + exit 1 + } + + PORT="$((${2} & 0xFFFF))"; shift 2 + ;; + -t | --tls ) + TLS='yes'; shift 1 + ;; + -V | --version ) + show_version; shift 1 + ;; + -- ) shift; break ;; + * ) break ;; + esac +done + + +[[ -f "${HOME}/.grenache-cli/grenache-cli.conf" ]] || { + echo "${ME##*/}: error: you need to run \`grenache-keygen' first." >&2 + exit 1 +} + +exec {stderr}>&2 + +[[ x"${GRENACHE_CLI_DEBUG:+set}" != xset ]] && { + exec 2>/dev/null +} + +[[ -z "${JQ_QUERY}" ]] && { + JQ_ARGV+=(-R) + JQ_QUERY="$(printf 'split("%s") | (.[0] + "\t" + .[1])' "${DELIMITER}")" +} + +while read service port +do + [[ -n "${service}" ]] || { + echo "${ME##*/}: warning: empty service name, skipping." >&"${stderr}" + continue + } + + [[ "$((${port} & 0xFFFF))" -gt 0 && "${port}" -eq "$((${port} & 0xFFFF))" ]] || { + echo "${ME##*/}: warning: invalid port number, skipping." >&"${stderr}" + continue + } + + NODES="$(@JQ@ -r '.' < <( + @CURL@ -qK "${HOME}/.grenache-cli/grenache-cli.conf" -A '@PACKAGE@/@PACKAGE_VERSION@' "http${TLS:+s}://${HOSTNAME}:${PORT}/announce" < <( \ + @JQ@ -cnM \ + --arg 'port' "${port}" \ + --arg 'service' "${service}" \ + --arg 'rid' "$(@UUIDGEN@)" \ + '{ "data": [$service, ($port | tonumber)], "rid": $rid }' \ + ) \ + ))" + + [[ "${NODES}" =~ ^[0-9]+$ ]] || { + echo "${ME##*/}: warning: unable to announce service ${service}: ${NODES}." >&"${stderr}" + continue + } + + [[ "${NODES}" -gt 0 ]] && { \ + EXIT_CODE=0 + } || { \ + echo "${ME##*/}: warning: service ${service} has not been indexed." >&"${stderr}" + } +done < <( + @JQ@ "${JQ_ARGV[@]}" "${JQ_QUERY}" < <( \ + [[ "${#}" -eq 0 ]] \ + && @SED@ -u 's/\s*[#;].*$//;/^\s*$/d' - \ + || printf '%s\n' "${@}" + ) +) + +exec {stderr}>&- +exit "${EXIT_CODE}" diff --git a/src/grenache-get.in b/src/grenache-get.in index 794a99d..b97bf68 100644 --- a/src/grenache-get.in +++ b/src/grenache-get.in @@ -56,7 +56,7 @@ _EOF # Show program's version. function show_version { @CAT@ <<_EOF -@PACKAGE_NAME@ (@host_cpu@-@host_os@) @PACKAGE_VERSION@ +${WHOAMI##*/} (@host_cpu@-@host_os@) @PACKAGE_NAME@/@PACKAGE_VERSION@ Copyright (C) 2017, 2018 Davide Scola <@PACKAGE_BUGREPORT@> This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR diff --git a/src/grenache-keygen.in b/src/grenache-keygen.in index 46a2f85..6761827 100644 --- a/src/grenache-keygen.in +++ b/src/grenache-keygen.in @@ -46,7 +46,7 @@ _EOF # Show program's version. function show_version { @CAT@ <<_EOF -@PACKAGE_NAME@ (@host_cpu@-@host_os@) @PACKAGE_VERSION@ +${WHOAMI##*/} (@host_cpu@-@host_os@) @PACKAGE_NAME@/@PACKAGE_VERSION@ Copyright (C) 2017, 2018 Davide Scola <@PACKAGE_BUGREPORT@> This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR diff --git a/src/grenache-lookup.in b/src/grenache-lookup.in index 8116ad0..f82e5cc 100644 --- a/src/grenache-lookup.in +++ b/src/grenache-lookup.in @@ -61,7 +61,7 @@ _EOF # Show program's version. function show_version { @CAT@ <<_EOF -@PACKAGE_NAME@ (@host_cpu@-@host_os@) @PACKAGE_VERSION@ +${WHOAMI##*/} (@host_cpu@-@host_os@) @PACKAGE_NAME@/@PACKAGE_VERSION@ Copyright (C) 2017, 2018 Davide Scola <@PACKAGE_BUGREPORT@> This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR diff --git a/src/grenache-put.in b/src/grenache-put.in index ad2348b..e11bf5b 100644 --- a/src/grenache-put.in +++ b/src/grenache-put.in @@ -58,7 +58,7 @@ _EOF # Show program's version. function show_version { @CAT@ <<_EOF -@PACKAGE_NAME@ (@host_cpu@-@host_os@) @PACKAGE_VERSION@ +${WHOAMI##*/} (@host_cpu@-@host_os@) @PACKAGE_NAME@/@PACKAGE_VERSION@ Copyright (C) 2017, 2018 Davide Scola <@PACKAGE_BUGREPORT@> This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR