fastdl
This commit is contained in:
parent
31a2ac82d0
commit
bcf798a5f9
4
.env
4
.env
@ -30,6 +30,10 @@ SRCDS_MAPCYCLE="mapcycle.txt"
|
||||
|
||||
SRCDS_ADMINS="STEAM_1:1:12270329"
|
||||
|
||||
# ----------
|
||||
# fastdl
|
||||
FASTDL_URL=https://fastdl.megastructure.surf
|
||||
|
||||
# ----------
|
||||
# mariadb
|
||||
MARIADB_ROOT_PASSWORD="surfsup"
|
||||
|
||||
@ -24,6 +24,7 @@ services:
|
||||
- ./etc:/home/steam/etc
|
||||
- ./data/cssds:/home/steam/cssds
|
||||
- tf2ds:/home/steam/tf2ds
|
||||
- fastdl-maps:/fastdl/maps:ro
|
||||
|
||||
db:
|
||||
image: mariadb:12
|
||||
@ -47,8 +48,8 @@ services:
|
||||
# Mount credentials (read-only)
|
||||
- ./src/mapsdl/credentials:/app/credentials:ro
|
||||
|
||||
# Mount maps directory (read-write)
|
||||
- ./data/cssds/cstrike/maps:/maps
|
||||
# Output bz2 files to shared FastDL volume
|
||||
- fastdl-maps:/maps
|
||||
|
||||
environment:
|
||||
- MAPS_DIR=/maps
|
||||
@ -62,5 +63,13 @@ services:
|
||||
# Run once and exit
|
||||
restart: "no"
|
||||
|
||||
fastdl:
|
||||
build: ./src/fastdl
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- fastdl-maps:/srv/maps:ro
|
||||
|
||||
volumes:
|
||||
tf2ds:
|
||||
fastdl-maps:
|
||||
|
||||
1
etc/cfg/mapcycle.txt
Normal file
1
etc/cfg/mapcycle.txt
Normal file
@ -0,0 +1 @@
|
||||
surf_boreas
|
||||
51
etc/run.sh
51
etc/run.sh
@ -451,6 +451,55 @@ EOF
|
||||
cfg() {
|
||||
cd
|
||||
cp etc/cfg/server.cfg cssds/cstrike/cfg/
|
||||
cp etc/cfg/mapcycle.txt cssds/cstrike/cfg/
|
||||
sed -i "s|sv_downloadurl .*|sv_downloadurl \"${FASTDL_URL:-}/cstrike/\"|" "$CSTRIKE/cfg/server.cfg"
|
||||
}
|
||||
|
||||
populate_maps() {
|
||||
local BZ2_DIR="/fastdl/maps"
|
||||
local MAPS_DIR="$CSTRIKE/maps"
|
||||
local MAPCYCLE="$CSTRIKE/cfg/mapcycle.txt"
|
||||
|
||||
echo "--------------------------------------------------------------"
|
||||
echo "Populating maps from compressed archive"
|
||||
echo "--------------------------------------------------------------"
|
||||
|
||||
if [ ! -f "$MAPCYCLE" ]; then
|
||||
echo "No mapcycle.txt found, skipping map population"
|
||||
echo "--------------------------------------------------------------"
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p "$MAPS_DIR"
|
||||
|
||||
local total=0 skipped=0 extracted=0 missing=0
|
||||
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
# skip empty lines and comments
|
||||
line=$(echo "$line" | sed 's|//.*||' | xargs)
|
||||
[ -z "$line" ] && continue
|
||||
|
||||
total=$((total + 1))
|
||||
local bz2="$BZ2_DIR/${line}.bsp.bz2"
|
||||
local bsp="$MAPS_DIR/${line}.bsp"
|
||||
|
||||
if [ -f "$bsp" ]; then
|
||||
skipped=$((skipped + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ ! -f "$bz2" ]; then
|
||||
missing=$((missing + 1))
|
||||
echo " [!] ${line}: not in fastdl volume"
|
||||
continue
|
||||
fi
|
||||
|
||||
bunzip2 -c "$bz2" > "$bsp"
|
||||
extracted=$((extracted + 1))
|
||||
done < "$MAPCYCLE"
|
||||
|
||||
echo "Maps: $total in mapcycle, $extracted extracted, $skipped already present, $missing not available"
|
||||
echo "--------------------------------------------------------------"
|
||||
}
|
||||
|
||||
|
||||
@ -482,6 +531,8 @@ main() {
|
||||
# Zones will be available after server starts and creates tables
|
||||
import_zone_data
|
||||
|
||||
populate_maps
|
||||
|
||||
run_cssds
|
||||
}
|
||||
|
||||
|
||||
2
src/fastdl/Dockerfile
Normal file
2
src/fastdl/Dockerfile
Normal file
@ -0,0 +1,2 @@
|
||||
FROM nginx:alpine
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
8
src/fastdl/nginx.conf
Normal file
8
src/fastdl/nginx.conf
Normal file
@ -0,0 +1,8 @@
|
||||
server {
|
||||
listen 80;
|
||||
root /srv;
|
||||
location /cstrike/maps/ {
|
||||
alias /srv/maps/;
|
||||
autoindex off;
|
||||
}
|
||||
}
|
||||
@ -156,8 +156,8 @@ export async function getLocalMaps(mapsDir: string): Promise<Set<string>> {
|
||||
|
||||
try {
|
||||
for await (const entry of Deno.readDir(mapsDir)) {
|
||||
if (entry.isFile && entry.name.endsWith(".bsp")) {
|
||||
const mapName = entry.name.replace(/\.bsp$/, "");
|
||||
if (entry.isFile && entry.name.endsWith(".bsp.bz2")) {
|
||||
const mapName = entry.name.replace(/\.bsp\.bz2$/, "");
|
||||
localMaps.add(mapName);
|
||||
}
|
||||
}
|
||||
@ -317,29 +317,32 @@ export async function downloadAndExtractMaps(
|
||||
console.log(`[${completed}/${mapsToDownload.size}] Downloading ${mapName}...`);
|
||||
|
||||
const archivePath = join(config.tempDir, gdriveFile.name);
|
||||
const bspPath = join(config.mapsDir, `${mapName}.bsp`);
|
||||
const tempBspPath = join(config.tempDir, `${mapName}.bsp`);
|
||||
const bz2Path = join(config.mapsDir, `${mapName}.bsp.bz2`);
|
||||
|
||||
await client.downloadFile(gdriveFile.id, archivePath);
|
||||
|
||||
if (gdriveFile.name.endsWith(".rar")) {
|
||||
await extractRAR(archivePath, mapName, config.mapsDir, config.tempDir);
|
||||
await extractRAR(archivePath, mapName, config.tempDir, config.tempDir);
|
||||
await Deno.remove(archivePath);
|
||||
} else if (gdriveFile.name.endsWith(".bz2")) {
|
||||
await decompressBZ2(archivePath, bspPath);
|
||||
await decompressBZ2(archivePath, tempBspPath);
|
||||
await Deno.remove(archivePath);
|
||||
} else if (gdriveFile.name.endsWith(".zip")) {
|
||||
await extractZIP(archivePath, mapName, config.mapsDir, config.tempDir);
|
||||
await extractZIP(archivePath, mapName, config.tempDir, config.tempDir);
|
||||
await Deno.remove(archivePath);
|
||||
} else if (gdriveFile.name.endsWith(".bsp")) {
|
||||
await moveFile(archivePath, bspPath);
|
||||
await moveFile(archivePath, tempBspPath);
|
||||
} else {
|
||||
throw new Error(`Unknown archive format: ${gdriveFile.name}`);
|
||||
}
|
||||
|
||||
await verifyBSP(bspPath);
|
||||
await verifyBSP(tempBspPath);
|
||||
await compressBSP(tempBspPath, bz2Path);
|
||||
await Deno.remove(tempBspPath);
|
||||
|
||||
stats.success++;
|
||||
console.log(` [OK] ${mapName} downloaded and extracted`);
|
||||
console.log(` [OK] ${mapName} downloaded and compressed`);
|
||||
} catch (error) {
|
||||
stats.failed++;
|
||||
console.error(` [X] Failed to download ${mapName}: ${(error as Error).message}`);
|
||||
@ -459,3 +462,13 @@ export async function verifyBSP(bspPath: string): Promise<void> {
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
export async function compressBSP(bspPath: string, bz2Path: string): Promise<void> {
|
||||
const process = new Deno.Command("bzip2", {
|
||||
args: ["-c", bspPath],
|
||||
stdout: "piped",
|
||||
});
|
||||
const { code, stdout } = await process.output();
|
||||
if (code !== 0) throw new Error(`bzip2 failed with exit code ${code}`);
|
||||
await Deno.writeFile(bz2Path, stdout);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user