diff --git a/.env.example b/.env.example old mode 100644 new mode 100755 index 7592a3a..ab37138 --- a/.env.example +++ b/.env.example @@ -50,6 +50,34 @@ PASSWORD=change-this-default-admin-password # 4. NEVER commit actual secrets to version control! +# ============================================================================= +# PLATFORM SELECTION +# ============================================================================= + +# Platform mode: "windows" (default) or "docker" +# PLATFORM=windows + +# ============================================================================= +# DOCKER MODE SETTINGS (required when PLATFORM=docker) +# ============================================================================= + +# Docker image name for ACC server containers (built from docker/acc-server/Dockerfile) +# ACC_IMAGE=acc-wine:latest + +# Host-side path for the shared ACC game installation volume. +# IMPORTANT: must be the HOST path — ACC containers are Docker siblings of the manager. +# ACC_GAME_VOLUME=/data/acc-game + +# Host-side base path for per-server config directories. +# ACC_CONFIG_BASE_PATH=/data/configs + +# Port pool for Docker-mode ACC server containers (one port per server). +# PORT_POOL_MIN=9600 +# PORT_POOL_MAX=9700 + +# Linux SteamCMD binary path (pre-installed in the manager Docker image). +# STEAMCMD_LINUX_PATH=/usr/games/steamcmd + # ============================================================================= # OPTIONAL SETTINGS (These are handled by system config in database) # ============================================================================= diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ff2b854 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,64 @@ +# Multi-stage build for the acc-server-manager Go backend. +# CGO_ENABLED=1 is required for mattn/go-sqlite3 (uses cgo). +# The binary is compiled for Linux (Docker mode default). + +# ─── Builder ────────────────────────────────────────────────────────────────── +FROM golang:1.25-bookworm AS builder + +WORKDIR /build + +# Install build dependencies for CGO + sqlite3. +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + libc6-dev \ + && rm -rf /var/lib/apt/lists/* + +# Download Go modules first (layer cache). +COPY go.mod go.sum ./ +RUN go mod download + +# Copy source and build. +COPY . . +RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 \ + go build -ldflags="-s -w" -o /acc-server-manager ./cmd/api + +# ─── Runtime ────────────────────────────────────────────────────────────────── +FROM debian:bookworm-slim AS runtime + +# Install runtime dependencies and SteamCMD. +# steamcmd is not in the standard Debian repo — download directly from Valve. +RUN dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + lib32gcc-s1 \ + && \ + rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /usr/games && \ + curl -sSL --retry 3 --retry-delay 5 \ + -o /tmp/steamcmd.tar.gz \ + "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" && \ + tar -xzf /tmp/steamcmd.tar.gz -C /usr/games && \ + rm /tmp/steamcmd.tar.gz && \ + chmod +x /usr/games/steamcmd.sh && \ + ln -sf /usr/games/steamcmd.sh /usr/games/steamcmd + +WORKDIR /app + +COPY --from=builder /acc-server-manager /app/acc-server-manager + +# Persistent data directories. +RUN mkdir -p /data/configs /data/acc-game /data/db + +ENV PLATFORM=docker +ENV PORT=3000 +ENV DB_NAME=/data/db/acc.db +ENV STEAMCMD_LINUX_PATH=/usr/games/steamcmd +ENV ACC_GAME_VOLUME=/data/acc-game +ENV ACC_CONFIG_BASE_PATH=/data/configs + +EXPOSE 3000 + +ENTRYPOINT ["/app/acc-server-manager"] diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/cmd/api/main.go b/cmd/api/main.go old mode 100644 new mode 100755 diff --git a/cmd/api/swagger.go b/cmd/api/swagger.go old mode 100644 new mode 100755 diff --git a/cmd/migrate/main.go b/cmd/migrate/main.go old mode 100644 new mode 100755 diff --git a/cmd/steam-crypt/main.go b/cmd/steam-crypt/main.go old mode 100644 new mode 100755 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8d06305 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,37 @@ +services: + manager: + build: + context: . + dockerfile: Dockerfile + image: acc-server-manager:latest + container_name: acc-server-manager + restart: unless-stopped + ports: + - "3000:3000" + environment: + PLATFORM: docker + DB_NAME: /data/db/acc.db + ACC_GAME_VOLUME: /var/lib/docker/volumes/acc-server-manager_acc-game/_data + ACC_CONFIG_BASE_PATH: /var/lib/docker/volumes/acc-server-manager_acc-configs/_data + STEAMCMD_LINUX_PATH: /usr/games/steamcmd + PORT_POOL_MIN: "9600" + PORT_POOL_MAX: "9700" + ACC_IMAGE: acc-wine:latest + env_file: + - .env + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - acc-game:/data/acc-game + - acc-configs:/data/configs + - acc-db:/data/db + networks: + - acc-net + +volumes: + acc-game: + acc-configs: + acc-db: + +networks: + acc-net: + driver: bridge diff --git a/docker/acc-server/Dockerfile b/docker/acc-server/Dockerfile new file mode 100644 index 0000000..5a8001a --- /dev/null +++ b/docker/acc-server/Dockerfile @@ -0,0 +1,41 @@ +# ACC Server container: Wine + accServer.exe +# Game files are mounted read-only from the shared acc-game volume. +# Per-server config files are mounted read-write from the manager's config volume. +FROM debian:bookworm-slim + +# Install Wine, Xvfb (headless display for Wine), and minimal runtime deps. +RUN dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + wine \ + wine32 \ + wine64 \ + xvfb \ + ca-certificates \ + && \ + rm -rf /var/lib/apt/lists/* + +# Create a non-root user for running the server. +RUN useradd -ms /bin/bash accserver + +WORKDIR /home/accserver + +# Copy entrypoint script. +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +# Volumes (bind-mounted by DockerRuntime.Create): +# /acc/game — shared game files, mounted read-only (ACC_GAME_VOLUME) +# /acc/cfg — per-server config dir, mounted read-write (server.GetConfigPath()) +VOLUME ["/acc/game", "/acc/cfg"] + +# Default server port — overridden at runtime via SERVER_PORT env var. +ENV SERVER_PORT=9600 +ENV WINEDEBUG=-all +ENV DISPLAY=:99 + +EXPOSE ${SERVER_PORT}/tcp +EXPOSE ${SERVER_PORT}/udp + +USER accserver +ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/acc-server/entrypoint.sh b/docker/acc-server/entrypoint.sh new file mode 100644 index 0000000..ed2db8b --- /dev/null +++ b/docker/acc-server/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +Xvfb :99 -screen 0 1024x768x16 & +XVFB_PID=$! + +cleanup() { + echo "Stopping ACC server..." + kill $XVFB_PID 2>/dev/null || true +} +trap cleanup SIGTERM SIGINT + +echo "Starting ACC server on port ${SERVER_PORT}..." + +exec wine /acc/game/server/accServer.exe \ + -serverCfgPath /acc/cfg \ + -port "${SERVER_PORT}" diff --git a/docs/API.md b/docs/API.md old mode 100644 new mode 100755 diff --git a/docs/CONFIG.md b/docs/CONFIG.md old mode 100644 new mode 100755 diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md old mode 100644 new mode 100755 diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md old mode 100644 new mode 100755 diff --git a/docs/SETUP.md b/docs/SETUP.md old mode 100644 new mode 100755 diff --git a/docs/STEAM_2FA_IMPLEMENTATION.md b/docs/STEAM_2FA_IMPLEMENTATION.md old mode 100644 new mode 100755 diff --git a/docs/SWAGGER.md b/docs/SWAGGER.md old mode 100644 new mode 100755 diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md old mode 100644 new mode 100755 diff --git a/go.mod b/go.mod old mode 100644 new mode 100755 index 13282e2..50acfa1 --- a/go.mod +++ b/go.mod @@ -1,15 +1,19 @@ module acc-server-manager -go 1.23.0 +go 1.25.0 require ( + github.com/docker/docker v24.0.9+incompatible + github.com/docker/go-connections v0.6.0 github.com/gofiber/fiber/v2 v2.52.8 github.com/gofiber/swagger v1.1.0 + github.com/gofiber/websocket/v2 v2.2.1 github.com/golang-jwt/jwt/v4 v4.5.2 github.com/google/uuid v1.6.0 github.com/joho/godotenv v1.5.1 github.com/qjebbs/go-jsons v0.0.0-20221222033332-a534c5fc1c4c github.com/swaggo/swag v1.16.3 + github.com/valyala/fasthttp v1.51.0 go.uber.org/dig v1.17.1 golang.org/x/crypto v0.39.0 golang.org/x/sync v0.15.0 @@ -20,13 +24,17 @@ require ( require ( github.com/KyleBanks/depth v1.2.1 // indirect + github.com/Microsoft/go-winio v0.4.21 // indirect github.com/andybalholm/brotli v1.1.0 // indirect + github.com/docker/distribution v2.7.1+incompatible // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/fasthttp/websocket v1.5.3 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/gofiber/websocket/v2 v2.2.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -36,13 +44,21 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/moby/term v0.5.2 // indirect + github.com/morikuni/aec v1.1.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect + github.com/stretchr/testify v1.11.1 // indirect github.com/swaggo/files/v2 v2.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/sys v0.33.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gotest.tools/v3 v3.5.2 // indirect ) diff --git a/go.sum b/go.sum old mode 100644 new mode 100755 index ceaa612..563e7b0 --- a/go.sum +++ b/go.sum @@ -1,9 +1,21 @@ +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Microsoft/go-winio v0.4.21 h1:+6mVbXh4wPzUrl1COX9A+ZCvEpYsOBZ6/+kwDnvLyro= +github.com/Microsoft/go-winio v0.4.21/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek= github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -20,8 +32,12 @@ github.com/gofiber/swagger v1.1.0 h1:ff3rg1fB+Rp5JN/N8jfxTiZtMKe/9tB9QDc79fPiJKQ github.com/gofiber/swagger v1.1.0/go.mod h1:pRZL0Np35sd+lTODTE5The0G+TMHfNY+oC4hM2/i5m8= github.com/gofiber/websocket/v2 v2.2.1 h1:C9cjxvloojayOp9AovmpQrk8VqvVnT8Oao3+IUygH7w= github.com/gofiber/websocket/v2 v2.2.1/go.mod h1:Ao/+nyNnX5u/hIFPuHl28a+NIkrqK7PRimyKaj4JxVU= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -32,6 +48,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -49,18 +67,31 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= +github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/qjebbs/go-jsons v0.0.0-20221222033332-a534c5fc1c4c h1:kmzxiX+OB0knCo1V0dkEkdPelzCdAzCURCfmFArn2/A= github.com/qjebbs/go-jsons v0.0.0-20221222033332-a534c5fc1c4c/go.mod h1:wNJrtinHyC3YSf6giEh4FJN8+yZV7nXBjvmfjhBIcw4= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM= github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= @@ -71,22 +102,53 @@ github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1S github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -96,3 +158,5 @@ gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE= gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg= gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= diff --git a/local/api/api.go b/local/api/api.go old mode 100644 new mode 100755 diff --git a/local/controller/config.go b/local/controller/config.go old mode 100644 new mode 100755 diff --git a/local/controller/controller.go b/local/controller/controller.go old mode 100644 new mode 100755 diff --git a/local/controller/leaderboard.go b/local/controller/leaderboard.go old mode 100644 new mode 100755 diff --git a/local/controller/lookup.go b/local/controller/lookup.go old mode 100644 new mode 100755 diff --git a/local/controller/membership.go b/local/controller/membership.go old mode 100644 new mode 100755 diff --git a/local/controller/server.go b/local/controller/server.go old mode 100644 new mode 100755 diff --git a/local/controller/service_control.go b/local/controller/service_control.go old mode 100644 new mode 100755 diff --git a/local/controller/state_history.go b/local/controller/state_history.go old mode 100644 new mode 100755 diff --git a/local/controller/system.go b/local/controller/system.go old mode 100644 new mode 100755 diff --git a/local/controller/websocket.go b/local/controller/websocket.go old mode 100644 new mode 100755 diff --git a/local/middleware/access_key.go b/local/middleware/access_key.go old mode 100644 new mode 100755 diff --git a/local/middleware/auth.go b/local/middleware/auth.go old mode 100644 new mode 100755 diff --git a/local/middleware/logging/request_logging.go b/local/middleware/logging/request_logging.go old mode 100644 new mode 100755 diff --git a/local/middleware/security/security.go b/local/middleware/security/security.go old mode 100644 new mode 100755 diff --git a/local/model/cache.go b/local/model/cache.go old mode 100644 new mode 100755 diff --git a/local/model/config.go b/local/model/config.go old mode 100644 new mode 100755 diff --git a/local/model/filter.go b/local/model/filter.go old mode 100644 new mode 100755 diff --git a/local/model/leaderboard.go b/local/model/leaderboard.go old mode 100644 new mode 100755 diff --git a/local/model/lookup.go b/local/model/lookup.go old mode 100644 new mode 100755 diff --git a/local/model/model.go b/local/model/model.go old mode 100644 new mode 100755 diff --git a/local/model/permission.go b/local/model/permission.go old mode 100644 new mode 100755 diff --git a/local/model/permissions.go b/local/model/permissions.go old mode 100644 new mode 100755 diff --git a/local/model/role.go b/local/model/role.go old mode 100644 new mode 100755 diff --git a/local/model/service_control.go b/local/model/service_control.go old mode 100644 new mode 100755 diff --git a/local/model/state_history.go b/local/model/state_history.go old mode 100644 new mode 100755 diff --git a/local/model/state_history_stats.go b/local/model/state_history_stats.go old mode 100644 new mode 100755 diff --git a/local/model/steam_2fa.go b/local/model/steam_2fa.go old mode 100644 new mode 100755 diff --git a/local/model/steam_credentials.go b/local/model/steam_credentials.go old mode 100644 new mode 100755 diff --git a/local/model/user.go b/local/model/user.go old mode 100644 new mode 100755 diff --git a/local/model/websocket.go b/local/model/websocket.go old mode 100644 new mode 100755 diff --git a/local/repository/base.go b/local/repository/base.go old mode 100644 new mode 100755 diff --git a/local/repository/config.go b/local/repository/config.go old mode 100644 new mode 100755 diff --git a/local/repository/leaderboard.go b/local/repository/leaderboard.go old mode 100644 new mode 100755 diff --git a/local/repository/lookup.go b/local/repository/lookup.go old mode 100644 new mode 100755 diff --git a/local/repository/membership.go b/local/repository/membership.go old mode 100644 new mode 100755 diff --git a/local/repository/repository.go b/local/repository/repository.go old mode 100644 new mode 100755 diff --git a/local/repository/server.go b/local/repository/server.go old mode 100644 new mode 100755 diff --git a/local/repository/service_control.go b/local/repository/service_control.go old mode 100644 new mode 100755 diff --git a/local/repository/state_history.go b/local/repository/state_history.go old mode 100644 new mode 100755 diff --git a/local/repository/steam_credentials.go b/local/repository/steam_credentials.go old mode 100644 new mode 100755 diff --git a/local/service/config.go b/local/service/config.go old mode 100644 new mode 100755 diff --git a/local/service/docker_log_streamer.go b/local/service/docker_log_streamer.go new file mode 100644 index 0000000..e84ad40 --- /dev/null +++ b/local/service/docker_log_streamer.go @@ -0,0 +1,74 @@ +package service + +import ( + "acc-server-manager/local/model" + "acc-server-manager/local/utl/logging" + "bufio" + "context" + "io" + "sync" + + "github.com/docker/docker/api/types" + dockerclient "github.com/docker/docker/client" + "github.com/docker/docker/pkg/stdcopy" + "github.com/google/uuid" +) + +type DockerLogStreamer struct { + client *dockerclient.Client + cancels sync.Map // uuid.UUID → context.CancelFunc +} + +func NewDockerLogStreamer(client *dockerclient.Client) *DockerLogStreamer { + return &DockerLogStreamer{client: client} +} + +func (s *DockerLogStreamer) Start(ctx context.Context, server *model.Server, handleLine func(string)) error { + if _, exists := s.cancels.Load(server.ID); exists { + return nil + } + if server.ContainerID == "" { + logging.Warn("DockerLogStreamer.Start: no container ID for server %s, skipping", server.ID) + return nil + } + + streamCtx, cancel := context.WithCancel(ctx) + s.cancels.Store(server.ID, cancel) + + go func() { + defer s.cancels.Delete(server.ID) + + rc, err := s.client.ContainerLogs(streamCtx, server.ContainerID, types.ContainerLogsOptions{ + ShowStdout: true, + ShowStderr: true, + Follow: true, + Timestamps: false, + }) + if err != nil { + logging.Error("DockerLogStreamer: failed to attach to container %s: %v", server.ContainerID[:12], err) + return + } + defer rc.Close() + + pr, pw := io.Pipe() + go func() { + defer pw.Close() + if _, err := stdcopy.StdCopy(pw, pw, rc); err != nil && err != io.EOF { + logging.Warn("DockerLogStreamer: stdcopy error for %s: %v", server.ServiceName, err) + } + }() + + scanner := bufio.NewScanner(pr) + for scanner.Scan() { + handleLine(scanner.Text()) + } + }() + + return nil +} + +func (s *DockerLogStreamer) Stop(serverID uuid.UUID) { + if v, ok := s.cancels.LoadAndDelete(serverID); ok { + v.(context.CancelFunc)() + } +} diff --git a/local/service/docker_runtime.go b/local/service/docker_runtime.go new file mode 100644 index 0000000..7b37544 --- /dev/null +++ b/local/service/docker_runtime.go @@ -0,0 +1,194 @@ +package service + +import ( + "acc-server-manager/local/model" + "acc-server-manager/local/repository" + "acc-server-manager/local/utl/env" + "acc-server-manager/local/utl/logging" + "context" + "fmt" + "strconv" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" + dockerclient "github.com/docker/docker/client" + "github.com/docker/go-connections/nat" + "github.com/google/uuid" +) + +type DockerRuntime struct { + client *dockerclient.Client + repo *repository.ServerRepository +} + +func NewDockerRuntime(client *dockerclient.Client, repo *repository.ServerRepository) *DockerRuntime { + return &DockerRuntime{ + client: client, + repo: repo, + } +} + +func (r *DockerRuntime) Create(ctx context.Context, server *model.Server) error { + image := env.GetACCImage() + gameVolume := env.GetACCGameVolume() + configPath := server.GetConfigPath() + + portStr := strconv.Itoa(server.Port) + natPort, err := nat.NewPort("tcp", portStr) + if err != nil { + return fmt.Errorf("invalid port %d: %v", server.Port, err) + } + natPortUDP, err := nat.NewPort("udp", portStr) + if err != nil { + return fmt.Errorf("invalid udp port %d: %v", server.Port, err) + } + + portBindings := nat.PortMap{ + natPort: []nat.PortBinding{{HostPort: portStr}}, + natPortUDP: []nat.PortBinding{{HostPort: portStr}}, + } + exposedPorts := nat.PortSet{ + natPort: struct{}{}, + natPortUDP: struct{}{}, + } + + binds := []string{ + fmt.Sprintf("%s:/acc/game:ro", gameVolume), + fmt.Sprintf("%s:/acc/cfg:rw", configPath), + } + + resp, err := r.client.ContainerCreate(ctx, &container.Config{ + Image: image, + ExposedPorts: exposedPorts, + Env: []string{ + fmt.Sprintf("SERVER_PORT=%d", server.Port), + }, + }, &container.HostConfig{ + Binds: binds, + PortBindings: portBindings, + RestartPolicy: container.RestartPolicy{Name: "unless-stopped"}, + }, nil, nil, server.ServiceName) + if err != nil { + return fmt.Errorf("failed to create container %s: %v", server.ServiceName, err) + } + + server.ContainerID = resp.ID + logging.Info("Created Docker container %s (ID: %s) for server %s", server.ServiceName, resp.ID[:12], server.ID) + return nil +} + +func (r *DockerRuntime) Delete(ctx context.Context, serverID uuid.UUID) error { + containerID, err := r.resolveContainerID(ctx, serverID) + if err != nil { + return err + } + if containerID == "" { + return nil + } + + err = r.client.ContainerRemove(ctx, containerID, types.ContainerRemoveOptions{ + Force: true, + RemoveVolumes: false, + }) + if err != nil { + return fmt.Errorf("failed to remove container %s: %v", containerID[:12], err) + } + logging.Info("Removed Docker container %s for server %s", containerID[:12], serverID) + return nil +} + +func (r *DockerRuntime) Start(ctx context.Context, serverID uuid.UUID) (string, error) { + containerID, err := r.resolveContainerID(ctx, serverID) + if err != nil { + return "", err + } + if err := r.client.ContainerStart(ctx, containerID, types.ContainerStartOptions{}); err != nil { + return "", fmt.Errorf("failed to start container: %v", err) + } + return model.StatusRunning.String(), nil +} + +func (r *DockerRuntime) Stop(ctx context.Context, serverID uuid.UUID) (string, error) { + containerID, err := r.resolveContainerID(ctx, serverID) + if err != nil { + return "", err + } + if err := r.client.ContainerStop(ctx, containerID, container.StopOptions{}); err != nil { + return "", fmt.Errorf("failed to stop container: %v", err) + } + return model.StatusStopped.String(), nil +} + +func (r *DockerRuntime) Restart(ctx context.Context, serverID uuid.UUID) (string, error) { + containerID, err := r.resolveContainerID(ctx, serverID) + if err != nil { + return "", err + } + if err := r.client.ContainerRestart(ctx, containerID, container.StopOptions{}); err != nil { + return "", fmt.Errorf("failed to restart container: %v", err) + } + return model.StatusRunning.String(), nil +} + +func (r *DockerRuntime) Status(ctx context.Context, serverID uuid.UUID) (string, error) { + server, err := r.repo.GetByID(ctx, serverID) + if err != nil || server == nil { + return model.StatusUnknown.String(), err + } + + containerID := server.ContainerID + if containerID == "" { + containerID, err = r.findContainerByName(ctx, server.ServiceName) + if err != nil || containerID == "" { + return model.StatusStopped.String(), nil + } + } + + info, err := r.client.ContainerInspect(ctx, containerID) + if err != nil { + return model.StatusUnknown.String(), nil + } + + return dockerStateToStatus(info.State.Status), nil +} + +func (r *DockerRuntime) resolveContainerID(ctx context.Context, serverID uuid.UUID) (string, error) { + server, err := r.repo.GetByID(ctx, serverID) + if err != nil { + return "", fmt.Errorf("failed to look up server %s: %v", serverID, err) + } + if server == nil { + return "", fmt.Errorf("server %s not found", serverID) + } + return server.ContainerID, nil +} + +func (r *DockerRuntime) findContainerByName(ctx context.Context, name string) (string, error) { + containers, err := r.client.ContainerList(ctx, types.ContainerListOptions{ + All: true, + Filters: filters.NewArgs(filters.Arg("name", "/"+name)), + }) + if err != nil { + return "", err + } + if len(containers) == 0 { + return "", nil + } + return containers[0].ID, nil +} + +func dockerStateToStatus(state string) string { + switch state { + case "running": + return model.StatusRunning.String() + case "exited", "dead": + return model.StatusStopped.String() + case "restarting": + return model.StatusRestarting.String() + case "paused": + return model.StatusStopped.String() + default: + return model.StatusUnknown.String() + } +} diff --git a/local/service/firewall_service.go b/local/service/firewall_service.go old mode 100644 new mode 100755 diff --git a/local/service/leaderboard.go b/local/service/leaderboard.go old mode 100644 new mode 100755 diff --git a/local/service/lookup.go b/local/service/lookup.go old mode 100644 new mode 100755 diff --git a/local/service/membership.go b/local/service/membership.go old mode 100644 new mode 100755 diff --git a/local/service/noop_firewall.go b/local/service/noop_firewall.go new file mode 100644 index 0000000..e57e598 --- /dev/null +++ b/local/service/noop_firewall.go @@ -0,0 +1,7 @@ +package service + +type NoOpFirewall struct{} + +func (f *NoOpFirewall) CreateServerRules(_ string, _, _ []int) error { return nil } +func (f *NoOpFirewall) DeleteServerRules(_ string, _, _ []int) error { return nil } +func (f *NoOpFirewall) UpdateServerRules(_ string, _, _ []int) error { return nil } diff --git a/local/service/service_manager.go b/local/service/service_manager.go old mode 100644 new mode 100755 diff --git a/local/service/state_history.go b/local/service/state_history.go old mode 100644 new mode 100755 diff --git a/local/service/websocket.go b/local/service/websocket.go old mode 100644 new mode 100755 diff --git a/local/service/windows_service.go b/local/service/windows_service.go old mode 100644 new mode 100755 diff --git a/local/utl/audit/audit.go b/local/utl/audit/audit.go old mode 100644 new mode 100755 diff --git a/local/utl/cache/cache.go b/local/utl/cache/cache.go old mode 100644 new mode 100755 diff --git a/local/utl/command/callback_executor.go b/local/utl/command/callback_executor.go old mode 100644 new mode 100755 diff --git a/local/utl/command/callbacks.go b/local/utl/command/callbacks.go old mode 100644 new mode 100755 diff --git a/local/utl/command/executor.go b/local/utl/command/executor.go old mode 100644 new mode 100755 diff --git a/local/utl/command/interactive_executor.go b/local/utl/command/interactive_executor.go old mode 100644 new mode 100755 diff --git a/local/utl/common/common.go b/local/utl/common/common.go old mode 100644 new mode 100755 diff --git a/local/utl/configs/configs.go b/local/utl/configs/configs.go old mode 100644 new mode 100755 diff --git a/local/utl/docker/client.go b/local/utl/docker/client.go new file mode 100644 index 0000000..87be22f --- /dev/null +++ b/local/utl/docker/client.go @@ -0,0 +1,12 @@ +package docker + +import ( + dockerclient "github.com/docker/docker/client" +) + +func NewDockerClient() (*dockerclient.Client, error) { + return dockerclient.NewClientWithOpts( + dockerclient.FromEnv, + dockerclient.WithAPIVersionNegotiation(), + ) +} diff --git a/local/utl/error_handler/controller_error_handler.go b/local/utl/error_handler/controller_error_handler.go old mode 100644 new mode 100755 diff --git a/local/utl/errors/safe_error.go b/local/utl/errors/safe_error.go old mode 100644 new mode 100755 diff --git a/local/utl/graceful/shutdown.go b/local/utl/graceful/shutdown.go old mode 100644 new mode 100755 diff --git a/local/utl/jwt/jwt.go b/local/utl/jwt/jwt.go old mode 100644 new mode 100755 diff --git a/local/utl/logging/base.go b/local/utl/logging/base.go old mode 100644 new mode 100755 diff --git a/local/utl/logging/debug.go b/local/utl/logging/debug.go old mode 100644 new mode 100755 diff --git a/local/utl/logging/error.go b/local/utl/logging/error.go old mode 100644 new mode 100755 diff --git a/local/utl/logging/info.go b/local/utl/logging/info.go old mode 100644 new mode 100755 diff --git a/local/utl/logging/logger.go b/local/utl/logging/logger.go old mode 100644 new mode 100755 diff --git a/local/utl/logging/warn.go b/local/utl/logging/warn.go old mode 100644 new mode 100755 diff --git a/local/utl/network/port.go b/local/utl/network/port.go old mode 100644 new mode 100755 diff --git a/local/utl/password/password.go b/local/utl/password/password.go old mode 100644 new mode 100755 diff --git a/local/utl/regex_handler/regex_handler.go b/local/utl/regex_handler/regex_handler.go old mode 100644 new mode 100755 diff --git a/local/utl/security/download_verifier.go b/local/utl/security/download_verifier.go old mode 100644 new mode 100755 diff --git a/local/utl/security/path_validator.go b/local/utl/security/path_validator.go old mode 100644 new mode 100755 diff --git a/local/utl/tracking/log_tailer.go b/local/utl/tracking/log_tailer.go old mode 100644 new mode 100755 diff --git a/local/utl/tracking/position_tracker.go b/local/utl/tracking/position_tracker.go old mode 100644 new mode 100755 diff --git a/local/utl/tracking/tracking.go b/local/utl/tracking/tracking.go old mode 100644 new mode 100755 diff --git a/local/utl/websocket/websocket.go b/local/utl/websocket/websocket.go old mode 100644 new mode 100755 diff --git a/scripts/README.md b/scripts/README.md old mode 100644 new mode 100755 diff --git a/scripts/build.ps1 b/scripts/build.ps1 old mode 100644 new mode 100755 diff --git a/scripts/deploy.bat b/scripts/deploy.bat old mode 100644 new mode 100755 diff --git a/scripts/deploy.config.example b/scripts/deploy.config.example old mode 100644 new mode 100755 diff --git a/scripts/deploy.ps1 b/scripts/deploy.ps1 old mode 100644 new mode 100755 diff --git a/scripts/generate-secrets.ps1 b/scripts/generate-secrets.ps1 old mode 100644 new mode 100755 diff --git a/scripts/generate-secrets.sh b/scripts/generate-secrets.sh old mode 100644 new mode 100755 diff --git a/swagger/docs.go b/swagger/docs.go old mode 100644 new mode 100755 diff --git a/swagger/swagger.json b/swagger/swagger.json old mode 100644 new mode 100755 diff --git a/swagger/swagger.yaml b/swagger/swagger.yaml old mode 100644 new mode 100755 diff --git a/tests/auth_helper.go b/tests/auth_helper.go old mode 100644 new mode 100755 diff --git a/tests/mocks/auth_middleware_mock.go b/tests/mocks/auth_middleware_mock.go old mode 100644 new mode 100755 diff --git a/tests/mocks/repository_mock.go b/tests/mocks/repository_mock.go old mode 100644 new mode 100755 diff --git a/tests/mocks/state_history_mock.go b/tests/mocks/state_history_mock.go old mode 100644 new mode 100755 diff --git a/tests/test_helper.go b/tests/test_helper.go old mode 100644 new mode 100755 diff --git a/tests/testdata/state_history_data.go b/tests/testdata/state_history_data.go old mode 100644 new mode 100755 diff --git a/tests/unit/controller/controller_simple_test.go b/tests/unit/controller/controller_simple_test.go old mode 100644 new mode 100755 diff --git a/tests/unit/controller/helper.go b/tests/unit/controller/helper.go old mode 100644 new mode 100755 diff --git a/tests/unit/controller/state_history_controller_test.go b/tests/unit/controller/state_history_controller_test.go old mode 100644 new mode 100755 diff --git a/tests/unit/repository/state_history_repository_test.go b/tests/unit/repository/state_history_repository_test.go old mode 100644 new mode 100755 diff --git a/tests/unit/service/auth_simple_test.go b/tests/unit/service/auth_simple_test.go old mode 100644 new mode 100755 diff --git a/tests/unit/service/cache_service_test.go b/tests/unit/service/cache_service_test.go old mode 100644 new mode 100755 diff --git a/tests/unit/service/config_service_test.go b/tests/unit/service/config_service_test.go old mode 100644 new mode 100755 diff --git a/tests/unit/service/state_history_service_test.go b/tests/unit/service/state_history_service_test.go old mode 100644 new mode 100755