Merge branch 'develop' into v2
This commit is contained in:
commit
b0d6be802c
14 changed files with 163 additions and 22 deletions
2
.github/docker/README.md
vendored
2
.github/docker/README.md
vendored
|
@ -12,7 +12,7 @@ You can provide additional settings using a custom `.env` file or by setting the
|
|||
|
||||
## Setup
|
||||
|
||||
Start the docker container and the required dependencies (either provide existing ones or start containers as well, see the [docker-compose.yml](docker-compose.yml) file as an example).
|
||||
Start the docker container and the required dependencies (either provide existing ones or start containers as well, see the [docker-compose.yml](https://github.com/pterodactyl/panel/blob/develop/docker-compose.example.yml) file as an example.
|
||||
|
||||
After the startup is complete you'll need to create a user.
|
||||
If you are running the docker container without docker-compose, use:
|
||||
|
|
5
.github/docker/entrypoint.sh
vendored
5
.github/docker/entrypoint.sh
vendored
|
@ -55,6 +55,11 @@ else
|
|||
rm -rf /etc/nginx/http.d/default.conf
|
||||
fi
|
||||
|
||||
if [[ -z $DB_PORT ]]; then
|
||||
echo -e "DB_PORT not specified, defaulting to 3306"
|
||||
DB_PORT=3306
|
||||
fi
|
||||
|
||||
## check for DB up before starting the panel
|
||||
echo "Checking database status."
|
||||
until nc -z -v -w30 $DB_HOST $DB_PORT
|
||||
|
|
|
@ -5,9 +5,9 @@ Release versions of Pterodactyl will include pre-compiled, minified, and hashed
|
|||
However, if you are interested in running custom themes or making modifications to the React files you'll need a build
|
||||
system in place to generate these compiled assets. To get your environment setup you'll need at minimum:
|
||||
|
||||
* Node.js 12
|
||||
* [Yarn](https://classic.yarnpkg.com/lang/en/) v1
|
||||
* [Go](https://golang.org/) 1.15.
|
||||
* [Node.js](https://nodejs.org/en/) v14.x.x
|
||||
* [Yarn](https://classic.yarnpkg.com/lang/en/) v1.x.x
|
||||
* [Go](https://golang.org/) 1.17.x
|
||||
|
||||
### Install Dependencies
|
||||
```bash
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"description": "For a long time, Minecraft server owners have had a dream that encompasses a free, easy, and reliable way to connect multiple Minecraft servers together. BungeeCord is the answer to said dream. Whether you are a small server wishing to string multiple game-modes together, or the owner of the ShotBow Network, BungeeCord is the ideal solution for you. With the help of BungeeCord, you will be able to unlock your community's full potential.",
|
||||
"features": [
|
||||
"eula",
|
||||
"java_version"
|
||||
"java_version",
|
||||
"pid_limit"
|
||||
],
|
||||
"images": [
|
||||
"ghcr.io\/pterodactyl\/yolks:java_8",
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"description": "Minecraft Forge Server. Minecraft Forge is a modding API (Application Programming Interface), which makes it easier to create mods, and also make sure mods are compatible with each other.",
|
||||
"features": [
|
||||
"eula",
|
||||
"java_version"
|
||||
"java_version",
|
||||
"pid_limit"
|
||||
],
|
||||
"images": [
|
||||
"ghcr.io\/pterodactyl\/yolks:java_17",
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"description": "High performance Spigot fork that aims to fix gameplay and mechanics inconsistencies.",
|
||||
"features": [
|
||||
"eula",
|
||||
"java_version"
|
||||
"java_version",
|
||||
"pid_limit"
|
||||
],
|
||||
"images": [
|
||||
"ghcr.io\/pterodactyl\/yolks:java_8",
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"description": "SpongeVanilla is the SpongeAPI implementation for Vanilla Minecraft.",
|
||||
"features": [
|
||||
"eula",
|
||||
"java_version"
|
||||
"java_version",
|
||||
"pid_limit"
|
||||
],
|
||||
"images": [
|
||||
"ghcr.io\/pterodactyl\/yolks:java_8",
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
"description": "Minecraft is a game about placing blocks and going on adventures. Explore randomly generated worlds and build amazing things from the simplest of homes to the grandest of castles. Play in Creative Mode with unlimited resources or mine deep in Survival Mode, crafting weapons and armor to fend off dangerous mobs. Do all this alone or with friends.",
|
||||
"features": [
|
||||
"eula",
|
||||
"java_version"
|
||||
"java_version",
|
||||
"pid_limit"
|
||||
],
|
||||
"images": [
|
||||
"ghcr.io\/pterodactyl\/yolks:java_8",
|
||||
|
|
|
@ -70,6 +70,7 @@ services:
|
|||
QUEUE_DRIVER: "redis"
|
||||
REDIS_HOST: "cache"
|
||||
DB_HOST: "database"
|
||||
DB_PORT: "3306"
|
||||
networks:
|
||||
default:
|
||||
ipam:
|
||||
|
|
|
@ -40,11 +40,12 @@ export interface SwitchProps {
|
|||
label?: string;
|
||||
description?: string;
|
||||
defaultChecked?: boolean;
|
||||
readOnly?: boolean;
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const Switch = ({ name, label, description, defaultChecked, onChange, children }: SwitchProps) => {
|
||||
const Switch = ({ name, label, description, defaultChecked, readOnly, onChange, children }: SwitchProps) => {
|
||||
const uuid = useMemo(() => v4(), []);
|
||||
|
||||
return (
|
||||
|
@ -57,6 +58,7 @@ const Switch = ({ name, label, description, defaultChecked, onChange, children }
|
|||
type={'checkbox'}
|
||||
onChange={e => onChange && onChange(e)}
|
||||
defaultChecked={defaultChecked}
|
||||
disabled={readOnly}
|
||||
/>
|
||||
}
|
||||
<Label htmlFor={uuid}/>
|
||||
|
|
|
@ -7,7 +7,7 @@ import ServerContentBlock from '@/components/elements/ServerContentBlock';
|
|||
import ServerDetailsBlock from '@/components/server/ServerDetailsBlock';
|
||||
import isEqual from 'react-fast-compare';
|
||||
import PowerControls from '@/components/server/PowerControls';
|
||||
import { EulaModalFeature, JavaVersionModalFeature, GSLTokenModalFeature } from 'feature/index';
|
||||
import { EulaModalFeature, JavaVersionModalFeature, GSLTokenModalFeature, PIDLimitModalFeature } from 'feature/index';
|
||||
import ErrorBoundary from '@/components/elements/ErrorBoundary';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
|
||||
|
@ -61,6 +61,7 @@ const ServerConsole = () => {
|
|||
{eggFeatures.includes('eula') && <EulaModalFeature/>}
|
||||
{eggFeatures.includes('java_version') && <JavaVersionModalFeature/>}
|
||||
{eggFeatures.includes('gsl_token') && <GSLTokenModalFeature/>}
|
||||
{eggFeatures.includes('pid_limit') && <PIDLimitModalFeature/>}
|
||||
</React.Suspense>
|
||||
</div>
|
||||
</ServerContentBlock>
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { ServerContext } from '@/state/server';
|
||||
import Modal from '@/components/elements/Modal';
|
||||
import tw from 'twin.macro';
|
||||
import Button from '@/components/elements/Button';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
import useFlash from '@/plugins/useFlash';
|
||||
import { SocketEvent } from '@/components/server/events';
|
||||
import { useStoreState } from 'easy-peasy';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
const PIDLimitModalFeature = () => {
|
||||
const [ visible, setVisible ] = useState(false);
|
||||
const [ loading ] = useState(false);
|
||||
|
||||
const status = ServerContext.useStoreState(state => state.status.value);
|
||||
const { clearFlashes } = useFlash();
|
||||
const { connected, instance } = ServerContext.useStoreState(state => state.socket);
|
||||
const isAdmin = useStoreState(state => state.user.data!.rootAdmin);
|
||||
|
||||
useEffect(() => {
|
||||
if (!connected || !instance || status === 'running') return;
|
||||
|
||||
const errors = [
|
||||
'pthread_create failed',
|
||||
'Exception in thread "Craft Async Scheduler Management Thread"',
|
||||
'unable to create new native thread',
|
||||
'unable to create native thread',
|
||||
];
|
||||
|
||||
const listener = (line: string) => {
|
||||
if (errors.some(p => line.toLowerCase().includes(p))) {
|
||||
setVisible(true);
|
||||
}
|
||||
};
|
||||
|
||||
instance.addListener(SocketEvent.CONSOLE_OUTPUT, listener);
|
||||
|
||||
return () => {
|
||||
instance.removeListener(SocketEvent.CONSOLE_OUTPUT, listener);
|
||||
};
|
||||
}, [ connected, instance, status ]);
|
||||
|
||||
useEffect(() => {
|
||||
clearFlashes('feature:pidLimit');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Modal visible={visible} onDismissed={() => setVisible(false)} closeOnBackground={false} showSpinnerOverlay={loading}>
|
||||
<FlashMessageRender key={'feature:pidLimit'} css={tw`mb-4`} />
|
||||
{isAdmin ?
|
||||
<>
|
||||
<div css={tw`mt-4 sm:flex items-center`}>
|
||||
<FontAwesomeIcon css={tw`pr-4`} icon={faExclamationTriangle} color={'orange'} size={'4x'}/>
|
||||
<h2 css={tw`text-2xl mb-4 text-neutral-100 `}>Memory or process limit reached...</h2>
|
||||
</div>
|
||||
<p css={tw`mt-4`}>This server has reached the maximum process or memory limit.</p>
|
||||
<p css={tw`mt-4`}>Increasing <code css={tw`font-mono bg-neutral-900`}>container_pid_limit</code> in the wings configuration, <code css={tw`font-mono bg-neutral-900`}>config.yml</code>, might help resolve this issue.</p>
|
||||
<p css={tw`mt-4`}><b>Note: Wings must be restarted for the configuration file changes to take effect</b></p>
|
||||
<div css={tw`mt-8 sm:flex items-center justify-end`}>
|
||||
<Button onClick={() => setVisible(false)} css={tw`w-full sm:w-auto border-transparent`}>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
:
|
||||
<>
|
||||
<div css={tw`mt-4 sm:flex items-center`}>
|
||||
<FontAwesomeIcon css={tw`pr-4`} icon={faExclamationTriangle} color={'orange'} size={'4x'}/>
|
||||
<h2 css={tw`text-2xl mb-4 text-neutral-100`}>Possible resource limit reached...</h2>
|
||||
</div>
|
||||
<p css={tw`mt-4`}>This server is attempting to use more resources than allocated. Please contact the administrator and give them the error below.</p>
|
||||
<p css={tw`mt-4`}><code css={tw`font-mono bg-neutral-900`}>pthread_create failed, Possibly out of memory or process/resource limits reached</code></p>
|
||||
<div css={tw`mt-8 sm:flex items-center justify-end`}>
|
||||
<Button onClick={() => setVisible(false)} css={tw`w-full sm:w-auto border-transparent`}>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default PIDLimitModalFeature;
|
|
@ -9,5 +9,6 @@ import { lazy } from 'react';
|
|||
const EulaModalFeature = lazy(() => import(/* webpackChunkName: "feature.eula" */'feature/eula/EulaModalFeature'));
|
||||
const JavaVersionModalFeature = lazy(() => import(/* webpackChunkName: "feature.java_version" */'feature/JavaVersionModalFeature'));
|
||||
const GSLTokenModalFeature = lazy(() => import(/* webpackChunkName: "feature.gsl_token" */'feature/GSLTokenModalFeature'));
|
||||
const PIDLimitModalFeature = lazy(() => import(/* webpackChunkName: "feature.pid_limit" */'feature/PIDLimitModalFeature'));
|
||||
|
||||
export { EulaModalFeature, JavaVersionModalFeature, GSLTokenModalFeature };
|
||||
export { EulaModalFeature, JavaVersionModalFeature, GSLTokenModalFeature, PIDLimitModalFeature };
|
||||
|
|
|
@ -4,12 +4,14 @@ import TitledGreyBox from '@/components/elements/TitledGreyBox';
|
|||
import { usePermissions } from '@/plugins/usePermissions';
|
||||
import InputSpinner from '@/components/elements/InputSpinner';
|
||||
import Input from '@/components/elements/Input';
|
||||
import Switch from '@/components/elements/Switch';
|
||||
import tw from 'twin.macro';
|
||||
import { debounce } from 'debounce';
|
||||
import updateStartupVariable from '@/api/server/updateStartupVariable';
|
||||
import useFlash from '@/plugins/useFlash';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
import getServerStartup from '@/api/swr/getServerStartup';
|
||||
import Select from '@/components/elements/Select';
|
||||
import isEqual from 'react-fast-compare';
|
||||
import { ServerContext } from '@/state/server';
|
||||
|
||||
|
@ -43,6 +45,9 @@ const VariableBox = ({ variable }: Props) => {
|
|||
.then(() => setLoading(false));
|
||||
}, 500);
|
||||
|
||||
const useSwitch = variable.rules.some(v => v === 'boolean' || v === 'in:0,1');
|
||||
const selectValues = variable.rules.find(v => v.startsWith('in:'))?.split(',') || [];
|
||||
|
||||
return (
|
||||
<TitledGreyBox
|
||||
title={
|
||||
|
@ -56,17 +61,52 @@ const VariableBox = ({ variable }: Props) => {
|
|||
>
|
||||
<FlashMessageRender byKey={FLASH_KEY} css={tw`mb-2 md:mb-4`}/>
|
||||
<InputSpinner visible={loading}>
|
||||
<Input
|
||||
onKeyUp={e => {
|
||||
if (canEdit && variable.isEditable) {
|
||||
setVariableValue(e.currentTarget.value);
|
||||
{useSwitch ?
|
||||
<>
|
||||
<Switch
|
||||
readOnly={!canEdit || !variable.isEditable}
|
||||
name={variable.envVariable}
|
||||
defaultChecked={variable.serverValue === '1'}
|
||||
onChange={() => {
|
||||
if (canEdit && variable.isEditable) {
|
||||
setVariableValue(variable.serverValue === '1' ? '0' : '1');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
:
|
||||
<>
|
||||
{selectValues.length > 0 ?
|
||||
<>
|
||||
<Select
|
||||
onChange={e => setVariableValue(e.target.value)}
|
||||
name={variable.envVariable}
|
||||
defaultValue={variable.serverValue}
|
||||
disabled={!canEdit || !variable.isEditable}
|
||||
>
|
||||
{selectValues.map(selectValue => (
|
||||
<option key={selectValue.replace('in:', '')} value={selectValue.replace('in:', '')}>{selectValue.replace('in:', '')}</option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
</>
|
||||
:
|
||||
<>
|
||||
<Input
|
||||
onKeyUp={e => {
|
||||
if (canEdit && variable.isEditable) {
|
||||
setVariableValue(e.currentTarget.value);
|
||||
}
|
||||
}}
|
||||
readOnly={!canEdit || !variable.isEditable}
|
||||
name={variable.envVariable}
|
||||
defaultValue={variable.serverValue}
|
||||
placeholder={variable.defaultValue}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
}}
|
||||
readOnly={!canEdit || !variable.isEditable}
|
||||
name={variable.envVariable}
|
||||
defaultValue={variable.serverValue}
|
||||
placeholder={variable.defaultValue}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
</InputSpinner>
|
||||
<p css={tw`mt-1 text-xs text-neutral-300`}>
|
||||
{variable.description}
|
||||
|
|
Loading…
Reference in a new issue