From e668af29ad2e6be286e7701cfb12a74f812c9015 Mon Sep 17 00:00:00 2001 From: Wanjohi <71614375+wanjohiryan@users.noreply.github.com> Date: Fri, 29 Mar 2024 09:56:16 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20feat:=20Add=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .scripts/proton | 358 ++++++++++++++++++++++++++++++++++++++++++++++ server.Dockerfile | 36 +++++ 2 files changed, 394 insertions(+) create mode 100644 .scripts/proton create mode 100644 server.Dockerfile diff --git a/.scripts/proton b/.scripts/proton new file mode 100644 index 00000000..f21f9424 --- /dev/null +++ b/.scripts/proton @@ -0,0 +1,358 @@ +#!/bin/bash +# Version 0.0.1 + +#Big thanks to github/@noabody +#For his wmstart script https://github.com/noabody/unibuild/blob/master/data/wstart + +#Dependencies: git, jq, curl, vulkan & wget + +# top level linux steam dir +pntop="$HOME/.steam" +# steamapps subdir +pnapp="$pntop/steam/steamapps" +# proton subdir normally under top/app +pnbin="$pnapp/common" +# proton prefix subdir normally under top/app +pnpfx="$pnapp/compatdata" +# proton ge +pnpge="$pntop/root/compatibilitytools.d" +# Program Files standard subdir +progs="drive_c/Program Files" +# windows steam client subdir under progs +stcmn="Steam/steamapps/common" +# temp folder +temp="$HOME/Downloads" + +# store cmdline args minus first option +clprm=("${@:2}") + +xcmd=() +i_mnus=() +myprnt=() +i_syms=() +# scalable built-in programs menu +pmenu=("Command Prompt/wineconsole.exe" "Control Panel/control.exe" "Registry Editor/regedit.exe" "Task Manager/taskmgr.exe" "Windows Explorer/explorer.exe" "Wine Configuration/winecfg.exe") +# prevent shell inheritance of env vars we use +unset WINEARCH WINEDLLPATH WINEPREFIX STEAM_COMPAT_CLIENT_INSTALL_PATH STEAM_COMPAT_DATA_PATH + +xarg="$1" + +xnint() { + xnbin="$pnbin" + xnpfx="$pnpfx" + dpth=(4 3) +} + +xpge() { + test -d "$pnpge" || mkdir -p "$pnpge" + test -d "$pnbin" || mkdir -p "$pnbin" + + if [[ ! -d "$(dirname "$pnpge")" ]]; then + echo -e "Could not create folder 'compatibilitytools.d/protonge' in:\n $(dirname "$pnpge")\n because that path does not exist.\nVerify script variable 'pnpge'" + elif [[ ! -d "$pnbin" ]]; then + echo -e "Could not create sym-link 'protonge' in:\n $pnbin\n because that path does not exist.\nVerify script variable 'pnbin'" + else + gedl="$(curl -sL https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest | jq -r ".tag_name")" + # gedl="$(gh release list -R GloriousEggroll/proton-ge-custom -L 1 | grep -Pio '^ge[^ ]+')" + gever="$(echo "$gedl" | grep -Pio '(?<=ge-proton).*')" + if [[ -f "$pnpge/protonge/version" ]]; then + if [[ -z "$(grep -Pio "$gever" "$pnpge/protonge/version")" ]]; then + echo -e "Available Proton GE $gever differs from installed, updating...\n" + chse=y + else + echo -e "Available Proton GE $gever matches installed, nothing to do.\n" + fi + else + echo -e "Proton GE not found, installing...\n" + chse=y + fi + fi + if [[ -n "$chse" ]]; then + wget "$(curl -s https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases/latest | grep browser_download_url | cut -d\" -f4 | grep .tar.gz)" -P "$temp"/ + + rm -rf "$pnpge/protonge" + tar -xf "$temp/$gedl".tar.gz -C "$pnpge/" + mv "$pnpge"/*roton* "$pnpge/protonge" + rm -f "$temp/$gedl".tar.gz + grep -Piq "$gever" "$pnpge/protonge/version" || perl -pi -e "s|(?<=ge-proton).*|$gever|gi" "$pnpge/protonge/version" + test -h "$pnbin/protonge" || ln -sf "$pnpge/protonge" "$pnbin" + fi +} + +xn64() { + xstrt="wine64" + xnldl="$xnbin/lib64:$xnbin/lib" + xndll="$xnbin/lib64/wine:$xnbin/lib/wine" +} + +xn32() { + xstrt="wine" + xnldl="$xnbin/lib" + xndll="$xnbin/lib/wine" +} + +w_menu() { + PS3="Please enter your choice: " + select answer in "${i_mnus[@]}"; do + for item in "${i_mnus[@]}"; do + if [[ $item == "$answer" ]]; then + break 2 + fi + done + done + # repeating menu requires valid selection from array + if [[ "$answer" = "quit" ]]; then + # pop quit from end of array for menu option + exit + else + xmrtn="$answer" + fi + unset i_mnus + clear +} + +xnexe() { + # menu installed wine/proton or exit + readarray -t i_mnus < <( + find -L "$xnbin" -maxdepth "${dpth[0]}" -type f -iname 'wine' ! \( -ipath '*/sbin*' \) 2>/dev/null | perl -pe "s|\Q$xnbin\E/(.*)[/]*bin/wine|\1| ; s|/$||" | sort + echo "quit" + ) + if [[ ${#i_mnus[@]} -gt 2 ]]; then + clear + w_menu + xnbin="$(realpath "$xnbin/$xmrtn")" + unset xmrtn + elif [[ ${#i_mnus[@]} -eq 2 ]]; then + xnbin="$(realpath "$xnbin/${i_mnus[0]}")" + else + echo "No installed Wine/Proton found." + exit 1 + fi +} + +xnenv() { + # core env vars allow proper targetting of wine/proton + xpath="$xnbin/bin:$PATH" + xcmd=(env PATH="$xpath" WINEDLLPATH="$xndll" LD_LIBRARY_PATH="$xnldl" WINEPREFIX="$xnpfx") + + xcmd+=(STEAM_COMPAT_DATA_PATH="${xnpfx///pfx}" STEAM_COMPAT_CLIENT_INSTALL_PATH="$pntop") +} + +xlnch() { + #command line launcher + if [[ -z "$dbg" ]]; then + ("${xcmd[@]}" >/dev/null 2>&1 &) + else + if [[ "$dbg" = "1" ]]; then + ("${xcmd[@]}" &) + elif [[ "$dbg" = "2" ]]; then + (WINEDEBUG="warn+all" "${xcmd[@]}" &) + fi + fi + # prepend cmd with dbg=1 to see command and default debug output + # dbg=2 to see command and all debug output, dbg=? for command only +} + +xbld() { + # cross-function custom prefix builder + pnpfx="$pnpfx/${clprm[0]}" + xnint + + if [[ -z "${clprm[0]}" ]]; then + echo -e "\n Proton prefix name required, use an appid from Steam: (e.g. 0, 730 ) \n" + elif [[ -d "$xnpfx" ]]; then + echo -e "\n Proton Prefix exists: $xnpfx \n" + else + xnexe + echo "Creating Proton Prefix: ${clprm[0]}" + + xnenv + mkdir -p "$xnpfx" + xcmd+=(STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" "run") + + xlnch + fi +} + +xnpre() { + if [[ -d "$xnpfx/$progs (x86)" ]]; then + xn64 + else + xn32 + fi +} + +xndef() { + # create default prefix cross-function + if [[ -z "$prfx" ]]; then + echo "INFO: to use a specific prefix, append prfx='your prefix' to this command" + if [[ ! -d "$xnpfx/0" ]]; then + # always create default 0 prefix + xnpfx="$xnpfx/0" + echo "Creating default prefix: $xnpfx" + mkdir -p "$xnpfx" + STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" run >/dev/null 2>&1 & + xnpfx="$xnpfx/pfx" + else + xnpfx="$xnpfx/0" + xnpfx="$xnpfx/pfx" + fi + else + xnpfx="$xnpfx/$prfx" + if [[ ! -d "$xnpfx" ]]; then + echo "Creating default prefix: $xnpfx" + mkdir -p "$xnpfx" + STEAM_COMPAT_DATA_PATH="$xnpfx" "${xnbin%/*}/proton" run >/dev/null 2>&1 & + xnpfx="$xnpfx/pfx" + else + xnpfx="$xnpfx/pfx" + fi + fi +} + +fewoth() { + # filtered list of variable type in standard paths + readarray -t i_mnus < <( + env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort + echo "quit" + ) +} + +fewexe() { + # filtered list of exe in standard paths + readarray -t i_mnus < <( + env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended ! \( -ipath '*cache*' -o -ipath '*/microsoft*' -o -ipath '*/windows*' -o -ipath '*/temp*' \) ! \( -iregex '.*(capture|clokspl|helper|iexplore|install|internal|kernel|[^ ]launcher|legacypm|overlay|proxy|redist|renderer|(crash|error)reporter|serv(er|ice)|setup|streaming|tutorial|unins|update).*' \) -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort + echo "quit" + ) + # valid exe will have gui and icon +} + +alloth() { + # unfiltered list of variable type in specified path + readarray -t i_mnus < <( + find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname "$xflt" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort + echo "quit" + ) +} + +allexe() { + # unfiltered list of exe in specified path + if [[ -n "$(stat --file-system --format=%T "$(stat --format=%m "$pedir" 2>/dev/null)" 2>/dev/null | grep -Pio 'fuse')" ]]; then + readarray -t i_mnus < <( + find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|" | sort + echo "quit" + ) + # skip exe validity tests if file is on network drive + else + readarray -t i_mnus < <( + env pedir="$pedir" find "$pedir" -maxdepth 7 -type f -regextype posix-extended -iname '*.exe' -exec sh -c '(readpe -h optional "$1" 2>/dev/null | grep -Piq '0x2.*gui') && (wrestool "$1" 2>/dev/null | grep -Piq 'type=icon') && echo "$1" 2>/dev/null | perl -pe "s|\Q$pedir\E/(.*)|\1|"' -- {} \; 2>/dev/null | sort + echo "quit" + ) + # perform exe validity tests if file is on local drive + fi +} + +xpmn() { + # use specified exe, menu specified folder, or menu system + if [[ -f "${clprm[0]}" ]]; then + # parse 1st cmdline arg, queue if valid file + pedir="$(realpath "${clprm[0]}")" + xmrtn="$(basename "$pedir")" + pedir="$(dirname "$pedir")" + else + if [[ -d "${clprm[0]}" ]]; then + # parse 1st cmdline arg, use as path if valid + pedir="$(realpath "${clprm[0]}")" + test -z "$xflt" && allexe || alloth + else + # if no cmdline path, use prefix drive_c + pedir="$xnpfx/drive_c" + test -z "$xflt" && fewexe || fewoth + fi + # create menu, from path, of file + test ${#i_mnus[@]} -gt 1 && w_menu + fi +} + +xnldr() { + # loader default to proton as applicable, otherwise wine + if [[ -z "$wn" ]]; then + xcmd+=("${xnbin%/*}/proton" "run") + else + if [[ "$wn" = "true" ]]; then + xcmd+=("$xstrt") + else + echo "unrecognised run option" + exit 1 + fi + fi +} + +xlyt() { + # prepare layout for launch + # 64-bit prefix, 32-bit prefix header, reset env to 32 + if [[ -n "$(readpe -h optional "$pedir/$xmrtn" 2>/dev/null | grep -Pi 'magic number.*0x10b')" && -d "$xnpfx/$progs (x86)" ]]; then + xn32 + xnenv + fi + xnldr + # if 1st arg is file/folder, skip it and run selection + remaining args + if [[ -e "${clprm[0]}" ]]; then + xcmd+=("$pedir/$xmrtn" "${clprm[@]:1}") + else + xcmd+=("$pedir/$xmrtn" "${clprm[@]}") + fi +} + +xnset() { + # set cross-fuction + xnint + # proton menu + xnexe + # create default prefix as required + xndef + # proton prefix + xnpre + # proton env vars + xnenv +} + +usage() { + echo -e "\n$(basename $0): ERROR - $*" 1>&2 + echo -e "\nusage: $(basename $0)\n [-i,--install] [-b,--build] [-r,--run] \n \n (install) install proton-ge \n (build) build a custom proton prefix \n (run) run an .exe program \n \n" 1>&2 +} + +if [[ $# -lt 1 ]]; then + usage "one option required!" +else + case $xarg in + -i | --install) + # proton ge + xpge + ;; + -p | --prefix) + # prefix builder + xbld + ;; + -r | --run) + # second arg should be the prefix to use. + # run program - 1st arg valid file to run, folder to menu, + # neither (sys menu), 2nd arg... passed to exe + xnset + xpmn + if [[ -n "$xmrtn" ]]; then + xlyt + # change to exe dir before run + cd "$(dirname "$pedir/$xmrtn")" + xlnch + fi + ;; + -* | \* | *) + # do_usage + usage "invalid option $1" + exit 1 + ;; + esac +fi + +#FIXME: it won't run anything AAAArgh! \ No newline at end of file diff --git a/server.Dockerfile b/server.Dockerfile new file mode 100644 index 00000000..c6faf6a6 --- /dev/null +++ b/server.Dockerfile @@ -0,0 +1,36 @@ +#This contains all the necessary libs for the server to work. +#NOTE: KEEP THIS IMAGE AS LEAN AS POSSIBLE. + +FROM ubuntu:latest + +#FIXME: install Vulkan drivers (should be done in the .scripts/gpu) +#FIXME: install https://git.dec05eba.com/gpu-screen-recorder (should be done in the .scripts/stream) + +ENV DEBIAN_FRONTEND=noninteractive \ + TIMEZONE=Africa/Nairobi + +#Install base libs +RUN apt update && \ + dpkg --add-architecture i386 && \ + apt install -y \ + software-properties-common \ + curl \ + wget \ + git \ + jq \ + locales \ + && rm -rf /var/lib/apt/lists/* \ + && locale-gen en_US.UTF-8 + +#Set language variables +ENV LANG=en_US.UTF-8 \ + LANGUAGE=en_US:en \ + LC_ALL=en_US.UTF-8 + +COPY .scripts/ /usr/bin/netris/ + +RUN ls -la /usr/bin/netris \ + && chmod +x /usr/bin/netris/proton + +#Install proton +RUN /usr/bin/netris/proton -i \ No newline at end of file From 854d51b2b25813e0b3eea4668e98b0b032781172 Mon Sep 17 00:00:00 2001 From: Wanjohi <71614375+wanjohiryan@users.noreply.github.com> Date: Fri, 29 Mar 2024 10:00:23 +0300 Subject: [PATCH 2/2] feat: workflows/server.yml --- .github/workflows/server.yml | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 .github/workflows/server.yml diff --git a/.github/workflows/server.yml b/.github/workflows/server.yml new file mode 100644 index 00000000..1f5b122c --- /dev/null +++ b/.github/workflows/server.yml @@ -0,0 +1,93 @@ +#Tabs not spaces, you moron :) + +name: CI for netris:server + +on: + pull_request: + paths: + - "server.Dockerfile" + - ".github/workflows/server.yml" + schedule: + - cron: 0 0 * * * # At the end of everyday + push: + branches: [main] + paths: + - "server.Dockerfile" + - ".github/workflows/server.yml" + tags: + - v*.*.* + release: + types: [created] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: wanjohiryan/netris + BASE_TAG_PREFIX: server + +concurrency: + group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + build-docker-pr: + name: Build image on pr + runs-on: ubuntu-latest + if: ${{ github.event_name == 'pull_request' }} + steps: + - + name: Checkout repo + uses: actions/checkout@v4 + - + name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Build Docker image + uses: docker/build-push-action@v5 + with: + file: server.Dockerfile + context: ./ + push: false + load: true + tags: netris:server + + build-docker-main: + name: Build image on merge to main + if: ${{github.ref == 'refs/heads/main'}} + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - + name: Checkout repo + uses: actions/checkout@v4 + - + name: Log into registry ${{ env.REGISTRY }} + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Extract Container metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }} + # + #tag on release, and a nightly build for 'dev' + tags: | + type=raw,value=nightly,enable={{is_default_branch}} + type=ref,event=tag + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + - + name: Build Docker image + uses: docker/build-push-action@v5 + with: + file: server.Dockerfile + context: ./ + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file