Bump yargs from 17.7.0 to 17.7.1 #509
@ -1,11 +0,0 @@
|
||||
FROM ghcr.io/sirherobrine23/initjs:latest
|
||||
# Install dependecies to Bedrock server
|
||||
RUN (apt update && apt install -y libssl1.1 || (echo "deb http://security.ubuntu.com/ubuntu focal-security main" | tee /etc/apt/sources.list.d/focal-security.list && apt update && apt install -y libssl1.1)) || echo exit $?
|
||||
|
||||
# Add non root user and Install oh my zsh
|
||||
ARG USERNAME="devcontainer"
|
||||
ARG USER_UID="1000"
|
||||
ARG USER_GID=$USER_UID
|
||||
RUN initjs create-user --username "${USERNAME}" --uid "${USER_UID}" --gid "${USER_GID}" --groups sudo --groups docker
|
||||
USER $USERNAME
|
||||
WORKDIR /home/$USERNAME
|
@ -1,49 +0,0 @@
|
||||
{
|
||||
"name": "Bds Maneger Core",
|
||||
"updateRemoteUserUID": false,
|
||||
"containerUser": "develop",
|
||||
"remoteUser": "develop",
|
||||
"overrideCommand": false,
|
||||
"postCreateCommand": "npm install",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"USERNAME": "develop",
|
||||
"USER_UID": "1000"
|
||||
}
|
||||
},
|
||||
"runArgs": [
|
||||
"--init",
|
||||
"--privileged"
|
||||
],
|
||||
"mounts": [
|
||||
"target=/var/lib/docker,type=volume,source=bdsmanegercore"
|
||||
],
|
||||
"extensions": [
|
||||
"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",
|
||||
"formulahendry.code-runner",
|
||||
"chrmarti.regex"
|
||||
],
|
||||
"settings": {
|
||||
"editor.tabSize": 2,
|
||||
"editor.minimap.enabled": false,
|
||||
"files.eol": "\n",
|
||||
"files.trimFinalNewlines": true,
|
||||
"files.trimTrailingWhitespace": true
|
||||
}
|
||||
}
|
@ -10,4 +10,4 @@ updates:
|
||||
schedule:
|
||||
interval: monthly
|
||||
assignees:
|
||||
- Sirherobrine23
|
||||
- Sirherobrine23
|
29
.github/spigotBuilld/index.mjs
vendored
29
.github/spigotBuilld/index.mjs
vendored
@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import { createReadStream, promises as fs } from "node:fs";
|
||||
import { Cloud, Extends } from "@sirherobrine23/coreutils";
|
||||
import path from "path";
|
||||
const { tenancy, fingerprint, privateKey, user, passphase } = process.env;
|
||||
const oracleBucket = await Cloud.oracleBucket({
|
||||
region: "sa-saopaulo-1",
|
||||
name: "bdsFiles",
|
||||
namespace: "grwodtg32n4d",
|
||||
auth: {
|
||||
type: "user",
|
||||
tenancy,
|
||||
fingerprint,
|
||||
privateKey,
|
||||
user,
|
||||
passphase
|
||||
}
|
||||
})
|
||||
const __dirname = path.resolve(process.cwd(), process.argv.slice(2)[0]||"");
|
||||
|
||||
await Extends.extendsFS.readdir({folderPath: __dirname}).then(files => files.filter(file => file.endsWith(".jar"))).then(async files => {
|
||||
for (const file of files) {
|
||||
const version = path.basename(file, ".jar").split("-")[1];
|
||||
if (!version) continue;
|
||||
console.log("Uploading %s, file: %O", version, "SpigotBuild/"+version+".jar");
|
||||
await oracleBucket.uploadFile("SpigotBuild/"+version+".jar", createReadStream(file)).then(() => console.log("Uploaded %s", version));
|
||||
await fs.unlink(file);
|
||||
}
|
||||
});
|
23
.github/uploadToBucket.mjs
vendored
Normal file
23
.github/uploadToBucket.mjs
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env node
|
||||
import { createReadStream } from "fs";
|
||||
import { oracleBucket } from "@sirherobrine23/cloud";
|
||||
import extendsFS from "@sirherobrine23/extends";
|
||||
import path from "node:path";
|
||||
|
||||
const [,, remote, local] = process.argv;
|
||||
const bucket = await oracleBucket.oracleBucket({
|
||||
region: "sa-saopaulo-1",
|
||||
namespace: "grwodtg32n4d",
|
||||
name: "bdsFiles",
|
||||
auth: {
|
||||
type: "preAuthentication",
|
||||
// Public auth (No write enabled).
|
||||
PreAuthenticatedKey: process.env.OCI_AUTHKEY
|
||||
}
|
||||
});
|
||||
|
||||
for await (const file of await extendsFS.readdir(path.resolve(process.cwd(), local))) {
|
||||
console.log("Uploading %O", file);
|
||||
await bucket.uploadFile(path.posix.resolve("/", remote ?? "", path.basename(file)), createReadStream(file));
|
||||
console.log("Success %O", file);
|
||||
}
|
24
.github/uploadphp/index.mjs
vendored
24
.github/uploadphp/index.mjs
vendored
@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import { createReadStream } from "node:fs";
|
||||
import coreutils, { extendFs } from "@sirherobrine23/coreutils";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs/promises";
|
||||
if (!process.env.OCI_AUTHKEY) throw new Error("No key auth");
|
||||
const ociKeyAuth = (process.env.OCI_AUTHKEY||"").trim();
|
||||
console.log("using key to upload '%s'", ociKeyAuth);
|
||||
|
||||
const files = (await extendFs.readdir({folderPath: path.join(process.cwd(), "phpOutput")})).filter(file => file.endsWith(".tar.gz")||file.endsWith(".zip")||file.endsWith(".tgz"));
|
||||
await Promise.all(files.map(async file => {
|
||||
const fileName = path.basename(file);
|
||||
console.log("Uploading %s", fileName);
|
||||
await coreutils.httpRequest.bufferFetch({
|
||||
url: `https://objectstorage.sa-saopaulo-1.oraclecloud.com/p/${ociKeyAuth}/n/grwodtg32n4d/b/bdsFiles/o/php_bin/${encodeURIComponent(fileName.toLowerCase())}`,
|
||||
method: "PUT",
|
||||
body: createReadStream(file),
|
||||
headers: {
|
||||
"Content-Length": (await fs.lstat(file)).size.toString(),
|
||||
"Content-Type": "application/octet-stream"
|
||||
}
|
||||
});
|
||||
console.log("Upload success to %s", fileName);
|
||||
}));
|
43
.github/workflows/code_analyzer.yml
vendored
43
.github/workflows/code_analyzer.yml
vendored
@ -1,43 +0,0 @@
|
||||
name: Code Analyze
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
schedule:
|
||||
- cron: "26 8 * * 1"
|
||||
|
||||
jobs:
|
||||
snyk:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Run Snyk to check for vulnerabilities
|
||||
uses: snyk/actions/node@master
|
||||
continue-on-error: true
|
||||
env:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
with:
|
||||
args: --sarif-file-output=snyk.sarif
|
||||
- name: Upload result to GitHub Code Scanning
|
||||
continue-on-error: true
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: snyk.sarif
|
||||
|
||||
codeql:
|
||||
name: CodeQL Analyze
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: javascript
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
43
.github/workflows/gendocs.yaml
vendored
43
.github/workflows/gendocs.yaml
vendored
@ -1,43 +0,0 @@
|
||||
name: Deploy bds core wiki
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "src/**/*"
|
||||
- "tests/**/*"
|
||||
- "package*.json"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
deploy_doc:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
name: Setup node.js
|
||||
with:
|
||||
node-version: latest
|
||||
|
||||
- run: npm ci
|
||||
|
||||
- name: Gen docs
|
||||
run: npm run docs
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
with:
|
||||
path: "docs"
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
@ -215,7 +215,7 @@ jobs:
|
||||
path: ./phpOutput
|
||||
|
||||
- name: Upload to bucket
|
||||
run: node .github/uploadphp/index.mjs
|
||||
run: node .github/uploadphp/index.mjs php_bin phpOutput
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
OCI_AUTHKEY: ${{ secrets.OCI_AUTHKEY }}
|
||||
OCI_AUTHKEY: ${{ secrets.OCI_AUTHKEY }}
|
69
.github/workflows/publish.yml
vendored
69
.github/workflows/publish.yml
vendored
@ -1,69 +0,0 @@
|
||||
name: Publish package
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- prereleased
|
||||
- released
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
publishpackage:
|
||||
runs-on: ubuntu-latest
|
||||
name: Publish
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
name: Code checkout
|
||||
with:
|
||||
persist-credentials: true
|
||||
ref: main
|
||||
fetch-depth: 2
|
||||
submodules: true
|
||||
|
||||
# Install basic tools
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
name: Setup node.js
|
||||
with:
|
||||
registry-url: https://registry.npmjs.org/
|
||||
node-version: latest
|
||||
|
||||
- name: Edit version
|
||||
shell: node {0}
|
||||
run: |
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const packagePath = path.join(process.cwd(), "package.json");
|
||||
const package = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
||||
package.version = "${{ github.ref }}";
|
||||
package.version = package.version.replace(/[A-Za-z_\/]+/, "");
|
||||
fs.writeFileSync(packagePath, JSON.stringify(package, null, 2));
|
||||
|
||||
# Install depencides and build
|
||||
- run: npm ci && npm run build
|
||||
|
||||
# Publish
|
||||
- run: npm publish --tag ${{ github.event.release.prerelease && 'next' || 'latest' }}
|
||||
name: Publish to npm
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_ORG_TOKEN }}
|
||||
|
||||
# Add version to environment variables
|
||||
- name: Add version to environment variables
|
||||
run: |
|
||||
cat package.json | jq -r '.version' > /tmp/version.txt
|
||||
echo "PACKAGE_VERSION=$(cat /tmp/version.txt)" >> $GITHUB_ENV
|
||||
|
||||
# Create pull request to update version in main branch
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
name: Create Pull Request
|
||||
continue-on-error: true
|
||||
with:
|
||||
commit-message: Update version v${{ env.PACKAGE_VERSION }}
|
||||
delete-branch: true
|
||||
assignees: SirHerobrine23
|
||||
reviewers: SirHerobrine23
|
||||
branch: update-version
|
||||
title: Update package version v${{ env.PACKAGE_VERSION }}
|
||||
body: Auto update package version, created with GitHub Actions
|
8
.github/workflows/spigotBuild.yaml
vendored
8
.github/workflows/spigotBuild.yaml
vendored
@ -107,10 +107,6 @@ jobs:
|
||||
path: artifacts
|
||||
|
||||
- name: Upload to actifial
|
||||
run: node .github/spigotBuilld/index.mjs artifacts
|
||||
run: node .github/uploadToBucket.ts SpigotBuild artifacts
|
||||
env:
|
||||
tenancy: ${{ secrets.OCI_TENANCY }}
|
||||
fingerprint: ${{ secrets.OCI_FING }}
|
||||
privateKey: ${{ secrets.OCI_PRIV }}
|
||||
user: ${{ secrets.OCI_USER }}
|
||||
passphase: ${{ secrets.OCI_PASSPHASE || '' }}
|
||||
OCI_AUTHKEY: ${{ secrets.OCI_AUTHKEY }}
|
@ -1,23 +1,13 @@
|
||||
|
||||
name: Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "src/**/*"
|
||||
- "tests/**/*"
|
||||
- "package*.json"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: "Test"
|
||||
env:
|
||||
BDS_HOME: "~/.bdsCore"
|
||||
bdscoreroot: "~/.bdsCore"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
name: Code checkout
|
||||
@ -36,8 +26,8 @@ jobs:
|
||||
|
||||
# Install dependecies
|
||||
- name: Install nodejs dependencies
|
||||
run: npm ci
|
||||
run: npm install --no-save
|
||||
|
||||
# Run test
|
||||
- name: Test
|
||||
run: npm run test
|
||||
# Build Core
|
||||
- name: Core Build
|
||||
run: cd package/core && npm run build
|
20
.gitignore
vendored
20
.gitignore
vendored
@ -1,17 +1,9 @@
|
||||
/*.log
|
||||
# Node
|
||||
node_modules/
|
||||
dist/
|
||||
src/**/*.d.ts
|
||||
src/**/*.d.js
|
||||
src/**/*.js
|
||||
docs/
|
||||
|
||||
# PHP Bins
|
||||
muslCrossMake/
|
||||
phpOutput/
|
||||
*.tar.gz
|
||||
*.tgz
|
||||
*.zip
|
||||
# Typescript
|
||||
packages/**/*.js
|
||||
packages/**/*.d.ts
|
||||
|
||||
# Spigot
|
||||
*.jar
|
||||
# PHP Pre builds
|
||||
phpOutput/
|
19
.gitpod.yml
19
.gitpod.yml
@ -1,19 +0,0 @@
|
||||
image:
|
||||
file: .devcontainer/Dockerfile
|
||||
tasks:
|
||||
- init: npm install
|
||||
vscode:
|
||||
extensions:
|
||||
- formulahendry.code-runner
|
||||
- github.vscode-pull-request-github
|
||||
- redhat.vscode-yaml
|
||||
- eamodio.gitlens
|
||||
- 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
|
||||
- cschleiden.vscode-github-actions
|
||||
- oderwat.indent-rainbow
|
||||
- ms-azuretools.vscode-docker
|
8
.hintrc
8
.hintrc
@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"development"
|
||||
],
|
||||
"hints": {
|
||||
"typescript-config/strict": "off"
|
||||
}
|
||||
}
|
11
.mocharc.yml
11
.mocharc.yml
@ -1,11 +0,0 @@
|
||||
exit: true
|
||||
colors: true
|
||||
full-trace: true
|
||||
recursive: true
|
||||
parallel: true
|
||||
timeout: 0
|
||||
node-option:
|
||||
- "experimental-specifier-resolution=node"
|
||||
- "loader=ts-node/esm"
|
||||
extension:
|
||||
- "test.ts"
|
@ -1,2 +0,0 @@
|
||||
!dist/
|
||||
backup_*.zip
|
22
.vscode/extensions.json
vendored
22
.vscode/extensions.json
vendored
@ -1,22 +0,0 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"formulahendry.code-runner",
|
||||
"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"
|
||||
]
|
||||
}
|
34
.vscode/launch.json
vendored
34
.vscode/launch.json
vendored
@ -1,34 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"name": "Current file",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"request": "launch",
|
||||
"env": {
|
||||
"BDSD_IGNORE_KEY": "1",
|
||||
"PORT": "3000"
|
||||
},
|
||||
"args": [
|
||||
"-r", "ts-node/register",
|
||||
"${file}"
|
||||
],
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"name": "Mocha Tests",
|
||||
"program": "${workspaceFolder}/node_modules/mocha/bin/mocha.js",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"request": "launch",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"args": [
|
||||
"-r", "ts-node/register",
|
||||
"--colors",
|
||||
"${workspaceFolder}/tests/**/*.ts"
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -8,9 +8,7 @@
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.exclude": {
|
||||
"**/node_modules/": true,
|
||||
// Ignore generate tsc files
|
||||
"**/dist/": true,
|
||||
"**/src/**/*.js": false,
|
||||
"**/src/**/*.d.ts": false,
|
||||
"**/src/**/*.js": true,
|
||||
"**/src/**/*.d.ts": true,
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
Email or Github issues.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
@ -1,8 +0,0 @@
|
||||
# Contributing to the core
|
||||
|
||||
We hope to have multiple platforms supported by the project, as I want to bring together multiple servers to be managed in one place.
|
||||
|
||||
Any new platform will have to fork the repository or open an issue to request the new platform.
|
||||
|
||||
1. not all servers can be added because of project licensing but we can talk to the maintainers if needed.
|
||||
2. This project is designed to run on various operating systems such as Android, Linux, Windows and MacOS (other systems can be added to be supported).
|
5
LICENSE
5
LICENSE
@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
Copyright (C) 2023 Matheus Sampaio Queiroga
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
<program> Copyright (C) 2023 Matheus Sampaio Queiroga
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
@ -672,4 +672,3 @@ may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
||||
|
12
README.md
12
README.md
@ -1,12 +0,0 @@
|
||||
# Bds Maneger Core
|
||||
|
||||
A quick way to install, update and start your Minecraft Java and Bedrock server.
|
||||
|
||||
## Current Bds core support servers
|
||||
|
||||
1. `Bedrock` (Mojang)
|
||||
2. `Java` (Mojang)
|
||||
3. `Pocketmine` (PMMP - Minecraft bedrock server writed in PHP)
|
||||
4. `Spigot` (Spigot-MC is Minecraft java server to add plugins and more to server)
|
||||
5. `Powernukkit` (Minecraft Bedrock Server in java)
|
||||
6. `Paper` (PaperMC is Minecraft java server with plugins and mods)
|
@ -1,135 +0,0 @@
|
||||
server-name=Dedicated Server
|
||||
# Used as the server name
|
||||
# Allowed values: Any string without semicolon symbol.
|
||||
|
||||
gamemode=survival
|
||||
# Sets the game mode for new players.
|
||||
# Allowed values: "survival", "creative", or "adventure"
|
||||
|
||||
force-gamemode=false
|
||||
# force-gamemode=false (or force-gamemode is not defined in the server.properties)
|
||||
# prevents the server from sending to the client gamemode values other
|
||||
# than the gamemode value saved by the server during world creation
|
||||
# even if those values are set in server.properties after world creation.
|
||||
#
|
||||
# force-gamemode=true forces the server to send to the client gamemode values
|
||||
# other than the gamemode value saved by the server during world creation
|
||||
# if those values are set in server.properties after world creation.
|
||||
|
||||
difficulty=easy
|
||||
# Sets the difficulty of the world.
|
||||
# Allowed values: "peaceful", "easy", "normal", or "hard"
|
||||
|
||||
allow-cheats=false
|
||||
# If true then cheats like commands can be used.
|
||||
# Allowed values: "true" or "false"
|
||||
|
||||
max-players=10
|
||||
# The maximum number of players that can play on the server.
|
||||
# Allowed values: Any positive integer
|
||||
|
||||
online-mode=true
|
||||
# If true then all connected players must be authenticated to Xbox Live.
|
||||
# Clients connecting to remote (non-LAN) servers will always require Xbox Live authentication regardless of this setting.
|
||||
# If the server accepts connections from the Internet, then it's highly recommended to enable online-mode.
|
||||
# Allowed values: "true" or "false"
|
||||
|
||||
allow-list=false
|
||||
# If true then all connected players must be listed in the separate allowlist.json file.
|
||||
# Allowed values: "true" or "false"
|
||||
|
||||
server-port=34215
|
||||
# Which IPv4 port the server should listen to.
|
||||
# Allowed values: Integers in the range [1, 65535]
|
||||
|
||||
server-portv6=33657
|
||||
# Which IPv6 port the server should listen to.
|
||||
# Allowed values: Integers in the range [1, 65535]
|
||||
|
||||
view-distance=32
|
||||
# The maximum allowed view distance in number of chunks.
|
||||
# Allowed values: Positive integer equal to 5 or greater.
|
||||
|
||||
tick-distance=4
|
||||
# The world will be ticked this many chunks away from any player.
|
||||
# Allowed values: Integers in the range [4, 12]
|
||||
|
||||
player-idle-timeout=30
|
||||
# After a player has idled for this many minutes they will be kicked. If set to 0 then players can idle indefinitely.
|
||||
# Allowed values: Any non-negative integer.
|
||||
|
||||
max-threads=8
|
||||
# Maximum number of threads the server will try to use. If set to 0 or removed then it will use as many as possible.
|
||||
# Allowed values: Any positive integer.
|
||||
|
||||
level-name=Bedrock level
|
||||
# Allowed values: Any string without semicolon symbol or symbols illegal for file name: /\n\r\t\f`?*\\<>|\":
|
||||
|
||||
level-seed=
|
||||
# Use to randomize the world
|
||||
# Allowed values: Any string
|
||||
|
||||
default-player-permission-level=member
|
||||
# Permission level for new players joining for the first time.
|
||||
# Allowed values: "visitor", "member", "operator"
|
||||
|
||||
texturepack-required=false
|
||||
# Force clients to use texture packs in the current world
|
||||
# Allowed values: "true" or "false"
|
||||
|
||||
content-log-file-enabled=false
|
||||
# Enables logging content errors to a file
|
||||
# Allowed values: "true" or "false"
|
||||
|
||||
compression-threshold=1
|
||||
# Determines the smallest size of raw network payload to compress
|
||||
# Allowed values: 0-65535
|
||||
|
||||
compression-algorithm=zlib
|
||||
# Determines the compression algorithm to use for networking
|
||||
# Allowed values: "zlib", "snappy"
|
||||
|
||||
server-authoritative-movement=server-auth
|
||||
# Allowed values: "client-auth", "server-auth", "server-auth-with-rewind"
|
||||
# Enables server authoritative movement. If "server-auth", the server will replay local user input on
|
||||
# the server and send down corrections when the client's position doesn't match the server's.
|
||||
# If "server-auth-with-rewind" is enabled and the server sends a correction, the clients will be instructed
|
||||
# to rewind time back to the correction time, apply the correction, then replay all the player's inputs since then. This results in smoother and more frequent corrections.
|
||||
# Corrections will only happen if correct-player-movement is set to true.
|
||||
|
||||
player-movement-score-threshold=20
|
||||
# The number of incongruent time intervals needed before abnormal behavior is reported.
|
||||
# Disabled by server-authoritative-movement.
|
||||
|
||||
player-movement-action-direction-threshold=0.85
|
||||
# The amount that the player's attack direction and look direction can differ.
|
||||
# Allowed values: Any value in the range of [0, 1] where 1 means that the
|
||||
# direction of the players view and the direction the player is attacking
|
||||
# must match exactly and a value of 0 means that the two directions can
|
||||
# differ by up to and including 90 degrees.
|
||||
|
||||
player-movement-distance-threshold=0.3
|
||||
# The difference between server and client positions that needs to be exceeded before abnormal behavior is detected.
|
||||
# Disabled by server-authoritative-movement.
|
||||
|
||||
player-movement-duration-threshold-in-ms=500
|
||||
# The duration of time the server and client positions can be out of sync (as defined by player-movement-distance-threshold)
|
||||
# before the abnormal movement score is incremented. This value is defined in milliseconds.
|
||||
# Disabled by server-authoritative-movement.
|
||||
|
||||
correct-player-movement=false
|
||||
# If true, the client position will get corrected to the server position if the movement score exceeds the threshold.
|
||||
|
||||
|
||||
server-authoritative-block-breaking=false
|
||||
# If true, the server will compute block mining operations in sync with the client so it can verify that the client should be able to break blocks when it thinks it can.
|
||||
|
||||
chat-restriction=None
|
||||
# Allowed values: "None", "Dropped", "Disabled"
|
||||
# This represents the level of restriction applied to the chat for each player that joins the server.
|
||||
# "None" is the default and represents regular free chat.
|
||||
# "Dropped" means the chat messages are dropped and never sent to any client. Players receive a message to let them know the feature is disabled.
|
||||
# "Disabled" means that unless the player is an operator, the chat UI does not even appear. No information is displayed to the player.
|
||||
|
||||
disable-player-interaction=false
|
||||
# If true, the server will inform clients that they should ignore other players when interacting with the world. This is not server authoritative.
|
@ -1,57 +0,0 @@
|
||||
#Minecraft server properties
|
||||
#Mon Oct 17 00:27:26 UTC 2022
|
||||
enable-jmx-monitoring=false
|
||||
rcon.port=25575
|
||||
level-seed=
|
||||
gamemode=survival
|
||||
enable-command-block=false
|
||||
enable-query=false
|
||||
generator-settings={}
|
||||
enforce-secure-profile=true
|
||||
level-name=world
|
||||
motd=A Minecraft Server
|
||||
query.port=25565
|
||||
pvp=true
|
||||
generate-structures=true
|
||||
max-chained-neighbor-updates=1000000
|
||||
difficulty=easy
|
||||
network-compression-threshold=256
|
||||
max-tick-time=60000
|
||||
require-resource-pack=false
|
||||
use-native-transport=true
|
||||
max-players=20
|
||||
online-mode=true
|
||||
enable-status=true
|
||||
allow-flight=false
|
||||
broadcast-rcon-to-ops=true
|
||||
view-distance=10
|
||||
server-ip=
|
||||
resource-pack-prompt=
|
||||
allow-nether=true
|
||||
server-port=25565
|
||||
enable-rcon=false
|
||||
sync-chunk-writes=true
|
||||
op-permission-level=4
|
||||
prevent-proxy-connections=false
|
||||
hide-online-players=false
|
||||
resource-pack=
|
||||
entity-broadcast-range-percentage=100
|
||||
simulation-distance=10
|
||||
rcon.password=
|
||||
player-idle-timeout=0
|
||||
force-gamemode=false
|
||||
rate-limit=0
|
||||
hardcore=false
|
||||
white-list=false
|
||||
broadcast-console-to-ops=true
|
||||
spawn-npcs=true
|
||||
previews-chat=false
|
||||
spawn-animals=true
|
||||
function-permission-level=2
|
||||
level-type=minecraft\:normal
|
||||
text-filtering-config=
|
||||
spawn-monsters=true
|
||||
enforce-whitelist=false
|
||||
spawn-protection=16
|
||||
resource-pack-sha1=
|
||||
max-world-size=29999984
|
1338
package-lock.json
generated
1338
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
58
package.json
58
package.json
@ -1,52 +1,16 @@
|
||||
{
|
||||
"name": "@the-bds-maneger/core",
|
||||
"version": "5.4.0",
|
||||
"description": "A very simple way to manage Minecraft servers",
|
||||
"author": "Sirherobrine23",
|
||||
"name": "@the-bds-maneger/monorepo",
|
||||
"private": true,
|
||||
"scripts": {},
|
||||
"author": "Matheus Sampaio Queiroga <srherobrine20@gmail.com>",
|
||||
"license": "GPL-3.0",
|
||||
"homepage": "https://sirherobrine23.org/BdsProject",
|
||||
"type": "module",
|
||||
"types": "./src/index.d.ts",
|
||||
"main": "./src/index.js",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"docs": "typedoc --readme none --out docs src/index.ts",
|
||||
"build": "tsc",
|
||||
"test": "mocha src"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Sirherobrine23/Bds-Maneger-Core.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"bugs": {
|
||||
"url": "https://github.com/Sirherobrine23/Bds-Maneger-Core/issues/new",
|
||||
"email": "support_bds@sirherobrine23.org"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sirherobrine23/coreutils": "^3.1.2",
|
||||
"adm-zip": "^0.5.10",
|
||||
"compare-versions": "^5.0.3",
|
||||
"debug": "^4.3.4",
|
||||
"prismarine-nbt": "^2.2.1",
|
||||
"tar": "^6.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/adm-zip": "^0.5.0",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/mocha": "^10.0.1",
|
||||
"@types/node": "^18.13.0",
|
||||
"@types/tar": "^6.1.3",
|
||||
"mocha": "^10.2.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "^4.1.2",
|
||||
"typedoc": "^0.23.24",
|
||||
"@types/node": "^18.14.0",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
},
|
||||
"workspaces": [
|
||||
"package/core",
|
||||
"package/cli",
|
||||
"package/docker"
|
||||
]
|
||||
}
|
||||
|
18
package/cli/package.json
Normal file
18
package/cli/package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "@the-bds-maneger/cli",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"scripts": {},
|
||||
"keywords": [],
|
||||
"author": "Matheus Sampaio Queiroga <srherobrine20@gmail.com>",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@the-bds-maneger/core": "*",
|
||||
"yargs": "^17.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/yargs": "^17.0.22"
|
||||
}
|
||||
}
|
39
package/cli/src/index.ts
Normal file
39
package/cli/src/index.ts
Normal file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env node
|
||||
import bdsCore from "@the-bds-maneger/core";
|
||||
import yargs from "yargs";
|
||||
|
||||
// Init yargs
|
||||
yargs(process.argv.slice(2)).version(false).help(true).strictCommands().demandCommand()
|
||||
|
||||
// bedrock
|
||||
.command("bedrock", "Bedrock", yargs => yargs.command("install", "Install Server", async yargs => {
|
||||
const options = yargs.option("altServer", {
|
||||
string: true,
|
||||
description: "Select a server other than Mojang",
|
||||
demandOption: false,
|
||||
choices: [
|
||||
"pocketmine",
|
||||
"powernukkit",
|
||||
"cloudbust"
|
||||
],
|
||||
}).option("list", {
|
||||
alias: "l",
|
||||
boolean: true,
|
||||
default: false,
|
||||
description: "List versions instead of installing"
|
||||
}).option("version", {
|
||||
alias: "V",
|
||||
string: true,
|
||||
default: "latest",
|
||||
description: "Server version to install",
|
||||
}).parseSync();
|
||||
if (options.list) return console.log(JSON.stringify(await bdsCore.Bedrock.listVersions({altServer: options.altServer as any}), null, 2));
|
||||
const data = await bdsCore.Bedrock.installServer({
|
||||
altServer: options.altServer as any,
|
||||
version: options.version,
|
||||
});
|
||||
console.log("Server ID: %O", data.id);
|
||||
}))
|
||||
|
||||
// run
|
||||
.parseAsync();
|
31
package/cli/tsconfig.json
Normal file
31
package/cli/tsconfig.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"target": "ESNext",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"strict": false,
|
||||
"noUnusedLocals": true,
|
||||
"isolatedModules": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true,
|
||||
"lib": [
|
||||
"ESNext"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"**/*.test.*"
|
||||
],
|
||||
"ts-node": {
|
||||
"esm": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../core"
|
||||
}
|
||||
]
|
||||
}
|
5
package/core/README.md
Normal file
5
package/core/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Bds Maneger Core
|
||||
|
||||
Este é um nucleo de utilização basica como: Fazer download do servidor, Gerenciar e outras coisas.
|
||||
|
||||
**Atualmente suportamos varias servidores, tanto para o Bedrock tanto o Java**
|
26
package/core/package.json
Normal file
26
package/core/package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@the-bds-maneger/core",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"types": "src/index.d.ts",
|
||||
"type": "module",
|
||||
"author": "Matheus Sampaio Queiroga <srherobrine20@gmail.com>",
|
||||
"license": "GPL-3.0",
|
||||
"scripts": {
|
||||
"build": "tsc --build --clean && tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sirherobrine23/cloud": "^3.2.1",
|
||||
"@sirherobrine23/extends": "^3.2.1",
|
||||
"@sirherobrine23/http": "^3.2.1",
|
||||
"semver": "^7.3.8",
|
||||
"tar": "^6.1.13",
|
||||
"unzip-stream": "^0.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/semver": "^7.3.13",
|
||||
"@types/tar": "^6.1.4",
|
||||
"@types/unzip-stream": "^0.3.1"
|
||||
}
|
||||
}
|
12
package/core/src/index.ts
Normal file
12
package/core/src/index.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export * from "./serverManeger.js";
|
||||
export * as Bedrock from "./servers/bedrock.js";
|
||||
export * as Java from "./servers/java.js";
|
||||
|
||||
import * as serverManeger from "./serverManeger.js";
|
||||
import * as Bedrock from "./servers/bedrock.js";
|
||||
import * as Java from "./servers/java.js";
|
||||
export default {
|
||||
...serverManeger,
|
||||
Bedrock,
|
||||
Java
|
||||
};
|
@ -1,11 +1,12 @@
|
||||
import { Cloud } from "@sirherobrine23/coreutils";
|
||||
import { oracleBucket } from "@sirherobrine23/cloud";
|
||||
|
||||
export const oracleBucket = await Cloud.oracleBucket({
|
||||
export const oracleStorage = await oracleBucket.oracleBucket({
|
||||
region: "sa-saopaulo-1",
|
||||
namespace: "grwodtg32n4d",
|
||||
name: "bdsFiles",
|
||||
auth: {
|
||||
type: "preAuthentication",
|
||||
// Public auth (No write enabled).
|
||||
PreAuthenticatedKey: "0IKM-5KFpAF8PuWoVe86QFsF4sipU2rXfojpaOMEdf4QgFQLcLlDWgMSPHWmjf5W"
|
||||
}
|
||||
});
|
121
package/core/src/serverManeger.ts
Normal file
121
package/core/src/serverManeger.ts
Normal file
@ -0,0 +1,121 @@
|
||||
import { extendsFS } from "@sirherobrine23/extends";
|
||||
import child_process from "node:child_process";
|
||||
import crypto from "node:crypto";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
|
||||
// Default bds maneger core
|
||||
export const bdsManegerRoot = process.env.bdscoreroot ? path.resolve(process.cwd(), process.env.bdscoreroot) : path.join(os.homedir(), ".bdsmaneger");
|
||||
if (!(await extendsFS.exists(bdsManegerRoot))) await fs.mkdir(bdsManegerRoot, {recursive: true});
|
||||
|
||||
export type runOptions = {
|
||||
cwd: string,
|
||||
env?: {[k: string]: string|number|boolean},
|
||||
command: string,
|
||||
args?: (string|number|boolean)[],
|
||||
serverActions?: {
|
||||
stop?(child: serverRun): void|Promise<void>,
|
||||
}
|
||||
};
|
||||
|
||||
export declare class serverRun extends child_process.ChildProcess {
|
||||
on(event: string, listener: (...args: any[]) => void): this;
|
||||
on(event: "error", listener: (err: Error) => void): this;
|
||||
on(event: "close", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
|
||||
on(event: "disconnect", listener: () => void): this;
|
||||
on(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
|
||||
on(event: "message", listener: (message: child_process.Serializable, sendHandle: child_process.SendHandle) => void): this;
|
||||
on(event: "spawn", listener: () => void): this;
|
||||
|
||||
once(event: string, listener: (...args: any[]) => void): this;
|
||||
once(event: "error", listener: (err: Error) => void): this;
|
||||
once(event: "close", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
|
||||
once(event: "disconnect", listener: () => void): this;
|
||||
once(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
|
||||
once(event: "message", listener: (message: child_process.Serializable, sendHandle: child_process.SendHandle) => void): this;
|
||||
once(event: "spawn", listener: () => void): this;
|
||||
|
||||
stopServer(): Promise<{code?: number, signal?: NodeJS.Signals}>;
|
||||
sendCommand(...args: (string|number|boolean)[]): this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export async function runServer(options: runOptions): Promise<serverRun> {
|
||||
const child = child_process.execFile(options.command, [...((options.args ?? []).map(String))], {
|
||||
maxBuffer: Infinity,
|
||||
cwd: options.cwd || process.cwd(),
|
||||
env: {
|
||||
...process.env,
|
||||
...Object.keys(options.env ?? {}).reduce((acc, a) => {
|
||||
acc[a] = String(options.env[a]);
|
||||
return acc;
|
||||
}, {})
|
||||
}
|
||||
}) as serverRun;
|
||||
child.sendCommand = function (...args) {
|
||||
if (!child.stdin.writable) {
|
||||
child.emit("error", new Error("cannot send command to server"));
|
||||
return child;
|
||||
};
|
||||
child.stdin.write(args.map(String).join(" ")+"\n");
|
||||
return child;
|
||||
}
|
||||
|
||||
child.stopServer = async function () {
|
||||
const stop = options.serverActions?.stop ?? function (child) {
|
||||
|
||||
};
|
||||
Promise.resolve().then(() => stop(child)).catch(err => child.emit("error", err));
|
||||
return new Promise((done, reject) => child.once("error", reject).once("exit", (code, signal) => done({code, signal})));
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
export type manegerOptions = {
|
||||
ID?: string,
|
||||
newID?: boolean,
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export async function serverManeger(options: manegerOptions) {
|
||||
if (!options) throw new TypeError("Por favor adicione as opções do serverManeger!");
|
||||
if (!options.ID) options.newID = true;
|
||||
if (options.newID) {
|
||||
while(true) {
|
||||
options.ID = crypto.randomBytes(16).toString("hex");
|
||||
if (!(await fs.readdir(bdsManegerRoot)).includes(options.ID)) break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Platform ID root path
|
||||
*/
|
||||
const rootPath = path.join(bdsManegerRoot, options.ID);
|
||||
if (!(await extendsFS.exists(rootPath))) await fs.mkdir(rootPath, {recursive: true});
|
||||
|
||||
// sub-folders
|
||||
const serverFolder = path.join(rootPath, "server");
|
||||
const backup = path.join(rootPath, "backups");
|
||||
|
||||
for await (const p of [
|
||||
serverFolder,
|
||||
backup,
|
||||
]) if (!(await extendsFS.exists(p))) await fs.mkdir(p, {recursive: true});
|
||||
|
||||
return {
|
||||
id: options.ID,
|
||||
rootPath,
|
||||
serverFolder,
|
||||
backup,
|
||||
async runCommand(options: Omit<runOptions, "cwd">) {
|
||||
return runServer({...options, cwd: serverFolder});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export type serverManegerV1 = Awaited<ReturnType<typeof serverManeger>>;
|
205
package/core/src/servers/bedrock.ts
Normal file
205
package/core/src/servers/bedrock.ts
Normal file
@ -0,0 +1,205 @@
|
||||
import coreHttp, { Github, large } from "@sirherobrine23/http";
|
||||
import { manegerOptions, runOptions, serverManeger } from "../serverManeger.js";
|
||||
import { commandExists } from "../childPromisses.js";
|
||||
import { oracleStorage } from "../internal.js";
|
||||
import { pipeline } from "node:stream/promises";
|
||||
import semver from "semver";
|
||||
import unzip from "unzip-stream";
|
||||
import utils from "node:util";
|
||||
import path from "node:path";
|
||||
import tar from "tar";
|
||||
import extendsFS from "@sirherobrine23/extends";
|
||||
|
||||
export type bedrockOptions = manegerOptions & {
|
||||
/**
|
||||
* Servidor alternativo ao invés do servidor ofical da Mojang
|
||||
*/
|
||||
altServer?: "pocketmine"|"powernukkit"|"cloudbust",
|
||||
};
|
||||
|
||||
const pocketmineGithub = await Github.GithubManeger("pmmp", "PocketMine-MP");
|
||||
|
||||
export async function listVersions(options: {altServer: "powernukkit"} & Omit<bedrockOptions, "altServer"|keyof manegerOptions>): Promise<{version: string, mcpeVersion: string, date: Date, variantType: "stable"|"snapshot", url: string}[]>;
|
||||
export async function listVersions(options: {altServer: "pocketmine"} & Omit<bedrockOptions, "altServer"|keyof manegerOptions>): Promise<Github.githubRelease[]>;
|
||||
export async function listVersions(): Promise<{version: string, date: Date, release?: "stable"|"preview", url: {[platform in NodeJS.Platform]?: {[arch in NodeJS.Architecture]?: string}}}[]>;
|
||||
export async function listVersions(options?: Omit<bedrockOptions, keyof manegerOptions>) {
|
||||
if (!options) options = {};
|
||||
if (options.altServer === "pocketmine") return pocketmineGithub.getRelease();
|
||||
else if (options.altServer === "powernukkit") {
|
||||
const releases_version = (await coreHttp.jsonRequest<{[k: string]: {version: string, releaseTime: number, minecraftVersion: string, artefacts: string[], commitId: string, snapshotBuild?: number}[]}>("https://raw.githubusercontent.com/PowerNukkit/powernukkit-version-aggregator/master/powernukkit-versions.json")).body;
|
||||
return Object.keys(releases_version).reduce((acc, key) => {
|
||||
for (const data of releases_version[key]) {
|
||||
const dt = new Date(data.releaseTime);
|
||||
const getArtefactExtension = (artefactId: string) => (artefactId.includes("REDUCED_JAR")) ? ".jar" : (artefactId.includes("REDUCED_SOURCES_JAR")) ? "-sources.jar" : (artefactId.includes("SHADED_JAR")) ? "-shaded.jar" : (artefactId.includes("SHADED_SOURCES_JAR")) ? "-shaded-sources.jar" : (artefactId.includes("JAVADOC_JAR")) ? "-javadoc.jar" : ".unknown";
|
||||
function buildArtefactUrl(data: any, artefactId?: string) {
|
||||
const buildReleaseArtefactUrl = (data: any, artefactId?: string) => !data.artefacts.includes(artefactId) ? null : utils.format("https://search.maven.org/remotecontent?filepath=org/powernukkit/powernukkit/%s/powernukkit-%s%s", data.version, data.version, getArtefactExtension(artefactId));
|
||||
const buildSnapshotArtefactUrl = (data: any, artefactId?: string) => !data.artefacts.includes(artefactId) ? null : utils.format("https://oss.sonatype.org/content/repositories/snapshots/org/powernukkit/powernukkit/%s-SNAPSHOT/powernukkit-%s-%s%s", data.version.substring(0, data.version.indexOf("-SNAPSHOT")), data.version.substring(0, data.version.indexOf("-SNAPSHOT")), dt.getUTCFullYear().toString().padStart(4, "0") + (dt.getUTCMonth() + 1).toString().padStart(2, "0") + dt.getUTCDate().toString().padStart(2, "0") + "." + dt.getUTCHours().toString().padStart(2, "0") + dt.getUTCMinutes().toString().padStart(2, "0") + dt.getUTCSeconds().toString().padStart(2, "0") + "-" + data.snapshotBuild, getArtefactExtension(artefactId));
|
||||
if (artefactId == "GIT_SOURCE") {
|
||||
if (data.commitId) return utils.format("https://github.com/PowerNukkit/PowerNukkit/tree/%s", data.commitId);
|
||||
else if (data.snapshotBuild && data.artefacts.includes("SHADED_SOURCES_JAR")) return buildSnapshotArtefactUrl(data, "SHADED_SOURCES_JAR");
|
||||
else if (data.snapshotBuild && data.artefacts.includes("REDUCED_SOURCES_JAR")) return buildSnapshotArtefactUrl(data, "REDUCED_SOURCES_JAR");
|
||||
else if (data.artefacts.includes("SHADED_SOURCES_JAR")) return buildReleaseArtefactUrl(data, "SHADED_SOURCES_JAR");
|
||||
else if (data.artefacts.includes("REDUCED_SOURCES_JAR")) return buildReleaseArtefactUrl(data, "REDUCED_SOURCES_JAR");
|
||||
} else if (data.snapshotBuild) return buildSnapshotArtefactUrl(data, artefactId);
|
||||
else return buildReleaseArtefactUrl(data, artefactId);
|
||||
return null;
|
||||
}
|
||||
const artefacts = data.artefacts.reduce((acc, artefactId) => {acc[artefactId] = buildArtefactUrl(data, artefactId); return acc;}, {} as {[key: string]: string});
|
||||
const verRel = {
|
||||
version: data.version,
|
||||
mcpeVersion: data.minecraftVersion,
|
||||
date: dt,
|
||||
variantType: (!data.snapshotBuild?"snapshot":"stable") as "stable"|"snapshot",
|
||||
url: artefacts.SHADED_JAR || artefacts.REDUCED_JAR
|
||||
};
|
||||
if (!!verRel.url) acc.push(verRel);
|
||||
}
|
||||
return acc;
|
||||
}, [] as {version: string, mcpeVersion: string, date: Date, variantType: "stable"|"snapshot", url: string}[]).filter(a => !!a.url).sort((b, a) => (b.date.getTime() - a.date.getTime()) - semver.compare(semver.valid(semver.coerce(a.version)), semver.valid(semver.coerce(b.version))));
|
||||
} else if (options.altServer === "cloudbust") throw new TypeError("O Cloudbust não tem listagem de versöes");
|
||||
return (await coreHttp.jsonRequest<{version: string, date: Date, release?: "stable"|"preview", url: {[platform in NodeJS.Platform]?: {[arch in NodeJS.Architecture]?: string}}}[]>("https://sirherobrine23.github.io/BedrockFetch/all.json")).body;
|
||||
}
|
||||
|
||||
export async function installServer(options: bedrockOptions & {version?: string, allowBeta?: boolean}): Promise<{id: string, version: string, mcpeVersion?: string, releaseDate: Date}> {
|
||||
const serverPath = await serverManeger(options);
|
||||
if (options.altServer === "pocketmine") {
|
||||
const version = (options.version ?? "latest").trim();
|
||||
const rel = (await pocketmineGithub.getRelease(version));
|
||||
if (!rel) throw new Error("Não foi possivel encontrar a versão informada do Pocketmine!");
|
||||
|
||||
const phpFile = (await oracleStorage.listFiles("php_bin")).find(file => file.name.includes(process.platform) && file.name.includes(process.arch));
|
||||
if (!phpFile) throw new Error(`Não foi possivel encontra os arquivos do php para o ${process.platform} com a arquitetura ${process.arch}`);
|
||||
if (phpFile.name.endsWith(".tar.gz")) await pipeline(await oracleStorage.getFileStream(phpFile.name), tar.extract({cwd: serverPath.serverFolder}));
|
||||
else if (phpFile.name.endsWith(".zip")) await pipeline(await oracleStorage.getFileStream(phpFile.name), unzip.Extract({path: serverPath.serverFolder}));
|
||||
else throw new Error("Arquivo encontrado não é suportado!");
|
||||
|
||||
// save phar
|
||||
await large.saveFile({
|
||||
url: rel.assets.find(a => a.name.endsWith(".phar"))?.browser_download_url,
|
||||
path: path.join(serverPath.serverFolder, "server.phar")
|
||||
});
|
||||
|
||||
return {
|
||||
id: serverPath.id,
|
||||
version: rel.tag_name,
|
||||
releaseDate: new Date(rel.published_at)
|
||||
};
|
||||
} else if (options.altServer === "powernukkit") {
|
||||
const version = (options.version ?? "latest").trim();
|
||||
const releases = await listVersions({altServer: "powernukkit"});
|
||||
const relVersion = releases.find(rel => {
|
||||
if (rel.variantType === "snapshot") if (!options.allowBeta) return false;
|
||||
if (version.toLowerCase() === "latest") return true;
|
||||
return (rel.version === version || rel.mcpeVersion === version);
|
||||
});
|
||||
if (!relVersion) throw new Error("A versão não foi encontrada, por favor verique a versão informada!");
|
||||
await large.saveFile({
|
||||
path: path.join(serverPath.serverFolder, "server.jar"),
|
||||
url: relVersion.url
|
||||
});
|
||||
return {
|
||||
id: serverPath.id,
|
||||
version: relVersion.version,
|
||||
mcpeVersion: relVersion.mcpeVersion,
|
||||
releaseDate: relVersion.date,
|
||||
};
|
||||
} else if (options.altServer === "cloudbust") {
|
||||
await large.saveFile({
|
||||
url: "https://ci.opencollab.dev/job/NukkitX/job/Server/job/bleeding/lastSuccessfulBuild/artifact/target/Cloudburst.jar",
|
||||
path: path.join(serverPath.serverFolder, "server.jar")
|
||||
});
|
||||
|
||||
return {
|
||||
id: serverPath.id,
|
||||
version: "bleeding",
|
||||
releaseDate: new Date()
|
||||
};
|
||||
}
|
||||
const bedrockVersion = (await listVersions()).find(rel => {
|
||||
if (rel.release === "preview" && !!options.allowBeta) return false;
|
||||
const version = (options.version ?? "latest").trim();
|
||||
if (version.toLowerCase() === "latest") return true;
|
||||
return rel.version === version;
|
||||
});
|
||||
if (!bedrockVersion) throw new Error("Não existe essa versão");
|
||||
let downloadUrl = bedrockVersion.url[process.platform]?.[process.arch];
|
||||
if ((["android", "linux"] as NodeJS.Process["platform"][]).includes(process.platform) && process.arch !== "x64") {
|
||||
if (!downloadUrl) {
|
||||
for (const emu of ["qemu-x86_64-static", "qemu-x86_64", "box64"]) {
|
||||
if (downloadUrl) break;
|
||||
if (await commandExists(emu)) downloadUrl = bedrockVersion.url.linux?.x64;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!downloadUrl) throw new Error(`Não existe o URL de download para ${process.platform} na arquitetura ${process.arch}`);
|
||||
await pipeline(await coreHttp.streamRequest(downloadUrl), unzip.Extract({path: serverPath.serverFolder}));
|
||||
return {
|
||||
id: serverPath.id,
|
||||
version: bedrockVersion.version,
|
||||
releaseDate: bedrockVersion.date,
|
||||
};
|
||||
}
|
||||
|
||||
export async function startServer(options: bedrockOptions) {
|
||||
const serverPath = await serverManeger(options);
|
||||
if (options.altServer === "powernukkit"||options.altServer === "cloudbust") {
|
||||
return serverPath.runCommand({
|
||||
command: "java",
|
||||
args: [
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:+ParallelRefProcEnabled",
|
||||
"-XX:MaxGCPauseMillis=200",
|
||||
"-XX:+UnlockExperimentalVMOptions",
|
||||
"-XX:+DisableExplicitGC",
|
||||
"-XX:+AlwaysPreTouch",
|
||||
"-XX:G1NewSizePercent=30",
|
||||
"-XX:G1MaxNewSizePercent=40",
|
||||
"-XX:G1HeapRegionSize=8M",
|
||||
"-XX:G1ReservePercent=20",
|
||||
"-XX:G1HeapWastePercent=5",
|
||||
"-XX:G1MixedGCCountTarget=4",
|
||||
"-XX:InitiatingHeapOccupancyPercent=15",
|
||||
"-XX:G1MixedGCLiveThresholdPercent=90",
|
||||
"-XX:G1RSetUpdatingPauseTimePercent=5",
|
||||
"-XX:SurvivorRatio=32",
|
||||
"-XX:+PerfDisableSharedMem",
|
||||
"-XX:MaxTenuringThreshold=1",
|
||||
"-Dusing.aikars.flags=https://mcflags.emc.gs",
|
||||
"-Daikars.new.flags=true",
|
||||
"-jar", "server.jar",
|
||||
],
|
||||
serverActions: {
|
||||
stop(child) {
|
||||
child.sendCommand("stop");
|
||||
},
|
||||
}
|
||||
})
|
||||
} else if (options.altServer === "pocketmine") {
|
||||
return serverPath.runCommand({
|
||||
command: (await extendsFS.readdir(serverPath.serverFolder)).find(file => file.endsWith("php")||file.endsWith("php.exe")),
|
||||
args: [
|
||||
"server.jar",
|
||||
"--no-wizard"
|
||||
]
|
||||
});
|
||||
}
|
||||
if (process.platform === "darwin") throw new Error("Run in docker or podman!");
|
||||
const run: Omit<runOptions, "cwd"> = {
|
||||
command: path.join(serverPath.serverFolder, "bedrock_server"),
|
||||
serverActions: {
|
||||
stop(child) {
|
||||
child.sendCommand("stop");
|
||||
},
|
||||
}
|
||||
};
|
||||
if ((["android", "linux"] as NodeJS.Process["platform"][]).includes(process.platform) && process.arch !== "x64") {
|
||||
for (const emu of ["qemu-x86_64-static", "qemu-x86_64", "box64"]) {
|
||||
if (await commandExists(emu)) {
|
||||
run.args = [emu, run.command];
|
||||
run.command = emu;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return serverPath.runCommand(run);
|
||||
}
|
88
package/core/src/servers/java.ts
Normal file
88
package/core/src/servers/java.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import { manegerOptions, serverManeger } from "../serverManeger.js";
|
||||
import coreHttp, { large } from "@sirherobrine23/http";
|
||||
import utils from "node:util";
|
||||
import path from "node:path";
|
||||
|
||||
export type javaOptions = manegerOptions & {
|
||||
/**
|
||||
* Servidor alternativo ao invés do servidor ofical da Mojang
|
||||
*/
|
||||
altServer?: "spigot"|"paper"|"purpur"
|
||||
};
|
||||
|
||||
export async function listVersions(options: Omit<javaOptions, keyof manegerOptions>) {
|
||||
if (options.altServer === "purpur") {
|
||||
return Promise.all((await coreHttp.jsonRequest<{versions: string[]}>("https://api.purpurmc.org/v2/purpur")).body.versions.map(async version => ({
|
||||
version,
|
||||
downloadUrl: utils.format("https://api.purpurmc.org/v2/purpur/%s/latest/download", version),
|
||||
date: new Date((await coreHttp.jsonRequest<{timestamp: number}>(utils.format("https://api.purpurmc.org/v2/purpur/%s/latest", version))).body.timestamp)
|
||||
})));
|
||||
} else if (options.altServer === "paper") {
|
||||
return Promise.all((await coreHttp.jsonRequest<{versions: string[]}>("https://api.papermc.io/v2/projects/paper")).body.versions.map(async version => {
|
||||
const build = (await coreHttp.jsonRequest<{builds: number[]}>(utils.format("https://api.papermc.io/v2/projects/paper/versions/%s", version))).body.builds.at(-1);
|
||||
const data = (await coreHttp.jsonRequest<{time: string, downloads: {[k: string]: {name: string, sha256: string}}}>(utils.format("https://api.papermc.io/v2/projects/paper/versions/%s/builds/%s", version, build))).body;
|
||||
|
||||
return {
|
||||
version,
|
||||
date: new Date(data.time),
|
||||
downloadUrl: utils.format("https://api.papermc.io/v2/projects/paper/versions/%s/builds/%s/downloads/%s", version, build, data.downloads["application"].name)
|
||||
}
|
||||
}));
|
||||
} else if (options.altServer === "spigot") {
|
||||
throw new Error("Não foi implementado!");
|
||||
}
|
||||
return (await Promise.all((await coreHttp.jsonRequest<{versions: {id: string, releaseTime: string, url: string}[]}>("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json")).body.versions.map(async data => ({
|
||||
version: data.id,
|
||||
date: new Date(data.releaseTime),
|
||||
downloadUrl: (await coreHttp.jsonRequest<{downloads: {[k: string]: {size: number, url: string}}}>(data.url)).body.downloads?.["server"]?.url
|
||||
})))).filter(a => !!a.downloadUrl);
|
||||
}
|
||||
|
||||
export async function installServer(options: javaOptions & {version?: string}) {
|
||||
const serverPath = await serverManeger(options);
|
||||
const version = (await listVersions(options)).find(rel => (!options.version || options.version === "latest" || rel.version === options.version));
|
||||
if (!version) throw new Error("Não existe a versão informada!");
|
||||
await large.saveFile({
|
||||
path: path.join(serverPath.serverFolder, "server.jar"),
|
||||
url: version.downloadUrl
|
||||
});
|
||||
return {
|
||||
...version,
|
||||
id: serverPath.id,
|
||||
};
|
||||
}
|
||||
|
||||
export async function startServer(options: javaOptions) {
|
||||
const serverPath = await serverManeger(options);
|
||||
return serverPath.runCommand({
|
||||
command: "java",
|
||||
args: [
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:+ParallelRefProcEnabled",
|
||||
"-XX:MaxGCPauseMillis=200",
|
||||
"-XX:+UnlockExperimentalVMOptions",
|
||||
"-XX:+DisableExplicitGC",
|
||||
"-XX:+AlwaysPreTouch",
|
||||
"-XX:G1NewSizePercent=30",
|
||||
"-XX:G1MaxNewSizePercent=40",
|
||||
"-XX:G1HeapRegionSize=8M",
|
||||
"-XX:G1ReservePercent=20",
|
||||
"-XX:G1HeapWastePercent=5",
|
||||
"-XX:G1MixedGCCountTarget=4",
|
||||
"-XX:InitiatingHeapOccupancyPercent=15",
|
||||
"-XX:G1MixedGCLiveThresholdPercent=90",
|
||||
"-XX:G1RSetUpdatingPauseTimePercent=5",
|
||||
"-XX:SurvivorRatio=32",
|
||||
"-XX:+PerfDisableSharedMem",
|
||||
"-XX:MaxTenuringThreshold=1",
|
||||
"-Dusing.aikars.flags=https://mcflags.emc.gs",
|
||||
"-Daikars.new.flags=true",
|
||||
"-jar", "server.jar",
|
||||
],
|
||||
serverActions: {
|
||||
stop(child) {
|
||||
child.sendCommand("stop");
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
27
package/core/tsconfig.json
Normal file
27
package/core/tsconfig.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"target": "ESNext",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"strict": false,
|
||||
"noUnusedLocals": true,
|
||||
"isolatedModules": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true,
|
||||
"lib": [
|
||||
"ESNext"
|
||||
],
|
||||
"composite": true
|
||||
},
|
||||
"exclude": [
|
||||
"**/*.test.*"
|
||||
],
|
||||
"ts-node": {
|
||||
"esm": true
|
||||
}
|
||||
}
|
17
package/docker/package.json
Normal file
17
package/docker/package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@the-bds-maneger/docker",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"bdsdocker": "./src/index.js"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Matheus Sampaio Queiroga <srherobrine20@gmail.com>",
|
||||
"license": "ISC"
|
||||
}
|
31
package/docker/tsconfig.json
Normal file
31
package/docker/tsconfig.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"target": "ESNext",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"strict": false,
|
||||
"noUnusedLocals": true,
|
||||
"isolatedModules": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true,
|
||||
"lib": [
|
||||
"ESNext"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"**/*.test.*"
|
||||
],
|
||||
"ts-node": {
|
||||
"esm": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../core"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export * as serverManeger from "./serverManeger.js";
|
||||
export * as Bedrock from "./platform/Bedrock.js";
|
||||
export * as Java from "./platform/Java.js";
|
@ -1,43 +0,0 @@
|
||||
export default {parse, stringify};
|
||||
export type properitiesBase = {[key: string]: string|number|true|false};
|
||||
|
||||
/**
|
||||
* Parse Proprieties files and return a map of properties.
|
||||
*
|
||||
* @param Proper - String with the properties or similar files
|
||||
* @returns
|
||||
*/
|
||||
export function parse<PropertiesObject extends properitiesBase>(Proper: string): PropertiesObject {
|
||||
const ProPri = {};
|
||||
const ProperSplit = Proper.replace(/\\\s+?\n/gi, "").split(/\r?\n/).map(Line => Line.trim()).filter(line => /.*(\s+)?\=(\s+)?.*/.test(line) && !/^#/.test(line));
|
||||
for (const Line of ProperSplit) {
|
||||
const LineMatch = Line.match(/^([^\s\=]+)\s*\=(.*)$/);
|
||||
const key = LineMatch[1].trim(), value = LineMatch[2].trim();
|
||||
ProPri[key] = value;
|
||||
if (ProPri[key] === "true") ProPri[key] = true;
|
||||
else if (ProPri[key] === "false") ProPri[key] = false;
|
||||
else if (/^[0-9]+\.[0-9]+/.test(ProPri[key]) && !/^[0-9]+\.[0-9]+\.[0-9]+/.test(ProPri[key])) ProPri[key] = parseFloat(ProPri[key]);
|
||||
else if (/^[0-9]+/.test(ProPri[key])) ProPri[key] = parseInt(ProPri[key]);
|
||||
}
|
||||
return ProPri as PropertiesObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert json to properities files.
|
||||
*
|
||||
* @param ProPri - String with properties file
|
||||
* @returns
|
||||
*/
|
||||
export function stringify(ProPri: properitiesBase): string {
|
||||
const Proper = [];
|
||||
for (const key of Object.keys(ProPri)) {
|
||||
if (ProPri[key] === null||ProPri[key] === undefined) Proper.push(`${key}=`);
|
||||
else if (ProPri[key] === true) Proper.push(`${key}=true`);
|
||||
else if (ProPri[key] === false) Proper.push(`${key}=false`);
|
||||
else if (typeof ProPri[key] === "number") Proper.push(`${key}=${ProPri[key]}`);
|
||||
else if (typeof ProPri[key] === "string") Proper.push(`${key}=${ProPri[key]}`);
|
||||
else if (typeof ProPri[key] === "object") Proper.push(`${key}=${JSON.stringify(ProPri[key])}`);
|
||||
else console.error(`[Proprieties.stringify] ${key} is not a valid type.`);
|
||||
}
|
||||
return Proper.join("\n");
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
import dgram from "node:dgram";
|
||||
import net from "node:net";
|
||||
|
||||
export type proxyUdpToTcpOptions = {
|
||||
udpType?: dgram.SocketType,
|
||||
listen?: number,
|
||||
portListen?: (port: number) => void
|
||||
};
|
||||
|
||||
export type proxyTcpToUdpClient = {
|
||||
udpType?: dgram.SocketType,
|
||||
listen?: number,
|
||||
remote: {
|
||||
host: string,
|
||||
port: number
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfer packets from UDP to TCP to send through some tunnel that only accepts TCP
|
||||
*
|
||||
* This also means that it will also have error transporting the data, so it is not guaranteed to work properly even more when dealing with UDP packets.
|
||||
*/
|
||||
export function proxyUdpToTcp(udpPort: number, options?: proxyUdpToTcpOptions) {
|
||||
const tcpServer = net.createServer();
|
||||
tcpServer.on("error", err => console.error(err));
|
||||
tcpServer.on("connection", socket => {
|
||||
const udpClient = dgram.createSocket(options?.udpType||"udp4");
|
||||
|
||||
// Close Sockets
|
||||
udpClient.once("close", () => socket.end());
|
||||
socket.once("close", () => udpClient.close());
|
||||
|
||||
// Print error
|
||||
udpClient.on("error", console.error);
|
||||
socket.on("error", console.error);
|
||||
|
||||
// Pipe Datas
|
||||
udpClient.on("message", data => socket.write(data));
|
||||
socket.on("data", data => udpClient.send(data));
|
||||
|
||||
// Connect
|
||||
udpClient.connect(udpPort);
|
||||
});
|
||||
|
||||
// Listen
|
||||
tcpServer.listen(options?.listen||0, function() {
|
||||
const addr = this.address();
|
||||
if (options?.portListen) options.portListen(addr.port);
|
||||
console.debug("bds proxy port listen, %s, (udp -> tcp)", addr.port);
|
||||
tcpServer.once("close", () => console.debug("bds proxy close, %s", addr.port));
|
||||
});
|
||||
|
||||
return tcpServer;
|
||||
}
|
||||
|
||||
export function proxyTcpToUdp(options: proxyTcpToUdpClient) {
|
||||
const sessions: {[keyIP: string]: net.Socket} = {};
|
||||
const udp = dgram.createSocket(options?.udpType||"udp4");
|
||||
|
||||
udp.on("error", console.error);
|
||||
udp.on("message", (msg, ipInfo) => {
|
||||
const keyInfo = `${ipInfo.address}:${ipInfo.port}`;
|
||||
|
||||
// Client TCP
|
||||
if (!sessions[keyInfo]) {
|
||||
sessions[keyInfo] = net.createConnection(options.remote);
|
||||
sessions[keyInfo].on("data", data => udp.send(data, ipInfo.port, ipInfo.address));
|
||||
sessions[keyInfo].on("error", console.error);
|
||||
sessions[keyInfo].once("close", () => {
|
||||
delete sessions[keyInfo];
|
||||
console.log("Client %s:%f close", ipInfo.address, ipInfo.port);
|
||||
});
|
||||
console.log("Client %s:%f connected", ipInfo.address, ipInfo.port);
|
||||
}
|
||||
|
||||
// Send message
|
||||
sessions[keyInfo].write(msg);
|
||||
});
|
||||
|
||||
// Listen port
|
||||
udp.bind(options.listen||0, function(){
|
||||
const addr = this.address();
|
||||
console.log("Port listen, %s (tcp -> udp)", addr.port);
|
||||
});
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import net from "net"
|
||||
export async function randomPort(): Promise<number> {
|
||||
return new Promise((res, rej) => {
|
||||
const srv = net.createServer();
|
||||
srv.listen(0, () => {
|
||||
const address = srv.address();
|
||||
if (typeof address === "string") return rej(new Error("Invalid listen port"));
|
||||
srv.close((_err) => res(address.port));
|
||||
});
|
||||
});
|
||||
}
|
@ -1,252 +0,0 @@
|
||||
import { createServerManeger, platformPathID, pathOptions, serverConfig } from "../serverManeger.js";
|
||||
import { promises as fs, createWriteStream } from "node:fs";
|
||||
import { oracleBucket } from "../lib/remote.js";
|
||||
import { promisify } from "node:util";
|
||||
import { pipeline } from "node:stream/promises";
|
||||
import * as childPromisses from "../lib/childPromisses.js";
|
||||
import coreUtils from "@sirherobrine23/coreutils";
|
||||
import AdmZip from "adm-zip";
|
||||
import path from "node:path";
|
||||
import tar from "tar";
|
||||
|
||||
export type bedrockRootOption = pathOptions & {
|
||||
variant?: "oficial"|"Pocketmine-PMMP"|"Powernukkit"|"Cloudbust"
|
||||
};
|
||||
|
||||
export const hostArchEmulate = Object.freeze([
|
||||
"qemu-x86_64-static",
|
||||
"qemu-x86_64",
|
||||
"box64"
|
||||
]);
|
||||
|
||||
type bedrockVersionJSON = {
|
||||
version: string,
|
||||
date: Date,
|
||||
release?: "stable"|"preview",
|
||||
url: {
|
||||
[platform in NodeJS.Platform]?: {
|
||||
[arch in NodeJS.Architecture]?: string
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function getPHPBin(options?: bedrockRootOption) {
|
||||
options = {variant: "oficial", ...options};
|
||||
const serverPath = await platformPathID("bedrock", options);
|
||||
const binFolder = path.join(serverPath.serverPath, "bin");
|
||||
const files = await coreUtils.Extends.readdir({folderPath: binFolder});
|
||||
const file = files.find((v) => v.endsWith("php.exe")||v.endsWith("php"));
|
||||
if (!file) throw new Error("PHP Bin not found");
|
||||
return file;
|
||||
}
|
||||
|
||||
export async function installServer(version?: string, options?: bedrockRootOption) {
|
||||
options = {variant: "oficial", ...options};
|
||||
const serverPath = await platformPathID("bedrock", options);
|
||||
if (options?.variant === "Pocketmine-PMMP") {
|
||||
if (!version) version = "latest";
|
||||
const phpBin = ((await oracleBucket.listFiles()) as any[]).filter(({name}) => name.includes("php_bin/")).filter(({name}) => name.includes(process.platform) && name.includes(process.arch)).at(0);
|
||||
if (!phpBin) throw new Error("PHP Bin not found");
|
||||
const binFolder = path.join(serverPath.serverPath, "bin");
|
||||
if (await coreUtils.Extends.exists(binFolder)) await fs.rm(binFolder, {recursive: true});
|
||||
await fs.mkdir(binFolder);
|
||||
await pipeline(await oracleBucket.getFileStream(phpBin.name), createWriteStream(path.join(binFolder, "phpTmp")));
|
||||
|
||||
if (phpBin.name.endsWith(".tar.gz")) {
|
||||
await tar.extract({
|
||||
file: path.join(binFolder, "phpTmp"),
|
||||
cwd: binFolder
|
||||
});
|
||||
} else if (phpBin.name.endsWith(".zip")) {
|
||||
await promisify((new AdmZip(path.join(binFolder, "phpTmp"))).extractAllToAsync)(binFolder, true, true);
|
||||
}
|
||||
await fs.rm(path.join(binFolder, "phpTmp"));
|
||||
|
||||
const rel = await (await coreUtils.http.Github.GithubManeger("pmmp", "PocketMine-MP")).getRelease();
|
||||
const relData = version.trim().toLowerCase() === "latest" ? rel.at(0) : rel.find((v) => v.tag_name === version.trim());
|
||||
if (!relData) throw new Error("Version not found");
|
||||
const phpAsset = relData.assets.find((a) => a.name.endsWith(".phar"))?.browser_download_url;
|
||||
if (!phpAsset) throw new Error("PHP asset not found");
|
||||
await coreUtils.http.large.saveFile({url: phpAsset, path: path.join(serverPath.serverPath, "PocketMine-MP.phar")});
|
||||
|
||||
return {
|
||||
version: relData.tag_name,
|
||||
releaseDate: new Date(relData.published_at),
|
||||
release: (relData.prerelease ? "preview" : "stable") as "preview"|"stable",
|
||||
url: phpAsset,
|
||||
phpBin: phpBin.name,
|
||||
};
|
||||
} else if (options?.variant === "Powernukkit") {
|
||||
if (!version) version = "latest";
|
||||
const versions = await coreUtils.http.jsonRequest<{version: string, mcpeVersion: string, date: string, url: string, variantType: "snapshot"|"stable"}[]>("https://mcpeversion-static.sirherobrine23.org/powernukkit/all.json").then(data => data.body);
|
||||
const versionData = version.trim().toLowerCase() === "latest" ? versions.at(-1) : versions.find((v) => v.version === version.trim() || v.mcpeVersion === version.trim());
|
||||
if (!versionData) throw new Error("Version not found");
|
||||
const url = versionData.url;
|
||||
if (!url) throw new Error("Platform not supported");
|
||||
await coreUtils.http.large.saveFile({url, path: path.join(serverPath.serverPath, "server.jar")});
|
||||
return {
|
||||
version: versionData.version,
|
||||
mcpeVersion: versionData.mcpeVersion,
|
||||
variantType: versionData.variantType,
|
||||
releaseDate: new Date(versionData.date),
|
||||
url,
|
||||
};
|
||||
} else if (options?.variant === "Cloudbust") {
|
||||
await coreUtils.http.large.saveFile({
|
||||
url: "https://ci.opencollab.dev/job/NukkitX/job/Server/job/bleeding/lastSuccessfulBuild/artifact/target/Cloudburst.jar",
|
||||
path: path.join(serverPath.serverPath, "server.jar")
|
||||
});
|
||||
|
||||
return {
|
||||
version: "bleeding",
|
||||
releaseDate: new Date(),
|
||||
release: "preview",
|
||||
url: "https://ci.opencollab.dev/job/NukkitX/job/Server/job/bleeding/lastSuccessfulBuild/artifact/target/Cloudburst.jar",
|
||||
};
|
||||
} else {
|
||||
if (!version) version = "latest";
|
||||
const versions = await coreUtils.http.jsonRequest<bedrockVersionJSON[]>("https://sirherobrine23.github.io/BedrockFetch/all.json").then(data => data.body);
|
||||
const versionData = version.trim().toLowerCase() === "latest" ? versions.at(-1) : versions.find((v) => v.version === version.trim());
|
||||
if (!versionData) throw new Error("Version not found");
|
||||
let currentPlatform = process.platform;
|
||||
if (currentPlatform === "android") currentPlatform = "linux";
|
||||
const url = versionData.url[currentPlatform]?.[process.arch];
|
||||
if (!url) throw new Error("Platform not supported");
|
||||
(await coreUtils.http.large.admZip(url)).zip.extractAllTo(serverPath.serverPath, true, true);
|
||||
return {
|
||||
version: versionData.version,
|
||||
releaseDate: new Date(versionData.date),
|
||||
release: versionData.release ?? "stable",
|
||||
url: url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function startServer(options?: bedrockRootOption) {
|
||||
// Bad fix options
|
||||
options = {variant: "oficial", ...options};
|
||||
const serverPath = await platformPathID("bedrock", options);
|
||||
// Server Object
|
||||
const serverExec: serverConfig = {
|
||||
exec: {
|
||||
cwd: serverPath.serverPath,
|
||||
},
|
||||
actions: {}
|
||||
};
|
||||
|
||||
if (options?.variant === "Pocketmine-PMMP") {
|
||||
serverExec.exec.exec = await getPHPBin();
|
||||
serverExec.exec.args = ["PocketMine-MP.phar", "--no-wizard"];
|
||||
serverExec.actions = {
|
||||
stopServer(child_process) {
|
||||
child_process.stdin.write("stop\n");
|
||||
},
|
||||
onStart(lineData, fnRegister) {
|
||||
if (!(lineData.includes("INFO") && lineData.includes("Done") && lineData.includes("help"))) return;
|
||||
const doneStart = new Date();
|
||||
fnRegister({
|
||||
serverAvaible: doneStart,
|
||||
bootUp: runStart.getTime() - doneStart.getTime()
|
||||
});
|
||||
},
|
||||
};
|
||||
} else if (options?.variant === "Powernukkit" || options?.variant === "Cloudbust") {
|
||||
serverExec.exec.exec = "java";
|
||||
serverExec.exec.args = [
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:+ParallelRefProcEnabled",
|
||||
"-XX:MaxGCPauseMillis=200",
|
||||
"-XX:+UnlockExperimentalVMOptions",
|
||||
"-XX:+DisableExplicitGC",
|
||||
"-XX:+AlwaysPreTouch",
|
||||
"-XX:G1NewSizePercent=30",
|
||||
"-XX:G1MaxNewSizePercent=40",
|
||||
"-XX:G1HeapRegionSize=8M",
|
||||
"-XX:G1ReservePercent=20",
|
||||
"-XX:G1HeapWastePercent=5",
|
||||
"-XX:G1MixedGCCountTarget=4",
|
||||
"-XX:InitiatingHeapOccupancyPercent=15",
|
||||
"-XX:G1MixedGCLiveThresholdPercent=90",
|
||||
"-XX:G1RSetUpdatingPauseTimePercent=5",
|
||||
"-XX:SurvivorRatio=32",
|
||||
"-XX:+PerfDisableSharedMem",
|
||||
"-XX:MaxTenuringThreshold=1",
|
||||
"-Dusing.aikars.flags=https://mcflags.emc.gs",
|
||||
"-Daikars.new.flags=true",
|
||||
"-jar", "server.jar"
|
||||
];
|
||||
serverExec.actions = {
|
||||
stopServer(child_process) {
|
||||
child_process.stdin.write("stop\n");
|
||||
},
|
||||
onStart(lineData, fnRegister) {
|
||||
if (!(lineData.includes("INFO") && lineData.includes("Done") && lineData.includes("help"))) return;
|
||||
const doneStart = new Date();
|
||||
fnRegister({
|
||||
serverAvaible: doneStart,
|
||||
bootUp: runStart.getTime() - doneStart.getTime()
|
||||
});
|
||||
},
|
||||
};
|
||||
} else {
|
||||
if (process.platform === "win32") serverExec.exec.exec = "bedrock_server.exe";
|
||||
else if (process.platform === "darwin") throw new Error("MacOS is not supported, run in Docker or Virtual Machine");
|
||||
else {
|
||||
serverExec.exec.exec = path.join(serverPath.serverPath, "bedrock_server");
|
||||
serverExec.exec.env = {
|
||||
LD_LIBRARY_PATH: serverPath.serverPath
|
||||
};
|
||||
}
|
||||
if ((["android", "linux"]).includes(process.platform) && process.arch !== "x64") {
|
||||
const exec = serverExec.exec.exec;
|
||||
serverExec.exec.exec = undefined;
|
||||
for (const command of hostArchEmulate) {
|
||||
if (await childPromisses.commandExists(command, true)) {
|
||||
serverExec.exec.args = [exec];
|
||||
serverExec.exec.exec = command;
|
||||
break;
|
||||
}
|
||||
if (!serverExec.exec.exec) throw new Error("No emulator found for this platform");
|
||||
}
|
||||
}
|
||||
|
||||
const startTest = /\[.*\]\s+Server\s+started\./;
|
||||
// Server actions
|
||||
serverExec.actions = {
|
||||
stopServer(child_process) {
|
||||
child_process.stdin.write("stop\n");
|
||||
},
|
||||
onStart(lineData, fnRegister) {if (startTest.test(lineData)) fnRegister({serverAvaible: new Date()});},
|
||||
playerActions(lineData, fnRegister) {
|
||||
const playerActionsV1 = /\[.*\]\s+Player\s+((dis|)connected):\s+(.*),\s+xuid:\s+([0-9]+)/;
|
||||
const newPlayerActions = /\[.*INFO\]\s+Player\s+(Spawned|connected|disconnected):\s+([\s\S\w]+)\s+(xuid:\s+([0-9]+))?/;
|
||||
const connectTime = new Date();
|
||||
if (!(newPlayerActions.test(lineData)||playerActionsV1.test(lineData))) return;
|
||||
let playerName: string, action: string, xuid: string;
|
||||
if (newPlayerActions.test(lineData)) {
|
||||
const [, actionV2,, playerNameV2,, xuidV2] = lineData.match(newPlayerActions);
|
||||
playerName = playerNameV2;
|
||||
action = actionV2;
|
||||
xuid = xuidV2;
|
||||
} else {
|
||||
const [, actionV1,, playerNameV1, xuidV1] = lineData.match(newPlayerActions);
|
||||
playerName = playerNameV1;
|
||||
action = actionV1;
|
||||
xuid = xuidV1;
|
||||
}
|
||||
fnRegister({
|
||||
player: playerName,
|
||||
action: action === "Spawned" ? "spawned" : action === "connected" ? "join" : "leave",
|
||||
actionDate: connectTime,
|
||||
sessionID: serverPath.id,
|
||||
more: {
|
||||
xuid
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const runStart = new Date();
|
||||
return createServerManeger(serverExec);
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { pathOptions } from "../serverManeger.js";
|
||||
|
||||
export type javaRootOption = pathOptions & {
|
||||
variant?: "oficial"|"Spigot"|"Paper"|"Purpur",
|
||||
};
|
||||
|
||||
export async function installServer(options?: javaRootOption) {
|
||||
options = {variant: "oficial", ...options};
|
||||
if (options?.variant === "Spigot") {
|
||||
} else if (options?.variant === "Paper") {
|
||||
} else if (options?.variant === "Purpur") {
|
||||
} else {}
|
||||
}
|
||||
|
||||
export default startServer;
|
||||
export async function startServer(options?: javaRootOption) {}
|
@ -1,216 +0,0 @@
|
||||
import { createInterface as readline } from "node:readline";
|
||||
import { promises as fs } from "node:fs";
|
||||
import child_process from "node:child_process";
|
||||
import { Cloud, Extends as extendFs } from "@sirherobrine23/coreutils";
|
||||
import crypto from "node:crypto";
|
||||
import path from "node:path";
|
||||
import os from "node:os";
|
||||
import EventEmitter from "node:events";
|
||||
|
||||
export type pathOptions = {
|
||||
id?: "default"|string,
|
||||
newId?: boolean,
|
||||
withBuildFolder?: boolean,
|
||||
};
|
||||
|
||||
export let bdsRoot = process.env.BDS_HOME?(process.env.BDS_HOME.startsWith("~")?process.env.BDS_HOME.replace("~", os.homedir()):process.env.BDS_HOME):path.join(os.homedir(), ".bdsManeger");
|
||||
export async function platformPathID(platform: "bedrock"|"java", options?: pathOptions) {
|
||||
if (!(["bedrock", "java"].includes(platform))) throw new Error("Invalid platform target");
|
||||
options = {id: "default", ...options};
|
||||
const platformRoot = path.join(bdsRoot, platform);
|
||||
if (!await extendFs.exists(platformRoot)) await fs.mkdir(platformRoot, {recursive: true});
|
||||
if (!options) options = {};
|
||||
|
||||
// Create if not exists
|
||||
const foldersAndLink = await fs.readdir(platformRoot);
|
||||
if (foldersAndLink.length === 0) options.newId = true;
|
||||
if (options.newId) {
|
||||
options.id = crypto.randomBytes(16).toString("hex");
|
||||
fs.mkdir(path.join(platformRoot, options.id), {recursive: true});
|
||||
if (await extendFs.exists(path.join(platformRoot, "default"))) await fs.unlink(path.join(platformRoot, "default"));
|
||||
await fs.symlink(path.join(platformRoot, options.id), path.join(platformRoot, "default"));
|
||||
} else if (!await extendFs.exists(path.join(platformRoot, options.id))) throw new Error("Folder ID not created!");
|
||||
|
||||
// Get real id
|
||||
if (!(/^[A-Za-z0-9]*$/).test(options.id)) throw new Error("Invalid Platform ID");
|
||||
if (options?.id === "default") options.id = path.basename(await fs.realpath(path.join(platformRoot, options.id)).catch(async () => (await fs.readdir(platformRoot)).sort().at(0)));
|
||||
|
||||
// Mount Paths
|
||||
const serverRoot = path.join(platformRoot, options.id);
|
||||
const serverPath = path.join(serverRoot, "server");
|
||||
const hooksPath = path.join(serverRoot, "hooks");
|
||||
const backupPath = path.join(serverRoot, "backup");
|
||||
const logsPath = path.join(serverRoot, "logs");
|
||||
let buildFolder: string;
|
||||
if (options?.withBuildFolder) buildFolder = path.join(serverRoot, "build");
|
||||
|
||||
// Create folder if not exists
|
||||
if (!(await extendFs.exists(serverRoot))) await fs.mkdir(serverRoot, {recursive: true});
|
||||
if (!(await extendFs.exists(serverPath))) await fs.mkdir(serverPath, {recursive: true});
|
||||
if (!(await extendFs.exists(hooksPath))) await fs.mkdir(hooksPath, {recursive: true});
|
||||
if (!(await extendFs.exists(backupPath))) await fs.mkdir(backupPath, {recursive: true});
|
||||
if (!(await extendFs.exists(logsPath))) await fs.mkdir(logsPath, {recursive: true});
|
||||
if (buildFolder && !(await extendFs.exists(buildFolder))) await fs.mkdir(buildFolder, {recursive: true});
|
||||
|
||||
return {
|
||||
id: options?.id,
|
||||
serverRoot,
|
||||
serverPath,
|
||||
hooksPath,
|
||||
backupPath,
|
||||
logsPath,
|
||||
buildFolder,
|
||||
platformIDs: foldersAndLink
|
||||
};
|
||||
}
|
||||
|
||||
export type playerAction = ({action: "join"|"spawned"|"leave"}|{
|
||||
action: "kick"|"ban",
|
||||
reason?: string,
|
||||
by?: string
|
||||
}) & {
|
||||
player: string,
|
||||
actionDate: Date,
|
||||
sessionID: string
|
||||
more?: any,
|
||||
latestAction?: playerAction
|
||||
}
|
||||
|
||||
export type serverConfig = {
|
||||
exec: {
|
||||
exec?: string,
|
||||
args?: string[],
|
||||
cwd?: string,
|
||||
env?: NodeJS.ProcessEnv & {[key: string]: string},
|
||||
},
|
||||
actions?: {
|
||||
stopServer?: (child_process: child_process.ChildProcess) => void,
|
||||
onStart?: (lineData: string, fnRegister: (data?: {serverAvaible?: Date, bootUp?: number}) => void) => void,
|
||||
playerActions?: (lineData: string, fnRegister: (data: playerAction) => void) => void,
|
||||
},
|
||||
maneger?: {
|
||||
backup?: {
|
||||
folderWatch: {local: string, remoteParent?: string}[],
|
||||
} & ({
|
||||
cloud: "google",
|
||||
config: Cloud.googleOptions
|
||||
}|{
|
||||
cloud: "oracle_bucket",
|
||||
config: Cloud.oracleOptions
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
declare class serverManeger extends EventEmitter {
|
||||
on(event: "error", fn: (lineLog: any) => void): this;
|
||||
once(event: "error", fn: (lineLog: any) => void): this;
|
||||
emit(event: "error", data: any): boolean;
|
||||
|
||||
on(event: "log", fn: (lineLog: string) => void): this;
|
||||
once(event: "log", fn: (lineLog: string) => void): this;
|
||||
emit(event: "log", data: string): boolean;
|
||||
|
||||
on(event: "rawLog", fn: (raw: any) => void): this;
|
||||
once(event: "rawLog", fn: (raw: any) => void): this;
|
||||
emit(event: "rawLog", data: any): boolean;
|
||||
|
||||
// Player actions
|
||||
on(event: "playerAction", fn: (playerAction: playerAction) => void): this;
|
||||
once(event: "playerAction", fn: (playerAction: playerAction) => void): this;
|
||||
emit(event: "playerAction", data: playerAction): boolean;
|
||||
|
||||
// Server started
|
||||
on(event: "serverStarted", fn: (data: {serverAvaible: Date, bootUp: number}) => void): this;
|
||||
once(event: "serverStarted", fn: (data: {serverAvaible: Date, bootUp: number}) => void): this;
|
||||
emit(event: "serverStarted", data: {serverAvaible: Date, bootUp: number}): boolean;
|
||||
}
|
||||
|
||||
export async function createServerManeger(serverOptions: serverConfig): Promise<serverManeger> {
|
||||
const internalStops: (() => any|void)[] = [];
|
||||
if (serverOptions?.maneger?.backup) {
|
||||
const { folderWatch, cloud } = serverOptions?.maneger?.backup;
|
||||
if (cloud === "oracle_bucket") {
|
||||
const { config } = serverOptions?.maneger?.backup;
|
||||
const ociClient = await Cloud.oracleBucket(config);
|
||||
for await (const folder of folderWatch) {
|
||||
ociClient;
|
||||
folder;
|
||||
}
|
||||
}
|
||||
}
|
||||
const serverExec = child_process.execFile(serverOptions.exec.exec, serverOptions.exec.args ?? [], {
|
||||
cwd: serverOptions.exec.cwd,
|
||||
windowsHide: true,
|
||||
maxBuffer: Infinity,
|
||||
env: {
|
||||
...process.env,
|
||||
...serverOptions.exec.env
|
||||
},
|
||||
});
|
||||
const playerActions: playerAction[] = [];
|
||||
const internalEvent = new class serverManeger extends EventEmitter {
|
||||
async stopServer() {
|
||||
const stopServer = serverOptions.actions?.stopServer ?? ((child_process) => child_process.kill("SIGKILL"));
|
||||
await Promise.resolve(stopServer(serverExec)).catch(err => internalEvent.emit("error", err));
|
||||
internalStops.forEach((fn) => Promise.resolve().then(() => fn()).catch(err => internalEvent.emit("error", err)));
|
||||
}
|
||||
|
||||
getPlayers() {
|
||||
return playerActions ?? [];
|
||||
}
|
||||
};
|
||||
serverExec.on("error", internalEvent.emit.bind(internalEvent, "error"));
|
||||
const stdoutReadline = readline({input: serverExec.stdout});
|
||||
stdoutReadline.on("line", (line) => internalEvent.emit("log", line));
|
||||
stdoutReadline.on("error", internalEvent.emit.bind(internalEvent, "error"));
|
||||
serverExec.stdout.on("data", (data) => internalEvent.emit("rawLog", data));
|
||||
|
||||
const stderrReadline = readline({input: serverExec.stderr});
|
||||
stderrReadline.on("line", (line) => internalEvent.emit("log", line));
|
||||
stderrReadline.on("error", internalEvent.emit.bind(internalEvent, "error"));
|
||||
serverExec.stderr.on("data", (data) => internalEvent.emit("rawLog", data));
|
||||
|
||||
// Server start
|
||||
if (serverOptions.actions?.onStart) {
|
||||
const serverStartFN = serverOptions.actions.onStart;
|
||||
let lock = false;
|
||||
const started = new Date();
|
||||
async function register(data?: {serverAvaible?: Date, bootUp?: number}) {
|
||||
if (lock) return;
|
||||
const eventData = {
|
||||
serverAvaible: data?.serverAvaible ?? new Date(),
|
||||
bootUp: data?.bootUp ?? new Date().getTime() - started.getTime()
|
||||
};
|
||||
internalEvent.emit("serverStarted", eventData);
|
||||
lock = true;
|
||||
stderrReadline.removeListener("line", register);
|
||||
stdoutReadline.removeListener("line", register);
|
||||
// emit and remove new listener for serverStarted
|
||||
internalEvent.removeAllListeners("serverStarted");
|
||||
internalEvent.prependListener("serverStarted", () => {
|
||||
internalEvent.emit("serverStarted", eventData);
|
||||
internalEvent.removeAllListeners("serverStarted");
|
||||
});
|
||||
}
|
||||
stdoutReadline.on("line", (line) => serverStartFN(line, register));
|
||||
stderrReadline.on("line", (line) => serverStartFN(line, register));
|
||||
}
|
||||
|
||||
// Player actions
|
||||
if (serverOptions.actions?.playerActions) {
|
||||
const playerFn = serverOptions.actions.playerActions;
|
||||
const registerData = (data: playerAction) => {
|
||||
const player = playerActions.find((player) => player.player === data.player);
|
||||
if (!player) playerActions.push(data);
|
||||
else {
|
||||
data.latestAction = player;
|
||||
playerActions[playerActions.indexOf(player)] = data;
|
||||
}
|
||||
internalEvent.emit("playerAction", data);
|
||||
}
|
||||
stdoutReadline.on("line", (line) => playerFn(line, registerData));
|
||||
stderrReadline.on("line", (line) => playerFn(line, registerData));
|
||||
}
|
||||
|
||||
return internalEvent;
|
||||
}
|
@ -4,22 +4,21 @@
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"target": "ESNext",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noUnusedLocals": true,
|
||||
"isolatedModules": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true,
|
||||
"lib": ["ES6"]
|
||||
"lib": [
|
||||
"ESNext"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"src/**/*.test.ts",
|
||||
"node_modules/**/*"
|
||||
"**/*.test.ts"
|
||||
],
|
||||
"ts-node": {
|
||||
"esm": true
|
||||
|
Reference in New Issue
Block a user