Compare commits
5 Commits
db73a24902
...
6cd3411795
Author | SHA1 | Date |
---|---|---|
|
6cd3411795 | ago%!(EXTRA string=2 months) |
|
5f00d6188c | ago%!(EXTRA string=2 months) |
|
d522f986e7 | ago%!(EXTRA string=2 months) |
|
99a810c02b | ago%!(EXTRA string=2 months) |
|
662f2909f3 | ago%!(EXTRA string=2 months) |
@ -0,0 +1,30 @@ |
||||
FROM ubuntu:latest |
||||
|
||||
WORKDIR /app |
||||
|
||||
COPY ./run.sh ./run.sh |
||||
|
||||
RUN apt -y update |
||||
RUN apt -y upgrade |
||||
|
||||
RUN apt -y install sudo software-properties-common |
||||
RUN dpkg --add-architecture i386 |
||||
RUN apt-add-repository multiverse |
||||
RUN apt -y update |
||||
RUN echo steam steam/question select "I AGREE" | sudo debconf-set-selections |
||||
RUN echo steam steam/license note '' | sudo debconf-set-selections |
||||
RUN apt install -y steamcmd lib32gcc-s1 |
||||
RUN echo "fs.file-max=100000" > /etc/sysctl.conf |
||||
RUN echo "* soft nofile 100000" > /etc/security/limits.conf |
||||
RUN echo "* hard nofile 100000" > /etc/security/limits.conf |
||||
RUN echo "session required pam_limits.so" > /etc/pam.d/common-session |
||||
|
||||
RUN useradd -m ark |
||||
RUN chown -R ark:ark . |
||||
RUN sudo -u ark -s |
||||
|
||||
RUN chmod +x ./run.sh |
||||
RUN ulimit -n 100000 |
||||
RUN /usr/games/steamcmd +force_install_dir /app +login anonymous +app_update 376030 validate +exit |
||||
|
||||
ENTRYPOINT [ "./run.sh" ] |
@ -0,0 +1,4 @@ |
||||
#!/bin/bash |
||||
|
||||
#./ShooterGame/Binaries/Linux/ShooterGameServer TheIsland?listen?SessionName=ArkServer?ServerPassword=123456?ServerAdminPassword=123456 -server -log -crossplay |
||||
./ShooterGame/Binaries/Linux/ShooterGameServer TheIsland?listen?SessionName=ArkServer -server -log -crossplay |
@ -0,0 +1,18 @@ |
||||
FROM ubuntu:latest |
||||
|
||||
WORKDIR /app |
||||
|
||||
ENV LD_LIBRARY_PATH=. |
||||
|
||||
COPY ./bedrock-server-1.21.60.10.zip ./bedrock-server.zip |
||||
|
||||
RUN apt -y update |
||||
RUN apt -y upgrade |
||||
RUN apt install -y 7zip curl |
||||
RUN 7z x ./bedrock-server.zip |
||||
RUN chmod +x ./bedrock_server |
||||
RUN rm -rf ./bedrock-server.zip |
||||
VOLUME [ "/app" ] |
||||
|
||||
ENTRYPOINT [ "./bedrock_server" ] |
||||
|
@ -0,0 +1,34 @@ |
||||
<?php |
||||
namespace App\Console; |
||||
use Illuminate\Console\Scheduling\Schedule; |
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel; |
||||
use Illuminate\Support\Facades\File; |
||||
use Illuminate\Support\Facades\Log; |
||||
use Illuminate\Support\Facades\Storage; |
||||
|
||||
class Kernel extends ConsoleKernel |
||||
{ |
||||
/** |
||||
* Define the application's command schedule. |
||||
* |
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule |
||||
* @return void |
||||
*/ |
||||
protected function schedule(Schedule $schedule) |
||||
{ |
||||
|
||||
$schedule->call(function() { |
||||
Log::info("Hello"); |
||||
})->everyThreeMinutes(); |
||||
} |
||||
/** |
||||
* Register the commands for the application. |
||||
* |
||||
* @return void |
||||
*/ |
||||
protected function commands() |
||||
{ |
||||
$this->load(__DIR__.'/Commands'); |
||||
require base_path('routes/console.php'); |
||||
} |
||||
} |
@ -0,0 +1,56 @@ |
||||
<?php |
||||
|
||||
namespace App\Docker; |
||||
|
||||
use Exception; |
||||
use Illuminate\Support\Facades\Log; |
||||
use Psr\Http\Message\ResponseInterface; |
||||
use React\Http\Browser; |
||||
use React\Socket\FixedUriConnector; |
||||
use React\Socket\UnixConnector; |
||||
use function React\Async\await; |
||||
|
||||
|
||||
class Exec |
||||
{ |
||||
protected $id; |
||||
protected $connector; |
||||
protected $browser; |
||||
|
||||
public function __construct($id) |
||||
{ |
||||
$this->id = $id; |
||||
$connection = Docker::connect(); |
||||
$this->connector = $connection->connector; |
||||
$this->browser = $connection->browser; |
||||
} |
||||
|
||||
public function getId() { return $this->id; } |
||||
|
||||
public function start($args = []) |
||||
{ |
||||
try { |
||||
Log::info("Starting exec :" . Docker::endpoint("/exec/" . $this->id . "/start")); |
||||
$response = await($this->browser->post( |
||||
Docker::endpoint("/exec/" . $this->id . "/start"), |
||||
[ "Content-Type" => "application/json"], |
||||
)); |
||||
return json_decode($response->getBody()); |
||||
} catch (Exception $e) { |
||||
throw $e; |
||||
} |
||||
} |
||||
|
||||
public function inspect() |
||||
{ |
||||
try { |
||||
$response = await($this->browser->get( |
||||
Docker::endpoint("/exec/" . $this->id . "/json"), |
||||
[ "Content-Type" => "text/plain" ] |
||||
)); |
||||
return json_decode($response->getBody()); |
||||
} catch (Exception $e) { |
||||
throw $e; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,179 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Controllers; |
||||
|
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Str; |
||||
|
||||
use App\Docker\Container; |
||||
use App\Jobs\InitServer; |
||||
use App\Models\ExposedPort; |
||||
use App\Models\Server; |
||||
use App\Models\Service; |
||||
use Carbon\Carbon; |
||||
use Exception; |
||||
use Illuminate\Support\Facades\Auth; |
||||
use Inertia\Inertia; |
||||
|
||||
|
||||
class ServerController extends Controller |
||||
{ |
||||
public function start(Request $request) |
||||
{ |
||||
$server = Server::where("uuid", $request->id)->first(); |
||||
if($server->status_id >= 3) { |
||||
try { |
||||
$container = new Container($server->container); |
||||
$container->start(); |
||||
$server->update([ |
||||
"status_id" => 1, |
||||
"start" => Carbon::now() |
||||
]); |
||||
return redirect()->back()->withErrors([ "message" => "Serveur lancé avec succès. Attendez quelque seconds avant de vous connectez." ]); |
||||
} catch(Exception $e) { return redirect()->back()->withErrors([ "error" => "Impossible de démarré le serveur." ]); } |
||||
|
||||
} else { return redirect()->back()->withErrors([ "error" => "Serveur déjà ou entrain de démarré." ]); } |
||||
} |
||||
|
||||
public function stop(Request $request) |
||||
{ |
||||
$server = Server::where("uuid", $request->id)->first(); |
||||
if($server->status_id < 3) { |
||||
try { |
||||
$server->update([ |
||||
"status_id" => 3, |
||||
"end" => Carbon::now() |
||||
]); |
||||
$container = new Container($server->container); |
||||
$container->stop(); |
||||
return redirect()->back()->withErrors([ "message" => "Serveur arrêté avec succès. Merci de votre visite." ]); |
||||
} catch(Exception $e) { return redirect()->back()->withErrors([ "error" => "Impossible de d'arrêter le serveur." ]); } |
||||
|
||||
} else { return redirect()->back()->withErrors([ "error" => "Serveur déjà ou entrain de s'arrêter." ]); } |
||||
} |
||||
|
||||
/** |
||||
* Display a listing of the resource. |
||||
*/ |
||||
public function index() |
||||
{ |
||||
return Inertia::render("Server/Index", [ |
||||
"banner" => "/img/banner.gif", |
||||
"servers" => (Auth::user()->admin ? Server::orderBy("start", "DESC")->orderBy("end", "DESC")->get() : Server::where("user_id", Auth::user()->id)->get())->jsonSerialize(), |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* Show the form for creating a new resource. |
||||
*/ |
||||
public function create() |
||||
{ |
||||
return Inertia::render('Server/Create', [ |
||||
"banner" => "/img/banner.jpg", |
||||
"services" => Service::all() |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* Store a newly created resource in storage. |
||||
*/ |
||||
public function store(Request $request) |
||||
{ |
||||
$request->validate([ |
||||
"name" => "required|string", |
||||
"service" => "required|string", |
||||
"launch" => "nullable" |
||||
]); |
||||
|
||||
$user = Auth::user(); |
||||
if(!$user->admin && count($user->server) >= 2) return redirect()->back()->withErrors(["error" => "Vous avez déjà trop de servers. Veillez en supprimer un!"]); |
||||
|
||||
$service = Service::where("uuid", $request->service)->first(); |
||||
if(!$service) return redirect()->back()->withErrors(["error" => "Impossible de trouver ce service!"]); |
||||
$server = Server::create([ |
||||
"uuid" => Str::uuid(), |
||||
"name" => preg_replace('/[^a-zA-Z0-9_.-]/', '', $request->name), |
||||
"service_id" => $service->id, |
||||
"status_id" => 3, |
||||
"user_id" => Auth::user()->id |
||||
]); |
||||
|
||||
$config = config($server->service->config); |
||||
$ports = explode("|", $server->service->ports); |
||||
|
||||
for ($i = 0; $i < count($ports); $i++) { |
||||
$port = ExposedPort::where("usable", true)->first(); |
||||
if(!$port) { |
||||
$server->exposedPorts()->update([ "usable" => true ]); |
||||
$server->exposedPorts()->detach(); |
||||
$server->delete(); |
||||
return redirect()->back()->withErrors(["error" => "Aucune place libre pour votre server, réessayer plus tard."]); |
||||
} |
||||
$server->exposedPorts()->attach($port->id); |
||||
$port->update(["usable" => false]); |
||||
|
||||
$config["ExposedPorts"][$ports[$i] . "/" . $server->service->protocol] = (object)[]; |
||||
$config["HostConfig"]["PortBindings"][$ports[$i] . "/" . $server->service->protocol] = [[ "HostPort" => "" . $port->number ]]; |
||||
} |
||||
|
||||
dispatch(new InitServer($server, $config, $request->launch ? true : false)); |
||||
return redirect(route("servers.index"))->withErrors([ "message" => "Serveur créer avec succès" . ($request->launch ? " et devrait se lancer d'une minute à l'autre." : ".") ]); |
||||
} |
||||
|
||||
/** |
||||
* Display the specified resource. |
||||
*/ |
||||
public function show(Request $request) |
||||
{ |
||||
$server = Server::where("uuid", $request->id)->firstOrFail(); |
||||
|
||||
return Inertia::render("Server/Show", [ |
||||
"banner" => "/img/banner.webp", |
||||
"server" => $server->jsonSerialize() |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* Update the specified resource in storage. |
||||
*/ |
||||
public function update(Request $request) |
||||
{ |
||||
$request->validate([ |
||||
"name" => "required|string|max:25", |
||||
]); |
||||
|
||||
$server = Server::where("uuid", $request->id)->first(); |
||||
$server->update([ |
||||
"name" => preg_replace('/[^a-zA-Z0-9_.-]/', '', $request->name) |
||||
]); |
||||
return redirect()->back()->withErrors(["message" => "Nom changé avec succès."]); |
||||
} |
||||
|
||||
public function makePublic(Request $request) |
||||
{ |
||||
$server = Server::where("uuid", $request->id)->first(); |
||||
$server->update([ |
||||
"public" => !$server->public, |
||||
]); |
||||
return redirect()->back()->withErrors(["message" => $server->public ? "Server rendu publiquement accéssible." : "Server rendu privé."]); |
||||
} |
||||
|
||||
/** |
||||
* Remove the specified resource from storage. |
||||
*/ |
||||
public function destroy(Request $request) |
||||
{ |
||||
$server = Server::where("uuid", $request->id)->first(); |
||||
if($server->container) { |
||||
try { |
||||
$container = new Container($server->container); |
||||
$data = $container->inspect()->State; |
||||
if($data->Running || $data->Paused || $data->Restarting) $container->kill(); |
||||
} catch(Exception) { return redirect()->back()->withErrors(["error" => "Problème pour éteindre le serveur. Réessayer!"]); } |
||||
} |
||||
$server->exposedPorts()->update([ "usable" => true ]); |
||||
$server->exposedPorts()->detach(); |
||||
$server->delete(); |
||||
return redirect(route("servers.index"))->withErrors(["message" => "Server supprimer avec succès."]); |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Middleware; |
||||
|
||||
use App\Models\Server; |
||||
use Closure; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\Auth; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class ResourceRules |
||||
{ |
||||
/** |
||||
* Handle an incoming request. |
||||
* |
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next |
||||
*/ |
||||
public function handle(Request $request, Closure $next): Response |
||||
{ |
||||
$server = Server::where("uuid", $request->id)->first(); |
||||
if(!$server) return redirect(route("servers.index"))->withErrors(["error" => "Impossible de trouver ce server!"]); |
||||
if(Auth::user()->id == $server->id || Auth::user()->admin) return $next($request); |
||||
return redirect(route("servers.index"))->withErrors(["error" => "Vous n'avez d'autorisation d'access a se serveur!"]); |
||||
} |
||||
} |
@ -0,0 +1,66 @@ |
||||
<?php |
||||
|
||||
namespace App\Jobs; |
||||
|
||||
use App\Docker\Container; |
||||
use App\Models\ExposedPort; |
||||
use Exception; |
||||
use Illuminate\Contracts\Queue\ShouldQueue; |
||||
use Illuminate\Foundation\Queue\Queueable; |
||||
use Illuminate\Support\Facades\Log; |
||||
use Illuminate\Support\Str; |
||||
|
||||
class InitServer implements ShouldQueue |
||||
{ |
||||
use Queueable; |
||||
|
||||
protected $server; |
||||
protected $config; |
||||
protected $launch; |
||||
/** |
||||
* Create a new job instance. |
||||
*/ |
||||
public function __construct($server, $config, $launch) |
||||
{ |
||||
$this->server = $server; |
||||
$this->launch = $launch; |
||||
$this->config = $config; |
||||
$server->update(["status_id" => 2]); |
||||
} |
||||
|
||||
/** |
||||
* Execute the job. |
||||
*/ |
||||
public function handle(): void |
||||
{ |
||||
try { |
||||
$container = Container::create($this->server->name . Str::random(5), $this->config); |
||||
if($this->launch) { |
||||
$container->start(); |
||||
$this->server->update([ |
||||
"container" => $container->getId(), |
||||
"status_id" => 1, |
||||
"start" => now(), |
||||
"end" => now() |
||||
]); |
||||
} else { |
||||
$this->server->update([ |
||||
"container" => $container->getId(), |
||||
"status_id" => 3, |
||||
"end" => now() |
||||
]); |
||||
} |
||||
}catch(Exception $e) { |
||||
$this->fail($e); |
||||
} |
||||
} |
||||
|
||||
public function fail($e): void |
||||
{ |
||||
$this->server->update([ |
||||
"status_id" => 4, |
||||
]); |
||||
$this->server->exposedPorts()->detach(); |
||||
Log::info(((object)$e)->getResponse()->getBody()); |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class ExposedPort extends Model |
||||
{ |
||||
protected $fillable = [ |
||||
'number', |
||||
'usable' |
||||
]; |
||||
} |
@ -0,0 +1,55 @@ |
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class Server extends Model |
||||
{ |
||||
protected $fillable = [ |
||||
"uuid", |
||||
'name', |
||||
"container", |
||||
"start", |
||||
"end", |
||||
"public", |
||||
"service_id", |
||||
"user_id", |
||||
"status_id", |
||||
]; |
||||
|
||||
public function jsonSerialize(): mixed |
||||
{ |
||||
return [ |
||||
"uuid" => $this->uuid, |
||||
'name' => $this->name, |
||||
"start" => $this->start, |
||||
"end" => $this->end, |
||||
"public" => $this->public, |
||||
"service" => $this->service, |
||||
"user" => $this->user, |
||||
"status" => $this->status, |
||||
"ports" => $this->exposedPorts()->pluck("number"), |
||||
]; |
||||
} |
||||
|
||||
public function exposedPorts() |
||||
{ |
||||
return $this->belongsToMany(ExposedPort::class); |
||||
} |
||||
|
||||
public function service() |
||||
{ |
||||
return $this->belongsTo(Service::class); |
||||
} |
||||
|
||||
public function status() |
||||
{ |
||||
return $this->belongsTo(Status::class); |
||||
} |
||||
|
||||
public function user() |
||||
{ |
||||
return $this->belongsTo(User::class); |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class Service extends Model |
||||
{ |
||||
protected $fillable = [ |
||||
"uuid", |
||||
'name', |
||||
"image", |
||||
"config", |
||||
"ports", |
||||
"protocol" |
||||
]; |
||||
|
||||
public function servers() |
||||
{ |
||||
return $this->hasMany(Server::class); |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class Spec extends Model |
||||
{ |
||||
protected $fillable = [ |
||||
"uuid", |
||||
"cpus", |
||||
"memory", |
||||
"storage" |
||||
]; |
||||
} |
@ -0,0 +1,13 @@ |
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class Status extends Model |
||||
{ |
||||
protected $fillable = [ |
||||
'title', |
||||
'message' |
||||
]; |
||||
} |
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
|
||||
class Netstat |
||||
{ |
||||
|
||||
public static function parseArgs($ssOutput) |
||||
{ |
||||
$lines = explode("\n", $ssOutput); |
||||
|
||||
// Step 2: Skip the header line |
||||
array_shift($lines); |
||||
|
||||
// Step 3: Parse each line and extract relevant details |
||||
$connections = []; |
||||
foreach ($lines as $line) { |
||||
// Ignore empty lines |
||||
if (empty(trim($line))) { |
||||
continue; |
||||
} |
||||
|
||||
// Use regex to match the structured output |
||||
if (preg_match('/(\S+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+users:\(\("([^"]+)",pid=(\d+),fd=(\d+)\)\)/', $line, $matches)) { |
||||
$connections[] = [ |
||||
'State' => $matches[1], // e.g., LISTEN |
||||
'Recv-Q' => $matches[2], // e.g., 0 |
||||
'Send-Q' => $matches[3], // e.g., 128 |
||||
'LocalAddress' => $matches[4], // e.g., 0.0.0.0:80 |
||||
'ForeignAddress' => $matches[5], // e.g., 0.0.0.0:* |
||||
'Program' => $matches[6], // e.g., nginx |
||||
'PID' => $matches[7], // e.g., 1234 |
||||
'FD' => $matches[8], // e.g., 6 |
||||
]; |
||||
} |
||||
} |
||||
return $connections; |
||||
|
||||
} |
||||
} |
||||
|
@ -0,0 +1,45 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
"endpoint" => "http://localhost", |
||||
"minecraftJava" => [ |
||||
"Hostname" => "mincraft-server", |
||||
"User" => "root", |
||||
"Image" => "minecraftjava:latest", |
||||
"AttachStdout" => false, |
||||
"AttachStderr" => false, |
||||
"OpenStdin" => true, |
||||
"Tty" => true, |
||||
"ExposedPorts" => [], |
||||
"HostConfig" => [ |
||||
"PortBindings" => [], |
||||
] |
||||
], |
||||
"minecraftBedrock" => [ |
||||
"Hostname" => "mincraft-server", |
||||
"User" => "root", |
||||
"Image" => "minecraftbedrock:latest", |
||||
"OpenStdin" => true, |
||||
"AttachStdout" => false, |
||||
"AttachStderr" => false, |
||||
"Tty" => true, |
||||
"ExposedPorts" => [], |
||||
"HostConfig" => [ |
||||
"PortBindings" => [], |
||||
] |
||||
], |
||||
"arkserver" => [ |
||||
"Hostname" => "ark-server", |
||||
"User" => "root", |
||||
"Image" => "arkserver:latest", |
||||
"OpenStdin" => true, |
||||
"AttachStdout" => false, |
||||
"AttachStderr" => false, |
||||
"Tty" => true, |
||||
"ExposedPorts" => [], |
||||
"HostConfig" => [ |
||||
"PortBindings" => [], |
||||
] |
||||
] |
||||
|
||||
]; |
@ -0,0 +1,32 @@ |
||||
<?php |
||||
|
||||
use App\Models\ExposedPort; |
||||
use Illuminate\Database\Migrations\Migration; |
||||
use Illuminate\Database\Schema\Blueprint; |
||||
use Illuminate\Support\Facades\DB; |
||||
use Illuminate\Support\Facades\Schema; |
||||
|
||||
return new class extends Migration |
||||
{ |
||||
/** |
||||
* Run the migrations. |
||||
*/ |
||||
public function up(): void |
||||
{ |
||||
Schema::create('exposed_ports', function (Blueprint $table) { |
||||
$table->id(); |
||||
$table->unsignedSmallInteger("number"); |
||||
$table->boolean("usable"); |
||||
$table->timestamps(); |
||||
}); |
||||
for($i = 25000; $i < 30000; $i++) ExposedPort::create([ "number" => $i, "usable" => true ]); |
||||
} |
||||
|
||||
/** |
||||
* Reverse the migrations. |
||||
*/ |
||||
public function down(): void |
||||
{ |
||||
Schema::dropIfExists('exposed_ports'); |
||||
} |
||||
}; |
@ -0,0 +1,62 @@ |
||||
<?php |
||||
|
||||
use App\Models\Service; |
||||
use Illuminate\Database\Migrations\Migration; |
||||
use Illuminate\Database\Schema\Blueprint; |
||||
use Illuminate\Support\Facades\Schema; |
||||
use Illuminate\Support\Str; |
||||
|
||||
return new class extends Migration |
||||
{ |
||||
/** |
||||
* Run the migrations. |
||||
*/ |
||||
public function up(): void |
||||
{ |
||||
Schema::create('services', function (Blueprint $table) { |
||||
$table->id(); |
||||
$table->uuid(); |
||||
$table->string("name"); |
||||
$table->string("image"); |
||||
$table->string("config"); |
||||
$table->string("protocol"); |
||||
$table->string("ports"); |
||||
$table->timestamps(); |
||||
}); |
||||
|
||||
Service::create([ |
||||
"uuid" => Str::uuid(), |
||||
"name" => "Minecraft Java edition", |
||||
"image" => "/img/minecraft-java.webp", |
||||
"config" => "docker.minecraftJava", |
||||
"protocol" => "tcp", |
||||
"ports" => "25565" |
||||
]); |
||||
|
||||
Service::create([ |
||||
"uuid" => Str::uuid(), |
||||
"name" => "Minecraft Bedrock edition", |
||||
"image" => "/img/minecraft-bedrock.webp", |
||||
"config" => "docker.minecraftBedrock", |
||||
"protocol" => "udp", |
||||
"ports" => "19132|19133" |
||||
]); |
||||
|
||||
Service::create([ |
||||
"uuid" => Str::uuid(), |
||||
"name" => "Ark Survial Evolved", |
||||
"image" => "/img/ark.jpeg", |
||||
"config" => "docker.arkserver", |
||||
"protocol" => "udp", |
||||
"ports" => "27015|7777" |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* Reverse the migrations. |
||||
*/ |
||||
public function down(): void |
||||
{ |
||||
Schema::dropIfExists('services'); |
||||
} |
||||
}; |
@ -0,0 +1,55 @@ |
||||
<?php |
||||
|
||||
use App\Models\Status; |
||||
use Illuminate\Database\Migrations\Migration; |
||||
use Illuminate\Database\Schema\Blueprint; |
||||
use Illuminate\Support\Facades\Schema; |
||||
|
||||
return new class extends Migration |
||||
{ |
||||
/** |
||||
* Run the migrations. |
||||
*/ |
||||
public function up(): void |
||||
{ |
||||
Schema::create('statuses', function (Blueprint $table) { |
||||
$table->id(); |
||||
$table->string("title"); |
||||
$table->string("message"); |
||||
$table->timestamps(); |
||||
}); |
||||
|
||||
Status::create([ |
||||
"title" => "Running", |
||||
"message" => "", |
||||
]); |
||||
|
||||
Status::create([ |
||||
"title" => "Pending", |
||||
"message" => "", |
||||
]); |
||||
|
||||
Status::create([ |
||||
"title" => "Offline", |
||||
"message" => "", |
||||
]); |
||||
|
||||
Status::create([ |
||||
"title" => "Stopping", |
||||
"message" => "", |
||||
]); |
||||
|
||||
Status::create([ |
||||
"title" => "Failed", |
||||
"message" => "", |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* Reverse the migrations. |
||||
*/ |
||||
public function down(): void |
||||
{ |
||||
Schema::dropIfExists('server_statuses'); |
||||
} |
||||
}; |
@ -0,0 +1,54 @@ |
||||
<?php |
||||
|
||||
use App\Models\Spec; |
||||
use Illuminate\Database\Migrations\Migration; |
||||
use Illuminate\Database\Schema\Blueprint; |
||||
use Illuminate\Support\Facades\Schema; |
||||
use Illuminate\Support\Str; |
||||
|
||||
return new class extends Migration |
||||
{ |
||||
/** |
||||
* Run the migrations. |
||||
*/ |
||||
public function up(): void |
||||
{ |
||||
Schema::create('specs', function (Blueprint $table) { |
||||
$table->id(); |
||||
$table->uuid("uuid"); |
||||
$table->unsignedTinyInteger("cpus"); |
||||
$table->unsignedBigInteger("memory"); |
||||
$table->unsignedBigInteger("storage"); |
||||
$table->timestamps(); |
||||
}); |
||||
|
||||
Spec::create([ |
||||
"uuid" => Str::uuid(), |
||||
"cpus" => 1, |
||||
"memory" => 2000000000, |
||||
"storage" => 20000000000 |
||||
]); |
||||
|
||||
Spec::create([ |
||||
"uuid" => Str::uuid(), |
||||
"cpus" => 1, |
||||
"memory" => 3000000000, |
||||
"storage" => 50000000000 |
||||
]); |
||||
|
||||
Spec::create([ |
||||
"uuid" => Str::uuid(), |
||||
"cpus" => 2, |
||||
"memory" => 5000000000, |
||||
"storage" => 40000000000 |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* Reverse the migrations. |
||||
*/ |
||||
public function down(): void |
||||
{ |
||||
Schema::dropIfExists('specs'); |
||||
} |
||||
}; |
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
use Illuminate\Database\Migrations\Migration; |
||||
use Illuminate\Database\Schema\Blueprint; |
||||
use Illuminate\Support\Facades\Schema; |
||||
|
||||
return new class extends Migration |
||||
{ |
||||
/** |
||||
* Run the migrations. |
||||
*/ |
||||
public function up(): void |
||||
{ |
||||
Schema::create('servers', function (Blueprint $table) { |
||||
$table->id(); |
||||
$table->uuid("uuid"); |
||||
$table->string("container", 511)->nullable(); |
||||
$table->string("name"); |
||||
$table->boolean("public")->default(false); |
||||
$table->dateTime("start")->nullable(); |
||||
$table->dateTime("end")->nullable(); |
||||
$table->unsignedBigInteger("service_id"); |
||||
$table->unsignedBigInteger("user_id"); |
||||
$table->unsignedBigInteger("status_id"); |
||||
$table->timestamps(); |
||||
|
||||
$table->foreign("service_id")->references("id")->on("services"); |
||||
$table->foreign("user_id")->references("id")->on("users"); |
||||
$table->foreign("status_id")->references("id")->on("statuses"); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Reverse the migrations. |
||||
*/ |
||||
public function down(): void |
||||
{ |
||||
Schema::dropIfExists('servers'); |
||||
} |
||||
}; |
@ -0,0 +1,32 @@ |
||||
<?php |
||||
|
||||
use Illuminate\Database\Migrations\Migration; |
||||
use Illuminate\Database\Schema\Blueprint; |
||||
use Illuminate\Support\Facades\Schema; |
||||
|
||||
return new class extends Migration |
||||
{ |
||||
/** |
||||
* Run the migrations. |
||||
*/ |
||||
public function up(): void |
||||
{ |
||||
Schema::create('exposed_port_server', function (Blueprint $table) { |
||||
$table->id(); |
||||
$table->unsignedBigInteger("server_id"); |
||||
$table->unsignedBigInteger("exposed_port_id")->unique(); |
||||
$table->timestamps(); |
||||
|
||||
$table->foreign("server_id")->references("id")->on("servers"); |
||||
$table->foreign("exposed_port_id")->references("id")->on("exposed_ports"); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Reverse the migrations. |
||||
*/ |
||||
public function down(): void |
||||
{ |
||||
Schema::dropIfExists('exposed_port_server'); |
||||
} |
||||
}; |
After Width: | Height: | Size: 463 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 713 B |
After Width: | Height: | Size: 859 B |
After Width: | Height: | Size: 924 B |
After Width: | Height: | Size: 995 B |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 974 B |
After Width: | Height: | Size: 490 B |
After Width: | Height: | Size: 397 B |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 846 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 376 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 399 B |
After Width: | Height: | Size: 456 B |
After Width: | Height: | Size: 137 KiB |
After Width: | Height: | Size: 899 KiB |
After Width: | Height: | Size: 714 KiB |
After Width: | Height: | Size: 576 KiB |
After Width: | Height: | Size: 151 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 67 KiB |
@ -1,30 +0,0 @@ |
||||
<script setup> |
||||
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue'; |
||||
import { Head } from '@inertiajs/vue3'; |
||||
</script> |
||||
|
||||
<template> |
||||
<Head title="Dashboard" /> |
||||
|
||||
<AuthenticatedLayout> |
||||
<template #header> |
||||
<h2 |
||||
class="text-xl font-semibold leading-tight text-textColor-800" |
||||
> |
||||
Dashboard |
||||
</h2> |
||||
</template> |
||||
|
||||
<div class="py-12"> |
||||
<div class="mx-auto max-w-7xl sm:px-6 lg:px-8"> |
||||
<div |
||||
class="overflow-hidden bg-white shadow-sm sm:rounded-lg" |
||||
> |
||||
<div class="p-6 text-textColor-900"> |
||||
You're logged in! |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</AuthenticatedLayout> |
||||
</template> |
@ -0,0 +1,29 @@ |
||||
<script setup> |
||||
import Layout from '@/Layouts/Layout.vue'; |
||||
import { Head, useForm } from '@inertiajs/vue3'; |
||||
import ServerElement from './Paritals/ServerElement.vue'; |
||||
|
||||
const props = defineProps({ |
||||
servers: { |
||||
type: Array, |
||||
default: [] |
||||
} |
||||
}); |
||||
|
||||
</script> |
||||
|
||||
<template> |
||||
<Head title="Spawn" /> |
||||
<Layout> |
||||
<!-- En-tête --> |
||||
<header class="max-w-6xl mx-auto my-10 text-center"> |
||||
<h1 class="text-3xl font-bold animate-fade-in">Liste des Serveurs</h1> |
||||
<p class="text-gray-400 mt-2">Gérez vos serveurs Minecraft, Ark et plus encore (Minecraft).</p> |
||||
</header> |
||||
|
||||
<!-- Liste des serveurs --> |
||||
<section class="max-w-6xl mx-auto grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 my-10"> |
||||
<ServerElement v-for="server in props.servers" :server="server"/> |
||||
</section> |
||||
</Layout> |
||||
</template> |
@ -0,0 +1,73 @@ |
||||
<script setup> |
||||
import { Link, useForm } from '@inertiajs/vue3'; |
||||
|
||||
|
||||
const props = defineProps({ |
||||
server: { |
||||
type: Object, |
||||
required: true |
||||
}, |
||||
editable: { |
||||
type: Boolean, |
||||
default: true |
||||
} |
||||
}); |
||||
if(props.editable) { |
||||
|
||||
} |
||||
const form = useForm(); |
||||
|
||||
const start = (uuid) => { |
||||
form.post(route("servers.start", uuid), { |
||||
onSuccess: () => { |
||||
vm.$forceUpdate() |
||||
} |
||||
}); |
||||
} |
||||
|
||||
const stop = (uuid) => { |
||||
form.post(route("servers.stop", uuid)); |
||||
} |
||||
|
||||
</script> |
||||
|
||||
<template> |
||||
<!-- Carte Serveur --> |
||||
<div class="bg-gray-800 rounded-lg shadow-lg p-6 slide-up relative"> |
||||
<div class="flex justify-between items-center"> |
||||
<h2 class="text-xl font-semibold flex items-center gap-2"> |
||||
<img src="/icons/server-icon.svg" alt="Serveur" class="w-6 h-6 rotate-on-hover invert"> |
||||
Serveur {{ props.server.name }} |
||||
</h2> |
||||
<span v-if="props.server.status.id < 3" class="px-3 py-1 text-sm font-bold rounded-lg bg-green-500 text-white">{{ props.server.status.title }}</span> |
||||
<span v-else class="px-3 py-1 text-sm font-bold rounded-lg bg-red-500 text-white">{{ props.server.status.title }}</span> |
||||
</div> |
||||
|
||||
<div class="mt-4 space-y-2 text-sm"> |
||||
<p><span class="font-medium">Type </span> {{ props.server.service.name }}</p> |
||||
<p v-if="props.editable" ><span class="font-medium">Dernier démarrage </span> {{ props.server.start ? props.server.start : "aucun" }}</p> |
||||
<p class="flex gap-2"> |
||||
<span class="font-medium">Lien :</span> |
||||
<p class="text-green-400 hover:underline"> |
||||
{{ props.server.ports.length && props.server.status.id < 3 ? "hosting.anulax.ch:" + props.server.ports[0] : "Indisponible" }} |
||||
</p> |
||||
</p> |
||||
</div> |
||||
|
||||
<!-- Actions --> |
||||
<div v-if="props.editable" class="mt-4 flex gap-2 w-full justify-end"> |
||||
<div v-if="props.server.status.id >= 3" @click="start(props.server.uuid)" class="bg-green-500 hover:bg-green-600 text-white f |
||||
glow-on-hover font-bold p-2 rounded-lg shadow-lg flex items-center gap-2"> |
||||
<img src="/icons/start-icon.svg" alt="Start" class="w-5 h-5 invert"> |
||||
</div> |
||||
<div v-else @click="stop(props.server.uuid)" class="bg-red-500 hover:bg-red-600 text-white |
||||
glow-on-hover font-bold p-2 rounded-lg shadow-lg flex items-center gap-2"> |
||||
<img src="/icons/stop-icon.svg" alt="Stop" class="w-5 h-5 invert"> |
||||
</div> |
||||
<Link :href="route('servers.show', props.server.uuid)" class="bg-blue-500 hover:bg-blue-600 text-white |
||||
glow-on-hover font-bold p-2 rounded-lg shadow-lg flex items-center gap-2"> |
||||
<img src="/icons/details-icon.svg" alt="Détails" class="w-5 h-5 invert"> |
||||
</Link> |
||||
</div> |
||||
</div> |
||||
</template> |
@ -0,0 +1,195 @@ |
||||
<script setup> |
||||
import InputError from '@/Components/InputError.vue'; |
||||
import TextInput from '@/Components/TextInput.vue'; |
||||
import Layout from '@/Layouts/Layout.vue'; |
||||
import { Head, useForm } from '@inertiajs/vue3'; |
||||
import { ref } from 'vue'; |
||||
|
||||
const props = defineProps({ |
||||
server: { |
||||
type: Object, |
||||
required: true |
||||
} |
||||
}); |
||||
|
||||
const isFocus = ref(false); |
||||
const form = useForm(); |
||||
const editForm = useForm({ name: props.server.name }); |
||||
|
||||
const start = (uuid) => { |
||||
form.post(route("servers.start", uuid)); |
||||
} |
||||
|
||||
const stop = (uuid) => { |
||||
form.post(route("servers.stop", uuid)); |
||||
} |
||||
|
||||
const del = (uuid) => { |
||||
if (prompt("Entrer le nom du server en confirmation.") == props.server.name) form.delete(route("servers.destroy", uuid)); |
||||
} |
||||
|
||||
const pub = (uuid) => { |
||||
if (props.server.public) form.post(route("servers.public", uuid)); |
||||
else if (prompt("Entrer le nom du server en confirmation.") == props.server.name) form.post(route("servers.public", uuid)); |
||||
} |
||||
|
||||
const edit = () => { |
||||
console.log(editForm.name); |
||||
editForm.post(route("servers.update", props.server.uuid)); |
||||
} |
||||
|
||||
const copie = () => { |
||||
navigator.clipboard.writeText('hosting.anulax.ch:' + props.server.ports[0]).then(() => alert("lien de connection copié!")) |
||||
} |
||||
|
||||
</script> |
||||
|
||||
<template> |
||||
|
||||
<Head title="Spawn" /> |
||||
<Layout> |
||||
<!-- En-tête --> |
||||
<header class="my-10 text-center"> |
||||
<h1 class="text-4xl font-bold flex items-center justify-center gap-2 fade-in"> |
||||
Dashboard du Serveur |
||||
</h1> |
||||
<p class="text-gray-300 mt-4 fade-in"> |
||||
Gérez et visualisez les informations clés de votre serveur en un coup d'œil. |
||||
</p> |
||||
</header> |
||||
|
||||
<!-- Cartes d'information --> |
||||
<main class="max-w-6xl mx-auto grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3 xl:gap-6 mb-6 slide-up"> |
||||
<!-- Carte : Informations Générales --> |
||||
<div class="bg-gray-800 rounded-lg shadow-lg p-6"> |
||||
<h2 class="text-2xl font-semibold border-b border-gray-700 pb-2 mb-4 flex items-center gap-2"> |
||||
<img src="/icons/server-icon.svg" alt="Général" class="w-6 h-6 rotate-on-hover invert"> |
||||
Informations Générales |
||||
</h2> |
||||
<div class="space-y-3 text-sm"> |
||||
<div class="flex justify-between"> |
||||
<span class="font-medium">Nom</span> |
||||
<span class="text-green-400 font-bold">{{ props.server.name }}</span> |
||||
</div> |
||||
<div class="flex justify-between"> |
||||
<span class="font-medium">Type de jeu</span> |
||||
<span>{{ props.server.service.name }}</span> |
||||
</div> |
||||
<div class="flex justify-between"> |
||||
<span class="font-medium">Public</span> |
||||
<span>{{ props.server.public ? "Oui" : "Non" }}</span> |
||||
</div> |
||||
<div class="flex flex-col gap-2"> |
||||
<div class="flex justify-between items-center mb-1"> |
||||
<div class="flex items-center gap-2"> |
||||
<span class="font-medium lg:hidden">Lien de connection</span> |
||||
<span class="font-medium xl:hidden lg:block hidden">Lien du server</span> |
||||
</div> |
||||
<div class="flex items-center gap-2"> |
||||
<p class="text-green-400 hover:underline"> |
||||
{{ props.server.ports.length && props.server.status.id < 3 ? "hosting.anulax.ch:" + |
||||
props.server.ports[0] : "Indisponible" }} </p> |
||||
<button v-show="props.server.ports.length && props.server.status.id < 3" |
||||
@click="copie" |
||||
class="bg-blue-500 hover:bg-blue-600 text-white font-bold p-1 rounded-lg shadow-lg glow-on-hover flex items-center"> |
||||
<img src="/icons/copy-icon.svg" alt="Copier" class="w-5 h-5 invert"> |
||||
</button> |
||||
</div> |
||||
</div> |
||||
|
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- Carte : Activité --> |
||||
<div class="bg-gray-800 rounded-lg shadow-lg p-6"> |
||||
<h2 class="text-2xl font-semibold border-b border-gray-700 pb-2 mb-4 flex items-center gap-2"> |
||||
<img src="/icons/stats-icon.svg" alt="Activité" class="w-6 h-6 rotate-on-hover invert">Activité |
||||
</h2> |
||||
<div class="space-y-3 text-sm mb-4"> |
||||
<div class="flex justify-between"> |
||||
<span class="font-medium">Statut</span> |
||||
<span class="text-green-400 font-bold">{{ props.server.status.title }}</span> |
||||
</div> |
||||
<div class="flex justify-between"> |
||||
<span class="font-medium">Dernier lancement</span> |
||||
<span class="text-green-400 font-bold">{{ props.server.start ? props.server.start : "Aucun" |
||||
}}</span> |
||||
</div> |
||||
<div class="flex justify-between"> |
||||
<span class="font-medium">Dernier arrêt </span> |
||||
<span class="text-red-400 font-bold">{{ props.server.end ? props.server.end : "Aucun" }}</span> |
||||
</div> |
||||
</div> |
||||
<div class="flex gap-3"> |
||||
<div @click="start(props.server.uuid)" v-if="props.server.status.id >= 3" |
||||
class="bg-green-500 hover:bg-green-600 text-white font-bold p-2 rounded-lg shadow-lg glow-on-hover flex items-center gap-2"> |
||||
<img src="/icons/start-icon.svg" alt="Start" class="w-5 h-5 invert"> |
||||
</div> |
||||
<div @click="stop(props.server.uuid)" v-else |
||||
class="bg-red-500 hover:bg-red-600 text-white font-bold p-2 rounded-lg shadow-lg glow-on-hover flex items-center gap-2"> |
||||
<img src="/icons/stop-icon.svg" alt="Stop" class="w-5 h-5 invert"> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- Carte : Hardware --> |
||||
<div class="bg-gray-800 rounded-lg shadow-lg p-6 lg:col-span-1 md:col-span-2 col-span-1"> |
||||
<h2 class="text-2xl font-semibold border-b border-gray-700 pb-2 mb-4 flex items-center gap-2"> |
||||
<img src="/icons/hardware-icon.svg" alt="Hardware" class="w-6 h-6 rotate-on-hover invert"> |
||||
Hardware(fake) |
||||
</h2> |
||||
<div class="space-y-3 text-sm"> |
||||
<div class="flex justify-between"> |
||||
<span class="font-medium">CPUs</span> |
||||
<span>1</span> |
||||
</div> |
||||
<div class="flex justify-between"> |
||||
<span class="font-medium">Memory</span> |
||||
<span>4GB</span> |
||||
</div> |
||||
<div class="flex justify-between"> |
||||
<span class="font-medium">Stockage</span> |
||||
<span>10GB</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</main> |
||||
<!-- Section Actions en haut --> |
||||
<section class="max-w-6xl mx-auto mb-10 fade-in"> |
||||
<div class="flex justify-between items-center bg-gray-800 p-4 rounded-lg shadow-lg"> |
||||
<div class="flex gap-3"> |
||||
<button |
||||
class="bg-blue-500 hover:bg-blue-600 text-white font-bold p-2 rounded-lg shadow-lg glow-on-hover flex items-center"> |
||||
<img src="/icons/share-icon.svg" alt="Partager" class="w-5 h-5 invert"> |
||||
</button> |
||||
</div> |
||||
<!-- Actions de gestion --> |
||||
<div class="flex gap-3 items-center"> |
||||
<form v-show="isFocus" @submit.prevent="edit"> |
||||
<TextInput v-model="editForm.name" type="text" |
||||
class="w-full px-3 py-1 rounded bg-gray-700 text-white" /> |
||||
<button type="submit"></button> |
||||
<InputError :message="form.errors.name" class="text-left mt-1"></InputError> |
||||
</form> |
||||
<button @click="isFocus = !isFocus" |
||||
class="bg-blue-500 hover:bg-blue-600 text-white font-bold p-2 rounded-lg shadow-lg glow-on-hover flex items-center gap-2"> |
||||
<img src="/icons/edit-icon.svg" alt="Edit" class="w-5 h-5 invert"> |
||||
</button> |
||||
<button v-if="props.server.public" @click="pub(props.server.uuid)" |
||||
class="bg-blue-500 hover:bg-blue-600 text-white font-bold p-2 rounded-lg shadow-lg glow-on-hover flex items-center"> |
||||
<img src="/icons/lock.svg" alt="Rendre Privé" class="w-5 h-5 invert"> |
||||
</button> |
||||
<button v-else @click="pub(props.server.uuid)" |
||||
class="bg-red-500 hover:bg-red-600 text-white font-bold p-2 rounded-lg shadow-lg glow-on-hover flex items-center"> |
||||
<img src="/icons/public-icon.svg" alt="Rendre public" class="w-5 h-5 invert"> |
||||
</button> |
||||
<button @click="del(props.server.uuid)" |
||||
class="bg-red-500 hover:bg-red-600 text-white font-bold p-2 rounded-lg shadow-lg glow-on-hover flex items-center gap-2"> |
||||
<img src="/icons/delete-icon.svg" alt="Delete" class="w-5 h-5 invert"> |
||||
</button> |
||||
</div> |
||||
</div> |
||||
</section> |
||||
</Layout> |
||||
</template> |
@ -1,8 +1,38 @@ |
||||
<?php |
||||
|
||||
use App\Docker\Container; |
||||
use App\Models\User; |
||||
use Carbon\Carbon; |
||||
use Illuminate\Foundation\Inspiring; |
||||
use Illuminate\Support\Facades\Artisan; |
||||
use Illuminate\Support\Facades\Log; |
||||
|
||||
Artisan::command('inspire', function () { |
||||
$this->comment(Inspiring::quote()); |
||||
})->purpose('Display an inspiring quote'); |
||||
|
||||
Artisan::command('create:user {name} {email} {password} {admin}', function ($name, $email, $password, $admin) { |
||||
User::create([ |
||||
"name" => $name, |
||||
"email" => $email, |
||||
"password" => bcrypt($password), |
||||
"admin" => $admin, |
||||
"email_verified_at" => Carbon::now() |
||||
]); |
||||
})->purpose('Display an inspiring quote'); |
||||
|
||||
Artisan::command('exec {id}', function ($id) { |
||||
try{ |
||||
$container = new Container($id); |
||||
$exec = $container->exec(["apt install -y iproute2"]); |
||||
Log::info(json_encode($exec->inspect(), JSON_PRETTY_PRINT)); |
||||
$exec->start(); |
||||
Log::info($container->logs()); |
||||
$exec = $container->exec(["echo hello"]); |
||||
$data = $exec->inspect(); |
||||
Log::info(json_encode($data, JSON_PRETTY_PRINT)); |
||||
$exec->start(); |
||||
|
||||
} catch (Exception $e) { Log::error(((object)$e)->getResponse()->getBody()); } |
||||
|
||||
})->purpose('Display an inspiring quote'); |
||||
|
@ -0,0 +1,2 @@ |
||||
* |
||||
!.gitignore |
@ -1 +0,0 @@ |
||||
a:3:{s:6:"_token";s:40:"nwGLpFjKisR3R1Mu3mdHCaXL39V8ByW0CVFN2n2E";s:9:"_previous";a:1:{s:3:"url";s:27:"http://localhost:8000/spawn";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}} |
@ -0,0 +1,11 @@ |
||||
mkdir -p icons && cd icons |
||||
|
||||
# Télécharger les icônes (vérifie que ces URL correspondent bien aux fichiers SVG) |
||||
wget -O server-icon.svg "https://www.svgrepo.com/download/452095/server.svg" |
||||
wget -O security-icon.svg "https://www.svgrepo.com/download/488474/security-shield.svg" |
||||
wget -O process-icon.svg "https://www.svgrepo.com/download/444524/process.svg" |
||||
wget -O create-icon.svg "https://www.svgrepo.com/download/513806/add.svg" |
||||
wget -O play-icon.svg "https://www.svgrepo.com/download/488502/play-button.svg" |
||||
wget -O auto-icon.svg "https://www.svgrepo.com/download/456246/automation.svg" |
||||
wget -O rocket-icon.svg "https://www.svgrepo.com/download/488478/rocket.svg" |
||||
wget -O arrow-icon.svg "https://www.svgrepo.com/download/502744/arrow-right.svg" |
@ -0,0 +1,27 @@ |
||||
{ |
||||
"Hostname": "mincraft-server", |
||||
"User": "root", |
||||
"Image": "minecraftbedrock:latest", |
||||
"OpenStdin": true, |
||||
"AttachStdout": false, |
||||
"AttachStderr": false, |
||||
"Tty": true, |
||||
"ExposedPorts": { |
||||
"19132/udp": {}, |
||||
"19133/udp": {} |
||||
}, |
||||
"HostConfig": { |
||||
"PortBindings": { |
||||
"19132/udp": [ |
||||
{ |
||||
"HostPort": 25004 |
||||
} |
||||
], |
||||
"19133/udp": [ |
||||
{ |
||||
"HostPort": 25005 |
||||
} |
||||
] |
||||
} |
||||
} |
||||
} |