diff --git a/Dockerfile b/Dockerfile index 5a53011..c1b93f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,13 @@ ENV DEBIAN_FRONTEND noninteractive ENV LC_ALL C.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US.UTF-8 +ENV WINEARCH win64 +ENV DISPLAY :0 +ENV WINEPREFIX /root/prefix32 +ENV AOTDIR "$WINEPREFIX/drive_c/Program Files (x86)/AgeOfTime" +WORKDIR /root/ +COPY webaudio.js /root/ RUN dpkg --add-architecture i386 && \ apt-get update && apt-get -y install python2 python-is-python2 xvfb x11vnc xdotool wget tar supervisor net-tools fluxbox gnupg2 && \ wget -O - https://dl.winehq.org/wine-builds/winehq.key | apt-key add - && \ @@ -13,73 +19,60 @@ RUN dpkg --add-architecture i386 && \ apt-get update && apt-get -y install \ wmctrl \ winehq-stable \ - libgl1:i386 bzip2 \ - gstreamer1.0-plugins-good \ - gstreamer1.0-pulseaudio \ - gstreamer1.0-tools \ - libglu1-mesa \ - libgtk2.0-0 \ - libncursesw5 \ - libopenal1 \ - libsdl-image1.2 \ - libsdl-ttf2.0-0 \ - libsdl1.2debian \ - libsndfile1 \ +# libgl1:i386 bzip2 \ +# gstreamer1.0-plugins-good \ +# gstreamer1.0-pulseaudio \ +# gstreamer1.0-tools \ +# libglu1-mesa \ +# libgtk2.0-0 \ +# libncursesw5 \ +# libopenal1 \ +# libsdl-image1.2 \ +# libsdl-ttf2.0-0 \ +# libsdl1.2debian \ +# libsndfile1 \ pulseaudio \ - ucspi-tcp \ cpulimit && \ mkdir /opt/wine-stable/share/wine/mono && wget -O - https://dl.winehq.org/wine/wine-mono/9.0.0/wine-mono-9.0.0-x86.tar.xz | tar -xJv -C /opt/wine-stable/share/wine/mono && \ - apt-get -y full-upgrade && apt-get clean && rm -rf /var/lib/apt/lists/* - -# the following can be used to skip download and use local file -# COPY AgeOfTime-29.exe /root/AgeOfTime-29.exe - -ENV WINEPREFIX /root/prefix32 -ENV WINEARCH win64 -ENV DISPLAY :0 -ENV AOTDIR "$WINEPREFIX/drive_c/Program Files/AgeOfTime" - -RUN wget -P /mono https://dl.winehq.org/wine/wine-mono/9.0.0/wine-mono-9.0.0-x86.msi && \ - wineboot -f -u && sleep 10 && xvfb-run msiexec /i /mono/wine-mono-9.0.0-x86.msi /quiet -# wineboot -u && msiexec /i /opt/wine-stable/share/wine/gecko/wine-gecko-2.47.1-x86.msi && \ -# rm -rf /mono/wine-mono-4.9.4.msi - -# download and install AgeOfTime -RUN cd /root && \ -# nohup /usr/bin/Xvfb :0 -screen 0 1024x768x24 && sleep 5 && \ + apt-get -y full-upgrade && apt-get clean && rm -rf /var/lib/apt/lists/* && \ + # install mono for wine + wget -P /mono https://dl.winehq.org/wine/wine-mono/9.0.0/wine-mono-9.0.0-x86.msi && \ + wineboot -i -f -u && \ + sleep 10 && \ + xvfb-run msiexec /i /mono/wine-mono-9.0.0-x86.msi /quiet && \ + rm -rf /mono/wine-mono-9.0.0-x86.msi && \ + # done with wine stuff + # download and install AgeOfTime + cd /root && \ wget https://ageoftime.com/files/AgeOfTime-29.exe && \ -# mkdir -p "$WINEPREFIX/drive_c/Program Files/" && \ cd "$WINEPREFIX/drive_c/" && \ chmod +x /root/AgeOfTime-29.exe && \ xvfb-run wine /root/AgeOfTime-29.exe -s && \ - rm -f /root/AgeOfTime-29.exe -# mv "$WINEPREFIX/drive_c/Program Files/AgeOfTime" "$WINEPREFIX/drive_c/AgeOfTime" - -WORKDIR /root/ -RUN wget -O - https://github.com/novnc/noVNC/archive/v1.1.0.tar.gz | tar -xzv -C /root/ && mv /root/noVNC-1.1.0 /root/novnc && ln -s /root/novnc/vnc_lite.html /root/novnc/index.html && \ - wget -O - https://github.com/novnc/websockify/archive/v0.9.0.tar.gz | tar -xzv -C /root/ && mv /root/websockify-0.9.0 /root/novnc/utils/websockify - -# lets copy age of time files instead of install -# COPY ["AgeOfTime", "$WINEPREFIX/drive_c/Program Files/AgeOfTime"] - -# Force vnc_lite.html to be used for novnc, to avoid having the directory listing page. -# Additionally, turn off the control bar. Finally, add a hook to start audio. -COPY webaudio.js /root/novnc/core/ -RUN rm -f /root/novnc/index.html && ln -s /root/novnc/vnc_lite.html /root/novnc/index.html \ - && sed -i 's/display:flex/display:none/' /root/novnc/app/styles/base.css \ - && sed -i "/import RFB/a \ - import WebAudio from './core/webaudio.js'" \ - /root/novnc/vnc_lite.html \ - && sed -i "/function connected(e)/a \ - var wa = new WebAudio('ws://localhost:8081/websockify'); \ - document.getElementsByTagName('canvas')[0].addEventListener('keydown', e => { wa.start(); });" \ - /root/novnc/vnc_lite.html + rm -f /root/AgeOfTime-29.exe && \ + # install noVNC \ + wget -O - https://github.com/novnc/noVNC/archive/v1.1.0.tar.gz | tar -xzv -C /root/ && mv /root/noVNC-1.1.0 /root/novnc && ln -s /root/novnc/vnc_lite.html /root/novnc/index.html && \ + wget -O - https://github.com/novnc/websockify/archive/v0.9.0.tar.gz | tar -xzv -C /root/ && mv /root/websockify-0.9.0 /root/novnc/utils/websockify && \ + # install noVNC audio patch + # Force vnc_lite.html to be used for novnc, to avoid having the directory listing page. + # Additionally, turn off the control bar. Finally, add a hook to start audio. + mv /root/webaudio.js /root/novnc/core/webaudio.js && \ + rm -f /root/novnc/index.html && ln -s /root/novnc/vnc_lite.html /root/novnc/index.html && \ + sed -i 's/display:flex/display:none/' /root/novnc/app/styles/base.css && \ + sed -i "/import RFB/a \ + import WebAudio from './core/webaudio.js'" \ + /root/novnc/vnc_lite.html && \ + sed -i "/function connected(e)/a \ + var wa = new WebAudio('ws://localhost:8081/websockify'); \ + document.getElementsByTagName('canvas')[0].addEventListener('keydown', e => { wa.start(); });" \ + /root/novnc/vnc_lite.html +COPY restart-aot-crash.sh /root/restart-aot-crash.sh +COPY start-aot.sh /root/start-aot.sh +COPY start.sh /root/start.sh +RUN chmod +x /root/*.sh && \ + ln -s "$AOTDIR" /root/AgeOfTime ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf -ADD restart-aot-crash.sh /root/restart-aot-crash.sh -ADD start-aot.sh /root/start-aot.sh -RUN chmod +x /root/restart-aot-crash.sh && chmod +x /root/start-aot.sh EXPOSE 8080 USER root -CMD ["/usr/bin/supervisord"] +CMD ["/root/start.sh"] diff --git a/restart-aot-crash.sh b/restart-aot-crash.sh index 2f8cfe4..e3dc55a 100644 --- a/restart-aot-crash.sh +++ b/restart-aot-crash.sh @@ -1,36 +1,45 @@ #!/bin/bash export DISPLAY=":0.0" +CPU_LIMIT_FILE="$AOTDIR/aot_cpu_limit" +CURRENT_LIMIT=0 -# this script checks for the presence of the wine "Program Error" -# dialog and if it is present it kills AgeOfTime and winedbg -# which causes supervisor to restart it - -# This script also applies cpu limits if the env variable AOT_CPU_LIMIT is set - -# Check if AOT_CPU_LIMIT is set and not zero -if [ -z "$AOT_CPU_LIMIT" ] || [ "$AOT_CPU_LIMIT" -eq 0 ]; then - SKIP_CPU_LIMIT=true -else - SKIP_CPU_LIMIT=false +# Initialize the CPU limit file with AOT_CPU_LIMIT if it's set +if [ ! -z "$AOT_CPU_LIMIT" ]; then + echo "$AOT_CPU_LIMIT" > "$CPU_LIMIT_FILE" fi +# give the x server time to start +sleep 5; + while true; do - if wmctrl -l|awk '{$3=""; $2=""; $1=""; print $0}' | grep '^\s*Program Error$'; then -# echo "AOT Program Error detected" - kill $(pidof AgeOfTime.exe) - kill $(pidof winedbg) - elif ! $SKIP_CPU_LIMIT && pidof AgeOfTime.exe >/dev/null; then - # AgeOfTime.exe is running - # Ensure cpulimit is installed and get the PID of AgeOfTime.exe - AOT_PID=$(pidof AgeOfTime.exe) - # Check if cpulimit is already running for AgeOfTime.exe to avoid stacking multiple limits - if ! pgrep -f "cpulimit.*$AOT_PID" > /dev/null; then - # Apply cpulimit to AgeOfTime.exe to limit it to 2 cores and 50% usage - # Note: cpulimit doesn't directly support core limitation, so we adjust the overall CPU percentage assuming 2 cores - # For more precise control, consider taskset or cgroups - cpulimit -p $AOT_PID -l $AOT_CPU_LIMIT + if [ -f "$CPU_LIMIT_FILE" ]; then + NEW_LIMIT=$(cat "$CPU_LIMIT_FILE") + # Validate NEW_LIMIT is a number greater than zero + if [[ "$NEW_LIMIT" =~ ^[0-9]+$ ]]; then + # Check if the limit has changed + if [ "$NEW_LIMIT" -ne "$CURRENT_LIMIT" ]; then + # If so, update CURRENT_LIMIT + CURRENT_LIMIT="$NEW_LIMIT" + # Kill existing cpulimit process if any + AOT_PID=$(pidof AgeOfTime.exe) + CPULIMIT_PID=$(pgrep -fl "cpulimit.*\-p $(pidof AgeOfTime.exe)" | awk '{print $1}') + if [ ! -z "$CPULIMIT_PID" ]; then + echo "Killing cpulimit process $CPULIMIT_PID" + kill "$CPULIMIT_PID" + fi + # Apply new cpulimit if >= 0 + if [ ! -z "$AOT_PID" ] && [ "$NEW_LIMIT" -gt 0 ]; then + echo "Creating cpulimit process (limit=$NEW_LIMIT)" + cpulimit -p "$AOT_PID" -l "$NEW_LIMIT" -b & + fi + fi fi fi - sleep 2 + if wmctrl -l | awk '{$3=""; $2=""; $1=""; print $0}' | grep '^\s*Program Error$'; then + kill $(pidof AgeOfTime.exe) + kill $(pidof winedbg) + fi + + sleep 1 done \ No newline at end of file diff --git a/start-aot.sh b/start-aot.sh index 796dd10..b1a26c1 100644 --- a/start-aot.sh +++ b/start-aot.sh @@ -6,7 +6,7 @@ export HOME=/root export LANG=en_US.UTF-8 #export WINEDEBUG="+alsa,+pulse,+winealsa,+winepulse,+d3d,+ddraw,+opengl,+winediag", cd "/root/prefix32/drive_c/Program Files (x86)/AgeOfTime" -#sleep 5 +sleep 5 # have to start with wineconsole as wine will cause a crash # for some weird reason. wine works fine outside of supervisor though strangely wineconsole AgeOfTime.exe \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..71b5fd4 --- /dev/null +++ b/start.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +/usr/bin/supervisord \ No newline at end of file diff --git a/supervisord.conf b/supervisord.conf index f8dd8c2..4519796 100644 --- a/supervisord.conf +++ b/supervisord.conf @@ -28,55 +28,65 @@ priority=1 [program:pulseaudio] command=/usr/bin/pulseaudio --disallow-module-loading -vvvv --disallow-exit --exit-idle-time=-1 stdout_logfile=/root/pulseaudio.log +stdout_logfile_maxbytes=1MB +stderr_logfile_maxbytes=1MB redirect_stderr=true priority=1 -[program:audiostream] -command=tcpserver localhost 5901 gst-launch-1.0 -q pulsesrc server=/tmp/pulseaudio.socket ! audio/x-raw, channels=2, rate=24000 ! cutter ! opusenc ! webmmux ! fdsink fd=1 -stdout_logfile=/root/audiostream.log -redirect_stderr=true -priority=1 +; [program:audiostream] +; command=tcpserver localhost 5901 gst-launch-1.0 -q pulsesrc server=/tmp/pulseaudio.socket ! audio/x-raw, channels=2, rate=24000 ! cutter ! opusenc ! webmmux ! fdsink fd=1 +; stdout_logfile=/root/audiostream.log +; stdout_logfile_maxbytes=1MB +; stderr_logfile_maxbytes=1MB +; redirect_stderr=true +; priority=1 -[program:websockify_audio] -command=websockify 8081 localhost:5901 -stdout_logfile=/root/websockify-audio.log -redirect_stderr=true -priority=1 +; [program:websockify_audio] +; command=websockify 8081 localhost:5901 +; stdout_logfile=/root/websockify-audio.log +; stdout_logfile_maxbytes=1MB +; stderr_logfile_maxbytes=1MB +; redirect_stderr=true +; priority=1 -[program:explorer] -command=/opt/wine-stable/bin/wine Explorer.exe -autorestart=true -stdout_logfile=/dev/fd/1 -stdout_logfile_maxbytes=0 -redirect_stderr=true -priority=1 +; [program:explorer] +; command=/opt/wine-stable/bin/wine Explorer.exe +; autorestart=true +; stdout_logfile=/dev/fd/1 +; stdout_logfile_maxbytes=0 +; redirect_stderr=true +; priority=1 -[program:fluxbox] -command=/usr/bin/fluxbox -autorestart=true -stdout_logfile=/dev/fd/1 -stdout_logfile_maxbytes=0 -redirect_stderr=true -priority=1 +; [program:fluxbox] +; command=/usr/bin/fluxbox +; autorestart=true +; stdout_logfile=/dev/fd/1 +; stdout_logfile_maxbytes=0 +; redirect_stderr=true +; priority=1 [program:restart-aot-if-crashed] command=/bin/bash -c "/root/restart-aot-crash.sh" umask=0022 stderr_logfile = /var/log/supervisor/restart-aot-if-crashed-stderr.log stdout_logfile = /var/log/supervisor/restart-aot-if-crashed-stdout.log +stdout_logfile_maxbytes=1MB +stderr_logfile_maxbytes=1MB autostart=true autorestart=true user=root redirect_stderr=true -environment=AOT_CPU_LIMIT=%(ENV_AOT_CPU_LIMIT)s +environment= + AOT_CPU_LIMIT="%(ENV_AOT_CPU_LIMIT)s", + AOTDIR="%(ENV_AOTDIR)s" [program:ageoftime] command=/root/start-aot.sh umask=0022 -stdout_logfile=/dev/stdout -stdout_logfile_maxbytes=0 -stderr_logfile=/dev/stderr -stderr_logfile_maxbytes=0 +stderr_logfile = /var/log/supervisor/ageoftime-stderr.log +stdout_logfile = /var/log/supervisor/ageoftime-stdout.log +stdout_logfile_maxbytes=1MB +stderr_logfile_maxbytes=1MB autostart=true autorestart=true user=root