srinetwork commited on
Commit
aa2b8b4
·
verified ·
1 Parent(s): c1edcb4

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +211 -44
Dockerfile CHANGED
@@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y \
11
  && rm -rf /var/lib/apt/lists/*
12
 
13
  # Install Python dependencies
14
- RUN pip3 install flask flask-sock psutil --break-system-packages
15
 
16
  WORKDIR /app
17
 
@@ -49,6 +49,9 @@ if [ ! -f eula.txt ]; then
49
  echo "✅ EULA accepted"
50
  fi
51
 
 
 
 
52
  # Create backup script
53
  cat > /app/backup.sh << 'BACKUPSCRIPT'
54
  #!/bin/bash
@@ -77,7 +80,7 @@ echo "✅ Auto-backup enabled (every 5 minutes)"
77
  echo ""
78
 
79
  # ==========================================
80
- # WEB TERMINAL SERVER (Mobile Responsive)
81
  # ==========================================
82
  cat > /app/web_terminal.py << 'PYTHON_SCRIPT'
83
  import os
@@ -88,9 +91,11 @@ import threading
88
  import time
89
  import queue
90
  import signal
 
91
  from flask import Flask, render_template_string
92
  from flask_sock import Sock
93
  import psutil
 
94
 
95
  app = Flask(__name__)
96
  sock = Sock(app)
@@ -100,11 +105,131 @@ output_queue = queue.Queue()
100
  command_queue = queue.Queue()
101
  server_ready = threading.Event()
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  def start_minecraft():
104
- global mc_process
105
  mc_dir = "/app/mcserver"
106
 
107
  print("[MC] Starting Minecraft server...", flush=True)
 
 
 
 
 
108
 
109
  mc_process = subprocess.Popen(
110
  ["java", "-Xms1G", "-Xmx14G", "-XX:+UseG1GC",
@@ -120,16 +245,20 @@ def start_minecraft():
120
  )
121
 
122
  print(f"[MC] Minecraft PID: {mc_process.pid}", flush=True)
 
123
 
124
  def read_output():
125
  try:
126
  for line in mc_process.stdout:
127
- output_queue.put(line)
 
128
  if "Done" in line and "For help, type" in line:
129
  server_ready.set()
130
  print("[MC] Server is ready!", flush=True)
 
131
  except Exception as e:
132
  print(f"[MC] Output error: {e}", flush=True)
 
133
 
134
  threading.Thread(target=read_output, daemon=True).start()
135
 
@@ -142,6 +271,7 @@ def start_minecraft():
142
  mc_process.stdin.write(cmd + "\n")
143
  mc_process.stdin.flush()
144
  print(f"[MC] Command: {cmd}", flush=True)
 
145
  except Exception as e:
146
  print(f"[MC] Command error: {e}", flush=True)
147
  except queue.Empty:
@@ -172,8 +302,6 @@ HTML_TEMPLATE = """
172
  touch-action: manipulation;
173
  }
174
 
175
- /* Mobile-first responsive design */
176
-
177
  /* Top Navigation */
178
  .top-nav {
179
  background: #252a30;
@@ -327,6 +455,7 @@ HTML_TEMPLATE = """
327
  .terminal-line.warn { color: #d29922; }
328
  .terminal-line.error { color: #f85149; }
329
  .terminal-line.success { color: #3fb950; }
 
330
 
331
  /* Command Input Area */
332
  .command-area {
@@ -827,9 +956,9 @@ HTML_TEMPLATE = """
827
  let ws = null;
828
  let reconnectAttempts = 0;
829
  let maxReconnectAttempts = 10;
830
- let serverStartTime = null;
831
  let isServerRunning = false;
832
  let sidebarOpen = false;
 
833
 
834
  function updateConnectionStatus(status, message) {
835
  connectionBar.className = 'connection-bar ' + status;
@@ -841,7 +970,7 @@ HTML_TEMPLATE = """
841
  connectionBar.innerHTML = '<i class="fas ' + icons[status] + '"></i><span>' + message + '</span>';
842
  }
843
 
844
- function updateServerStatus(running) {
845
  isServerRunning = running;
846
  const statusEl = document.getElementById('serverStatus');
847
 
@@ -853,7 +982,9 @@ HTML_TEMPLATE = """
853
  stopBtn.disabled = false;
854
  commandInput.disabled = false;
855
  sendBtn.disabled = false;
856
- if (!serverStartTime) serverStartTime = Date.now();
 
 
857
  } else {
858
  statusEl.className = 'status-indicator status-offline';
859
  statusEl.innerHTML = '<span class="pulse"></span>Offline';
@@ -869,6 +1000,20 @@ HTML_TEMPLATE = """
869
  function addTerminalLine(text, type = '') {
870
  const line = document.createElement('div');
871
  line.className = 'terminal-line ' + type;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
872
  line.textContent = text;
873
  terminal.appendChild(line);
874
  terminal.scrollTop = terminal.scrollHeight;
@@ -879,20 +1024,24 @@ HTML_TEMPLATE = """
879
  }
880
  }
881
 
882
- function formatUptime(ms) {
883
- const seconds = Math.floor(ms / 1000);
884
- const minutes = Math.floor(seconds / 60);
885
- const hours = Math.floor(minutes / 60);
886
- const days = Math.floor(hours / 24);
887
- if (days > 0) return days + 'd ' + (hours % 24) + 'h';
888
- if (hours > 0) return hours + 'h ' + (minutes % 60) + 'm';
889
- if (minutes > 0) return minutes + 'm ' + (seconds % 60) + 's';
890
- return seconds + 's';
 
 
 
891
  }
892
 
893
  function updateUptime() {
894
  if (serverStartTime && isServerRunning) {
895
- const uptime = Date.now() - serverStartTime;
 
896
  document.getElementById('uptime').textContent = formatUptime(uptime);
897
  document.getElementById('uptimeSub').textContent = 'Running';
898
  } else {
@@ -918,17 +1067,24 @@ HTML_TEMPLATE = """
918
  const data = JSON.parse(event.data);
919
 
920
  if (data.type === 'output') {
921
- addTerminalLine(data.data.trim());
922
  } else if (data.type === 'stats') {
923
  document.getElementById('cpuLoad').textContent = data.cpu.toFixed(1) + '%';
924
  document.getElementById('memoryUsage').textContent = data.memory.toFixed(1) + '%';
925
  const memTotal = (data.memoryTotal / 1024 / 1024 / 1024).toFixed(2);
926
  const memUsed = ((data.memoryTotal * data.memory / 100) / 1024 / 1024 / 1024).toFixed(2);
927
  document.getElementById('memorySub').textContent = memUsed + ' / ' + memTotal + ' GB';
928
- updateServerStatus(data.running);
 
 
929
  if (data.players !== undefined) {
930
  document.getElementById('playerCount').textContent = data.players;
931
  }
 
 
 
 
 
932
  }
933
  };
934
 
@@ -953,7 +1109,6 @@ HTML_TEMPLATE = """
953
  const cmd = commandInput.value.trim();
954
  if (cmd && ws && ws.readyState === WebSocket.OPEN) {
955
  ws.send(JSON.stringify({type: 'command', data: cmd}));
956
- addTerminalLine('> ' + cmd, 'info');
957
  commandInput.value = '';
958
  }
959
  }
@@ -961,7 +1116,6 @@ HTML_TEMPLATE = """
961
  function sendCmd(cmd) {
962
  if (ws && ws.readyState === WebSocket.OPEN) {
963
  ws.send(JSON.stringify({type: 'command', data: cmd}));
964
- addTerminalLine('[' + cmd + ']', 'info');
965
  }
966
  }
967
 
@@ -1033,7 +1187,7 @@ HTML_TEMPLATE = """
1033
  }, false);
1034
 
1035
  document.getElementById('serverAddress').textContent = window.location.hostname;
1036
- addTerminalLine('Connecting to Minecraft server...', 'info');
1037
  </script>
1038
  </body>
1039
  </html>
@@ -1052,27 +1206,18 @@ def health():
1052
 
1053
  @sock.route('/ws')
1054
  def websocket(ws):
 
1055
  print("[WS] Client connected", flush=True)
1056
 
1057
- # Send recent history
1058
- history = []
1059
- temp_list = []
1060
- while not output_queue.empty() and len(temp_list) < 100:
1061
- try:
1062
- line = output_queue.get_nowait()
1063
- temp_list.append(line)
1064
- except:
1065
- break
1066
-
1067
- for line in temp_list:
1068
- output_queue.put(line)
1069
- history.append(line)
1070
-
1071
- for line in history[-50:]:
1072
- try:
1073
- ws.send(json.dumps({'type': 'output', 'data': line}))
1074
- except:
1075
- break
1076
 
1077
  def send_stats():
1078
  while True:
@@ -1081,12 +1226,18 @@ def websocket(ws):
1081
  memory = psutil.virtual_memory()
1082
  running = mc_process is not None and mc_process.poll() is None
1083
 
 
 
 
 
 
1084
  ws.send(json.dumps({
1085
  'type': 'stats',
1086
  'cpu': cpu,
1087
  'memory': memory.percent,
1088
  'memoryTotal': memory.total,
1089
  'running': running,
 
1090
  'players': 0
1091
  }))
1092
  except Exception as e:
@@ -1134,6 +1285,7 @@ def websocket(ws):
1134
 
1135
  def cleanup(signum=None, frame=None):
1136
  print("\n[MAIN] Shutting down...", flush=True)
 
1137
  if mc_process:
1138
  try:
1139
  mc_process.stdin.write("stop\n")
@@ -1150,12 +1302,25 @@ signal.signal(signal.SIGTERM, cleanup)
1150
  signal.signal(signal.SIGINT, cleanup)
1151
 
1152
  if __name__ == '__main__':
 
 
 
 
1153
  print("[MAIN] Starting web server...", flush=True)
1154
 
1155
  # Start Minecraft immediately
1156
  mc_thread = threading.Thread(target=start_minecraft, daemon=True)
1157
  mc_thread.start()
1158
 
 
 
 
 
 
 
 
 
 
1159
  from werkzeug.serving import run_simple
1160
  run_simple('0.0.0.0', 7860, app, threaded=True, use_reloader=False)
1161
  PYTHON_SCRIPT
@@ -1174,9 +1339,11 @@ fi
1174
 
1175
  echo ""
1176
  echo "=========================================="
1177
- echo "✅ Minecraft Server with Mobile Responsive Web Terminal is LIVE!"
1178
  echo "🌐 Access at: https://your-space.hf.space"
1179
  echo "📱 Mobile optimized interface enabled"
 
 
1180
  echo "=========================================="
1181
 
1182
  # Keep container alive
 
11
  && rm -rf /var/lib/apt/lists/*
12
 
13
  # Install Python dependencies
14
+ RUN pip3 install flask flask-sock psutil requests --break-system-packages
15
 
16
  WORKDIR /app
17
 
 
49
  echo "✅ EULA accepted"
50
  fi
51
 
52
+ # Create logs directory for persistent storage
53
+ mkdir -p /app/logs
54
+
55
  # Create backup script
56
  cat > /app/backup.sh << 'BACKUPSCRIPT'
57
  #!/bin/bash
 
80
  echo ""
81
 
82
  # ==========================================
83
+ # WEB TERMINAL SERVER (Fixed Uptime + Persistent Logs)
84
  # ==========================================
85
  cat > /app/web_terminal.py << 'PYTHON_SCRIPT'
86
  import os
 
91
  import time
92
  import queue
93
  import signal
94
+ import requests
95
  from flask import Flask, render_template_string
96
  from flask_sock import Sock
97
  import psutil
98
+ from datetime import datetime
99
 
100
  app = Flask(__name__)
101
  sock = Sock(app)
 
105
  command_queue = queue.Queue()
106
  server_ready = threading.Event()
107
 
108
+ # Persistent storage variables
109
+ server_start_time = None
110
+ logs_history = []
111
+ LOGS_FILE = "/app/logs/console_logs.txt"
112
+ UPTIME_FILE = "/app/logs/server_start_time.txt"
113
+ GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN', '')
114
+ GITHUB_REPO = "Walukapah/mcserver"
115
+
116
+ def load_logs_from_file():
117
+ """Load previous logs from local file"""
118
+ global logs_history
119
+ try:
120
+ if os.path.exists(LOGS_FILE):
121
+ with open(LOGS_FILE, 'r', encoding='utf-8') as f:
122
+ logs_history = f.read().splitlines()
123
+ # Keep only last 1000 lines
124
+ logs_history = logs_history[-1000:]
125
+ print(f"[LOGS] Loaded {len(logs_history)} lines from file", flush=True)
126
+ except Exception as e:
127
+ print(f"[LOGS] Error loading logs: {e}", flush=True)
128
+ logs_history = []
129
+
130
+ def save_logs_to_file():
131
+ """Save logs to local file"""
132
+ try:
133
+ os.makedirs(os.path.dirname(LOGS_FILE), exist_ok=True)
134
+ with open(LOGS_FILE, 'w', encoding='utf-8') as f:
135
+ f.write('\n'.join(logs_history[-1000:]))
136
+ except Exception as e:
137
+ print(f"[LOGS] Error saving logs: {e}", flush=True)
138
+
139
+ def push_logs_to_github():
140
+ """Push logs to GitHub for persistent storage"""
141
+ try:
142
+ if not GITHUB_TOKEN:
143
+ return
144
+
145
+ # Read current logs
146
+ if not os.path.exists(LOGS_FILE):
147
+ return
148
+
149
+ with open(LOGS_FILE, 'r', encoding='utf-8') as f:
150
+ content = f.read()
151
+
152
+ # GitHub API - get current file SHA
153
+ api_url = f"https://api.github.com/repos/{GITHUB_REPO}/contents/logs/console_logs.txt"
154
+ headers = {
155
+ "Authorization": f"token {GITHUB_TOKEN}",
156
+ "Accept": "application/vnd.github.v3+json"
157
+ }
158
+
159
+ # Check if file exists
160
+ sha = None
161
+ try:
162
+ resp = requests.get(api_url, headers=headers, timeout=10)
163
+ if resp.status_code == 200:
164
+ sha = resp.json().get('sha')
165
+ except:
166
+ pass
167
+
168
+ # Create or update file
169
+ import base64
170
+ encoded_content = base64.b64encode(content.encode()).decode()
171
+
172
+ data = {
173
+ "message": f"Update logs - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
174
+ "content": encoded_content,
175
+ "branch": "main"
176
+ }
177
+ if sha:
178
+ data["sha"] = sha
179
+
180
+ resp = requests.put(api_url, headers=headers, json=data, timeout=10)
181
+ if resp.status_code in [200, 201]:
182
+ print("[LOGS] Pushed to GitHub successfully", flush=True)
183
+ except Exception as e:
184
+ print(f"[LOGS] GitHub push error: {e}", flush=True)
185
+
186
+ def load_uptime_from_file():
187
+ """Load server start time from file"""
188
+ global server_start_time
189
+ try:
190
+ if os.path.exists(UPTIME_FILE):
191
+ with open(UPTIME_FILE, 'r') as f:
192
+ timestamp = f.read().strip()
193
+ if timestamp:
194
+ server_start_time = float(timestamp)
195
+ print(f"[UPTIME] Loaded start time: {datetime.fromtimestamp(server_start_time)}", flush=True)
196
+ except Exception as e:
197
+ print(f"[UPTIME] Error loading uptime: {e}", flush=True)
198
+ server_start_time = None
199
+
200
+ def save_uptime_to_file():
201
+ """Save server start time to file"""
202
+ try:
203
+ os.makedirs(os.path.dirname(UPTIME_FILE), exist_ok=True)
204
+ with open(UPTIME_FILE, 'w') as f:
205
+ f.write(str(server_start_time))
206
+ except Exception as e:
207
+ print(f"[UPTIME] Error saving uptime: {e}", flush=True)
208
+
209
+ def add_log_line(line):
210
+ """Add a log line to history and save"""
211
+ global logs_history
212
+ timestamp = datetime.now().strftime('%H:%M:%S')
213
+ log_entry = f"[{timestamp}] {line}"
214
+ logs_history.append(log_entry)
215
+ # Keep only last 1000 lines
216
+ if len(logs_history) > 1000:
217
+ logs_history = logs_history[-1000:]
218
+ output_queue.put(log_entry)
219
+ # Save to file periodically (every 10 lines)
220
+ if len(logs_history) % 10 == 0:
221
+ save_logs_to_file()
222
+
223
  def start_minecraft():
224
+ global mc_process, server_start_time
225
  mc_dir = "/app/mcserver"
226
 
227
  print("[MC] Starting Minecraft server...", flush=True)
228
+ add_log_line("[SYSTEM] Starting Minecraft server...")
229
+
230
+ # Record start time
231
+ server_start_time = time.time()
232
+ save_uptime_to_file()
233
 
234
  mc_process = subprocess.Popen(
235
  ["java", "-Xms1G", "-Xmx14G", "-XX:+UseG1GC",
 
245
  )
246
 
247
  print(f"[MC] Minecraft PID: {mc_process.pid}", flush=True)
248
+ add_log_line(f"[SYSTEM] Minecraft server started with PID: {mc_process.pid}")
249
 
250
  def read_output():
251
  try:
252
  for line in mc_process.stdout:
253
+ line = line.rstrip()
254
+ add_log_line(line)
255
  if "Done" in line and "For help, type" in line:
256
  server_ready.set()
257
  print("[MC] Server is ready!", flush=True)
258
+ add_log_line("[SYSTEM] Server is ready!")
259
  except Exception as e:
260
  print(f"[MC] Output error: {e}", flush=True)
261
+ add_log_line(f"[ERROR] Output reader error: {e}")
262
 
263
  threading.Thread(target=read_output, daemon=True).start()
264
 
 
271
  mc_process.stdin.write(cmd + "\n")
272
  mc_process.stdin.flush()
273
  print(f"[MC] Command: {cmd}", flush=True)
274
+ add_log_line(f"> {cmd}")
275
  except Exception as e:
276
  print(f"[MC] Command error: {e}", flush=True)
277
  except queue.Empty:
 
302
  touch-action: manipulation;
303
  }
304
 
 
 
305
  /* Top Navigation */
306
  .top-nav {
307
  background: #252a30;
 
455
  .terminal-line.warn { color: #d29922; }
456
  .terminal-line.error { color: #f85149; }
457
  .terminal-line.success { color: #3fb950; }
458
+ .terminal-line.system { color: #a855f7; font-weight: 500; }
459
 
460
  /* Command Input Area */
461
  .command-area {
 
956
  let ws = null;
957
  let reconnectAttempts = 0;
958
  let maxReconnectAttempts = 10;
 
959
  let isServerRunning = false;
960
  let sidebarOpen = false;
961
+ let serverStartTime = null;
962
 
963
  function updateConnectionStatus(status, message) {
964
  connectionBar.className = 'connection-bar ' + status;
 
970
  connectionBar.innerHTML = '<i class="fas ' + icons[status] + '"></i><span>' + message + '</span>';
971
  }
972
 
973
+ function updateServerStatus(running, startTime = null) {
974
  isServerRunning = running;
975
  const statusEl = document.getElementById('serverStatus');
976
 
 
982
  stopBtn.disabled = false;
983
  commandInput.disabled = false;
984
  sendBtn.disabled = false;
985
+ if (startTime) {
986
+ serverStartTime = startTime * 1000; // Convert to milliseconds
987
+ }
988
  } else {
989
  statusEl.className = 'status-indicator status-offline';
990
  statusEl.innerHTML = '<span class="pulse"></span>Offline';
 
1000
  function addTerminalLine(text, type = '') {
1001
  const line = document.createElement('div');
1002
  line.className = 'terminal-line ' + type;
1003
+
1004
+ // Check if it's a system message
1005
+ if (text.includes('[SYSTEM]')) {
1006
+ line.className += ' system';
1007
+ } else if (text.includes('> ')) {
1008
+ line.className += ' info';
1009
+ } else if (text.toLowerCase().includes('error') || text.toLowerCase().includes('exception')) {
1010
+ line.className += ' error';
1011
+ } else if (text.toLowerCase().includes('warn')) {
1012
+ line.className += ' warn';
1013
+ } else if (text.toLowerCase().includes('done') || text.toLowerCase().includes('success')) {
1014
+ line.className += ' success';
1015
+ }
1016
+
1017
  line.textContent = text;
1018
  terminal.appendChild(line);
1019
  terminal.scrollTop = terminal.scrollHeight;
 
1024
  }
1025
  }
1026
 
1027
+ function formatUptime(seconds) {
1028
+ if (!seconds || seconds <= 0) return 'Offline';
1029
+
1030
+ const days = Math.floor(seconds / 86400);
1031
+ const hours = Math.floor((seconds % 86400) / 3600);
1032
+ const minutes = Math.floor((seconds % 3600) / 60);
1033
+ const secs = Math.floor(seconds % 60);
1034
+
1035
+ if (days > 0) return days + 'd ' + hours + 'h ' + minutes + 'm';
1036
+ if (hours > 0) return hours + 'h ' + minutes + 'm ' + secs + 's';
1037
+ if (minutes > 0) return minutes + 'm ' + secs + 's';
1038
+ return secs + 's';
1039
  }
1040
 
1041
  function updateUptime() {
1042
  if (serverStartTime && isServerRunning) {
1043
+ const now = Date.now();
1044
+ const uptime = Math.floor((now - serverStartTime) / 1000);
1045
  document.getElementById('uptime').textContent = formatUptime(uptime);
1046
  document.getElementById('uptimeSub').textContent = 'Running';
1047
  } else {
 
1067
  const data = JSON.parse(event.data);
1068
 
1069
  if (data.type === 'output') {
1070
+ addTerminalLine(data.data);
1071
  } else if (data.type === 'stats') {
1072
  document.getElementById('cpuLoad').textContent = data.cpu.toFixed(1) + '%';
1073
  document.getElementById('memoryUsage').textContent = data.memory.toFixed(1) + '%';
1074
  const memTotal = (data.memoryTotal / 1024 / 1024 / 1024).toFixed(2);
1075
  const memUsed = ((data.memoryTotal * data.memory / 100) / 1024 / 1024 / 1024).toFixed(2);
1076
  document.getElementById('memorySub').textContent = memUsed + ' / ' + memTotal + ' GB';
1077
+
1078
+ updateServerStatus(data.running, data.serverStartTime);
1079
+
1080
  if (data.players !== undefined) {
1081
  document.getElementById('playerCount').textContent = data.players;
1082
  }
1083
+ } else if (data.type === 'history') {
1084
+ // Load history logs
1085
+ data.logs.forEach(log => {
1086
+ addTerminalLine(log);
1087
+ });
1088
  }
1089
  };
1090
 
 
1109
  const cmd = commandInput.value.trim();
1110
  if (cmd && ws && ws.readyState === WebSocket.OPEN) {
1111
  ws.send(JSON.stringify({type: 'command', data: cmd}));
 
1112
  commandInput.value = '';
1113
  }
1114
  }
 
1116
  function sendCmd(cmd) {
1117
  if (ws && ws.readyState === WebSocket.OPEN) {
1118
  ws.send(JSON.stringify({type: 'command', data: cmd}));
 
1119
  }
1120
  }
1121
 
 
1187
  }, false);
1188
 
1189
  document.getElementById('serverAddress').textContent = window.location.hostname;
1190
+ addTerminalLine('[SYSTEM] Connecting to Minecraft server...', 'system');
1191
  </script>
1192
  </body>
1193
  </html>
 
1206
 
1207
  @sock.route('/ws')
1208
  def websocket(ws):
1209
+ global server_start_time
1210
  print("[WS] Client connected", flush=True)
1211
 
1212
+ # Send history logs first
1213
+ try:
1214
+ if logs_history:
1215
+ ws.send(json.dumps({
1216
+ 'type': 'history',
1217
+ 'logs': logs_history[-100:] # Send last 100 lines
1218
+ }))
1219
+ except Exception as e:
1220
+ print(f"[WS] History send error: {e}", flush=True)
 
 
 
 
 
 
 
 
 
 
1221
 
1222
  def send_stats():
1223
  while True:
 
1226
  memory = psutil.virtual_memory()
1227
  running = mc_process is not None and mc_process.poll() is None
1228
 
1229
+ # Calculate actual uptime from server_start_time
1230
+ uptime_to_send = None
1231
+ if running and server_start_time:
1232
+ uptime_to_send = server_start_time
1233
+
1234
  ws.send(json.dumps({
1235
  'type': 'stats',
1236
  'cpu': cpu,
1237
  'memory': memory.percent,
1238
  'memoryTotal': memory.total,
1239
  'running': running,
1240
+ 'serverStartTime': uptime_to_send,
1241
  'players': 0
1242
  }))
1243
  except Exception as e:
 
1285
 
1286
  def cleanup(signum=None, frame=None):
1287
  print("\n[MAIN] Shutting down...", flush=True)
1288
+ save_logs_to_file()
1289
  if mc_process:
1290
  try:
1291
  mc_process.stdin.write("stop\n")
 
1302
  signal.signal(signal.SIGINT, cleanup)
1303
 
1304
  if __name__ == '__main__':
1305
+ # Load previous logs and uptime
1306
+ load_logs_from_file()
1307
+ load_uptime_from_file()
1308
+
1309
  print("[MAIN] Starting web server...", flush=True)
1310
 
1311
  # Start Minecraft immediately
1312
  mc_thread = threading.Thread(target=start_minecraft, daemon=True)
1313
  mc_thread.start()
1314
 
1315
+ # Start GitHub push thread (every 5 minutes)
1316
+ def github_push_loop():
1317
+ while True:
1318
+ time.sleep(300)
1319
+ push_logs_to_github()
1320
+
1321
+ github_thread = threading.Thread(target=github_push_loop, daemon=True)
1322
+ github_thread.start()
1323
+
1324
  from werkzeug.serving import run_simple
1325
  run_simple('0.0.0.0', 7860, app, threaded=True, use_reloader=False)
1326
  PYTHON_SCRIPT
 
1339
 
1340
  echo ""
1341
  echo "=========================================="
1342
+ echo "✅ Minecraft Server with Fixed Uptime + Persistent Logs is LIVE!"
1343
  echo "🌐 Access at: https://your-space.hf.space"
1344
  echo "📱 Mobile optimized interface enabled"
1345
+ echo "💾 Logs are now persistent across refreshes"
1346
+ echo "⏰ Uptime tracking fixed"
1347
  echo "=========================================="
1348
 
1349
  # Keep container alive