124 lines
3.5 KiB
Bash
Executable File
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
|