Update Platforms #390

Merged
Sirherobrine23 merged 10 commits from StashCode into main 2022-06-09 20:22:38 +00:00
53 changed files with 1107 additions and 1170 deletions

View File

@ -1,12 +1,18 @@
FROM debian:latest
ENV DEBIAN_FRONTEND="noninteractive"
RUN \
apt update && \
apt install -y git curl wget sudo procps zsh tar screen ca-certificates procps lsb-release xdg-utils g++ libatomic1 libnss3 libatk-bridge2.0-0 gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxrandr2 libxrender1 libxss1 libxtst6 fonts-liberation libnss3 libgbm-dev
ARG DEBIAN_FRONTEND="noninteractive"
RUN apt update && apt install -y git curl wget sudo procps zsh tar screen ca-certificates procps lsb-release xdg-utils g++ gconf-service gpg
# Install node.js
RUN wget $(wget -qO- https://api.github.com/repos/Sirherobrine23/DebianNodejsFiles/releases | grep 'browser_download_url' | grep "$(dpkg --print-architecture)" | cut -d '"' -f 4 | sort | uniq | tail -n 1) -q -O /tmp/nodejs.deb && dpkg -i /tmp/nodejs.deb && rm -rfv /tmp/nodejs.deb && npm install -g npm@latest
# Install Docker and Docker Compose
VOLUME [ "/var/lib/docker" ]
RUN wget -qO- https://get.docker.com | sh && \
wget -q $(wget -qO- https://api.github.com/repos/docker/compose/releases | grep 'browser_download_url' | grep -v '.sha' | grep $(uname -s) | grep $(uname -m) | cut -d '"' -f 4 | sort | tail -n1)\
-O /usr/local/bin/docker-compose && chmod +x -v /usr/local/bin/docker-compose
# Install openjdk
RUN \
apt update && \
RUN apt update && \
JAVAVERSIONS="$(apt search openjdk|grep '/'|grep 'openjdk-'|sed 's|/| |g'|awk '{print $1}'|grep 'jre'|sed -e 's|-jre.*||g'|uniq)";\
case $JAVAVERSIONS in \
*17* ) apt install -y openjdk-17*;; \
@ -14,61 +20,55 @@ RUN \
*) echo "Unsupported Java Version, avaibles"; echo "$JAVAVERSIONS";exit 0;; \
esac
# Install latest node
RUN VERSION=$(wget -qO- https://api.github.com/repos/Sirherobrine23/DebianNodejsFiles/releases/latest |grep 'name' | grep "nodejs"|grep "$(dpkg --print-architecture)"|cut -d '"' -f 4 | sed 's|nodejs_||g' | sed -e 's|_.*.deb||g'|sort | uniq|tail -n 1); wget -q "https://github.com/Sirherobrine23/DebianNodejsFiles/releases/download/debs/nodejs_${VERSION}_$(dpkg --print-architecture).deb" -O /tmp/nodejs.deb && dpkg -i /tmp/nodejs.deb && rm -rfv /tmp/nodejs.deb && npm install -g npm@latest
# Install Docker and Docker Compose
RUN curl https://get.docker.com | sh && \
compose_version="$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep tag_name | cut -d \" -f 4)"; \
wget -q https://github.com/docker/compose/releases/download/${compose_version}/docker-compose-`uname -s`-`uname -m` -O /usr/local/bin/docker-compose && \
chmod +x -v /usr/local/bin/docker-compose
VOLUME [ "/var/lib/docker" ]
# Create docker and minikube start script
ARG DOCKERD_ARGS="--experimental"
RUN (echo '#''!/bin/bash';\
echo 'EXISTDOCKER="1"';\
echo "if command -v dockerd &> /dev/null; then";\
echo ' if ! [[ -f "/var/run/docker.sock" ]];then';\
echo " (sudo dockerd ${DOCKERD_ARGS}) &";\
echo " sleep 5s";\
echo " fi";\
echo "else";\
echo ' EXISTDOCKER="0"';\
echo "fi";\
echo "";\
echo "# Run script";\
echo 'if ! [[ -z "\$@" ]]; then';\
echo ' sh -c "\$@"';\
echo "fi";\
echo "";\
echo "# Check docker is running";\
echo 'if [[ "\${EXISTDOCKER}" == "0" ]];then';\
echo " while true; do";\
echo " if ! (docker info &> /dev/null) || ps -ef | grep -v grep | grep -q dockerd; then";\
echo ' echo "Dockerd stopped"';\
echo " break";\
echo " fi";\
echo " sleep 4s";\
echo " done";\
echo "fi";\
echo "";\
echo "# Sleep script";\
echo "sleep infinity";\
echo "exit") | tee /usr/local/bin/start.sh && chmod a+x /usr/local/bin/start.sh
# Add non root user
ARG USERNAME=gitpod
ARG USER_UID=1000
ARG USERNAME="devcontainer"
ARG USER_UID="1000"
ARG USER_GID=$USER_UID
RUN \
groupadd --gid $USER_GID $USERNAME && \
RUN groupadd --gid $USER_GID $USERNAME && \
adduser --disabled-password --gecos "" --shell /usr/bin/zsh --uid $USER_UID --gid $USER_GID $USERNAME && \
usermod -aG sudo $USERNAME && echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/$USERNAME && \
chmod 0440 /etc/sudoers.d/$USERNAME && \
usermod -aG docker $USERNAME
chmod 0440 /etc/sudoers.d/$USERNAME && usermod -aG docker $USERNAME
USER $USERNAME
WORKDIR /home/$USERNAME
CMD [ "/usr/bin/zsh" ]
# Set default entrypoint
ENTRYPOINT [ "/usr/local/bin/start.sh" ]
# Install oh my zsh
RUN yes | sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" && \
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ~/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting && \
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions && \
sed -e 's|ZSH_THEME=".*"|ZSH_THEME="strug"|g' -i ~/.zshrc && \
sed -e 's|plugins=(.*)|plugins=(git docker zsh-syntax-highlighting zsh-autosuggestions)|g' -i ~/.zshrc
# Create Start Script
ENV DOCKERD_ARGS=""
RUN (\
echo '#''!/bin/bash';\
echo "set -e";\
echo 'if ! [[ -f "/var/run/docker.sock" ]];then';\
echo " (sudo dockerd ${DOCKERD_ARGS}) &";\
echo "fi";\
echo 'if ! [[ -z "$@" ]]; then';\
echo ' sh -c "$@"';\
echo "fi";\
echo "";\
echo "while true; do";\
echo " if ps -ef | grep -v grep | grep -q dockerd; then";\
echo ' echo "Docker daemon is running"';\
echo " elif docker info &> /dev/null; then";\
echo ' echo "Docker daemon is running"';\
echo " else";\
echo " break";\
echo " fi";\
echo " sleep 4s";\
echo "done";\
echo "";\
echo "echo Dockerd stopped";\
echo "exit 2")|sudo tee /usr/local/bin/start.sh && sudo chmod +x /usr/local/bin/start.sh
ENTRYPOINT [ "/usr/local/bin/start.sh" ]
sed -e 's|ZSH_THEME=".*"|ZSH_THEME="strug"|g' -i ~/.zshrc && sed -e 's|plugins=(.*)|plugins=(git docker zsh-syntax-highlighting zsh-autosuggestions)|g' -i ~/.zshrc

View File

@ -1,3 +0,0 @@
node_modules/
.git/
dist/

14
.github/FUNDING.yml vendored
View File

@ -1,14 +1,2 @@
# These are supported funding model platforms
github:
- Sirherobrine23
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
- Sirherobrine23

View File

@ -23,19 +23,13 @@ jobs:
node-version: "${{ matrix.node_version }}.x"
- name: Install latest java
env:
DEBIAN_FRONTEND: "noninteractive"
run: |
sudo apt update
JAVAVERSIONS="$(sudo apt search openjdk|grep '/'|grep 'openjdk-'|sed 's|/| |g'|awk '{print $1}'|grep 'jre'|sed -e 's|-jre.*||g'|uniq)"
case $JAVAVERSIONS in
*17* ) sudo apt install -y openjdk-17-*headless;;
*16* ) sudo apt install -y openjdk-16-*headless;;
*) echo "Unsupported Java Version, avaibles"; echo "$JAVAVERSIONS";exit 0;;
esac
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: "17"
- name: Install node depencies
run: npm ci
- name: Test
run: npm run test:host -- --exit-on-error --show-return
run: npm run test -- --show-log

View File

@ -1,7 +1,22 @@
{
"recommendations": [
"github.copilot",
"formulahendry.code-runner",
"chrmarti.regex"
"chrmarti.regex",
"benshabatnoam.google-translate-ext",
"eamodio.gitlens",
"github.vscode-pull-request-github",
"visualstudioexptteam.vscodeintellicode",
"redhat.vscode-yaml",
"ms-vscode-remote.remote-containers",
"wix.vscode-import-cost",
"eg2.vscode-npm-script",
"christian-kohler.npm-intellisense",
"christian-kohler.path-intellisense",
"aaron-bond.better-comments",
"vscode-icons-team.vscode-icons",
"me-dutour-mathieu.vscode-github-actions",
"cschleiden.vscode-github-actions",
"oderwat.indent-rainbow",
"ms-azuretools.vscode-docker"
]
}

16
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Bds Test",
"type": "node",
"request": "launch",
"runtimeExecutable": "node",
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
"args": ["testProject.ts"],
"cwd": "${workspaceRoot}",
"internalConsoleOptions": "openOnSessionStart",
"skipFiles": ["<node_internals>/**", "node_modules/**"]
}
]
}

View File

@ -1,6 +1,11 @@
{
"files.eol": "\n",
"editor.tabSize": 2,
"files.encoding": "utf8",
"files.defaultLanguage": "typescript",
"editor.minimap.enabled": false,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"files.exclude": {
"**/dist/": true,
"**/node_modules/": true

View File

@ -1,8 +1,14 @@
# Hello little programmers!
# Contributing to Core Core for server management and events
Bds Manager Core accepts contributions provided that
- Be a fork of the repository
- have the latest repository modifications applied to the repository in the `main` branch
- to add a platform to the project, maintaining scripts
Read Code of Conduct fist!
[Bds Manager Core code of conduct](CODE_OF_CONDUCT.md)
[Bds Manager Core code of conduct](CODE_OF_CONDUCT.md)
## TL;DR
[Add Platform](https://github.com/The-Bds-Maneger/Bds-Maneger-Core/wiki/Add-new-Platform-to-Core)
Bds Manager Core accepts contributions provided that:
* Be a fork of the repository.
* have the latest repository modifications applied to the repository in the `main` branch.
* to add a platform to the project, maintaining scripts.

314
package-lock.json generated
View File

@ -19,15 +19,13 @@
"adm-zip": "^0.5.9",
"axios": "^0.27.0",
"cron": "^2.0.0",
"dir-compare": "^4.0.0",
"fs-extra": "^10.0.1",
"mongoose": "^6.3.6",
"prismarine-nbt": "^2.2.1",
"simple-git": "^3.6.0",
"tar": "^6.1.11"
},
"devDependencies": {
"@types/adm-zip": "^0.5.0",
"@types/cli-color": "^2.0.2",
"@types/cron": "^2.0.0",
"@types/fs-extra": "^9.0.13",
"@types/node": "^17.0.22",
@ -94,40 +92,6 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@kwsites/file-exists": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
"integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
"dependencies": {
"debug": "^4.1.1"
}
},
"node_modules/@kwsites/file-exists/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/@kwsites/file-exists/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/@kwsites/promise-deferred": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
"integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw=="
},
"node_modules/@sindresorhus/is": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@ -205,12 +169,6 @@
"@types/node": "*"
}
},
"node_modules/@types/cli-color": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/cli-color/-/cli-color-2.0.2.tgz",
"integrity": "sha512-1ErQIcmNHtNViGKTtB/TIKqMkC2RkKI2nBneCr9hSCPo9H05g9VzjlaXPW3H0vaI8zFGjJZvSav+VKDKCtKgKA==",
"dev": true
},
"node_modules/@types/cron": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/cron/-/cron-2.0.0.tgz",
@ -463,7 +421,8 @@
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/base64-js": {
"version": "1.5.1",
@ -542,6 +501,7 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -565,9 +525,9 @@
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
},
"node_modules/bson": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/bson/-/bson-4.6.2.tgz",
"integrity": "sha512-VeJKHShcu1b/ugl0QiujlVuBepab714X9nNyBdA1kfekuDGecxgpTA2Z6nYbagrWFeiIyzSWIOzju3lhj+RNyQ==",
"version": "4.6.4",
"resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz",
"integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==",
"dependencies": {
"buffer": "^5.6.0"
},
@ -811,7 +771,8 @@
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"node_modules/configstore": {
"version": "5.0.1",
@ -1030,15 +991,6 @@
"node": ">=0.3.1"
}
},
"node_modules/dir-compare": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.0.0.tgz",
"integrity": "sha512-wC7thVKL3V656tO61rbEDE4LTeeYrUC2pAUL00AaXYghBhjjVNRyBlpH6POzb44ZuK23OSrqF6TbSC/QYeqfAg==",
"dependencies": {
"minimatch": "^3.0.4",
"p-limit": "^3.1.0 "
}
},
"node_modules/domexception": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
@ -1774,9 +1726,9 @@
}
},
"node_modules/ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
@ -2367,6 +2319,7 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
@ -2415,14 +2368,14 @@
}
},
"node_modules/mongodb": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.3.1.tgz",
"integrity": "sha512-sNa8APSIk+r4x31ZwctKjuPSaeKuvUeNb/fu/3B6dRM02HpEgig7hTHM8A/PJQTlxuC/KFWlDlQjhsk/S43tBg==",
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.5.0.tgz",
"integrity": "sha512-A2l8MjEpKojnhbCM0MK3+UOGUSGvTNNSv7AkP1fsT7tkambrkkqN/5F2y+PhzsV0Nbv58u04TETpkaSEdI2zKA==",
"dependencies": {
"bson": "^4.6.1",
"bson": "^4.6.2",
"denque": "^2.0.1",
"mongodb-connection-string-url": "^2.4.1",
"socks": "^2.6.1"
"mongodb-connection-string-url": "^2.5.2",
"socks": "^2.6.2"
},
"engines": {
"node": ">=12.9.0"
@ -2453,15 +2406,15 @@
}
},
"node_modules/mongoose": {
"version": "6.2.10",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.2.10.tgz",
"integrity": "sha512-Yp+6UH5M0AlxAVGdC2/Deq0St+2qW73oKCnhJDr83bOZ12eflTLTT5uQF0p6KzvtFj86XWbq/7ApvO4yW6h1sA==",
"version": "6.3.6",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.3.6.tgz",
"integrity": "sha512-/Cixfo+bA32EHQ5Y7sxMj5ZOXFiAFlvA3X4mFruUET9OsbJZfstg4n2FzxovX8Q7EcoQ7Ry1bnOp9AeXtodF7w==",
"dependencies": {
"bson": "^4.2.2",
"bson": "^4.6.2",
"kareem": "2.3.5",
"mongodb": "4.3.1",
"mpath": "0.8.4",
"mquery": "4.0.2",
"mongodb": "4.5.0",
"mpath": "0.9.0",
"mquery": "4.0.3",
"ms": "2.1.3",
"sift": "16.0.0"
},
@ -2479,17 +2432,17 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/mpath": {
"version": "0.8.4",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz",
"integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==",
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/mquery": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.2.tgz",
"integrity": "sha512-oAVF0Nil1mT3rxty6Zln4YiD6x6QsUWYz927jZzjMxOK2aqmhEz5JQ7xmrKK7xRFA2dwV+YaOpKU/S+vfNqKxA==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz",
"integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==",
"dependencies": {
"debug": "4.x"
},
@ -2843,20 +2796,6 @@
"node": ">=6"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dependencies": {
"yocto-queue": "^0.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/package-json": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
@ -3374,41 +3313,6 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
"node_modules/simple-git": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.7.1.tgz",
"integrity": "sha512-+Osjtsumbtew2y9to0pOYjNzSIr4NkKGBg7Po5SUtjQhaJf2QBmiTX/9E9cv9rmc7oUiSGFIB9e7ys5ibnT9+A==",
"dependencies": {
"@kwsites/file-exists": "^1.1.1",
"@kwsites/promise-deferred": "^1.1.1",
"debug": "^4.3.3"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/steveukx/"
}
},
"node_modules/simple-git/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/simple-git/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
@ -3443,7 +3347,7 @@
"node_modules/sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
"optional": true,
"dependencies": {
"memory-pager": "^1.0.2"
@ -4192,17 +4096,6 @@
"engines": {
"node": ">=6"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
},
"dependencies": {
@ -4253,34 +4146,6 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"@kwsites/file-exists": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
"integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
"requires": {
"debug": "^4.1.1"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"@kwsites/promise-deferred": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
"integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw=="
},
"@sindresorhus/is": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
@ -4349,12 +4214,6 @@
"@types/node": "*"
}
},
"@types/cli-color": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/cli-color/-/cli-color-2.0.2.tgz",
"integrity": "sha512-1ErQIcmNHtNViGKTtB/TIKqMkC2RkKI2nBneCr9hSCPo9H05g9VzjlaXPW3H0vaI8zFGjJZvSav+VKDKCtKgKA==",
"dev": true
},
"@types/cron": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/cron/-/cron-2.0.0.tgz",
@ -4563,7 +4422,8 @@
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"base64-js": {
"version": "1.5.1",
@ -4615,6 +4475,7 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -4635,9 +4496,9 @@
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
},
"bson": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/bson/-/bson-4.6.2.tgz",
"integrity": "sha512-VeJKHShcu1b/ugl0QiujlVuBepab714X9nNyBdA1kfekuDGecxgpTA2Z6nYbagrWFeiIyzSWIOzju3lhj+RNyQ==",
"version": "4.6.4",
"resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz",
"integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==",
"requires": {
"buffer": "^5.6.0"
}
@ -4806,7 +4667,8 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"configstore": {
"version": "5.0.1",
@ -4978,15 +4840,6 @@
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"dir-compare": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.0.0.tgz",
"integrity": "sha512-wC7thVKL3V656tO61rbEDE4LTeeYrUC2pAUL00AaXYghBhjjVNRyBlpH6POzb44ZuK23OSrqF6TbSC/QYeqfAg==",
"requires": {
"minimatch": "^3.0.4",
"p-limit": "^3.1.0 "
}
},
"domexception": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
@ -5518,9 +5371,9 @@
}
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
},
"ipaddr.js": {
"version": "1.9.1",
@ -5949,6 +5802,7 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -5982,15 +5836,15 @@
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
},
"mongodb": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.3.1.tgz",
"integrity": "sha512-sNa8APSIk+r4x31ZwctKjuPSaeKuvUeNb/fu/3B6dRM02HpEgig7hTHM8A/PJQTlxuC/KFWlDlQjhsk/S43tBg==",
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.5.0.tgz",
"integrity": "sha512-A2l8MjEpKojnhbCM0MK3+UOGUSGvTNNSv7AkP1fsT7tkambrkkqN/5F2y+PhzsV0Nbv58u04TETpkaSEdI2zKA==",
"requires": {
"bson": "^4.6.1",
"bson": "^4.6.2",
"denque": "^2.0.1",
"mongodb-connection-string-url": "^2.4.1",
"mongodb-connection-string-url": "^2.5.2",
"saslprep": "^1.0.3",
"socks": "^2.6.1"
"socks": "^2.6.2"
}
},
"mongodb-connection-string-url": {
@ -6014,15 +5868,15 @@
}
},
"mongoose": {
"version": "6.2.10",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.2.10.tgz",
"integrity": "sha512-Yp+6UH5M0AlxAVGdC2/Deq0St+2qW73oKCnhJDr83bOZ12eflTLTT5uQF0p6KzvtFj86XWbq/7ApvO4yW6h1sA==",
"version": "6.3.6",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.3.6.tgz",
"integrity": "sha512-/Cixfo+bA32EHQ5Y7sxMj5ZOXFiAFlvA3X4mFruUET9OsbJZfstg4n2FzxovX8Q7EcoQ7Ry1bnOp9AeXtodF7w==",
"requires": {
"bson": "^4.2.2",
"bson": "^4.6.2",
"kareem": "2.3.5",
"mongodb": "4.3.1",
"mpath": "0.8.4",
"mquery": "4.0.2",
"mongodb": "4.5.0",
"mpath": "0.9.0",
"mquery": "4.0.3",
"ms": "2.1.3",
"sift": "16.0.0"
},
@ -6035,14 +5889,14 @@
}
},
"mpath": {
"version": "0.8.4",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz",
"integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g=="
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
"integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew=="
},
"mquery": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.2.tgz",
"integrity": "sha512-oAVF0Nil1mT3rxty6Zln4YiD6x6QsUWYz927jZzjMxOK2aqmhEz5JQ7xmrKK7xRFA2dwV+YaOpKU/S+vfNqKxA==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz",
"integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==",
"requires": {
"debug": "4.x"
},
@ -6312,14 +6166,6 @@
"integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==",
"dev": true
},
"p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"requires": {
"yocto-queue": "^0.1.0"
}
},
"package-json": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
@ -6719,31 +6565,6 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
"simple-git": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.7.1.tgz",
"integrity": "sha512-+Osjtsumbtew2y9to0pOYjNzSIr4NkKGBg7Po5SUtjQhaJf2QBmiTX/9E9cv9rmc7oUiSGFIB9e7ys5ibnT9+A==",
"requires": {
"@kwsites/file-exists": "^1.1.1",
"@kwsites/promise-deferred": "^1.1.1",
"debug": "^4.3.3"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
@ -6767,7 +6588,7 @@
"sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
"integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
"optional": true,
"requires": {
"memory-pager": "^1.0.2"
@ -7321,11 +7142,6 @@
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
},
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
}
}
}

View File

@ -1,11 +1,21 @@
{
"name": "@the-bds-maneger/core",
"version": "3.0.2",
"description": "A very simple way to manage Minecraft servers",
"author": "Sirherobrine23",
"license": "AGPL-3.0-or-later",
"homepage": "https://sirherobrine23.org/Bds_Maneger_Project",
"private": false,
"publishConfig": {
"access": "public"
},
"version": "3.0.2",
"description": "A very simple way to manage Minecraft servers",
"maintainers": [
{
"name": "Matheus Sampaio Queiroga",
"email": "srherobrine20@gmail.com",
"url": "https://sirherobrine23.org"
}
],
"types": "./dist/dts/index.d.ts",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.mjs",
@ -16,42 +26,30 @@
"scripts": {
"dev": "nodemon",
"build": "run-s build:*",
"test:host": "node testProject.js",
"test": "docker build . -f test.Dockerfile",
"test": "ts-node testProject.ts",
"build:cjs": "tsc --outDir dist/cjs --module commonjs",
"build:esm": "tsc --outDir dist/esm --module es6 && node -e 'const fs = require(\"fs\");const path = require(\"path\");const read = (pathRe) => {for (const fileFolde of fs.readdirSync(pathRe)) {const filePath = path.join(pathRe, fileFolde);if (fs.statSync(filePath).isDirectory()) read(filePath);else {console.log(filePath, \"-->\", filePath.replace(/\\.js$/, \".mjs\"));fs.renameSync(filePath, filePath.replace(/\\.js$/, \".mjs\"));}}};read(\"dist/esm\");'"
},
"nodemonConfig": {
"delay": 2500,
"exec": "npm run test",
"ext": "json,ts",
"watch": [
"src/**/*",
"package.json",
"package-lock.json"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/The-Bds-Maneger/Bds-Maneger-Core.git"
},
"keywords": [
"minecraft",
"typescript",
"bds",
"bds-server",
"bds_maneger",
"bds-maneger",
"bds_project",
"minecraft",
"bedrock",
"java",
"pocketmine",
"server_mode",
"rest",
"typescript"
"spigot"
],
"author": "Sirherobrine23",
"license": "AGPL-3.0-or-later",
"bugs": {
"url": "https://github.com/The-Bds-Maneger/Bds-Maneger-Core/issues/new"
"url": "https://github.com/The-Bds-Maneger/Bds-Maneger-Core/issues/new",
"email": "support_bds@sirherobrine23.org"
},
"homepage": "https://docs.bdsmaneger.com/Bds Maneger core",
"engines": {
"node": ">=16.0.0"
},
@ -66,15 +64,13 @@
"adm-zip": "^0.5.9",
"axios": "^0.27.0",
"cron": "^2.0.0",
"dir-compare": "^4.0.0",
"fs-extra": "^10.0.1",
"mongoose": "^6.3.6",
"prismarine-nbt": "^2.2.1",
"simple-git": "^3.6.0",
"tar": "^6.1.11"
},
"devDependencies": {
"@types/adm-zip": "^0.5.0",
"@types/cli-color": "^2.0.2",
"@types/cron": "^2.0.0",
"@types/fs-extra": "^9.0.13",
"@types/node": "^17.0.22",
@ -83,5 +79,15 @@
"npm-run-all": "^4.1.5",
"ts-node": "^10.7.0",
"typescript": "^4.6.4"
},
"nodemonConfig": {
"delay": 2500,
"exec": "npm run test",
"ext": "json,ts",
"watch": [
"src/**/*",
"package.json",
"package-lock.json"
]
}
}
}

View File

@ -1,4 +0,0 @@
import * as bedrock from "./bedrock/install";
export default {bedrock};
export {bedrock};

View File

@ -1,107 +0,0 @@
import path from "node:path";
import fs, { promises as fsPromise } from "node:fs";
import simpleGit from "simple-git";
import { compare as compareDir } from "dir-compare";
import { backupRoot as backupFolderPath } from "../pathControl";
import { genericAddFiles } from "./root";
export type gitBackupOption = {
repoUrl?: string;
branch?: string;
Auth?: {
Username?: string;
PasswordToken: string
}
};
async function initGitRepo(RepoPath: string, options?: gitBackupOption): Promise<void> {
if (fs.existsSync(RepoPath)) {
if (fs.existsSync(path.join(RepoPath, ".git"))) {
if (!(!!options?.Auth?.Username || !!options?.Auth?.PasswordToken)) return;
// remove old origin
const gitRe = simpleGit(RepoPath);
const urlParsed = new URL(options?.repoUrl);
const remotes = await gitRe.getRemotes(true);
let gitUrl = options.repoUrl;
if (options?.Auth?.Username || options?.Auth?.PasswordToken) {
if (options.Auth?.Username && options.Auth?.PasswordToken) {
if (options.Auth?.PasswordToken.startsWith("ghp_")) options.Auth.Username = "oauth2";
const urlParse = new URL(gitUrl);
gitUrl = `${urlParse.protocol}//${options.Auth.Username}:${options.Auth.PasswordToken}@${urlParse.host}${urlParse.pathname}`;
}
}
for (const remote of remotes) {
if (remote.refs.fetch.includes(urlParsed.hostname) && remote.refs.push.includes(urlParsed.hostname)) {
await gitRe.removeRemote(remote.name);
await gitRe.addRemote(remote.name, gitUrl);
}
}
}
}
await fsPromise.mkdir(RepoPath, {recursive: true});
if (options) {
if (options.repoUrl) {
let gitUrl = options.repoUrl;
if (options?.Auth?.Username || options?.Auth?.PasswordToken) {
if (options.Auth?.Username && options.Auth?.PasswordToken) {
if (options.Auth?.PasswordToken.startsWith("ghp_")) options.Auth.Username = "oauth2";
const urlParse = new URL(gitUrl);
gitUrl = `${urlParse.protocol}//${options.Auth.Username}:${options.Auth.PasswordToken}@${urlParse.host}${urlParse.pathname}`;
}
}
const gitClone = simpleGit(RepoPath);
await gitClone.clone(gitUrl, RepoPath);
if (options.branch) await gitClone.checkout(options.branch);
} else {
console.log("No Repo Url, creating empty repo");
await initGitRepo(RepoPath);
return;
}
} else {
// Create empty git repo and create main branch
const gitInit = simpleGit(RepoPath);
await gitInit.init()
// Create main branch
await gitInit.checkoutBranch("main", "master");
}
const git = simpleGit(RepoPath);
if (!!(await git.getConfig("user.email"))) await git.addConfig("user.email", "support_bds@sirherobrine23.org");
if (!!(await git.getConfig("user.name"))) await git.addConfig("user.name", "BDS-Backup");
return;
}
/**
* Create a backup in the git repository and push it to the remote if is authenticated (in each commit all existing files will be deleted).
*
* @param options - Config git repository
*/
export async function gitBackup(options?: gitBackupOption): Promise<void>{
const gitFolder = path.join(backupFolderPath, "gitBackup");
await initGitRepo(gitFolder, options);
const TempFiles = await genericAddFiles();
const git = simpleGit(gitFolder, {baseDir: gitFolder});
await git.stash();
await git.pull();
const Difff = (await compareDir(TempFiles.tempFolderPath, gitFolder, {excludeFilter: ".git"})).diffSet.filter(a => a.type1 === "missing"||a.type2 === "missing").filter(a => a.type1 === "file"||a.type2 === "file");
await Promise.all(Difff.map(async file => {
// Delete files
const FileDelete = path.join(file.path2, file.name2);
await fsPromise.rm(FileDelete, {force: true});
}));
await Promise.all((await TempFiles.listFiles()).map(async file => {
const gitPath = path.join(gitFolder, file);
const tempFolderPath = path.join(TempFiles.tempFolderPath, file);
if (!(fs.existsSync(path.join(gitFolder, path.parse(file).dir)))) await fsPromise.mkdir(path.join(gitFolder, path.parse(file).dir), {recursive: true}).catch(() => {});
await fsPromise.copyFile(tempFolderPath, gitPath);
}))
await TempFiles.cleanFolder();
await git.add(gitFolder).then(() => git.commit(`BDS Backup - ${new Date()}`).catch(console.error));
if (!!((options||{}).Auth||{}).Username) {
console.log("Pushing to remote");
await git.push([
"--force",
"--set-upstream"
]);
}
return;
}

View File

@ -1,4 +1,3 @@
import * as gitA from "./git";
import * as zipA from "./zip";
export const git = gitA;
export const zip = zipA;
import * as zip from "./zip";
export default {zip}
export {zip}

View File

@ -1,26 +1,21 @@
import path from "node:path";
import fs, { promises as fsPromise } from "node:fs";
import AdmZip from "adm-zip";
import { backupRoot as backupFolderPath } from "../pathControl";
import { genericAddFiles } from "./root";
import platforms from "../platform/index";
import AdmZip from "adm-zip";
export type zipOptions = true|false|{path: string};
export async function createZipBackup(WriteFile: zipOptions = false) {
export async function createZipBackup(options: zipOptions) {
if (!(fs.existsSync(backupFolderPath))) await fsPromise.mkdir(backupFolderPath, {recursive: true});
// Add Folders and files
const TempFolder = await genericAddFiles()
// Create empty zip Buffer
const zip = new AdmZip();
for (const file of await TempFolder.listFiles()) zip.addLocalFile(path.join(TempFolder.tempFolderPath, file), (path.sep+path.parse(file).dir));
await TempFolder.cleanFolder();
// Get Zip Buffer
const zipBuffer = zip.toBuffer();
let BackupFile = path.resolve(backupFolderPath, `${new Date().toString().replace(/[-\(\)\:\s+]/gi, "_")}.zip`);
if (WriteFile === true) await fsPromise.writeFile(BackupFile, zipBuffer);
else if (typeof WriteFile === "object") {
if (!!WriteFile.path) BackupFile = path.resolve(WriteFile.path);
await fsPromise.writeFile(BackupFile, zipBuffer);
zip.addFile("bedrock.zip", await platforms.bedrock.backup.CreateBackup());
zip.addFile("java.zip", await platforms.java.backup.CreateBackup());
zip.addFile("pocketmine.zip", await platforms.pocketmine.backup.CreateBackup());
zip.addFile("spigot.zip", await platforms.spigot.backup.CreateBackup());
if (typeof options === "boolean") return zip.toBuffer();
else {
const filePath = options?.path;
if (!filePath) throw new Error("No file path provided");
await fsPromise.writeFile(filePath, zip.toBuffer());
return filePath;
}
return zipBuffer;
}

View File

@ -1,23 +0,0 @@
import downloadServer from "./download_server";
export const name = "installServer";
export async function pocketmine() {
console.log("Installing pocketmine server");
const data = await downloadServer("pocketmine", "latest");
console.log(data);
return data;
}
export async function java() {
console.log("Installing java server");
const data = await downloadServer("java", "latest");
console.log(data);
return data;
}
export async function spigot() {
console.log("Installing spigot server");
const data = await downloadServer("spigot", "latest");
console.log(data);
return data;
}

View File

@ -1,36 +1,11 @@
import * as bdsTypes from "./globalType";
import * as platform from "./platform/index";
import platform from "./platform/index";
export default DownloadServer;
export async function DownloadServer(Platform: bdsTypes.Platform, Version: string|boolean): Promise<{Version: string, Date: Date, url: string}> {
if (Platform === "bedrock") {
const bedrockInfo = await platform.bedrock.DownloadServer(Version);
return {
Version: bedrockInfo.version,
Date: bedrockInfo.publishDate,
url: bedrockInfo.url
};
} else if (Platform === "java") {
const javaInfo = await platform.java.DownloadServer(Version);
return {
Version: javaInfo.version,
Date: javaInfo.publishDate,
url: javaInfo.url
};
} else if (Platform === "spigot") {
const spigotInfo = await platform.spigot.DownloadServer(Version);
return {
Version: spigotInfo.version,
Date: spigotInfo.publishDate,
url: spigotInfo.url
};
} else if (Platform === "pocketmine") {
const pocketmineInfo = await platform.pocketmine.DownloadServer(Version);
return {
Version: pocketmineInfo.version,
Date: pocketmineInfo.publishDate,
url: pocketmineInfo.url
};
}
throw new Error("No file found for this Platform and Arch");
export async function DownloadServer(Platform: bdsTypes.Platform, Version: string|boolean): Promise<{version: string, url: string; publishDate: Date}> {
if (Platform === "bedrock") return platform.bedrock.DownloadServer(Version);
else if (Platform === "java") return platform.java.DownloadServer(Version);
else if (Platform === "spigot") return platform.spigot.DownloadServer(Version);
else if (Platform === "pocketmine") return platform.pocketmine.DownloadServer(Version);
throw new Error("Invalid Platform");
}

View File

@ -1,9 +1,8 @@
import { CronJob } from "cron";
import { gitBackupOption } from "./backup/git";
export type Platform = "bedrock"|"java"|"pocketmine"|"spigot";
export const PlatformArray = ["bedrock", "java", "pocketmine", "spigot"];
// Bds Session on declaretion function types
export type bdsSessionCommands = {
/** Exec any commands in server */
execCommand: (...command: Array<string|number>) => bdsSessionCommands;
@ -16,46 +15,55 @@ export type bdsSessionCommands = {
/** Stop Server */
stop: () => Promise<number|null>;
};
export type startServerOptions = {
/** Save only worlds/maps without server software - (Beta) */
storageOnlyWorlds?: boolean;
gitBackup?: gitBackupOption;
};
export type playerAction1 = {player: string, Date: Date; xuid?: string|undefined}
export type playerAction2 = playerAction1 & {action: "connect"|"disconnect"|"unknown"}
// Server events
export type serverListen = {port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6"};
export type playerObject = {[player: string]: {action: "connect"|"disconnect"|"unknown"; date: Date; history: Array<{action: "connect"|"disconnect"|"unknown"; date: Date}>}};
export interface serverOn {
(act: "started", fn: (data: Date) => void);
(act: "err", fn: (data: Error|number) => void);
(act: "closed", fn: (data: number) => void);
(act: "player_ban", fn: (data: playerAction1) => void);
(act: "player", fn: (data: playerAction2) => void);
(act: "player_connect", fn: (data: playerAction1) => void);
(act: "player_disconnect", fn: (data: playerAction1) => void);
(act: "player_unknown", fn: (data: playerAction1) => void);
(act: "port_listen", fn: (data: {port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6"}) => void);
(act: "log", fn: (data: string) => void);
(act: "log_stdout", fn: (data: string) => void);
(act: "log_stderr", fn: (data: string) => void);
}
// Type to Bds Session (All Platforms)
export type BdsSession = {
/** Server Session ID */
id: string;
/** Server Started date */
startDate: Date;
logFile?: string;
/** register cron job to create backups */
creteBackup: (crontime: string|Date, option?: {type: "zip", pathStorage?: string}) => CronJob;
/** Get server players historic connections */
Player: playerObject;
/** Get Server ports. listening. */
ports: Array<serverListen>;
/** if exists server map get world seed, fist map not get seed */
seed?: string|number;
/** Server Started */
started: boolean;
/** Some platforms may have a plugin manager. */
addonManeger?: any;
/** register cron job to create backups */
creteBackup: (crontime: string|Date, option?: {type: "git"; config: gitBackupOption}|{type: "zip"}) => CronJob;
/** callback to log event */
log: {
on: (eventName: "all"|"err"|"out", listener: (data: string) => void) => void;
once: (eventName: "all"|"err"|"out", listener: (data: string) => void) => void;
};
/** If the server crashes or crashes, the callbacks will be called. */
onExit: (callback: (code: number) => void) => void;
/** Server actions, example on avaible to connect or banned¹ */
server: {
/** Server actions, example on avaible to connect or banned¹ */
on: (act: "started"|"ban", call: (...any) => void) => void;
/** Server actions, example on avaible to connect or banned¹ */
once: (act: "started"|"ban", call: (...any) => void) => void;
};
/** Get server players historic connections */
getPlayer: () => {[player: string]: {action: "connect"|"disconnect"|"unknown"; date: Date; history: Array<{action: "connect"|"disconnect"|"unknown"; date: Date}>}};
/** This is a callback that call a function, for some player functions */
onPlayer: (callback: (data: {player: string; action?: "connect"|"disconnect"|"unknown"; date: Date;}) => string) => void;
/** Get Server ports. listening. */
ports: () => Array<{port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6"}>;
/** Basic server functions. */
commands: bdsSessionCommands;
/** Server actions, example on avaible to connect or banned¹ */
server: {
/** Server actions */
on: serverOn;
/** Server actions */
once: serverOn;
/** Server Started date */
startDate: Date;
/** Server Started */
started: boolean;
};
};

View File

@ -1,8 +1,22 @@
// import
import * as Server from "./server";
// import All platforms and old functions
// New Methods
import * as platform from "./platform/index";
// Old functions
import * as downloadServer from "./download_server";
import * as worldManeger from "./worldManeger";
import * as serverConfig from "./serverConfig";
import * as bdsTypes from "./globalType";
import * as platform from "./platform/index";
import * as backup from "./backup/index";
export default {Server, downloadServer, serverConfig, bdsTypes, platform, backup};
import * as Server from "./server";
// Export all modules
export default {
bdsTypes,
platform,
downloadServer,
worldManeger,
serverConfig,
backup,
Server,
};

View File

@ -1,4 +1,11 @@
export default parse;
/**
* Parse Proprieties files and return a map of properties.
*
* @param Proper - String with the properties or similar files
* @returns
*/
export function parse(Proper: string): {[key: string]: string|number|true|false|null} {
const ProPri = {};
const ProperSplit = Proper.replace(/\r\n/g, "\n").replace(/\\\n/gi, "").split("\n").map(Line => Line.trim()).filter(line => /.*(\s+)?\=(\s+)?.*/.test(line) && !/^#/.test(line));
@ -15,6 +22,12 @@ export function parse(Proper: string): {[key: string]: string|number|true|false|
return ProPri;
}
/**
* Convert json to properities files.
*
* @param ProPri - String with properties file
* @returns
*/
export function stringify(ProPri: {[key: string]: any}): string {
const Proper = [];
for (const key in Object.keys(ProPri)) {

50
src/lib/customEvents.ts Normal file
View File

@ -0,0 +1,50 @@
import events from "node:events";
import { playerAction1, playerAction2 } from '../globalType';
declare interface bdsServerEvent {
// Emit
emit(act: "started", data: Date): boolean;
emit(act: "err", data: Error|number): boolean;
emit(act: "closed", data: number): boolean;
emit(act: "port_listen", data: {port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6"}): boolean;
emit(act: "log", data: string): boolean;
emit(act: "log_stdout", data: string): boolean;
emit(act: "log_stderr", data: string): boolean;
emit(act: "player", data: playerAction2): boolean;
emit(act: "player_ban", data: playerAction1): boolean;
emit(act: "player_connect", data: playerAction1): boolean;
emit(act: "player_disconnect", data: playerAction1): boolean;
emit(act: "player_unknown", data: playerAction1): boolean;
// on
on(act: "started", fn: (data: Date) => void): this;
on(act: "err", fn: (data: Error|number) => void): this;
on(act: "closed", fn: (data: number) => void): this;
on(act: "player_ban", fn: (data: playerAction1) => void): this;
on(act: "player", fn: (data: playerAction2) => void): this;
on(act: "player_connect", fn: (data: playerAction1) => void): this;
on(act: "player_disconnect", fn: (data: playerAction1) => void): this;
on(act: "player_unknown", fn: (data: playerAction1) => void): this;
on(act: "port_listen", fn: (data: {port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6"}) => void): this;
on(act: "log", fn: (data: string) => void): this;
on(act: "log_stdout", fn: (data: string) => void): this;
on(act: "log_stderr", fn: (data: string) => void): this;
// Once
once(act: "started", fn: (data: Date) => void): this;
once(act: "err", fn: (data: Error|number) => void): this;
once(act: "closed", fn: (data: number) => void): this;
once(act: "player_ban", fn: (data: playerAction1) => void): this;
once(act: "player", fn: (data: playerAction2) => void): this;
once(act: "player_connect", fn: (data: playerAction1) => void): this;
once(act: "player_disconnect", fn: (data: playerAction1) => void): this;
once(act: "player_unknown", fn: (data: playerAction1) => void): this;
once(act: "port_listen", fn: (data: {port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6"}) => void): this;
once(act: "log", fn: (data: string) => void): this;
once(act: "log_stdout", fn: (data: string) => void): this;
once(act: "log_stderr", fn: (data: string) => void): this;
}
class bdsServerEvent extends events {}
export default bdsServerEvent;
export {bdsServerEvent};

View File

@ -0,0 +1,52 @@
import mongoose from "mongoose";
import { Platform } from '../globalType';
export type PlayerSchema = {
Player: string,
Ban: boolean,
Platform: Platform,
FistDate: Date,
LastUpdateDate: Date,
ConnectionHistoric: Array<{
ConnectionType: "connect" | "disconnect" | "unknown",
Date: Date
}>
};
export const schema = new mongoose.Schema<PlayerSchema>({
Player: {
type: String,
required: true
},
Ban: {
type: Boolean,
required: true
},
Platform: {
type: String,
enum: ["bedrock", "java", "pocketmine", "spigot"],
required: true
},
FistDate: {
type: Date,
required: true
},
LastUpdateDate: {
type: Date,
required: true
},
ConnectionHistoric: [
{
ConnectionType: {
type: String,
enum: ["connect", "disconnect", "unknown"],
required: true
},
Date: {
type: Date,
required: true
}
}
]
});
export default schema;

View File

@ -0,0 +1,13 @@
import * as net from "node:net";
export default async function portIsAllocated(port: number): Promise<boolean> {
return new Promise<boolean>((resolve) => {
const tester = net.createServer()
tester.once("error", () => () => resolve(true));
tester.once("listening", () => {
tester.once("close", () => resolve(false));
tester.close();
});
tester.listen(port);
});
}

View File

@ -0,0 +1,31 @@
import * as bedrock from "./index";
export default async function bedrockTest() {
// Download Server
const download = await bedrock.DownloadServer(true);
console.log("Version: %s, Date: %o, url: %s", download.version, download.publishDate, download.url);
// Config
const currentConfig = await bedrock.config.getConfig();
console.log("Current config: %o", currentConfig);
currentConfig.gamemode = Math.floor(Math.random() * 2) > 3 ? "survival" : "creative";
currentConfig.worldName = "test"+Math.floor(Math.random()*100);
const newConfig = await bedrock.config.CreateServerConfig(currentConfig);
console.log("New config: %o", newConfig);
// Run Server
const server = await bedrock.server.startServer();
if (process.argv.includes("--show-log")) server.server.on("log", console.log);
server.server.once("started", () => console.log("Server started"));
await new Promise((resolve, reject) => {
server.server.once("started", resolve);
server.server.once("closed", resolve);
server.server.once("err", reject);
});
await server.commands.stop();
// Backup
const zipFile = await bedrock.backup.CreateBackup();
console.log("Backup created: %o", zipFile.length);
return;
}

View File

@ -4,7 +4,7 @@ import fs, { promises as fsPromise } from "node:fs";
import AdmZip from "adm-zip";
import * as Proprieties from "../../lib/Proprieties"
import { parse as nbtParse, NBT, Metadata as nbtData, NBTFormat } from "prismarine-nbt";
import { getBuffer } from "../../HttpRequests";
import { getBuffer } from "../../lib/HttpRequests";
import { serverRoot } from "../../pathControl";
const serverPath = path.join(serverRoot, "bedrock");
@ -48,7 +48,7 @@ export type bedrockConfig = {
texturepackRequired?: true|false
};
export async function CreateServerConfig(config: bedrockConfig): Promise<bedrockConfig&{configArray: string}> {
export async function CreateServerConfig(config: bedrockConfig): Promise<bedrockConfig> {
if (!!config.difficulty) {
if (typeof config.difficulty === "number") {
if (config.difficulty === 1) config.difficulty = "peaceful";
@ -203,8 +203,7 @@ export async function CreateServerConfig(config: bedrockConfig): Promise<bedrock
tickDistance,
playerIdleTimeout,
maxCpuThreads,
texturepackRequired,
configArray: configFileArray.join("\n")
texturepackRequired
}
}
@ -221,6 +220,10 @@ type bedrockParsedConfig = {
difficulty: "peaceful"|"easy"|"normal"|"hard",
/** The seed to be used for randomizing the world (`If left empty a seed will be chosen at random`). */
worldSeed: string|number,
port: {
v4: number,
v6: number
},
/** World NBT */
nbtParsed: {parsed: NBT, type: NBTFormat, metadata: nbtData}
};
@ -232,6 +235,10 @@ export async function getConfig(): Promise<bedrockParsedConfig> {
difficulty: "normal",
maxPlayers: 0,
worldSeed: "",
port: {
v4: 19132,
v6: 19133
},
nbtParsed: undefined
};
if (fs.existsSync(path.join(serverPath, "server.properties"))) {
@ -241,6 +248,21 @@ export async function getConfig(): Promise<bedrockParsedConfig> {
if (ProPri["gamemode"] !== undefined) config.gamemode = String(ProPri["gamemode"]) as "survival"|"creative"|"adventure";
if (ProPri["max-players"] !== undefined) config.maxPlayers = Number(ProPri["max-players"]);
if (ProPri["difficulty"] !== undefined) config.difficulty = String(ProPri["difficulty"]) as "peaceful"|"easy"|"normal"|"hard";
if (ProPri["server-port"] !== undefined) config.port.v4 = Number(ProPri["server-port"]);
if (ProPri["server-portv6"] !== undefined) config.port.v6 = Number(ProPri["server-portv6"]);
if (ProPri["level-seed"] !== undefined) config.worldSeed = String(ProPri["level-seed"]);
// if (ProPri["allow-cheats"] !== undefined) config.allowCheats = Boolean(ProPri["allow-cheats"]);
// if (ProPri["allow-list"] !== undefined) config.allowList = Boolean(ProPri["allow-list"]);
// if (ProPri["texturepack-required"] !== undefined) config.texturepackRequired = Boolean(ProPri["texturepack-required"]);
// if (ProPri["view-distance"] !== undefined) config.viewDistance = Number(ProPri["view-distance"]);
// if (ProPri["tick-distance"] !== undefined) config.tickDistance = Number(ProPri["tick-distance"]);
// if (ProPri["player-idle-timeout"] !== undefined) config.playerIdleTimeout = Number(ProPri["player-idle-timeout"]);
// if (ProPri["max-threads"] !== undefined) config.maxCpuThreads = Number(ProPri["max-threads"]);
// if (ProPri["default-player-permission-level"] !== undefined) config.PlayerDefaultPermissionLevel = String(ProPri["default-player-permission-level"]);
// if (ProPri["emit-server-telemetry"] !== undefined) config.emitServerTelemetry = Boolean(ProPri["emit-server-telemetry"]);
// if (ProPri["content-log-file-enabled"] !== undefined) config.contentLogFileEnabled = Boolean(ProPri["content-log-file-enabled"]);
// if (ProPri["compression-threshold"] !== undefined) config.compressionThreshold = Number(ProPri["compression-threshold"]);
// if (ProPri["server-authoritative-movement"] !== undefined) config.
const worldDatePath = path.join(serverPath, "worlds", config.worldName, "level.dat");
if (fs.existsSync(worldDatePath)) config.nbtParsed = await nbtParse(await fsPromise.readFile(worldDatePath));
if (ProPri["level-seed"] !== undefined) config.worldSeed = String(ProPri["level-seed"]);

View File

@ -2,8 +2,8 @@ import path from "node:path";
import fs from "node:fs";
import adm_zip from "adm-zip";
import * as versionManeger from "@the-bds-maneger/server_versions";
import * as httpRequests from "../../HttpRequests";
import { runCommandAsync } from "../../childProcess"
import * as httpRequests from "../../lib/HttpRequests";
import { runCommandAsync } from "../../lib/childProcess"
import { serverRoot } from "../../pathControl";
export default async function download(version: string|boolean) {

View File

@ -1,23 +0,0 @@
import { DownloadServer, config, server } from "./index";
export async function testBedrock() {
const downlaod = await DownloadServer("latest");
console.log(downlaod);
const currentConfig = await config.getConfig();
console.log(currentConfig);
currentConfig.worldName = "test";
const newConfig = await config.CreateServerConfig(currentConfig);
console.log(newConfig);
console.log("Starting bedrock server...");
const session = await server.startServer();
session.log.on("all", console.log);
await new Promise(res => {
session.server.once("started", (date: Date) => {
console.log("bedrock started at", date);
console.log("Stoping bedrock");
res("");
});
});
console.log("Stoping bedrock");
return session.commands.stop();
}

View File

@ -1,5 +1,14 @@
import DownloadServer from "./download";
import * as config from "./config";
import * as server from "./server";
import DownloadServer from "./download";
import * as backup from "./backup";
export {DownloadServer, config, server, backup};
import * as addon from "./addon";
// export
export {
DownloadServer,
config,
server,
backup,
addon
};

View File

@ -1,26 +1,26 @@
import path from "node:path";
import fs from "node:fs";
import events from "events";
import crypto from "crypto";
import node_cron from "cron";
import * as child_process from "../../childProcess";
import * as child_process from "../../lib/childProcess";
import { backupRoot, serverRoot } from "../../pathControl";
import { BdsSession, bdsSessionCommands } from "../../globalType";
import { BdsSession, bdsSessionCommands, playerAction2 } from '../../globalType';
import { getConfig } from "./config";
import { gitBackup, gitBackupOption } from "../../backup/git";
import { createZipBackup } from "../../backup/zip";
import events from "../../lib/customEvents";
import portislisten from "../../lib/portIsAllocated";
const bedrockSesions: {[key: string]: BdsSession} = {};
export function getSessions() {return bedrockSesions;}
const ServerPath = path.join(serverRoot, "bedrock");
export async function startServer(): Promise<BdsSession> {
if (!(fs.existsSync(ServerPath))) throw new Error("Install server first");
const SessionID = crypto.randomUUID();
const Process: {command: string; args: Array<string>; env: {[env: string]: string};} = {
command: "",
args: [],
env: {...process.env}
};
const serverConfig = await getConfig();
if (await portislisten(serverConfig.port.v4)) throw new Error("Port is already in use");
if (await portislisten(serverConfig.port.v6)) throw new Error("Port is already in use");
const Process: {command: string; args: Array<string>; env: {[env: string]: string};} = {command: "", args: [], env: {...process.env}};
if (process.platform === "darwin") throw new Error("Run Docker image");
Process.command = path.resolve(ServerPath, "bedrock_server"+(process.platform === "win32"?".exe":""));
if (process.platform !== "win32") {
@ -37,67 +37,45 @@ export async function startServer(): Promise<BdsSession> {
}
// Start Server
const serverEvents = new events();
const StartDate = new Date();
const serverEvents = new events({captureRejections: false});
serverEvents.setMaxListeners(0);
const ServerProcess = await child_process.execServer({runOn: "host"}, Process.command, Process.args, {env: Process.env, cwd: ServerPath});
const { onExit } = ServerProcess;
const onLog = {on: ServerProcess.on, once: ServerProcess.once};
const playerCallbacks: {[id: string]: {callback: (data: {player: string; action: "connect"|"disconnect"|"unknown"; date: Date;}) => void}} = {};
const onPlayer = (callback: (data: {player: string; action: "connect"|"disconnect"|"unknown"; date: Date;}) => void) => {
const uid = crypto.randomUUID();
playerCallbacks[uid] = {callback: callback};
return uid;
};
// Log Server redirect to callbacks events and exit
ServerProcess.on("out", data => serverEvents.emit("log_stdout", data));
ServerProcess.on("err", data => serverEvents.emit("log_stderr", data));
ServerProcess.on("all", data => serverEvents.emit("log", data));
ServerProcess.Exec.on("exit", code => {
serverEvents.emit("closed", code);
if (code === null) serverEvents.emit("err", new Error("Server exited with code null"));
});
const playersConnections: {
[player: string]: {
action: "connect"|"disconnect"|"unknown";
date: Date;
history: Array<{
action: "connect"|"disconnect"|"unknown";
date: Date
}>
}
} = {};
const ports: Array<{port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6";}> = [];
// on start
serverEvents.on("log", lineData => {
// [2022-05-19 22:35:09:315 INFO] Server started.
if (/\[.*\]\s+Server\s+started\./.test(lineData)) serverEvents.emit("started", new Date());
});
// Port
onLog.on("all", data => {
serverEvents.on("log", data => {
const portParse = data.match(/(IPv[46])\s+supported,\s+port:\s+(.*)/);
if (!!portParse) {
ports.push({
port: parseInt(portParse[2]),
version: portParse[1] as "IPv4"|"IPv6",
protocol: "UDP"
});
}
if (!!portParse) serverEvents.emit("port_listen", {port: parseInt(portParse[2]), protocol: "UDP", version: portParse[1] as "IPv4"|"IPv6"});
});
// Player
onLog.on("all", data => {
serverEvents.on("log", data => {
if (/r\s+.*\:\s+.*\,\s+xuid\:\s+.*/gi.test(data)) {
const actionDate = new Date();
const [action, player, xuid] = (data.match(/r\s+(.*)\:\s+(.*)\,\s+xuid\:\s+(.*)/)||[]).slice(1, 4);
const __PlayerAction: {player: string, xuid: string|undefined, action: "connect"|"disconnect"|"unknown"} = {
player: player,
xuid: xuid,
action: "unknown"
};
if (action === "connected") __PlayerAction.action = "connect"; else if (action === "disconnected") __PlayerAction.action = "disconnect";
if (!playersConnections[__PlayerAction.player]) playersConnections[__PlayerAction.player] = {
action: __PlayerAction.action,
date: actionDate,
history: [{
action: __PlayerAction.action,
date: actionDate
}]
}; else {
playersConnections[__PlayerAction.player].action = __PlayerAction.action;
playersConnections[__PlayerAction.player].date = actionDate;
playersConnections[__PlayerAction.player].history.push({
action: __PlayerAction.action,
date: actionDate
});
}
const playerAction: playerAction2 = {player: player, xuid: xuid, action: "unknown", Date: actionDate};
if (action === "connected") playerAction.action = "connect";
else if (action === "disconnected") playerAction.action = "disconnect";
// Server player event
serverEvents.emit("player", playerAction);
delete playerAction.action;
if (action === "connect") serverEvents.emit("player_connect", playerAction);
else if (action === "disconnect") serverEvents.emit("player_disconnect", playerAction);
else serverEvents.emit("player_unknown", playerAction);
}
});
@ -132,12 +110,10 @@ export async function startServer(): Promise<BdsSession> {
}
}
const backupCron = (crontime: string|Date, option?: {type: "git"; config: gitBackupOption}|{type: "zip", config?: {pathZip?: string}}): node_cron.CronJob => {
const backupCron = (crontime: string|Date, option?: {type: "zip", config?: {pathZip?: string}}): node_cron.CronJob => {
// Validate Config
if (option) {
if (option.type === "git") {
if (!option.config) throw new Error("Config is required");
} else if (option.type === "zip") {}
if (option.type === "zip") {}
else option = {type: "zip"};
}
async function lockServerBackup() {
@ -152,10 +128,7 @@ export async function startServer(): Promise<BdsSession> {
}
if (!option) option = {type: "zip"};
const CrontimeBackup = new node_cron.CronJob(crontime, async () => {
if (option.type === "git") {
await lockServerBackup();
await gitBackup(option.config).catch(() => undefined).then(() => unLockServerBackup());
} else if (option.type === "zip") {
if (option.type === "zip") {
await lockServerBackup();
if (!!option?.config?.pathZip) await createZipBackup({path: path.resolve(backupRoot, option?.config?.pathZip)}).catch(() => undefined);
else await createZipBackup(true).catch(() => undefined);
@ -163,7 +136,7 @@ export async function startServer(): Promise<BdsSession> {
}
});
CrontimeBackup.start();
onExit().catch(() => null).then(() => CrontimeBackup.stop());
serverEvents.on("closed", () => CrontimeBackup.stop());
return CrontimeBackup;
}
@ -171,43 +144,51 @@ export async function startServer(): Promise<BdsSession> {
const logFile = path.resolve(process.env.LOG_PATH||path.resolve(ServerPath, "../log"), `bedrock_${SessionID}.log`);
if(!(fs.existsSync(path.parse(logFile).dir))) fs.mkdirSync(path.parse(logFile).dir, {recursive: true});
const logStream = fs.createWriteStream(logFile, {flags: "w+"});
logStream.write(`[${StartDate.toString()}] Server started\n\n`);
logStream.write(`[${(new Date()).toString()}] Server started\n\n`);
ServerProcess.Exec.stdout.pipe(logStream);
ServerProcess.Exec.stderr.pipe(logStream);
const serverOn = (act: "started" | "ban", call: (...any: any[]) => void) => serverEvents.on(act, call);
const serverOnce = (act: "started" | "ban", call: (...any: any[]) => void) => serverEvents.once(act, call);
// Session Object
const Seesion: BdsSession = {
id: SessionID,
startDate: StartDate,
logFile: logFile,
creteBackup: backupCron,
onExit: onExit,
onPlayer: onPlayer,
ports: () => ports,
getPlayer: () => playersConnections,
server: {
on: serverOn,
once: serverOnce
},
seed: (await getConfig()).worldSeed,
started: false,
addonManeger: undefined,
log: onLog,
seed: serverConfig.worldSeed,
ports: [],
Player: {},
commands: serverCommands,
server: {
on: (act, fn) => serverEvents.on(act, fn),
once: (act, fn) => serverEvents.once(act, fn),
started: false,
startDate: new Date(),
}
};
onLog.on("all", lineData => {
// [2022-05-19 22:35:09:315 INFO] Server started.
if (/\[.*\]\s+Server\s+started\./.test(lineData)) {
Seesion.started = true;
serverEvents.emit("started", new Date());
}
serverEvents.on("port_listen", Seesion.ports.push);
serverEvents.on("started", date => {Seesion.server.started = true; Seesion.server.startDate = date;});
serverEvents.on("player", playerAction => {
// Add to object
const playerExist = !!Seesion.Player[playerAction.player];
if (playerExist) {
Seesion.Player[playerAction.player].action = playerAction.action;
Seesion.Player[playerAction.player].date = playerAction.Date;
Seesion.Player[playerAction.player].history.push({
action: playerAction.action,
date: playerAction.Date
});
} else Seesion.Player[playerAction.player] = {
action: playerAction.action,
date: playerAction.Date,
history: [{
action: playerAction.action,
date: playerAction.Date
}]
};
});
// Return Session
bedrockSesions[SessionID] = Seesion;
onExit().catch(() => null).then(() => delete bedrockSesions[SessionID]);
serverEvents.on("closed", () => delete bedrockSesions[SessionID]);
return Seesion;
}

View File

@ -2,4 +2,30 @@ import * as bedrock from "./bedrock/index";
import * as pocketmine from "./pocketmine/index";
import * as java from "./java/index";
import * as spigot from "./spigot/index";
export {bedrock, pocketmine, java, spigot}
//
// import { BdsSession } from "../globalType";
//
// type globalPlatform = {
// [platform: string]: {
// /**
// * Download Server (and ¹auto install).
// *
// * 1: **In java server required java installation (if not installed, it will install it)**
// */
// DownloadServer: (version: string|boolean) => Promise<{version: string, publishDate: Date, url: string}>,
// server: {
// /** get server session */
// startServer: () => Promise<BdsSession>,
// /** Get all Server Sessions */
// getSessions: () => {[sessionId: string]: BdsSession}
// },
// backup: {
// /** Create Platform Backup, and return Buffer zip File */
// CreateBackup: () => Promise<Buffer>,
// /** Restore Zip Backup, this option replace local files */
// RestoreBackup: (buffer: Buffer) => Promise<void>,
// },
// }
// };
// export default {bedrock, java, pocketmine, spigot} as globalPlatform;
export default {bedrock, java, pocketmine, spigot};

View File

@ -0,0 +1,40 @@
import * as fsOld from "node:fs";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import admZip from "adm-zip";
import { serverRoot } from "../../pathControl";
const javaPath = path.join(serverRoot, "java");
const filesFoldertoIgnore = ["Server.jar", "eula.txt", "libraries", "logs", "usercache.json", "versions"];
/**
* Create backup for Worlds and Settings
*/
export async function CreateBackup(): Promise<Buffer> {
if (!(fsOld.existsSync(javaPath))) throw new Error("Install server");
const filesLint = (await fs.readdir(javaPath)).filter(file => !(filesFoldertoIgnore.some(folder => folder === file)));
const zip = new admZip();
for (const file of filesLint) {
const filePath = path.join(javaPath, file);
const stats = await fs.stat(filePath);
if (stats.isSymbolicLink()) {
const realPath = await fs.realpath(filePath);
const realStats = await fs.stat(realPath);
if (realStats.isDirectory()) zip.addLocalFolder(realPath, file);
else zip.addLocalFile(realPath, file);
} else if (stats.isDirectory()) zip.addLocalFolder(filePath);
else zip.addLocalFile(filePath);
}
return zip.toBuffer();
}
/**
* Restore backup for Worlds and Settings
*
* WARNING: This will overwrite existing files and World folder files
*/
export async function RestoreBackup(zipBuffer: Buffer): Promise<void> {
const zip = new admZip(zipBuffer);
await new Promise((resolve, reject) => zip.extractAllToAsync(javaPath, true, true, (err) => !!err ? reject(err) : resolve("")));
return;
}

View File

@ -1,7 +1,7 @@
import path from "node:path";
import fs from "node:fs";
import * as versionManeger from "@the-bds-maneger/server_versions";
import * as httpRequests from "../../HttpRequests";
import * as httpRequests from "../../lib/HttpRequests";
import { serverRoot } from "../../pathControl";
export default async function download(version: string|boolean) {

View File

@ -1,3 +1,10 @@
import * as server from "./server";
import DownloadServer from "./download";
export {server, DownloadServer};
import * as server from "./server";
import * as backup from "./backup";
// Export
export {
DownloadServer,
server,
backup
};

View File

@ -0,0 +1,23 @@
import * as java from "./index";
export default async function javaTest() {
// Download and install server
const download = await java.DownloadServer(true);
console.log("Version: %s, Date: %o, url: %s", download.version, download.publishDate, download.url);
// Start Server
const server = await java.server.startServer();
if (process.argv.includes("--show-log")) server.server.on("log", console.log);
server.server.once("started", () => console.log("Server started"));
server.server.on("port_listen", port => console.log("Server listening on port: %o with protocol: %s", port.port, port.protocol));
await new Promise((resolve, reject) => {
server.server.once("started", resolve);
server.server.once("closed", code => code === null ? resolve(code) : reject(code));
});
await server.commands.stop();
// Backup
const zipFile = await java.backup.CreateBackup();
console.log("Backup created: %o", zipFile.length);
return;
}

View File

@ -1,13 +1,12 @@
import path from "node:path";
import fs from "node:fs";
import events from "events";
import crypto from "crypto";
import node_cron from "cron";
import * as child_process from "../../childProcess";
import * as child_process from "../../lib/childProcess";
import { backupRoot, serverRoot } from "../../pathControl";
import { BdsSession, bdsSessionCommands } from "../../globalType";
import { gitBackup, gitBackupOption } from "../../backup/git";
import { BdsSession, bdsSessionCommands } from '../../globalType';
import { createZipBackup } from "../../backup/zip";
import events from "../../lib/customEvents";
const javaSesions: {[key: string]: BdsSession} = {};
export function getSessions() {return javaSesions;}
@ -19,27 +18,24 @@ export async function startServer(): Promise<BdsSession> {
const serverEvents = new events();
const StartDate = new Date();
const ServerProcess = await child_process.execServer({runOn: "host"}, "java", ["-jar", "Server.jar"], {cwd: ServerPath});
const { onExit } = ServerProcess;
const onLog = {on: ServerProcess.on, once: ServerProcess.once};
const playerCallbacks: {[id: string]: {callback: (data: {player: string; action: "connect"|"disconnect"|"unknown"; date: Date;}) => void}} = {};
const onPlayer = (callback: (data: {player: string; action: "connect"|"disconnect"|"unknown"; date: Date;}) => void) => {
const uid = crypto.randomUUID();
playerCallbacks[uid] = {callback: callback};
return uid;
};
const ports: Array<{port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6";}> = [];
const playersConnections: {[player: string]: {action: "connect"|"disconnect"|"unknown", date: Date, history: Array<{action: "connect"|"disconnect"|"unknown", date: Date}>}} = {};
// Log Server redirect to callbacks events and exit
ServerProcess.on("out", data => serverEvents.emit("log_stdout", data));
ServerProcess.on("err", data => serverEvents.emit("log_stderr", data));
ServerProcess.on("all", data => serverEvents.emit("log", data));
ServerProcess.Exec.on("exit", code => {
serverEvents.emit("closed", code);
if (code === null) serverEvents.emit("err", new Error("Server exited with code null"));
});
// Detect server start
serverEvents.on("log", lineData => {
// [22:35:26] [Server thread/INFO]: Done (6.249s)! For help, type "help"
if (/\[.*\].*\s+Done\s+\(.*\)\!.*/.test(lineData)) serverEvents.emit("started", new Date());
});
// Parse ports
onLog.on("all", data => {
serverEvents.on("log", data => {
const portParse = data.match(/Starting\s+Minecraft\s+server\s+on\s+(.*)\:(\d+)/);
if (!!portParse) {
ports.push({
port: parseInt(portParse[2]),
version: "IPv4/IPv6"
});
}
if (!!portParse) serverEvents.emit("port_listen", {port: parseInt(portParse[2]), protocol: "TCP", version: "IPv4/IPv6",});
});
// Run Command
@ -73,12 +69,10 @@ export async function startServer(): Promise<BdsSession> {
}
}
const backupCron = (crontime: string|Date, option?: {type: "git"; config: gitBackupOption}|{type: "zip", config?: {pathZip?: string}}): node_cron.CronJob => {
const backupCron = (crontime: string|Date, option?: {type: "zip", config?: {pathZip?: string}}): node_cron.CronJob => {
// Validate Config
if (option) {
if (option.type === "git") {
if (!option.config) throw new Error("Config is required");
} else if (option.type === "zip") {}
if (option.type === "zip") {}
else option = {type: "zip"};
}
async function lockServerBackup() {
@ -93,10 +87,7 @@ export async function startServer(): Promise<BdsSession> {
}
if (!option) option = {type: "zip"};
const CrontimeBackup = new node_cron.CronJob(crontime, async () => {
if (option.type === "git") {
await lockServerBackup();
await gitBackup(option.config).catch(() => undefined).then(() => unLockServerBackup());
} else if (option.type === "zip") {
if (option.type === "zip") {
await lockServerBackup();
if (!!option?.config?.pathZip) await createZipBackup({path: path.resolve(backupRoot, option?.config?.pathZip)}).catch(() => undefined);
else await createZipBackup(true).catch(() => undefined);
@ -104,7 +95,7 @@ export async function startServer(): Promise<BdsSession> {
}
});
CrontimeBackup.start();
onExit().catch(() => null).then(() => CrontimeBackup.stop());
serverEvents.on("closed", () => CrontimeBackup.stop());
return CrontimeBackup;
}
@ -116,39 +107,28 @@ export async function startServer(): Promise<BdsSession> {
ServerProcess.Exec.stdout.pipe(logStream);
ServerProcess.Exec.stderr.pipe(logStream);
const serverOn = (act: "started" | "ban", call: (...any: any[]) => void) => serverEvents.on(act, call);
const serverOnce = (act: "started" | "ban", call: (...any: any[]) => void) => serverEvents.once(act, call);
// Session Object
const Seesion: BdsSession = {
id: SessionID,
startDate: StartDate,
creteBackup: backupCron,
onExit: onExit,
onPlayer: onPlayer,
ports: () => ports,
getPlayer: () => playersConnections,
server: {
on: serverOn,
once: serverOnce
},
ports: [],
Player: {},
seed: undefined,
started: false,
addonManeger: undefined,
log: onLog,
commands: serverCommands,
server: {
on: (act, fn) => serverEvents.on(act, fn),
once: (act, fn) => serverEvents.once(act, fn),
started: false,
startDate: StartDate
}
};
onLog.on("all", lineData => {
// [22:35:26] [Server thread/INFO]: Done (6.249s)! For help, type "help"
if (/\[.*\].*\s+Done\s+\(.*\)\!.*/.test(lineData)) {
Seesion.started = true;
serverEvents.emit("started", new Date());
}
});
// Server Events
serverEvents.on("port_listen", port => Seesion.ports.push(port));
serverEvents.on("started", StartDate => {Seesion.server.started = true; Seesion.server.startDate = StartDate;});
// Return Session
javaSesions[SessionID] = Seesion;
onExit().catch(() => null).then(() => delete javaSesions[SessionID]);
serverEvents.on("closed", () => delete javaSesions[SessionID]);
return Seesion;
}

View File

@ -1,4 +1,4 @@
import * as httpRequest from "../../HttpRequests";
import * as httpRequest from "../../lib/HttpRequests";
export async function getPlugins(): Promise<Array<{
id: number,

View File

@ -0,0 +1,39 @@
import * as fsOld from "node:fs";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import admZip from "adm-zip";
import { serverRoot } from '../../pathControl';
const javaPath = path.join(serverRoot, "pocketmine");
const filesFoldertoIgnore = ["PocketMine.phar", "bin", "server.log"];
/**
* Create backup for Worlds and Settings
*/
export async function CreateBackup(): Promise<Buffer> {
if (!(fsOld.existsSync(javaPath))) throw new Error("Install server");
const filesLint = (await fs.readdir(javaPath)).filter(file => !(filesFoldertoIgnore.some(folder => folder === file)));
const zip = new admZip();
for (const file of filesLint) {
const filePath = path.join(javaPath, file);
const stats = await fs.stat(filePath);
if (stats.isSymbolicLink()) {
const realPath = await fs.realpath(filePath);
const realStats = await fs.stat(realPath);
if (realStats.isDirectory()) zip.addLocalFolder(realPath, file);
else zip.addLocalFile(realPath, file);
} else if (stats.isDirectory()) zip.addLocalFolder(filePath);
else zip.addLocalFile(filePath);
}
return zip.toBuffer();
}
/**
* Restore backup for Worlds and Settings
*
* WARNING: This will overwrite existing files and World folder files
*/
export async function RestoreBackup(zipBuffer: Buffer): Promise<void> {
const zip = new admZip(zipBuffer);
await new Promise((resolve, reject) => zip.extractAllToAsync(javaPath, true, true, (err) => !!err ? reject(err) : resolve("")));
return;
}

View File

@ -4,8 +4,8 @@ import os from "os";
import adm_zip from "adm-zip";
import tar from "tar";
import * as versionManeger from "@the-bds-maneger/server_versions";
import * as httpRequests from "../../HttpRequests";
import * as childProcess from "../../childProcess";
import * as httpRequests from "../../lib/HttpRequests";
import * as childProcess from "../../lib/childProcess";
import Readdirrec from "../../lib/listRecursive";
import { serverRoot } from "../../pathControl";
@ -52,7 +52,6 @@ async function InstallPrebuildPHP(serverPath: string) {
const ztsFind = await Readdirrec(path.resolve(serverPath, "bin"), [/.*debug-zts.*/]);
if (ztsFind.length === 0) return urlBin;
const phpIniPath = (await Readdirrec(path.resolve(serverPath, "bin"), [/php\.ini$/]))[0].path;
console.log("Updating php.ini");
let phpIni = await fs.promises.readFile(phpIniPath, "utf8");
if (phpIni.includes("extension_dir")) {
await fs.promises.writeFile(phpIniPath, phpIni.replace(/extension_dir=.*/g, ""));

View File

@ -1,5 +1,14 @@
import DownloadServer from "./download";
import * as addons from "./addons";
import * as config from "./config";
import * as server from "./server";
import DownloadServer from "./download";
export {addons, config, server, DownloadServer};
import * as backup from "./backup";
// Export
export {
DownloadServer,
addons,
config,
server,
backup
};

View File

@ -0,0 +1,23 @@
import * as pocketmine from "./index";
export default async function pocketmineTest() {
// Download Server
const download = await pocketmine.DownloadServer(true);
console.log("Version: %s, Date: %o, url: %s", download.version, download.publishDate, download.url);
// Run Server
const server = await pocketmine.server.startServer();
if (process.argv.includes("--show-log")) server.server.on("log", console.log);
server.server.once("started", () => console.log("Server started"));
await new Promise((resolve, reject) => {
server.server.once("started", resolve);
server.server.once("closed", resolve);
server.server.once("err", reject);
});
await server.commands.stop();
// Backup
const zipFile = await pocketmine.backup.CreateBackup();
console.log("Backup created: %o", zipFile.length);
return;
}

View File

@ -1,123 +1,79 @@
import path from "node:path";
import fs from "node:fs";
import events from "events";
import crypto from "crypto";
import node_cron from "cron";
import * as child_process from "../../childProcess";
import * as child_process from "../../lib/childProcess";
import { backupRoot, serverRoot } from "../../pathControl";
import { BdsSession, bdsSessionCommands } from "../../globalType";
import { gitBackup, gitBackupOption } from "../../backup/git";
import { BdsSession, bdsSessionCommands, serverListen, playerAction2 } from '../../globalType';
import { createZipBackup } from "../../backup/zip";
import events from "../../lib/customEvents";
const pocketmineSesions: {[key: string]: BdsSession} = {};
export function getSessions() {return pocketmineSesions;}
export function parseUserAction(data: string): {player: string; action: "connect"|"disconnect"|"unknown"; date: Date; xuid?: string;}|void {
if (/\[.*\]:\s+(.*)\s+(.*)\s+the\s+game/gi.test(data)) {
const actionDate = new Date();
const [action, player] = (data.match(/[.*]:\s+(.*)\s+(.*)\s+the\s+game/gi)||[]).slice(1, 3);
const __PlayerAction: {player: string, action: "connect"|"disconnect"|"unknown"} = {
player: player,
action: "unknown"
};
if (action === "joined") __PlayerAction.action = "connect";
else if (action === "left") __PlayerAction.action = "disconnect";
return {
player: __PlayerAction.player,
action: __PlayerAction.action,
date: actionDate
};
}
return;
}
const ServerPath = path.join(serverRoot, "pocketmine");
export async function startServer(): Promise<BdsSession> {
const SessionID = crypto.randomUUID();
const Process: {command: string; args: Array<string>; env: {[env: string]: string};} = {
command: "",
args: [],
env: {...process.env}
};
Process.args.push(path.join(ServerPath, "PocketMine.phar"));
const Process: {command: string; args: Array<string>} = {command: "", args: []};
if (process.platform === "win32") Process.command = path.resolve(ServerPath, "bin/php/php.exe");
else {
Process.command = path.resolve(ServerPath, "bin/bin/php");
await child_process.runAsync("chmod", ["a+x", Process.command]);
}
Process.args.push(path.join(ServerPath, "PocketMine.phar"), "--no-wizard", "--enable-ansi");
// Start Server
const serverEvents = new events();
const StartDate = new Date();
const ServerProcess = await child_process.execServer({runOn: "host"}, Process.command, Process.args, {env: Process.env, cwd: ServerPath});
const { onExit } = ServerProcess;
const onLog = {on: ServerProcess.on, once: ServerProcess.once};
const playerCallbacks: {[id: string]: {callback: (data: {player: string; action: "connect"|"disconnect"|"unknown"; date: Date;}) => void}} = {};
const onPlayer = (callback: (data: {player: string; action: "connect"|"disconnect"|"unknown"; date: Date;}) => void) => {
const uid = crypto.randomUUID();
playerCallbacks[uid] = {callback: callback};
return uid;
};
const ServerProcess = await child_process.execServer({runOn: "host"}, Process.command, Process.args, {cwd: ServerPath});
const { onExit, on: execOn } = ServerProcess;
// Log Server redirect to callbacks events and exit
execOn("out", data => serverEvents.emit("log_stdout", data));
execOn("err", data => serverEvents.emit("log_stderr", data));
execOn("all", data => serverEvents.emit("log", data));
onExit().catch(err => {serverEvents.emit("err", err);return null}).then(code => serverEvents.emit("closed", code));
const playersConnections: {
[player: string]: {
action: "connect"|"disconnect"|"unknown";
date: Date;
history: Array<{
action: "connect"|"disconnect"|"unknown";
date: Date
}>
}
} = {};
const ports: Array<{port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6";}> = [];
// On server started
serverEvents.on("log", lineData => {
// [22:52:05.580] [Server thread/INFO]: Done (0.583s)! For help, type "help" or "?"
if (/\[.*\].*\s+Done\s+\(.*\)\!.*/.test(lineData)) serverEvents.emit("started", new Date());
});
// Port
onLog.on("all", data => {
// Port listen
serverEvents.on("log", data => {
// [16:49:31.284] [Server thread/INFO]: Minecraft network interface running on [::]:19133
// [16:49:31.273] [Server thread/INFO]: Minecraft network interface running on 0.0.0.0:19132
if (/\[.*\]:\s+Minecraft\s+network\s+interface\s+running\s+on\s+(.*)/gi.test(data)) {
const portParse = data.match(/\[.*\]:\s+Minecraft\s+network\s+interface\s+running\s+on\s+(.*)/)[1];
if (!!portParse) {
if (/\[.*\]/.test(portParse)) {
ports.push({
port: parseInt(portParse.match(/\[.*\]:\s+(.*)/)[1]),
version: "IPv6"
});
} else {
ports.push({
port: parseInt(portParse.split(":")[1]),
version: "IPv4"
});
if (/\[.*\]:\s+Minecraft\s+network\s+interface\s+running\s+on\s+.*/gi.test(data)) {
const matchString = data.match(/\[.*\]:\s+Minecraft\s+network\s+interface\s+running\s+on\s+(.*)/);
if (!!matchString) {
const portParse = matchString[1];
const portObject: serverListen = {port: 0, version: "IPv4", protocol: "UDP"};
const isIpv6 = /\[.*\]:/.test(portParse);
if (!isIpv6) portObject.port = parseInt(portParse.split(":")[1]);
else {
portObject.port = parseInt(portParse.replace(/\[.*\]:/, "").trim())
portObject.version = "IPv6";
}
serverEvents.emit("port_listen", portObject);
}
}
});
// Player
onLog.on("all", data => {
// Player Actions
serverEvents.on("log", data => {
const actionDate = new Date();
if (/\[.*\]:\s+(.*)\s+(.*)\s+the\s+game/gi.test(data)) {
const actionDate = new Date();
const [action, player] = (data.match(/[.*]:\s+(.*)\s+(.*)\s+the\s+game/gi)||[]).slice(1, 3);
const __PlayerAction: {player: string, action: "connect"|"disconnect"|"unknown"} = {
player: player,
action: "unknown"
};
if (action === "joined") __PlayerAction.action = "connect";
else if (action === "left") __PlayerAction.action = "disconnect";
if (!playersConnections[__PlayerAction.player]) playersConnections[__PlayerAction.player] = {
action: __PlayerAction.action,
date: actionDate,
history: [{
action: __PlayerAction.action,
date: actionDate
}]
}; else {
playersConnections[__PlayerAction.player].action = __PlayerAction.action;
playersConnections[__PlayerAction.player].date = actionDate;
playersConnections[__PlayerAction.player].history.push({
action: __PlayerAction.action,
date: actionDate
});
}
const playerAction: playerAction2 = {player: player, action: "unknown", Date: actionDate};
if (action === "joined") playerAction.action = "connect";
else if (action === "left") playerAction.action = "disconnect";
// Server player event
serverEvents.emit("player", playerAction);
delete playerAction.action;
if (action === "connect") serverEvents.emit("player_connect", playerAction);
else if (action === "disconnect") serverEvents.emit("player_disconnect", playerAction);
else serverEvents.emit("player_unknown", playerAction);
}
});
@ -152,12 +108,10 @@ export async function startServer(): Promise<BdsSession> {
}
}
const backupCron = (crontime: string|Date, option?: {type: "git"; config: gitBackupOption}|{type: "zip", config?: {pathZip?: string}}): node_cron.CronJob => {
const backupCron = (crontime: string|Date, option?: {type: "zip", config?: {pathZip?: string}}): node_cron.CronJob => {
// Validate Config
if (option) {
if (option.type === "git") {
if (!option.config) throw new Error("Config is required");
} else if (option.type === "zip") {}
if (option.type === "zip") {}
else option = {type: "zip"};
}
async function lockServerBackup() {
@ -172,10 +126,7 @@ export async function startServer(): Promise<BdsSession> {
}
if (!option) option = {type: "zip"};
const CrontimeBackup = new node_cron.CronJob(crontime, async () => {
if (option.type === "git") {
await lockServerBackup();
await gitBackup(option.config).catch(() => undefined).then(() => unLockServerBackup());
} else if (option.type === "zip") {
if (option.type === "zip") {
await lockServerBackup();
if (!!option?.config?.pathZip) await createZipBackup({path: path.resolve(backupRoot, option?.config?.pathZip)}).catch(() => undefined);
else await createZipBackup(true).catch(() => undefined);
@ -183,7 +134,7 @@ export async function startServer(): Promise<BdsSession> {
}
});
CrontimeBackup.start();
onExit().catch(() => null).then(() => CrontimeBackup.stop());
serverEvents.on("closed", () => CrontimeBackup.stop());
return CrontimeBackup;
}
@ -195,39 +146,44 @@ export async function startServer(): Promise<BdsSession> {
ServerProcess.Exec.stdout.pipe(logStream);
ServerProcess.Exec.stderr.pipe(logStream);
const serverOn = (act: "started" | "ban", call: (...any: any[]) => void) => serverEvents.on(act, call);
const serverOnce = (act: "started" | "ban", call: (...any: any[]) => void) => serverEvents.once(act, call);
// Session Object
const Seesion: BdsSession = {
id: SessionID,
startDate: StartDate,
creteBackup: backupCron,
onExit: onExit,
onPlayer: onPlayer,
ports: () => ports,
getPlayer: () => playersConnections,
server: {
on: serverOn,
once: serverOnce
},
ports: [],
Player: {},
seed: undefined,
started: false,
addonManeger: undefined,
log: onLog,
commands: serverCommands,
server: {
on: (act, fn) => serverEvents.on(act, fn),
once: (act, fn) => serverEvents.once(act, fn),
startDate: StartDate,
started: false
}
};
onLog.on("all", lineData => {
// [22:52:05.580] [Server thread/INFO]: Done (0.583s)! For help, type "help" or "?"
if (/\[.*\].*\s+Done\s+\(.*\)\!.*/.test(lineData)) {
Seesion.started = true;
serverEvents.emit("started", new Date());
serverEvents.on("started", StartDate => {Seesion.server.startDate = StartDate; Seesion.server.started = true;});
serverEvents.on("port_listen", portObject => Seesion.ports.push(portObject));
serverEvents.on("player", playerAction => {
if (!Seesion.Player[playerAction.player]) Seesion.Player[playerAction.player] = {
action: playerAction.action,
date: playerAction.Date,
history: [{
action: playerAction.action,
date: playerAction.Date
}]
}; else {
Seesion.Player[playerAction.player].action = playerAction.action;
Seesion.Player[playerAction.player].date = playerAction.Date;
Seesion.Player[playerAction.player].history.push({
action: playerAction.action,
date: playerAction.Date
});
}
});
// Return Session
pocketmineSesions[SessionID] = Seesion;
onExit().catch(() => null).then(() => delete pocketmineSesions[SessionID]);
serverEvents.on("closed", () => delete pocketmineSesions[SessionID]);
return Seesion;
}

View File

@ -0,0 +1,40 @@
import * as fsOld from "node:fs";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import admZip from "adm-zip";
import { serverRoot } from '../../pathControl';
const javaPath = path.join(serverRoot, "spigot");
const filesFoldertoIgnore = ["Server.jar", "bundler", "eula.txt", "help.yml", "logs", "usercache.json"];
/**
* Create backup for Worlds and Settings
*/
export async function CreateBackup(): Promise<Buffer> {
if (!(fsOld.existsSync(javaPath))) throw new Error("Install server");
const filesLint = (await fs.readdir(javaPath)).filter(file => !(filesFoldertoIgnore.some(folder => folder === file)));
const zip = new admZip();
for (const file of filesLint) {
const filePath = path.join(javaPath, file);
const stats = await fs.stat(filePath);
if (stats.isSymbolicLink()) {
const realPath = await fs.realpath(filePath);
const realStats = await fs.stat(realPath);
if (realStats.isDirectory()) zip.addLocalFolder(realPath, file);
else zip.addLocalFile(realPath, file);
} else if (stats.isDirectory()) zip.addLocalFolder(filePath);
else zip.addLocalFile(filePath);
}
return zip.toBuffer();
}
/**
* Restore backup for Worlds and Settings
*
* WARNING: This will overwrite existing files and World folder files
*/
export async function RestoreBackup(zipBuffer: Buffer): Promise<void> {
const zip = new admZip(zipBuffer);
await new Promise((resolve, reject) => zip.extractAllToAsync(javaPath, true, true, (err) => !!err ? reject(err) : resolve("")));
return;
}

View File

@ -1,7 +1,7 @@
import path from "node:path";
import fs from "node:fs";
import * as versionManeger from "@the-bds-maneger/server_versions";
import * as httpRequests from "../../HttpRequests";
import * as httpRequests from "../../lib/HttpRequests";
import { serverRoot } from "../../pathControl";
export default async function download(version: string|boolean) {

View File

@ -1,2 +1,10 @@
import DownloadServer from "./download";
export {DownloadServer};
import * as server from "./server";
import * as backup from "./backup";
// Export
export {
DownloadServer,
server,
backup
};

View File

@ -0,0 +1,132 @@
import path from "node:path";
import fs from "node:fs";
import crypto from "node:crypto";
import node_cron from "cron";
import * as child_process from "../../lib/childProcess";
import { backupRoot, serverRoot } from "../../pathControl";
import { BdsSession, bdsSessionCommands } from '../../globalType';
import { createZipBackup } from "../../backup/zip";
import events from "../../lib/customEvents";
const javaSesions: {[key: string]: BdsSession} = {};
export function getSessions() {return javaSesions;}
const ServerPath = path.join(serverRoot, "spigot");
export async function startServer(): Promise<BdsSession> {
const SessionID = crypto.randomUUID();
// Start Server
const serverEvents = new events();
const StartDate = new Date();
const ServerProcess = await child_process.execServer({runOn: "host"}, "java", ["-jar", "Server.jar"], {cwd: ServerPath});
const { onExit, on: execOn } = ServerProcess;
// Log Server redirect to callbacks events and exit
execOn("out", data => serverEvents.emit("log_stdout", data));
execOn("err", data => serverEvents.emit("log_stderr", data));
execOn("all", data => serverEvents.emit("log", data));
onExit().catch(err => {serverEvents.emit("err", err);return null}).then(code => serverEvents.emit("closed", code));
// Server Start
serverEvents.on("log", lineData => {
// [22:35:26] [Server thread/INFO]: Done (6.249s)! For help, type "help"
if (/\[.*\].*\s+Done\s+\(.*\)\!.*/.test(lineData)) serverEvents.emit("started", new Date());
});
// Parse ports
serverEvents.on("log", data => {
const portParse = data.match(/Starting\s+Minecraft\s+server\s+on\s+(.*)\:(\d+)/);
if (!!portParse) serverEvents.emit("port_listen", {port: parseInt(portParse[2]), version: "IPv4/IPv6", protocol: "TCP"});
});
// Run Command
const serverCommands: bdsSessionCommands = {
/**
* Run any commands in server.
* @param command - Run any commands in server without parse commands
* @returns - Server commands
*/
execCommand: (...command) => {
ServerProcess.writelf(command.map(a => String(a)).join(" "));
return serverCommands;
},
tpPlayer: (player: string, x: number, y: number, z: number) => {
serverCommands.execCommand("tp", player, x, y, z);
return serverCommands;
},
worldGamemode: (gamemode: "survival"|"creative"|"hardcore") => {
serverCommands.execCommand("gamemode", gamemode);
return serverCommands;
},
userGamemode: (player: string, gamemode: "survival"|"creative"|"hardcore") => {
serverCommands.execCommand("gamemode", gamemode, player);
return serverCommands;
},
stop: (): Promise<number|null> => {
if (ServerProcess.Exec.exitCode !== null||ServerProcess.Exec.killed) return Promise.resolve(ServerProcess.Exec.exitCode);
if (ServerProcess.Exec.killed) return Promise.resolve(ServerProcess.Exec.exitCode);
ServerProcess.writelf("stop");
return ServerProcess.onExit();
}
}
const backupCron = (crontime: string|Date, option?: {type: "zip", config?: {pathZip?: string}}): node_cron.CronJob => {
// Validate Config
if (option) {
if (option.type === "zip") {}
else option = {type: "zip"};
}
async function lockServerBackup() {
serverCommands.execCommand("save hold");
await new Promise(accept => setTimeout(accept, 1000));
serverCommands.execCommand("save query");
await new Promise(accept => setTimeout(accept, 1000));
}
async function unLockServerBackup() {
serverCommands.execCommand("save resume");
await new Promise(accept => setTimeout(accept, 1000));
}
if (!option) option = {type: "zip"};
const CrontimeBackup = new node_cron.CronJob(crontime, async () => {
if (option.type === "zip") {
await lockServerBackup();
if (!!option?.config?.pathZip) await createZipBackup({path: path.resolve(backupRoot, option?.config?.pathZip)}).catch(() => undefined);
else await createZipBackup(true).catch(() => undefined);
await unLockServerBackup();
}
});
CrontimeBackup.start();
serverEvents.on("closed", () => CrontimeBackup.stop());
return CrontimeBackup;
}
// Session log
const logFile = path.resolve(process.env.LOG_PATH||path.resolve(ServerPath, "../log"), `bedrock_${SessionID}.log`);
if(!(fs.existsSync(path.parse(logFile).dir))) fs.mkdirSync(path.parse(logFile).dir, {recursive: true});
const logStream = fs.createWriteStream(logFile, {flags: "w+"});
logStream.write(`[${StartDate.toString()}] Server started\n\n`);
ServerProcess.Exec.stdout.pipe(logStream);
ServerProcess.Exec.stderr.pipe(logStream);
// Session Object
const Seesion: BdsSession = {
id: SessionID,
creteBackup: backupCron,
ports: [],
Player: {},
seed: undefined,
commands: serverCommands,
server: {
on: (act, fn) => serverEvents.on(act, fn),
once: (act, fn) => serverEvents.once(act, fn),
started: false,
startDate: StartDate
}
};
serverEvents.on("started", StartDate => {Seesion.server.startDate = StartDate; Seesion.server.started = true;});
serverEvents.on("port_listen", portObject => Seesion.ports.push(portObject));
// Return Session
javaSesions[SessionID] = Seesion;
serverEvents.on("closed", () => delete javaSesions[SessionID]);
return Seesion;
}

View File

@ -0,0 +1,23 @@
import * as spigot from "./index";
export default async function spigotTest() {
// Download and install server
const download = await spigot.DownloadServer(true);
console.log("Version: %s, Date: %o, url: %s", download.version, download.publishDate, download.url);
// Start Server
const server = await spigot.server.startServer();
if (process.argv.includes("--show-log")) server.server.on("log", console.log);
server.server.once("started", () => console.log("Server started"));
server.server.on("port_listen", port => console.log("Server listening on port: %o with protocol: %s", port.port, port.protocol));
await new Promise((resolve, reject) => {
server.server.once("started", resolve);
server.server.once("closed", code => code === null ? resolve(code) : reject(code));
});
await server.commands.stop();
// Backup
const zipFile = await spigot.backup.CreateBackup();
console.log("Backup created: %o", zipFile.length);
return;
}

View File

@ -1,38 +0,0 @@
import * as server from "./server";
export const name = "startServer";
export const depends = "installServer";
export async function java() {
console.log("Starting java server...");
const session = await server.Start("java");
session.log.on("all", console.log);
await new Promise(res => {
session.server.once("started", (date: Date) => {
console.log("java started at", date);
console.log("Stoping java");
res("");
});
});
return session.commands.stop();
}
export async function pocketmine() {
console.log("Starting pocketmine server...");
const session = await server.Start("pocketmine");
session.log.on("all", console.log);
session.log.on("all", data => {
// [*] PocketMine-MP set-up wizard
if (/set-up\s+wizard/.test(data)) {
console.log("Auto setup wizard");
session.commands.execCommand("eng").execCommand("y").execCommand("y");
}
});
await new Promise(res => {
session.server.once("started", (date: Date) => {
console.log("pocketmine started at", date);
console.log("Stoping pocketmine");
res("")
});
});
return session.commands.stop();
}

View File

@ -1,178 +1,22 @@
import path from "node:path";
import fs from "node:fs";
import events from "events";
import crypto from "crypto";
import node_cron from "cron";
import * as platformManeger from "./platform";
import * as child_process from "./childProcess";
import { parseConfig as serverConfigParse } from "./serverConfig";
import * as worldManeger from "./worldManeger";
import * as bdsTypes from "./globalType";
import { backupRoot, serverRoot } from "./pathControl";
import { gitBackup, gitBackupOption } from "./backup/git";
import { createZipBackup } from "./backup/zip";
import platformManeger from "./platform";
import { BdsSession, Platform } from "./globalType";
// Server Sessions
const Sessions: {[Session: string]: bdsTypes.BdsSession} = {};
export function getSessions(): {[SessionID: string]: bdsTypes.BdsSession} {return {
const Sessions: {[Session: string]: BdsSession} = {};
export function getSessions(): {[SessionID: string]: BdsSession} {return {
...Sessions,
...(platformManeger.bedrock.server.getSessions()),
...(platformManeger.pocketmine.server.getSessions()),
...(platformManeger.java.server.getSessions()),
...(platformManeger.spigot.server.getSessions()),
};}
// Start Server
export default Start;
export async function Start(Platform: bdsTypes.Platform, options?: bdsTypes.startServerOptions): Promise<bdsTypes.BdsSession> {
const SessionID = crypto.randomUUID();
const ServerPath = path.join(serverRoot, Platform);
if (!(fs.existsSync(ServerPath))) fs.mkdirSync(ServerPath, {recursive: true});
const Process: {command: string; args: Array<string>; env: {[env: string]: string};} = {
command: "",
args: [],
env: {}
};
export default StartServer;
export async function StartServer(Platform: Platform): Promise<BdsSession> {
if (Platform === "bedrock") return platformManeger.bedrock.server.startServer();
else if (Platform === "java") return platformManeger.java.server.startServer();
else if (Platform === "pocketmine") return platformManeger.pocketmine.server.startServer();
else if (Platform === "spigot") {
Process.command = "java";
Process.args.push("-jar");
Process.args.push(path.resolve(ServerPath, "Spigot.jar"));
}
if (options?.storageOnlyWorlds) {
await worldManeger.storageWorld(Platform, ServerPath, (await serverConfigParse(Platform)).world);
}
// Start Server
const serverEvents = new events();
const StartDate = new Date();
const ServerProcess = await child_process.execServer({runOn: "host"}, Process.command, Process.args, {env: Process.env, cwd: ServerPath});
const { onExit } = ServerProcess;
const onLog = {on: ServerProcess.on, once: ServerProcess.once};
const playerCallbacks: {[id: string]: {callback: (data: {player: string; action: "connect"|"disconnect"|"unknown"; date: Date;}) => void}} = {};
const onPlayer = (callback: (data: {player: string; action: "connect"|"disconnect"|"unknown"; date: Date;}) => void) => {
const uid = crypto.randomUUID();
playerCallbacks[uid] = {callback: callback};
return uid;
};
const playersConnections: {
[player: string]: {
action: "connect"|"disconnect"|"unknown";
date: Date;
history: Array<{
action: "connect"|"disconnect"|"unknown";
date: Date
}>
}
} = {};
const ports: Array<{port: number; protocol?: "TCP"|"UDP"; version?: "IPv4"|"IPv6"|"IPv4/IPv6";}> = [];
// Run Command
const serverCommands: bdsTypes.bdsSessionCommands = {
/**
* Run any commands in server.
* @param command - Run any commands in server without parse commands
* @returns - Server commands
*/
execCommand: (...command) => {
ServerProcess.Exec.stdin.write(command.map(a => String(a)).join(" ")+"\n");
return serverCommands;
},
tpPlayer: (player: string, x: number, y: number, z: number) => {
serverCommands.execCommand("tp", player, x, y, z);
return serverCommands;
},
worldGamemode: (gamemode: "survival"|"creative"|"hardcore") => {
if (Platform === "spigot"||Platform === "pocketmine") serverCommands.execCommand("gamemode", gamemode);
return serverCommands;
},
userGamemode: (player: string, gamemode: "survival"|"creative"|"hardcore") => {
if (Platform === "spigot"||Platform === "pocketmine") serverCommands.execCommand("gamemode", gamemode, player);
return serverCommands;
},
stop: (): Promise<number|null> => {
if (ServerProcess.Exec.exitCode !== null||ServerProcess.Exec.killed) return Promise.resolve(ServerProcess.Exec.exitCode);
if (Platform === "spigot"||Platform === "pocketmine") serverCommands.execCommand("stop");
else ServerProcess.Exec.kill();
if (ServerProcess.Exec.killed) return Promise.resolve(ServerProcess.Exec.exitCode);
return ServerProcess.onExit();
}
}
const backupCron = (crontime: string|Date, option?: {type: "git"; config: gitBackupOption}|{type: "zip", config?: {pathZip?: string}}): node_cron.CronJob => {
// Validate Config
if (option) {
if (option.type === "git") {
if (!option.config) throw new Error("Config is required");
} else if (option.type === "zip") {}
else option = {type: "zip"};
}
async function lockServerBackup() {
if (Platform === "bedrock") {
serverCommands.execCommand("save hold");
await new Promise(accept => setTimeout(accept, 1000));
serverCommands.execCommand("save query");
await new Promise(accept => setTimeout(accept, 1000));
}
}
async function unLockServerBackup() {
if (Platform === "bedrock") {
serverCommands.execCommand("save resume");
await new Promise(accept => setTimeout(accept, 1000));
}
}
if (!option) option = {type: "zip"};
const CrontimeBackup = new node_cron.CronJob(crontime, async () => {
if (option.type === "git") {
await lockServerBackup();
await gitBackup(option.config).catch(() => undefined).then(() => unLockServerBackup());
} else if (option.type === "zip") {
await lockServerBackup();
if (!!option?.config?.pathZip) await createZipBackup({path: path.resolve(backupRoot, option?.config?.pathZip)}).catch(() => undefined);
else await createZipBackup(true).catch(() => undefined);
await unLockServerBackup();
}
});
CrontimeBackup.start();
onExit().catch(() => null).then(() => CrontimeBackup.stop());
return CrontimeBackup;
}
// Session log
const logFile = path.resolve(process.env.LOG_PATH||path.resolve(ServerPath, "../log"), `${Platform}_${SessionID}.log`);
if(!(fs.existsSync(path.parse(logFile).dir))) fs.mkdirSync(path.parse(logFile).dir, {recursive: true});
const logStream = fs.createWriteStream(logFile, {flags: "w+"});
logStream.write(`[${StartDate.toString()}] Server started\n\n`);
ServerProcess.Exec.stdout.pipe(logStream);
ServerProcess.Exec.stderr.pipe(logStream);
const serverOn = (act: "started" | "ban", call: (...any: any[]) => void) => serverEvents.on(act, call);
const serverOnce = (act: "started" | "ban", call: (...any: any[]) => void) => serverEvents.once(act, call);
// Session Object
const Seesion: bdsTypes.BdsSession = {
id: SessionID,
startDate: StartDate,
creteBackup: backupCron,
onExit: onExit,
onPlayer: onPlayer,
ports: () => ports,
getPlayer: () => playersConnections,
server: {
on: serverOn,
once: serverOnce
},
seed: undefined,
started: false,
addonManeger: undefined,
log: onLog,
commands: serverCommands,
};
// Return Session
Sessions[SessionID] = Seesion;
onExit().catch(() => null).then(() => delete Sessions[SessionID]);
return Seesion;
else if (Platform === "spigot") return platformManeger.spigot.server.startServer();
throw new Error(`Platform ${Platform} is not supported`);
}

View File

@ -1,6 +0,0 @@
FROM ghcr.io/the-bds-maneger/container:latest
WORKDIR /testApp
COPY ./package*.json ./
RUN npm ci
COPY ./ ./
RUN npm run test:host -- --exit-on-error --show-return

View File

@ -1,65 +0,0 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const { execSync } = require("child_process");
const testDir = path.join(__dirname, ".testDir");
if (fs.existsSync(testDir)) fs.rmSync(testDir, { recursive: true });
fs.mkdirSync(testDir);
/**
* Read dir recursively
*
* @param {string} dir
* @param {Array<RegExp>} filterFile
* @returns {Promise<Array<string>>}
*/
async function readdirRecursive(dir, filterFile) {
if (!fs.existsSync(dir)) throw new Error(`Directory not found: ${dir}`);
if (!(fs.statSync(dir).isDirectory())) return [dir];
if (!filterFile) filterFile = [];
/** @type {Array<string>} */
const files = [];
/** @type {Array<string>} */
const dirs = fs.readdirSync(dir);
for (const d of dirs) {
const dirPath = path.resolve(dir, d);
if (fs.statSync(dirPath).isDirectory()) files.push(...(await readdirRecursive(dirPath, filterFile)));
else {
if (filterFile.length <= 0) files.push(dirPath);
else {
if (filterFile.some(f => f.test(d))) files.push(dirPath);
}
}
}
return files;
}
if (fs.existsSync(path.join(__dirname, "dist"))) fs.rmSync(path.join(__dirname, "dist"), {recursive: true, force: true});
console.log("Building project");
execSync("npm run build:cjs", { stdio: "inherit" });
(async function() {
/** @type {Array<{filePath: string, funcs: {name?: string, depends?: string}}>} */
const Files = await readdirRecursive(path.join(__dirname, "dist/cjs"), [/\.test\.js$/]).then(res => res.map(x => ({filePath: x, funcs: require(x)})));
const Sort = [];
while (Files.length > 0) {
const File = Files.shift();
if (!File.funcs.depends||!File.funcs.name) Sort.push(File);
else {
const depends = File.funcs.depends;
if (Sort.some(f => f.funcs.name === depends)) Sort.push(File);
else Files.push(File);
}
}
// return console.log(Sort);
for (const {filePath: file, funcs: main} of Sort) {
const logFile = path.join(testDir, file.replace(path.join(__dirname, "dist/cjs"), "").replace(/\/|\\/gi, "_").replace(/\.test\.[tj]s$/, "").replace(/^_/, ""), "");
const log = [];
for (const func of Object.keys(main).filter(key => typeof main[key] === "function")) {
const Data = await main[func]();
console.log(`${file}#${func}: %o`, Data);
}
fs.writeFileSync(logFile+".json", JSON.stringify(log, null, 2));
}
})();

49
testProject.ts Normal file
View File

@ -0,0 +1,49 @@
import * as fs from "node:fs/promises";
import * as fsOld from "node:fs";
import * as path from "node:path";
async function readDirAndFilter(dir: string, test: Array<RegExp> = [/.*/]) {
if (!(fsOld.existsSync(dir))) throw new Error(`${dir} does not exist`);
const files = await fs.readdir(dir);
const parseFiles: Array<string> = []
await Promise.all(files.map(async (fd) => {
const stat = await fs.stat(path.join(dir, fd));
if (stat.isDirectory()) return readDirAndFilter(path.join(dir, fd), test).then(res => parseFiles.push(...res)).catch(err => console.error(err));
else if (stat.isFile()) {
const match = test.some(reg => reg.test(fd));
if (match) parseFiles.push(path.join(dir, fd));
}
}));
return parseFiles;
}
async function runTest() {
const mainFind = path.join(process.cwd(), "src");
const testsFiles = await readDirAndFilter(mainFind, [/.*\.test\.ts$/]);
for (const file of testsFiles) {
console.log("************** Start Script: %s **************", file);
const testScript = await import(file) as {[key: string]: () => Promise<void>};
if (!!testScript.default) {
console.log("************** Start Test: %s **************", file);
await testScript.default();
}
for (const key in testScript) {
if (key === "default") continue;
console.log("************** Start Test: %s **************", key);
await testScript[key]();
}
console.log("************** End Script: %s **************", file);
}
}
runTest().then(() => {
console.log("Test passed");
process.exitCode = 0;
}).catch((err: Error) => {
console.error("Test failed");
console.error(err);
process.exitCode = 1;
}).then(() => {
console.log("Exit with code: %d", process.exitCode);
return process.exit();
});