From be22de56ca856b0868c6e6ff57d668310a0ab2a2 Mon Sep 17 00:00:00 2001 From: mohammad Date: Thu, 12 Mar 2026 00:39:53 +0300 Subject: [PATCH] logging and containerization setup --- README.md | 42 ++++++++++ dev | 177 +++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 58 +++++++++++++ docker/Dockerfile | 14 ++++ docker/couchbase-init.sh | 35 ++++++++ 5 files changed, 326 insertions(+) create mode 100755 dev create mode 100644 docker-compose.yml create mode 100644 docker/Dockerfile create mode 100755 docker/couchbase-init.sh diff --git a/README.md b/README.md index a0e59c9..a5511f1 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,48 @@ behavior while enabling modernization behind compatibility boundaries. - Prefer a single entrypoint script or container orchestration for local dev. - Add small smoke tests to validate service health and database connectivity. +## Local Dev (C Services) + +If Couchbase is running on `localhost:8091` with bucket `hbs` (password `aci`), +use the repo-local entrypoint to build and run the core servers: + +```sh +./dev build +./dev start +./dev logs +``` + +Override targets via env vars: + +```sh +HM_GAMESERVER_IP=127.0.0.1 HM_GAMESERVER_PORT=3724 ./dev start +``` + +Stop with: + +```sh +./dev stop +``` + +For the full Ubuntu install flow (Couchbase + web + client), use +`hearthmod/host_ctl_ubuntu.sh`. + +## Docker Dev + +Docker runs Couchbase plus the C servers. Start with: + +```sh +./dev docker-build +./dev docker-start +./dev docker-logs +``` + +Stop with: + +```sh +./dev docker-stop +``` + ## Protocol Notes See `PROTOCOL-NOTES.md` for the current opcode decoder map and client-derived diff --git a/dev b/dev new file mode 100755 index 0000000..b3aa136 --- /dev/null +++ b/dev @@ -0,0 +1,177 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) + +LOG_DIR=${HM_LOG_DIR:-"$ROOT_DIR/hm_log"} +GAMESERVER_IP=${HM_GAMESERVER_IP:-"127.0.0.1"} +GAMESERVER_PORT=${HM_GAMESERVER_PORT:-"3724"} + +GAMESERVER_BIN="$ROOT_DIR/hm_gameserver/hm_gameserver" +LOBBYSERVER_BIN="$ROOT_DIR/hm_lobbyserver/hm_lobbyserver" + +GAMESERVER_PID="$LOG_DIR/hm_gameserver.pid" +LOBBYSERVER_PID="$LOG_DIR/hm_lobbyserver.pid" + +usage() { + cat < + +Commands: + build Build gameserver and lobbyserver + start Start gameserver and lobbyserver + stop Stop running servers + status Show server status + logs Tail server logs + docker-build Build docker images + docker-start Start dockerized stack + docker-stop Stop dockerized stack + docker-status Show docker stack status + docker-logs Tail dockerized logs + +Environment: + HM_LOG_DIR Log directory (default: ./hm_log) + HM_GAMESERVER_IP Lobby points to this IP (default: 127.0.0.1) + HM_GAMESERVER_PORT Lobby points to this port (default: 3724) + HM_SKIP_COUCHBASE_CHECK=1 Skip Couchbase availability check +EOF +} + +docker_compose() { + if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then + docker compose "$@" + return + fi + + if command -v docker-compose >/dev/null 2>&1; then + docker-compose "$@" + return + fi + + echo "docker compose not found" >&2 + exit 1 +} + +require_bin() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "Missing required binary: $1" >&2 + exit 1 + fi +} + +check_couchbase() { + if [ "${HM_SKIP_COUCHBASE_CHECK:-}" = "1" ]; then + return 0 + fi + + if command -v curl >/dev/null 2>&1; then + if ! curl -s --max-time 2 http://localhost:8091/pools >/dev/null; then + echo "Couchbase not reachable on localhost:8091." >&2 + echo "Start Couchbase and restore bucket 'hbs' or set HM_SKIP_COUCHBASE_CHECK=1." >&2 + exit 1 + fi + else + echo "curl not found; cannot verify Couchbase availability." >&2 + echo "Install curl or set HM_SKIP_COUCHBASE_CHECK=1." >&2 + exit 1 + fi +} + +build() { + require_bin make + make -C "$ROOT_DIR/hm_gameserver" + make -C "$ROOT_DIR/hm_lobbyserver" +} + +start() { + check_couchbase + mkdir -p "$LOG_DIR" + + if [ ! -x "$GAMESERVER_BIN" ] || [ ! -x "$LOBBYSERVER_BIN" ]; then + echo "Binaries missing; run ./dev build first." >&2 + exit 1 + fi + + if [ -f "$GAMESERVER_PID" ] || [ -f "$LOBBYSERVER_PID" ]; then + echo "PID files exist; run ./dev stop first." >&2 + exit 1 + fi + + nohup "$GAMESERVER_BIN" > "$LOG_DIR/hm_gameserver.out" 2>&1 & + echo $! > "$GAMESERVER_PID" + + nohup "$LOBBYSERVER_BIN" \ + --gameserver="$GAMESERVER_IP" \ + --gameserver_port="$GAMESERVER_PORT" \ + > "$LOG_DIR/hm_lobbyserver.out" 2>&1 & + echo $! > "$LOBBYSERVER_PID" + + echo "Servers started. Logs in $LOG_DIR" +} + +stop() { + if [ -f "$GAMESERVER_PID" ]; then + kill "$(cat "$GAMESERVER_PID")" 2>/dev/null || true + rm -f "$GAMESERVER_PID" + fi + + if [ -f "$LOBBYSERVER_PID" ]; then + kill "$(cat "$LOBBYSERVER_PID")" 2>/dev/null || true + rm -f "$LOBBYSERVER_PID" + fi +} + +status() { + if [ -f "$GAMESERVER_PID" ] && kill -0 "$(cat "$GAMESERVER_PID")" 2>/dev/null; then + echo "hm_gameserver running (pid $(cat "$GAMESERVER_PID"))" + else + echo "hm_gameserver not running" + fi + + if [ -f "$LOBBYSERVER_PID" ] && kill -0 "$(cat "$LOBBYSERVER_PID")" 2>/dev/null; then + echo "hm_lobbyserver running (pid $(cat "$LOBBYSERVER_PID"))" + else + echo "hm_lobbyserver not running" + fi +} + +logs() { + tail -f "$LOG_DIR/hm_gameserver.out" "$LOG_DIR/hm_lobbyserver.out" +} + +case "${1:-}" in + build) + build + ;; + start) + start + ;; + stop) + stop + ;; + status) + status + ;; + logs) + logs + ;; + docker-build) + docker_compose build + ;; + docker-start) + docker_compose up -d + ;; + docker-stop) + docker_compose down + ;; + docker-status) + docker_compose ps + ;; + docker-logs) + docker_compose logs -f --tail=200 gameserver lobbyserver + ;; + *) + usage + exit 1 + ;; +esac diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..1295fe3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,58 @@ +version: "3.8" + +services: + couchbase: + image: couchbase:community-6.6.0 + ports: + - "8091-8096:8091-8096" + - "11210:11210" + volumes: + - couchbase-data:/opt/couchbase/var + + couchbase-init: + image: couchbase:community-6.6.0 + depends_on: + - couchbase + entrypoint: ["/bin/bash", "/init-couchbase.sh"] + volumes: + - ./docker/couchbase-init.sh:/init-couchbase.sh:ro + environment: + COUCHBASE_HOST: couchbase + COUCHBASE_ADMIN_USER: Administrator + COUCHBASE_ADMIN_PASS: password + COUCHBASE_BUCKET: hbs + COUCHBASE_BUCKET_PASS: aci + + gameserver: + build: + context: . + dockerfile: docker/Dockerfile + depends_on: + - couchbase-init + working_dir: /workspace + volumes: + - .:/workspace + environment: + HM_COUCHBASE_HOST: couchbase + command: ["bash", "-lc", "make -C hm_gameserver && ./hm_gameserver/hm_gameserver"] + ports: + - "3724:3724" + + lobbyserver: + build: + context: . + dockerfile: docker/Dockerfile + depends_on: + - couchbase-init + - gameserver + working_dir: /workspace + volumes: + - .:/workspace + environment: + HM_COUCHBASE_HOST: couchbase + command: ["bash", "-lc", "make -C hm_lobbyserver && ./hm_lobbyserver/hm_lobbyserver --gameserver=gameserver --gameserver_port=3724"] + ports: + - "45678:45678" + +volumes: + couchbase-data: diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..2182382 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:18.04 + +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + curl \ + libev-dev \ + libjson-c-dev \ + libcouchbase-dev \ + python \ + python-pip \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /workspace diff --git a/docker/couchbase-init.sh b/docker/couchbase-init.sh new file mode 100755 index 0000000..afca283 --- /dev/null +++ b/docker/couchbase-init.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +HOST=${COUCHBASE_HOST:-couchbase} +ADMIN_USER=${COUCHBASE_ADMIN_USER:-Administrator} +ADMIN_PASS=${COUCHBASE_ADMIN_PASS:-password} +BUCKET=${COUCHBASE_BUCKET:-hbs} +BUCKET_PASS=${COUCHBASE_BUCKET_PASS:-aci} + +echo "Waiting for Couchbase at ${HOST}:8091..." +until curl -s "http://${HOST}:8091/pools" >/dev/null; do + sleep 2 +done + +status=$(curl -s -o /dev/null -w "%{http_code}" "http://${HOST}:8091/pools/default") +if [ "$status" != "200" ]; then + couchbase-cli cluster-init -c "${HOST}:8091" \ + --cluster-username "${ADMIN_USER}" \ + --cluster-password "${ADMIN_PASS}" \ + --cluster-ramsize 512 \ + --services data +fi + +if ! couchbase-cli bucket-list -c "${HOST}:8091" -u "${ADMIN_USER}" -p "${ADMIN_PASS}" | grep -q "${BUCKET}"; then + couchbase-cli bucket-create -c "${HOST}:8091" \ + -u "${ADMIN_USER}" -p "${ADMIN_PASS}" \ + --bucket="${BUCKET}" \ + --bucket-password="${BUCKET_PASS}" \ + --bucket-type=couchbase \ + --bucket-ramsize=200 \ + --bucket-replica=1 \ + --wait +fi + +echo "Couchbase initialized."