diff --git a/.gitignore b/.gitignore index 617f925..354bfa3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ ### Linux template *~ +# Exclude any file inside the server and server-dev directory +server/* +server-dev/* # temporary files which can be created if a process still has a handle open of a deleted file .fuse_hidden* diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 0000000..73f1a1b --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,113 @@ + +# StayInTarkov LINUX Container +# +# Copyright 2024 StayInTarkov +# Use of this source code is governed by an MIT +# license that can be found in the LICENSE file. + +ARG NODE=20.11.1 +ARG BREAKING_CHANGE=false + +FROM alpine as git +# https://lore.kernel.org/git/20240514181641.150112-1-sandals@crustytoothpaste.net/T/ +ENV GIT_CLONE_PROTECTION_ACTIVE=false +# work around until git and git lfs resolve their differences. +RUN apk add git git-lfs + +ARG SIT_COMMIT +ARG SIT_BRANCH=development +ARG SIT_PR +ARG SPT_COMMIT +ARG SPT_BRANCH=master +ARG SPT_PR + + +FROM git as spt +WORKDIR /opt +# invalidate cache and repull if upstream is different. +ADD https://dev.sp-tarkov.com/api/v1/repos/SPT/Server/git/refs/heads/${SPT_BRANCH} /opt/spt_version.json +# pull pr if provided, pull commit if provided, else single branch. +RUN if [ -n "$SPT_PR" ] && echo "$SPT_PR" | grep -Eq "^[0-9]+$"; then \ + git clone https://dev.sp-tarkov.com/SPT/Server.git spt && \ + cd spt && \ + git fetch origin pull/$SPT_PR/head:pr_$SPT_PR && \ + git checkout pr_$SPT_PR && \ + git-lfs pull; \ + elif [ -n "$SPT_COMMIT" ]; then \ + git clone --single-branch --branch $SPT_BRANCH https://dev.sp-tarkov.com/SPT/Server.git spt && \ + cd spt && \ + git checkout $SPT_COMMIT && \ + git-lfs pull; \ + else \ + git clone --single-branch --branch $SPT_BRANCH https://dev.sp-tarkov.com/SPT/Server.git spt && \ + cd spt && \ + git-lfs pull; \ + fi + +FROM git as sit +WORKDIR /opt +# invalidate cache and repull if upstream is different. +ADD https://api.github.com/repos/stayintarkov/SIT.Aki-Server-Mod/git/refs/heads/${SIT_BRANCH} /opt/sit_version.json +# pull pr if provided, pull commit if provided, else single branch. +RUN if [ -n "$SIT_PR" ] && echo "$SIT_PR" | grep -Eq "^[0-9]+$"; then \ + git clone https://github.com/stayintarkov/SIT.Aki-Server-Mod.git sit && \ + cd sit && \ + git fetch origin pull/$SIT_PR/head:pr_$SIT_PR && \ + git checkout pr_$SIT_PR && \ + echo "pr_${SIT_PR}" > /opt/sit/version; \ + elif [ -n "$SIT_COMMIT" ]; then \ + git clone --single-branch --branch $SIT_BRANCH https://github.com/stayintarkov/SIT.Aki-Server-Mod.git sit && \ + cd sit && \ + git checkout $SIT_COMMIT && \ + echo "$SIT_COMMIT" > /opt/sit/version; \ + else \ + git clone --single-branch --branch $SIT_BRANCH https://github.com/stayintarkov/SIT.Aki-Server-Mod.git sit && \ + cat /opt/sit_version.json | sed -n 's/.*"sha":"\([^"]*\)".*/\1/p' > /opt/sit/version; \ + fi + + +FROM node:${NODE}-alpine as builder +# spt needs git to build:release +RUN apk add git +COPY --from=spt /opt/spt /opt/builder +WORKDIR /opt/builder/project +RUN npm install +RUN npm run build:release +RUN mv build/ /opt/server/ +COPY --from=sit /opt/sit /opt/server/user/mods/SITCoop +WORKDIR /opt/server/user/mods/SITCoop +RUN npm install +RUN rm -rf .git +RUN rm -rf /opt/builder + +FROM alpine as server +RUN apk update && \ +apk --no-cache add libgcc libstdc++ libc6-compat curl screen dos2unix && \ +rm -rf /var/cache/apk/* + +FROM server as development +ENV BREAKING=${BREAKING_CHANGE} +ENV buildver "development" +WORKDIR /opt +COPY --from=builder /opt/server /opt/srv +COPY ./entrypoint.alpine.sh /opt/entrypoint.sh +# Fix for Windows +RUN dos2unix /opt/entrypoint.sh +# Set permissions +RUN chmod +x /opt/entrypoint.sh + +# Exposing ports +EXPOSE 6969 +EXPOSE 6970 +EXPOSE 6971 + +VOLUME ["/opt/server"] + +WORKDIR /opt/server +ENTRYPOINT ["/opt/entrypoint.sh"] +# Specify the default command to run when the container starts +CMD ["/opt/server/Aki.Server.exe"] + +FROM development as release +ENV buildver "release" +RUN sed -n 's/.*"version": "\(.*\)".*/\1/p' /opt/srv/user/mods/SITCoop/package.json > /opt/srv/user/mods/SITCoop/version diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index ded516c..3615032 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -2,12 +2,23 @@ services: tarkov-sitcoop-dev: build: context: . + dockerfile: Dockerfile.alpine + # target: development args: SIT_BRANCH: "development" - SIT: "HEAD^" - SPT_BRANCH: "3.8.1-DEV" - SPT: "HEAD^" + SIT_COMMIT: + SIT_PR: + SPT_BRANCH: "master" + SPT_COMMIT: + SPT_PR: container_name: sitcoop-dev + # command: /bin/ash + environment: + - BACKEND_IP= + - SERVER_NAME= + - HEADLESS=true + - UPDATE=false + - LOG_REQUESTS=true volumes: - ./server-dev:/opt/server ports: diff --git a/docker-compose.yml b/docker-compose.yml index 48547e8..9f7d7eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,6 +2,12 @@ services: tarkov-sitcoop: image: stayintarkov/stayintarkov:latest container_name: sitcoop + environment: + - BACKEND_IP= + - SERVER_NAME= + - HEADLESS=true + - UPDATE=false + - LOG_REQUESTS=true volumes: - ./server:/opt/server ports: diff --git a/entrypoint.alpine.sh b/entrypoint.alpine.sh new file mode 100644 index 0000000..d4ec08b --- /dev/null +++ b/entrypoint.alpine.sh @@ -0,0 +1,124 @@ +#!/bin/ash + +# Copyright 2024 StayInTarkov +# Use of this source code is governed by an MIT +# license that can be found in the LICENSE file. + +# Read the existing version from the version file (if it exists) +EXISTING_VERSION=$(cat /opt/server/version 2>/dev/null) +SIT_VERSION=$(cat /opt/srv/user/mods/SITCoop/version 2>/dev/null) + +# Grab user ENV input if exists else default +HEADLESS=${HEADLESS:-true} +FORCE=${FORCE:-false} +SPT_IP=${SPT_IP:-0.0.0.0} +SPT_BACKEND_IP=${BACKEND_IP:-$(curl -s4 ipv4.icanhazip.com)} +SPT_LOG_REQUESTS=${LOG_REQUESTS:-true} +NEW_SERVER_NAME=${SERVER_NAME:-SIT $SIT_VERSION} +SPT_CONFIG_PATH=Aki_Data/Server/config +#SPT_CONFIG_PATH=SPT_Data/Server/config + +#DBUG +echo "DEBUG build: $buildver, HEADLESS: $HEADLESS, BREAKKING: $BREAKING, FORCE: $FORCE" + +echo "Stay In Tarkov Docker" +echo "github.com/StayInTarkov/SIT.Docker" + +sit_setup() { + start=$(date +%s) + echo "Started copying files to your volume/directory.. Please wait." + cp -r /opt/srv/* /opt/server/ + rm -rf /opt/srv + end=$(date +%s) + + echo "Files copied to your machine in $(($end-$start)) seconds." + echo "Starting the server to generate all the required files" + cd /opt/server + chown $(id -u):$(id -g) ./* -Rf + + sed -ir 's/"ip": .*,/"ip": "'$SPT_IP'",/' /opt/server/$SPT_CONFIG_PATH/http.json + MOD_IP=$(sed -n 's/.*"ip": "\(.*\)",/\1/p' /opt/server/$SPT_CONFIG_PATH/http.json) + echo "SPT_IP: $MOD_IP, updating http.json" + + sed -ir 's/"backendIp": .*,/"backendIp": "'$SPT_BACKEND_IP'",/' /opt/server/$SPT_CONFIG_PATH/http.json + MOD_BIP=$(sed -n 's/.*"backendIp": "\(.*\)",/\1/p' /opt/server/$SPT_CONFIG_PATH/http.json) + echo "BACKEND_IP: $MOD_BIP, updating http.json" + + sed -ir "s/\"serverName\": \".*\"/\"serverName\": \"$NEW_SERVER_NAME\"/" /opt/server/$SPT_CONFIG_PATH/core.json + MODIFIED_NAME=$(sed -n 's/.*"serverName": "\([^"]*\)".*/\1/p' /opt/server/$SPT_CONFIG_PATH/core.json) + echo "serverName: $MODIFIED_NAME, updating core.json" + + sed -ir 's/"logRequests": .*,/"logRequests": '"$SPT_LOG_REQUESTS"',/' /opt/server/$SPT_CONFIG_PATH/http.json + MOD_LOGQ=$(sed -n 's/.*"logRequests": \(.*\),/\1/p' /opt/server/$SPT_CONFIG_PATH/http.json) + echo "logRequests: $MOD_LOGQ, updating http.json" + + # remove previous install.log n boot server once in bg to generate files. + rm /opt/server/install.log + screen -L -Logfile "install.log" -d -m -S SPTServer ./Aki.Server.exe + # 3.9 upcoming + # screen -L -Logfile "install.log" -d -m -S AkiServer ./SPT.Server.exe + while [ ! -f "/opt/server/user/mods/SITCoop/config/coopConfig.json" ]; do + sleep 10 # sleep till coopConfig.json is generated + done + # kill Aki.Server + pid=$(screen -ls | grep 'SPTServer' | awk '{print $1}' | cut -d '.' -f 1) + kill -9 "$pid" +} + +# perform one-time server setup if no version file is found +if [ -d "/opt/srv" ]; then + if [ ! -e "/opt/server/version" ]; then + echo "No version file found, running first-time setup..." + + sit_setup + + # will prevent setup from running again + echo "saving $SIT_VERSION to /opt/server/version" + printf "%s" "$SIT_VERSION" > /opt/server/version + echo "SIT Version installed: $(cat /opt/server/version)" + # set headless to false only for inital set up. + HEADLESS = false + +# new SIT version found, always reinstall update unless BREAKING flag present, else print version diff. + elif [ "$EXISTING_VERSION" != "$SIT_VERSION" ] || [ "$FORCE" = true ]; then + echo "new SIT version: $SIT_VERSION" + echo "existing SIT version: $EXISTING_VERSION" + if [ "$BREAKING" = false ]; then + echo "SIT Update found, no breaking change detected, installing update..." + sit_setup + # will prevent setup from running again + echo "saving $SIT_VERSION to /opt/server/version" + printf "%s" "$SIT_VERSION" > /opt/server/version + echo "SIT Version updated: $(cat /opt/server/version)" + elif [ "$FORCE" = true ]; then + echo "Breaking SIT Update found, FORCE flag set, installing update..." + sit_setup + # will prevent setup from running again + echo "saving $SIT_VERSION to /opt/server/version" + printf "%s" "$SIT_VERSION" > /opt/server/version + echo "SIT Version updated: $(cat /opt/server/version)" + else + echo "WARNING: breaking change found in SIT update" + echo "please check release notes to ensure proper steps are taken" + echo "use -e FORCE=true to update server..." + echo "FORCE flag not set, update aborted." + echo "Starting SIT Server in 5 seconds.." + sleep 5 + fi + fi +# quit if not headless + if [ "$HEADLESS" = false ]; then + echo "SIT.Docker setup is now complete!" + echo "You can configure and start your container." + exit 0 + fi +fi + +# delete js n js.map files from existing mods (ignore SITCoop) and make sure server generates them fresh to prevent errors from copying windows artifact files. +echo "clearing mod *.js *.js.map artifact cache..." +find /opt/server/user/mods -type d -name "SITCoop" -prune -o \ +-type f \( -name "*.js" -o -name "*.js.map" \) \ +-exec sh -c 'for x; do ts="${x%.*}.ts"; [ -f "$ts" ] && rm "$x"; done' _ {} + + +# continue to run whichever command was passed in (typically running Aki.Server.exe) +exec "$@"