forked from EvergreenCrypto/docker-finance
bash: lib_fetch: prices: CLI: allow multiple APIs
- Fetch from all available price APIs within a single command * allows passing multiple CLI APIs to `api` argument * will now fetch from all available APIs if `api` is not given * will warn if API config block is missing or die of no APIs are found - Related refactoring
This commit is contained in:
@@ -63,7 +63,7 @@ function lib_fetch::__parse_args()
|
||||
|
||||
Asset values (see documentation):
|
||||
|
||||
price${global_arg_delim_2}<asset1,asset2,...>
|
||||
price${global_arg_delim_2}<asset1${global_arg_delim_3}asset2${global_arg_delim_3}...>
|
||||
|
||||
api${global_arg_delim_2}<mobula|coingecko>
|
||||
|
||||
@@ -277,12 +277,15 @@ function lib_fetch::__parse_args()
|
||||
|
||||
# Arg: api
|
||||
if [ ! -z "$_arg_api" ]; then
|
||||
if [[ ! "$_arg_api" =~ ^coingecko$|^mobula$ ]]; then
|
||||
lib_utils::die_usage "$_usage"
|
||||
fi
|
||||
declare -gr global_arg_api="$_arg_api"
|
||||
read -ra _read <<<"$_arg_api"
|
||||
for _arg in "${_read[@]}"; do
|
||||
if [[ ! "$_arg" =~ ^coingecko$|^mobula$ ]]; then
|
||||
lib_utils::die_usage "$_usage"
|
||||
fi
|
||||
done
|
||||
declare -gr global_arg_api=("${_read[@]}")
|
||||
else
|
||||
declare -gr global_arg_api="mobula"
|
||||
declare -gr global_arg_api=("coingecko" "mobula")
|
||||
fi
|
||||
|
||||
# Arg: account
|
||||
@@ -539,88 +542,13 @@ function lib_fetch::__fetch_account()
|
||||
fi
|
||||
}
|
||||
|
||||
function lib_fetch::__fetch_price()
|
||||
function lib_fetch::__parse_price()
|
||||
{
|
||||
#
|
||||
# Test configuration for supported members
|
||||
#
|
||||
local _master_prices="$1"
|
||||
lib_utils::print_debug "$_master_prices"
|
||||
|
||||
lib_fetch::__parse_yaml "get-value" "price.${global_arg_api}" &>/dev/null \
|
||||
|| lib_utils::die_fatal "'${global_arg_api}' is unavailable"
|
||||
|
||||
local -r _members=("key" "asset")
|
||||
for _member in "${_members[@]}"; do
|
||||
if _value=$(lib_fetch::__parse_yaml "get-value" "price.${global_arg_api}.${_member}"); then
|
||||
|
||||
if [[ "$_member" == "key" ]]; then
|
||||
local _api_key="$_value"
|
||||
[ -z "$_api_key" ] \
|
||||
&& lib_utils::print_warning "${global_arg_api} has empty ${_member}"
|
||||
fi
|
||||
|
||||
if [[ "$_member" == "asset" ]]; then
|
||||
[[ $(lib_fetch::__parse_yaml "get-type" "price.${global_arg_api}.${_member}") != "sequence" ]] \
|
||||
&& lib_utils::die_fatal "Invalid asset sequence!"
|
||||
fi
|
||||
else
|
||||
lib_utils::die_fatal "$_member is unavailable"
|
||||
fi
|
||||
done
|
||||
|
||||
#
|
||||
# Prepare given assets and filesystem layout
|
||||
#
|
||||
|
||||
# Get assets from configuration
|
||||
if [ -z "${global_arg_price[*]}" ]; then
|
||||
# Parse out each asset
|
||||
while read _line; do
|
||||
local _assets+=("$_line")
|
||||
done < <(lib_fetch::__parse_yaml "get-values" "price.${global_arg_api}.asset")
|
||||
else
|
||||
# Get assets from CLI
|
||||
local _assets=("${global_arg_price[*]}")
|
||||
fi
|
||||
|
||||
# Set base dir for price files (subdirs will be by year)
|
||||
local -r _prices_dir="${global_child_profile_flow}/prices"
|
||||
[ ! -d "$_prices_dir" ] && mkdir -p "$_prices_dir"
|
||||
|
||||
# Prices master file
|
||||
local -r _master_prices="${_prices_dir}/master.prices"
|
||||
|
||||
lib_utils::print_custom "\n"
|
||||
lib_utils::print_info \
|
||||
"Fetching prices in year '${global_arg_year}' for '${global_parent_profile}/${global_child_profile}' ..."
|
||||
lib_utils::print_custom "\n"
|
||||
|
||||
#
|
||||
# Execute fetch for master price file creation
|
||||
#
|
||||
|
||||
declare -x API_FETCH_YEAR="$global_arg_year"
|
||||
lib_utils::print_debug "$API_FETCH_YEAR"
|
||||
|
||||
declare -x API_PRICES_PATH="$_master_prices"
|
||||
lib_utils::print_debug "$API_PRICES_PATH"
|
||||
|
||||
declare -x API_PRICES_API="$global_arg_api"
|
||||
lib_utils::print_debug "$API_PRICES_API"
|
||||
|
||||
declare -x API_PRICES_KEY="$_api_key"
|
||||
lib_utils::print_debug "$API_PRICES_KEY"
|
||||
|
||||
declare -x API_PRICES_ASSETS="${_assets[*]}"
|
||||
lib_utils::print_debug "$API_PRICES_ASSETS"
|
||||
|
||||
lib_fetch::__fetch_exec "prices" "crypto"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
lib_utils::print_custom "\n"
|
||||
lib_utils::print_info "Fetching prices completed successfully!"
|
||||
else
|
||||
return $?
|
||||
fi
|
||||
# Parse master file into respective years
|
||||
[ ! -f "$_master_prices" ] && lib_utils::die_fatal "Master prices not found!"
|
||||
|
||||
#
|
||||
# Master prices line format:
|
||||
@@ -628,13 +556,11 @@ function lib_fetch::__fetch_price()
|
||||
# P 2023/01/01 USD 1
|
||||
#
|
||||
|
||||
lib_utils::print_normal "\n ─ Parsing master prices file ..."
|
||||
lib_utils::print_normal "\n ─ Parsing master prices file"
|
||||
|
||||
# Temporary storage
|
||||
local -r _tmp_dir="$(mktemp -d -p /tmp docker-finance_XXX)"
|
||||
|
||||
# Parse master file into respective years
|
||||
[ ! -f "$_master_prices" ] && lib_utils::die_fatal "Master prices not found!"
|
||||
local _tmp_dir
|
||||
_tmp_dir="$(mktemp -d -p /tmp docker-finance_XXX)"
|
||||
|
||||
lib_utils::print_custom " \e[32m│\e[0m\n"
|
||||
echo "$(<$_master_prices)" \
|
||||
@@ -648,7 +574,8 @@ function lib_fetch::__fetch_price()
|
||||
if [[ "$global_arg_year" == "all" || "$_year" == "$global_arg_year" ]]; then
|
||||
|
||||
# Prices year location
|
||||
local _sub_dir="${_prices_dir}/${_year}"
|
||||
local _sub_dir
|
||||
_sub_dir="$(dirname $_master_prices)/${_year}"
|
||||
[ ! -d "$_sub_dir" ] && mkdir -p "$_sub_dir"
|
||||
|
||||
# Prices year journal
|
||||
@@ -676,9 +603,119 @@ function lib_fetch::__fetch_price()
|
||||
lib_utils::print_debug "$_journal"
|
||||
sort -u -o "$_journal" "$_journal"
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
local _return=$?
|
||||
|
||||
# Cleanup
|
||||
[ -d "$_tmp_dir" ] && rm -fr "$_tmp_dir"
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
function lib_fetch::__fetch_price()
|
||||
{
|
||||
# Reconstruct global API arg into only available API(s)
|
||||
local _arg_api=()
|
||||
|
||||
#
|
||||
# Test configuration for supported members
|
||||
#
|
||||
|
||||
for _api in "${global_arg_api[@]}"; do
|
||||
|
||||
if ! lib_fetch::__parse_yaml "get-value" "price.${_api}" &>/dev/null; then
|
||||
lib_utils::print_warning "'${_api}' price API is not set"
|
||||
continue
|
||||
fi
|
||||
|
||||
local _members=("key" "asset")
|
||||
for _member in "${_members[@]}"; do
|
||||
if _value=$(lib_fetch::__parse_yaml "get-value" "price.${_api}.${_member}"); then
|
||||
|
||||
if [[ "$_member" == "key" ]]; then
|
||||
[ -z "$_value" ] \
|
||||
&& lib_utils::print_warning "${_api} has empty ${_member}"
|
||||
fi
|
||||
|
||||
if [[ "$_member" == "asset" ]]; then
|
||||
[[ $(lib_fetch::__parse_yaml "get-type" "price.${_api}.${_member}") != "sequence" ]] \
|
||||
&& lib_utils::die_fatal "Invalid asset sequence!"
|
||||
fi
|
||||
else
|
||||
lib_utils::die_fatal "'${_member}' is unavailable"
|
||||
fi
|
||||
done
|
||||
|
||||
# Available API(s)
|
||||
_arg_api+=("$_api")
|
||||
|
||||
done
|
||||
|
||||
[ ${#_arg_api[@]} -eq 0 ] && lib_utils::die_fatal "No price API has been set"
|
||||
|
||||
#
|
||||
# Prepare given assets and filesystem layout
|
||||
#
|
||||
|
||||
# Prices master file
|
||||
# NOTE: base dir of all price files (subdirs will be by year)
|
||||
local _master_prices="${global_child_profile_flow}/prices/master.prices"
|
||||
|
||||
for _api in "${_arg_api[@]}"; do
|
||||
|
||||
# Get API key from configuration
|
||||
local _key
|
||||
_key="$(lib_fetch::__parse_yaml "get-value" "price.${_api}.key")"
|
||||
|
||||
# Get assets from configuration
|
||||
if [ -z "${global_arg_price[*]}" ]; then
|
||||
# Parse out each asset
|
||||
while read _line; do
|
||||
local _assets+=("$_line")
|
||||
done < <(lib_fetch::__parse_yaml "get-values" "price.${_api}.asset")
|
||||
else
|
||||
# Get assets from CLI
|
||||
local _assets=("${global_arg_price[*]}")
|
||||
fi
|
||||
|
||||
lib_utils::print_custom "\n"
|
||||
lib_utils::print_info \
|
||||
"Fetching prices from '${_api}' since year '${global_arg_year}' for '${global_parent_profile}/${global_child_profile}' ..."
|
||||
lib_utils::print_custom "\n"
|
||||
|
||||
#
|
||||
# Execute fetch for master prices file creation
|
||||
#
|
||||
|
||||
declare -x API_FETCH_YEAR="$global_arg_year"
|
||||
lib_utils::print_debug "$API_FETCH_YEAR"
|
||||
|
||||
declare -x API_PRICES_PATH="$_master_prices"
|
||||
lib_utils::print_debug "$API_PRICES_PATH"
|
||||
|
||||
declare -x API_PRICES_API="$_api"
|
||||
lib_utils::print_debug "$API_PRICES_API"
|
||||
unset _api
|
||||
|
||||
declare -x API_PRICES_KEY="$_key"
|
||||
lib_utils::print_debug "$API_PRICES_KEY"
|
||||
unset _key
|
||||
|
||||
declare -x API_PRICES_ASSETS="${_assets[*]}"
|
||||
lib_utils::print_debug "$API_PRICES_ASSETS"
|
||||
unset _assets
|
||||
|
||||
lib_fetch::__fetch_exec "prices" "crypto" || return $?
|
||||
|
||||
#
|
||||
# Parse master prices file into final journal
|
||||
#
|
||||
|
||||
lib_fetch::__parse_price "$API_PRICES_PATH" || return $?
|
||||
|
||||
done
|
||||
|
||||
local -r _return=$?
|
||||
|
||||
if [ $_return -eq 0 ]; then
|
||||
@@ -688,8 +725,7 @@ function lib_fetch::__fetch_price()
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
[ -d "$_tmp_dir" ] && rm -fr "$_tmp_dir"
|
||||
[ -f "$_master_prices" ] && rm -f "$_master_prices"
|
||||
[ -f "$API_PRICES_PATH" ] && rm -f "$API_PRICES_PATH"
|
||||
|
||||
return $_return
|
||||
}
|
||||
@@ -714,12 +750,16 @@ function lib_fetch::__fetch_exec()
|
||||
[ -z "$_subtype" ] && lib_utils::die_fatal
|
||||
|
||||
local _dir="${DOCKER_FINANCE_CONTAINER_REPO}/src/finance/lib/internal/fetch"
|
||||
|
||||
local _ifs="$IFS"
|
||||
IFS=' '
|
||||
|
||||
# TODO: remove no-limit after internal fetching writes per-paginated instead of per-fetch
|
||||
local _php=("/usr/bin/php" "-d" "memory_limit=\"-1\"" "-d" "include_path=\"/usr/local/lib:${_dir}\"")
|
||||
lib_utils::print_debug "${_php[@]}"
|
||||
|
||||
IFS=' '
|
||||
lib_utils::print_debug "${_php[*]}"
|
||||
"${_php[@]}" "${_dir}/fetch.php" "$_type" "$_subtype"
|
||||
IFS="$_ifs"
|
||||
}
|
||||
|
||||
# vim: sw=2 sts=2 si ai et
|
||||
|
||||
Reference in New Issue
Block a user