Files

124 lines
3.5 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
env_file="${1:-}"
if [[ -z "${env_file}" ]]; then
echo "Usage: $0 <env-file>"
exit 1
fi
if [[ ! -f "${env_file}" ]]; then
echo "Missing env file: ${env_file}"
exit 1
fi
set_kv() {
local key="$1"
local value="$2"
local esc
esc="${value//\\/\\\\}"
esc="${esc//&/\\&}"
esc="${esc//|/\\|}"
if grep -q "^${key}=" "${env_file}"; then
sed -i -E "s|^${key}=.*|${key}=${esc}|" "${env_file}"
else
echo "${key}=${value}" >> "${env_file}"
fi
}
get_kv() {
local key="$1"
local value
value="$(grep -E "^${key}=" "${env_file}" | tail -n1 | cut -d= -f2- || true)"
echo "${value}"
}
is_valid_port() {
local port="$1"
[[ "${port}" =~ ^[0-9]+$ ]] || return 1
(( port >= 1 && port <= 65535 ))
}
port_in_use() {
local port="$1"
if ! command -v ss >/dev/null 2>&1; then
# If we cannot inspect sockets, do not block startup. Keep current/default value.
return 1
fi
if ss -H -ltn 2>/dev/null | awk '{print $4}' | grep -E -q "(^|:|\\])${port}$"; then
return 0
fi
if ss -H -lun 2>/dev/null | awk '{print $5}' | grep -E -q "(^|:|\\])${port}$"; then
return 0
fi
return 1
}
port_set_is_free() {
local api_port="$1"
local gateway_port="$((api_port - 1))"
local p2p_port="$((api_port + 1))"
local qdn_port="$((api_port + 3))"
if ! is_valid_port "${api_port}" || ! is_valid_port "${gateway_port}" || ! is_valid_port "${p2p_port}" || ! is_valid_port "${qdn_port}"; then
return 1
fi
if port_in_use "${api_port}" || port_in_use "${gateway_port}" || port_in_use "${p2p_port}" || port_in_use "${qdn_port}"; then
return 1
fi
return 0
}
pick_api_port() {
local candidates=("$@")
local candidate
for candidate in "${candidates[@]}"; do
if port_set_is_free "${candidate}"; then
echo "${candidate}"
return 0
fi
done
return 1
}
# Preferred order requested for API:
# 12391, then 22391/32391/42391/52391, then 12291/22291/32291/42291/52291.
preferred_api=(
12391
22391 32391 42391 52391
12291 22291 32291 42291 52291
)
configured_api="$(get_kv "QORTAL_NODE_API_HOST_PORT")"
selected_api=""
# Respect explicit non-default API port overrides and keep P2P in sync as API+1.
if is_valid_port "${configured_api}" && [[ "${configured_api}" != "12391" ]]; then
selected_api="${configured_api}"
else
if selected_api="$(pick_api_port "${preferred_api[@]}")"; then
:
else
echo "Unable to find free Qortal Gateway/API/P2P/QDN port set in requested range/order." >&2
exit 1
fi
fi
selected_gateway="$((selected_api - 1))"
selected_p2p="$((selected_api + 1))"
selected_qdn="$((selected_api + 3))"
if ! is_valid_port "${selected_gateway}" || ! is_valid_port "${selected_p2p}" || ! is_valid_port "${selected_qdn}"; then
echo "Computed invalid Qortal Gateway/P2P/QDN port from API port ${selected_api}: Gateway=${selected_gateway}, P2P=${selected_p2p}, QDN=${selected_qdn}" >&2
exit 1
fi
set_kv "QORTAL_NODE_GATEWAY_HOST_PORT" "${selected_gateway}"
set_kv "QORTAL_NODE_API_HOST_PORT" "${selected_api}"
set_kv "QORTAL_NODE_P2P_HOST_PORT" "${selected_p2p}"
set_kv "QORTAL_NODE_QDN_HOST_PORT" "${selected_qdn}"
echo "Selected Qortal node host ports: Gateway=${selected_gateway}, API=${selected_api}, P2P=${selected_p2p}, QDN=${selected_qdn}"
if port_in_use "${selected_gateway}" || port_in_use "${selected_api}" || port_in_use "${selected_p2p}" || port_in_use "${selected_qdn}"; then
echo "Note: selected Gateway/API/P2P/QDN port appears in use; this may be expected if qortal_node is already running."
fi
exit 0