2017-07-20 01:49:41 +00:00
< ? php
namespace Pterodactyl\Repositories\Eloquent ;
2018-01-28 23:14:14 +00:00
use Generator ;
2017-08-05 22:26:30 +00:00
use Pterodactyl\Models\Node ;
2018-01-05 04:49:50 +00:00
use Illuminate\Support\Collection ;
2017-08-27 19:55:25 +00:00
use Pterodactyl\Repositories\Concerns\Searchable ;
2018-01-05 04:49:50 +00:00
use Illuminate\Database\Eloquent\ModelNotFoundException ;
use Illuminate\Contracts\Pagination\LengthAwarePaginator ;
2017-07-20 01:49:41 +00:00
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface ;
2017-08-05 22:20:07 +00:00
use Pterodactyl\Exceptions\Repository\RecordNotFoundException ;
2017-07-20 01:49:41 +00:00
2017-08-19 03:19:06 +00:00
class NodeRepository extends EloquentRepository implements NodeRepositoryInterface
2017-07-20 01:49:41 +00:00
{
2017-08-19 03:19:06 +00:00
use Searchable ;
2017-07-20 01:49:41 +00:00
/**
2018-01-05 04:49:50 +00:00
* Return the model backing this repository .
*
* @ return string
2017-07-20 01:49:41 +00:00
*/
public function model ()
{
return Node :: class ;
}
2017-07-22 02:17:42 +00:00
2017-08-05 22:20:07 +00:00
/**
2018-01-05 04:49:50 +00:00
* Return the usage stats for a single node .
*
* @ param \Pterodactyl\Models\Node $node
* @ return array
2017-08-05 22:20:07 +00:00
*/
2018-01-05 04:49:50 +00:00
public function getUsageStats ( Node $node ) : array
2017-08-05 22:20:07 +00:00
{
2017-10-01 00:04:36 +00:00
$stats = $this -> getBuilder () -> select (
$this -> getBuilder () -> raw ( 'IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk' )
2018-01-05 04:49:50 +00:00
) -> join ( 'servers' , 'servers.node_id' , '=' , 'nodes.id' ) -> where ( 'node_id' , $node -> id ) -> first ();
2017-10-01 00:04:36 +00:00
2018-01-05 04:49:50 +00:00
return collect ([ 'disk' => $stats -> sum_disk , 'memory' => $stats -> sum_memory ]) -> mapWithKeys ( function ( $value , $key ) use ( $node ) {
$maxUsage = $node -> { $key };
if ( $node -> { $key . '_overallocate' } > 0 ) {
$maxUsage = $node -> { $key } * ( 1 + ( $node -> { $key . '_overallocate' } / 100 ));
}
2017-08-05 22:20:07 +00:00
2018-01-05 04:49:50 +00:00
$percent = ( $value / $maxUsage ) * 100 ;
2017-08-05 22:20:07 +00:00
2018-01-05 04:49:50 +00:00
return [
$key => [
'value' => number_format ( $value ),
'max' => number_format ( $maxUsage ),
'percent' => $percent ,
'css' => ( $percent <= self :: THRESHOLD_PERCENTAGE_LOW ) ? 'green' : (( $percent > self :: THRESHOLD_PERCENTAGE_MEDIUM ) ? 'red' : 'yellow' ),
],
];
}) -> toArray ();
2017-08-05 22:20:07 +00:00
}
2018-05-26 22:16:13 +00:00
/**
* Return the usage stats for a single node .
*
* @ param \Pterodactyl\Models\Node $node
* @ return array
*/
public function getUsageStatsRaw ( Node $node ) : array
{
$stats = $this -> getBuilder () -> select (
$this -> getBuilder () -> raw ( 'IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk' )
) -> join ( 'servers' , 'servers.node_id' , '=' , 'nodes.id' ) -> where ( 'node_id' , $node -> id ) -> first ();
return collect ([ 'disk' => $stats -> sum_disk , 'memory' => $stats -> sum_memory ]) -> mapWithKeys ( function ( $value , $key ) use ( $node ) {
$maxUsage = $node -> { $key };
if ( $node -> { $key . '_overallocate' } > 0 ) {
$maxUsage = $node -> { $key } * ( 1 + ( $node -> { $key . '_overallocate' } / 100 ));
}
return [
$key => [
'value' => $value ,
'max' => $maxUsage ,
],
];
}) -> toArray ();
}
2017-08-05 22:20:07 +00:00
/**
2018-01-05 04:49:50 +00:00
* Return all available nodes with a searchable interface .
*
* @ return \Illuminate\Contracts\Pagination\LengthAwarePaginator
2017-08-05 22:20:07 +00:00
*/
2018-01-05 04:49:50 +00:00
public function getNodeListingData () : LengthAwarePaginator
2017-08-05 22:20:07 +00:00
{
$instance = $this -> getBuilder () -> with ( 'location' ) -> withCount ( 'servers' );
2018-01-05 04:49:50 +00:00
if ( $this -> hasSearchTerm ()) {
2018-01-21 17:38:16 +00:00
$instance -> search ( $this -> getSearchTerm ());
2017-08-05 22:20:07 +00:00
}
2018-01-05 04:49:50 +00:00
return $instance -> paginate ( 25 , $this -> getColumns ());
2017-08-05 22:20:07 +00:00
}
/**
2018-01-05 04:49:50 +00:00
* Return a single node with location and server information .
*
* @ param \Pterodactyl\Models\Node $node
* @ param bool $refresh
* @ return \Pterodactyl\Models\Node
2017-08-05 22:20:07 +00:00
*/
2018-01-05 04:49:50 +00:00
public function loadLocationAndServerCount ( Node $node , bool $refresh = false ) : Node
2017-08-05 22:20:07 +00:00
{
2018-01-05 04:49:50 +00:00
if ( ! $node -> relationLoaded ( 'location' ) || $refresh ) {
$node -> load ( 'location' );
}
2017-08-05 22:20:07 +00:00
2018-01-05 04:49:50 +00:00
// This is quite ugly and can probably be improved down the road.
// And by probably, I mean it should.
if ( is_null ( $node -> servers_count ) || $refresh ) {
$node -> load ( 'servers' );
$node -> setRelation ( 'servers_count' , count ( $node -> getRelation ( 'servers' )));
unset ( $node -> servers );
2017-08-05 22:20:07 +00:00
}
2018-01-05 04:49:50 +00:00
return $node ;
2017-08-05 22:20:07 +00:00
}
/**
2018-01-05 04:49:50 +00:00
* Attach a paginated set of allocations to a node mode including
* any servers that are also attached to those allocations .
*
* @ param \Pterodactyl\Models\Node $node
* @ param bool $refresh
* @ return \Pterodactyl\Models\Node
2017-08-05 22:20:07 +00:00
*/
2018-01-05 04:49:50 +00:00
public function loadNodeAllocations ( Node $node , bool $refresh = false ) : Node
2017-08-05 22:20:07 +00:00
{
2018-01-05 04:49:50 +00:00
$node -> setRelation ( 'allocations' ,
2018-01-09 04:23:12 +00:00
$node -> allocations () -> orderByRaw ( 'server_id IS NOT NULL DESC, server_id IS NULL' ) -> orderByRaw ( 'INET_ATON(ip) ASC' ) -> orderBy ( 'port' , 'asc' ) -> with ( 'server:id,name' ) -> paginate ( 50 )
2017-08-05 22:20:07 +00:00
);
2018-01-05 04:49:50 +00:00
return $node ;
2017-08-05 22:20:07 +00:00
}
/**
2018-01-05 04:49:50 +00:00
* Return a node with all of the servers attached to that node .
*
* @ param int $id
* @ return \Pterodactyl\Models\Node
*
* @ throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
2017-08-05 22:20:07 +00:00
*/
2018-01-05 04:49:50 +00:00
public function getNodeServers ( int $id ) : Node
2017-08-05 22:20:07 +00:00
{
2018-01-05 04:49:50 +00:00
try {
return $this -> getBuilder () -> with ([
'servers.user' , 'servers.nest' , 'servers.egg' ,
]) -> findOrFail ( $id , $this -> getColumns ());
} catch ( ModelNotFoundException $exception ) {
throw new RecordNotFoundException ;
2017-08-05 22:20:07 +00:00
}
}
2017-07-22 02:17:42 +00:00
/**
2018-01-05 04:49:50 +00:00
* Return a collection of nodes for all locations to use in server creation UI .
*
* @ return \Illuminate\Support\Collection
2017-07-22 02:17:42 +00:00
*/
2018-01-05 04:49:50 +00:00
public function getNodesForServerCreation () : Collection
2017-07-22 02:17:42 +00:00
{
2018-01-05 04:49:50 +00:00
return $this -> getBuilder () -> with ( 'allocations' ) -> get () -> map ( function ( Node $item ) {
$filtered = $item -> getRelation ( 'allocations' ) -> where ( 'server_id' , null ) -> map ( function ( $map ) {
2017-07-22 02:17:42 +00:00
return collect ( $map ) -> only ([ 'id' , 'ip' , 'port' ]);
});
$item -> ports = $filtered -> map ( function ( $map ) {
return [
'id' => $map [ 'id' ],
'text' => sprintf ( '%s:%s' , $map [ 'ip' ], $map [ 'port' ]),
];
}) -> values ();
return [
'id' => $item -> id ,
'text' => $item -> name ,
'allocations' => $item -> ports ,
];
}) -> values ();
}
2018-01-28 23:14:14 +00:00
/**
* Return the IDs of all nodes that exist in the provided locations and have the space
* available to support the additional disk and memory provided .
*
* @ param array $locations
* @ param int $disk
* @ param int $memory
* @ return \Generator
*/
public function getNodesWithResourceUse ( array $locations , int $disk , int $memory ) : Generator
{
$instance = $this -> getBuilder ()
-> select ([ 'nodes.id' , 'nodes.memory' , 'nodes.disk' , 'nodes.memory_overallocate' , 'nodes.disk_overallocate' ])
-> selectRaw ( 'IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk' )
2018-02-17 21:52:41 +00:00
-> leftJoin ( 'servers' , 'servers.node_id' , '=' , 'nodes.id' )
2018-01-28 23:14:14 +00:00
-> where ( 'nodes.public' , 1 );
if ( ! empty ( $locations )) {
$instance -> whereIn ( 'nodes.location_id' , $locations );
}
2018-02-17 21:51:28 +00:00
return $instance -> groupBy ( 'nodes.id' ) -> cursor ();
2018-01-28 23:14:14 +00:00
}
2017-07-20 01:49:41 +00:00
}