Complete C# server cutover
This commit is contained in:
Regular → Executable
+47
-180
@@ -9,204 +9,71 @@ else
|
||||
fi
|
||||
cd -- "${SCRIPT_DIR}"
|
||||
|
||||
SERVER_DIR="${SCRIPT_DIR}"
|
||||
VENV_DIR="${SERVER_DIR}/.venv"
|
||||
REQUIREMENTS_FILE="${SERVER_DIR}/requirements-server.txt"
|
||||
REQUIREMENTS_HASH_FILE="${VENV_DIR}/.requirements-server.sha256"
|
||||
CONFIG_FILE="${SERVER_DIR}/commonwealth-server.json"
|
||||
ENTRY_POINT="${SERVER_DIR}/consumer_server_cli.py"
|
||||
|
||||
CONFIG_FILE="${SCRIPT_DIR}/commonwealth-server.json"
|
||||
UPDATE_DEPENDENCIES=0
|
||||
SERVER_ARGS=()
|
||||
ARGS=("$@")
|
||||
ARG_INDEX=0
|
||||
while [[ ${ARG_INDEX} -lt ${#ARGS[@]} ]]; do
|
||||
arg="${ARGS[${ARG_INDEX}]}"
|
||||
INDEX=0
|
||||
while [[ ${INDEX} -lt ${#ARGS[@]} ]]; do
|
||||
arg="${ARGS[${INDEX}]}"
|
||||
case "${arg}" in
|
||||
--update-dependencies)
|
||||
UPDATE_DEPENDENCIES=1
|
||||
;;
|
||||
--update-dependencies) UPDATE_DEPENDENCIES=1 ;;
|
||||
--config|-c)
|
||||
ARG_INDEX=$((ARG_INDEX + 1))
|
||||
if [[ ${ARG_INDEX} -ge ${#ARGS[@]} ]]; then
|
||||
echo "ERROR: ${arg} requires a config file path." >&2
|
||||
exit 1
|
||||
fi
|
||||
CONFIG_FILE="${ARGS[${ARG_INDEX}]}"
|
||||
;;
|
||||
--config=*)
|
||||
CONFIG_FILE="${arg#--config=}"
|
||||
;;
|
||||
--host|--port|-H|-p|--interactive|-i)
|
||||
SERVER_ARGS+=("${arg}")
|
||||
if [[ "${arg}" == "--host" || "${arg}" == "-H" || "${arg}" == "--port" || "${arg}" == "-p" ]]; then
|
||||
ARG_INDEX=$((ARG_INDEX + 1))
|
||||
if [[ ${ARG_INDEX} -ge ${#ARGS[@]} ]]; then
|
||||
echo "ERROR: ${arg} requires a value." >&2
|
||||
exit 1
|
||||
fi
|
||||
SERVER_ARGS+=("${ARGS[${ARG_INDEX}]}")
|
||||
fi
|
||||
;;
|
||||
--host=*|--port=*)
|
||||
SERVER_ARGS+=("${arg}")
|
||||
;;
|
||||
*.json)
|
||||
# File managers / "Open with" often pass the config path as $1.
|
||||
CONFIG_FILE="${arg}"
|
||||
;;
|
||||
-*)
|
||||
echo "ERROR: Unknown option: ${arg}" >&2
|
||||
echo "Supported: --update-dependencies, --config PATH, --host HOST, --port PORT, --interactive" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [[ -f "${arg}" ]]; then
|
||||
CONFIG_FILE="${arg}"
|
||||
else
|
||||
echo "ERROR: Unexpected argument: ${arg}" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
INDEX=$((INDEX + 1)); [[ ${INDEX} -lt ${#ARGS[@]} ]] || { echo "ERROR: ${arg} requires a path" >&2; exit 1; }
|
||||
CONFIG_FILE="${ARGS[${INDEX}]}" ;;
|
||||
--config=*) CONFIG_FILE="${arg#--config=}" ;;
|
||||
--host|--port|-H|-p)
|
||||
SERVER_ARGS+=("${arg}"); INDEX=$((INDEX + 1)); [[ ${INDEX} -lt ${#ARGS[@]} ]] || { echo "ERROR: ${arg} requires a value" >&2; exit 1; }
|
||||
SERVER_ARGS+=("${ARGS[${INDEX}]}") ;;
|
||||
--host=*|--port=*|--interactive|-i) SERVER_ARGS+=("${arg}") ;;
|
||||
*.json) CONFIG_FILE="${arg}" ;;
|
||||
-*) echo "ERROR: Unknown option: ${arg}" >&2; exit 1 ;;
|
||||
*) [[ -f "${arg}" ]] && CONFIG_FILE="${arg}" || { echo "ERROR: Unexpected argument: ${arg}" >&2; exit 1; } ;;
|
||||
esac
|
||||
ARG_INDEX=$((ARG_INDEX + 1))
|
||||
INDEX=$((INDEX + 1))
|
||||
done
|
||||
|
||||
echo
|
||||
echo "================================================================================"
|
||||
echo " Commonwealth Online Server - Start Script"
|
||||
echo "================================================================================"
|
||||
echo
|
||||
if [[ "${CONFIG_FILE}" != /* ]]; then CONFIG_FILE="${SCRIPT_DIR}/${CONFIG_FILE}"; fi
|
||||
CONFIG_FILE="$(cd -- "$(dirname -- "${CONFIG_FILE}")" && pwd)/$(basename -- "${CONFIG_FILE}")"
|
||||
|
||||
die() {
|
||||
echo "ERROR: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
detect_python() {
|
||||
local candidate
|
||||
for candidate in python3 python; do
|
||||
if command -v "${candidate}" >/dev/null 2>&1; then
|
||||
if "${candidate}" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)'; then
|
||||
echo "${candidate}"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
resolve_server() {
|
||||
local apphost="${SCRIPT_DIR}/CommonwealthOnline.Server"
|
||||
local dll="${SCRIPT_DIR}/CommonwealthOnline.Server.dll"
|
||||
local project="${SCRIPT_DIR}/CommonwealthOnline.Server.csproj"
|
||||
if [[ -f "${apphost}" ]]; then
|
||||
chmod +x "${apphost}" 2>/dev/null || true
|
||||
SERVER_CMD=("${apphost}")
|
||||
return 0
|
||||
fi
|
||||
if [[ -f "${dll}" ]] && command -v dotnet >/dev/null 2>&1; then
|
||||
SERVER_CMD=(dotnet "${dll}")
|
||||
return 0
|
||||
fi
|
||||
if [[ -f "${project}" ]] && command -v dotnet >/dev/null 2>&1; then
|
||||
SERVER_CMD=(dotnet run --project "${project}" -c Release --no-launch-profile --)
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ ! -f "${REQUIREMENTS_FILE}" ]]; then
|
||||
die "Missing requirements file: ${REQUIREMENTS_FILE}"
|
||||
if ! resolve_server; then
|
||||
echo "ERROR: CommonwealthOnline.Server is not published and the .NET 8 SDK/runtime is unavailable." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${ENTRY_POINT}" ]]; then
|
||||
die "Missing server entry point: ${ENTRY_POINT}"
|
||||
if [[ ${UPDATE_DEPENDENCIES} -eq 1 ]]; then
|
||||
command -v dotnet >/dev/null 2>&1 || { echo "ERROR: --update-dependencies requires the .NET SDK" >&2; exit 1; }
|
||||
dotnet restore "${SCRIPT_DIR}/CommonwealthOnline.Server.csproj"
|
||||
fi
|
||||
|
||||
if ! BASE_PYTHON="$(detect_python)"; then
|
||||
die "Python 3.9+ is required. Install python3 (and python3-venv on Debian/Ubuntu)."
|
||||
fi
|
||||
|
||||
echo "Using system interpreter: ${BASE_PYTHON} ($("${BASE_PYTHON}" --version 2>&1))"
|
||||
|
||||
if [[ ! -x "${VENV_DIR}/bin/python" ]]; then
|
||||
echo "Creating virtual environment at ${VENV_DIR}..."
|
||||
if ! "${BASE_PYTHON}" -m venv "${VENV_DIR}"; then
|
||||
die "Failed to create virtual environment. On Debian/Ubuntu install python3-venv."
|
||||
fi
|
||||
fi
|
||||
|
||||
VENV_PYTHON="${VENV_DIR}/bin/python"
|
||||
if [[ ! -x "${VENV_PYTHON}" ]]; then
|
||||
die "Virtual environment interpreter missing: ${VENV_PYTHON}"
|
||||
fi
|
||||
|
||||
if ! "${VENV_PYTHON}" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)'; then
|
||||
die "Virtual environment Python is older than 3.9."
|
||||
fi
|
||||
|
||||
hash_requirements() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum -- "${REQUIREMENTS_FILE}" | awk '{print $1}'
|
||||
else
|
||||
"${VENV_PYTHON}" - <<'PY'
|
||||
from hashlib import sha256
|
||||
from pathlib import Path
|
||||
print(sha256(Path("requirements-server.txt").read_bytes()).hexdigest())
|
||||
PY
|
||||
fi
|
||||
}
|
||||
|
||||
CURRENT_HASH="$(hash_requirements)"
|
||||
STORED_HASH=""
|
||||
if [[ -f "${REQUIREMENTS_HASH_FILE}" ]]; then
|
||||
STORED_HASH="$(tr -d '[:space:]' < "${REQUIREMENTS_HASH_FILE}")"
|
||||
fi
|
||||
|
||||
NEED_INSTALL=0
|
||||
if [[ ! -f "${REQUIREMENTS_HASH_FILE}" ]]; then
|
||||
NEED_INSTALL=1
|
||||
elif [[ "${CURRENT_HASH}" != "${STORED_HASH}" ]]; then
|
||||
NEED_INSTALL=1
|
||||
elif [[ "${UPDATE_DEPENDENCIES}" -eq 1 ]]; then
|
||||
NEED_INSTALL=1
|
||||
fi
|
||||
|
||||
if [[ "${NEED_INSTALL}" -eq 1 ]]; then
|
||||
echo "Installing dedicated-server dependencies into .venv..."
|
||||
if ! "${VENV_PYTHON}" -m pip install --upgrade pip >/dev/null 2>&1; then
|
||||
echo "WARNING: Could not upgrade pip quietly; continuing with existing pip."
|
||||
fi
|
||||
if ! "${VENV_PYTHON}" -m pip install -r "${REQUIREMENTS_FILE}"; then
|
||||
die "Failed to install dependencies from ${REQUIREMENTS_FILE}."
|
||||
fi
|
||||
printf '%s\n' "${CURRENT_HASH}" > "${REQUIREMENTS_HASH_FILE}"
|
||||
echo "Dependencies installed."
|
||||
else
|
||||
echo "Dependencies are up to date."
|
||||
fi
|
||||
echo
|
||||
|
||||
if [[ ! -f "${CONFIG_FILE}" ]]; then
|
||||
echo "Generating default configuration file..."
|
||||
if ! "${VENV_PYTHON}" -u "${ENTRY_POINT}" config init "${CONFIG_FILE}"; then
|
||||
die "Failed to generate config file."
|
||||
fi
|
||||
echo
|
||||
echo "Generating default configuration: ${CONFIG_FILE}"
|
||||
"${SERVER_CMD[@]}" config init "${CONFIG_FILE}"
|
||||
fi
|
||||
|
||||
INTERACTIVE_ARGS=()
|
||||
if [[ -t 0 && -t 1 ]]; then
|
||||
INTERACTIVE_ARGS+=(--interactive)
|
||||
echo "Starting Commonwealth Online Server (interactive)..."
|
||||
echo "Type help for commands. Type quit or press Ctrl+C to stop."
|
||||
else
|
||||
echo "Starting Commonwealth Online Server (non-interactive)..."
|
||||
echo "Manage the server with: ${VENV_PYTHON} -u consumer_server_cli.py status"
|
||||
if [[ -t 0 && -t 1 ]] && [[ ! " ${SERVER_ARGS[*]} " =~ " --interactive " ]] && [[ ! " ${SERVER_ARGS[*]} " =~ " -i " ]]; then
|
||||
SERVER_ARGS+=(--interactive)
|
||||
fi
|
||||
echo
|
||||
|
||||
# Resolve config to an absolute path after cd'ing into the server directory.
|
||||
if [[ "${CONFIG_FILE}" != /* ]]; then
|
||||
CONFIG_FILE="${SERVER_DIR}/${CONFIG_FILE}"
|
||||
fi
|
||||
CONFIG_FILE="$(cd -- "$(dirname -- "${CONFIG_FILE}")" && pwd)/$(basename -- "${CONFIG_FILE}")"
|
||||
|
||||
# Do not source .venv/bin/activate — invoke the venv interpreter directly.
|
||||
# Always pass --config explicitly so a bare path is never a positional serve arg.
|
||||
CMD=(
|
||||
"${VENV_PYTHON}"
|
||||
-u
|
||||
"${ENTRY_POINT}"
|
||||
serve
|
||||
--config
|
||||
"${CONFIG_FILE}"
|
||||
)
|
||||
if [[ ${#INTERACTIVE_ARGS[@]} -gt 0 ]]; then
|
||||
CMD+=("${INTERACTIVE_ARGS[@]}")
|
||||
fi
|
||||
if [[ ${#SERVER_ARGS[@]} -gt 0 ]]; then
|
||||
CMD+=("${SERVER_ARGS[@]}")
|
||||
fi
|
||||
exec "${CMD[@]}"
|
||||
echo "Starting Commonwealth Online C# server"
|
||||
exec "${SERVER_CMD[@]}" serve --config "${CONFIG_FILE}" "${SERVER_ARGS[@]}"
|
||||
|
||||
Reference in New Issue
Block a user