Admin: Spieldateien auf allen Hosts per SteamCMD aktualisieren, mit Prozentanzeige
Ein kurzlebiger Container je Host aktualisiert CS2 im Spieldateien-Volume. Hosts mit laufenden Servern werden ausgelassen (erzwingbar), während des Updates startet dort kein neuer Server. Fertig nur, wenn Steam die App als vollständig installiert meldet.
This commit is contained in:
1 parent
2c57b8c170
commit
3c5a9b4162
7 files changed
+281
-5
No files matched your search
@@ -685,13 +685,15 @@ function DockerHostsPanel({ token, setNotice }) {
|
||||
|
||||
// Während das Image lädt, alle 3 Sekunden den Stand holen (ohne die bearbeiteten Zeilen zu überschreiben)
|
||||
const pulling = !!data?.pull?.running;
|
||||
const updating = !!data?.files?.running;
|
||||
const [forceFiles, setForceFiles] = useState(false);
|
||||
useEffect(() => {
|
||||
if (!pulling) return undefined;
|
||||
if (!pulling && !updating) return undefined;
|
||||
const timer = setInterval(() => {
|
||||
load().then((res) => setData((d) => ({ ...d, pull: res.pull }))).catch(() => {});
|
||||
load().then((res) => setData((d) => ({ ...d, pull: res.pull, files: res.files }))).catch(() => {});
|
||||
}, 3000);
|
||||
return () => clearInterval(timer);
|
||||
}, [pulling, load]);
|
||||
}, [pulling, updating, load]);
|
||||
|
||||
if (!data) return null;
|
||||
if (!data.editable) {
|
||||
@@ -742,6 +744,14 @@ function DockerHostsPanel({ token, setNotice }) {
|
||||
run(() => api('/admin/docker-hosts', { method: 'DELETE', token }), 'Hosts aus der .env aktiv');
|
||||
};
|
||||
|
||||
const updateFiles = () => {
|
||||
const warn = forceFiles
|
||||
? 'Spieldateien auf ALLEN Hosts aktualisieren, auch wo Server laufen? Laufende Server können dabei abstürzen.'
|
||||
: 'Spieldateien auf allen Hosts ohne laufende Server aktualisieren?';
|
||||
if (!window.confirm(warn)) return;
|
||||
run(() => api('/admin/docker-hosts/update-files', { method: 'POST', body: { force: forceFiles }, token }));
|
||||
};
|
||||
|
||||
const pull = () => {
|
||||
if (!window.confirm(`Image ${data.image} auf allen Hosts neu laden? Laufende Server laufen weiter.`)) return;
|
||||
run(() => api('/admin/docker-hosts/pull', { method: 'POST', token }));
|
||||
@@ -799,9 +809,51 @@ function DockerHostsPanel({ token, setNotice }) {
|
||||
)}
|
||||
</ul>
|
||||
)}
|
||||
|
||||
<h3>Spieldateien aktualisieren</h3>
|
||||
<p className="small muted">
|
||||
Holt das neueste CS2-Update per SteamCMD in das Volume jedes Hosts. Das Image-Update oben reicht dafür nicht.
|
||||
Hosts mit laufenden Servern werden ausgelassen, damit niemandem die Dateien unter dem laufenden Server ausgetauscht werden.
|
||||
Bestehende Server nutzen die neuen Dateien erst nach einem Neustart.
|
||||
</p>
|
||||
<div className="admin-actions">
|
||||
<button className="btn btn-sm btn-primary" disabled={busy || updating || dirty} onClick={updateFiles}>
|
||||
{updating ? filesLabel(data.files) : 'Spieldateien aktualisieren'}
|
||||
</button>
|
||||
<label className="admin-check small">
|
||||
<input type="checkbox" checked={forceFiles} onChange={(e) => setForceFiles(e.target.checked)} disabled={updating} />
|
||||
auch Hosts mit laufenden Servern
|
||||
</label>
|
||||
</div>
|
||||
{data.files?.results?.length > 0 && (
|
||||
<ul className="pull-results">
|
||||
{data.files.results.map((r) => (
|
||||
<li key={r.name} className={`pull-${r.state === 'skipped' ? 'skipped' : r.state}`}>
|
||||
<strong>{r.name}</strong>
|
||||
<span>{r.state === 'running' ? 'läuft' : r.state === 'ok' ? 'fertig' : r.state === 'skipped' ? 'ausgelassen' : 'fehlgeschlagen'}</span>
|
||||
{r.message && <code className="small">{r.message}</code>}
|
||||
{r.state === 'running' && r.progress != null && (
|
||||
<span className="files-bar" role="progressbar" aria-valuenow={Math.round(r.progress)} aria-valuemin={0} aria-valuemax={100}>
|
||||
<i style={{ width: `${Math.min(100, r.progress)}%` }} />
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
{data.files.finishedAt && (
|
||||
<li className="small muted">Zuletzt fertig: {new Date(data.files.finishedAt).toLocaleString('de-DE')}</li>
|
||||
)}
|
||||
</ul>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
/** Knopftext während des Spieldateien-Updates: "Update läuft 43 %" (niedrigster Stand der laufenden Hosts) */
|
||||
function filesLabel(files) {
|
||||
const running = files?.results?.filter((r) => r.state === 'running') ?? [];
|
||||
const known = running.filter((r) => r.progress != null).map((r) => r.progress);
|
||||
return known.length ? `Update läuft ${Math.floor(Math.min(...known))} %` : 'Update läuft …';
|
||||
}
|
||||
|
||||
/** Datum und Uhrzeit auf Deutsch, z. B. 29.10.2026, 12:54 Uhr */
|
||||
function formatDateTime(ms) {
|
||||
return `${new Date(ms).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' })} Uhr`;
|
||||
|
||||
Reference in new issue
Block a user