Files
RomhackPlaza/app/Services/FileServersService.php

133 lines
4.0 KiB
PHP
Raw Normal View History

2026-05-20 18:25:15 +02:00
<?php
namespace App\Services;
use App\Models\EntryFile;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
class FileServersService {
public const FAVORITE_SERVER_TIME = 3600; // In seconds.
private const ZEUS_TOKEN_EXPIRATION = 600; // In seconds.
private string $apiKey;
private array $servers;
public function __construct()
{
$this->apiKey = config('fileservers.secret_key');
$this->servers = config('fileservers.servers');
}
public function generateZeusToken( int $user_id, string $to, string $action ){
$info = [
'user_id' => $user_id,
'to' => $to,
'action' => $action,
'generated_at' => time(),
'expires_at' => time() + self::ZEUS_TOKEN_EXPIRATION,
'romhackplaza' => bin2hex(random_bytes(16)),
];
$json = json_encode( $info );
$sig = hash_hmac( 'sha256', $json, $this->apiKey );
$end = base64_encode( $json ) . "|" . $sig;
return $end;
}
public function getRandomServerKey(): string
{
$keys = array_keys($this->servers);
return $keys[array_rand($keys)];
}
public function getEntryFileServerKey( EntryFile $file ): string
{
$serverKey = null;
if( $file->favorite_server !== null && $file->favorite_at !== null ) {
if( time() < $file->favorite_at + static::FAVORITE_SERVER_TIME ) {
$serverKey = $file->favorite_server;
}
}
if( $serverKey === null || !isset( $this->servers[$serverKey] ) ) {
$serverKey = $this->getRandomServerKey();
}
return $serverKey;
}
/**
* Download URL requires 'filepath' and 'filename'.
*
* @param EntryFile $file
* @return string
*/
public function getDownloadFileUrl( EntryFile $file ): string
{
$serverKey = $this->getEntryFileServerKey( $file );
$url = $this->servers[$serverKey]['download'] ?? "#";
if( $url === "#" )
return $url;
return $url . "&" . http_build_query( [ 'filename' => $file->filename, 'filepath' => $file->filepath ] );
}
/**
* @throws ConnectionException
*/
public function uploadChunk(
UploadedFile $chunk,
string $fileUUID,
int $currentChunk,
int $totalChunks,
string $filename,
string $type
){
// Define or get favorite server.
if( $currentChunk === 0 ){
$serverKey = $this->getRandomServerKey();
Cache::put("favorite_server_{$fileUUID}", $serverKey, now()->addHours(2) );
} else {
$serverKey = Cache::get( "favorite_server_{$fileUUID}" );
abort_if( !$serverKey, 422, "File upload expired, please retry." );
}
$server = $this->servers[$serverKey];
$filepath = $type . '/' . $fileUUID;
$response = Http::withHeaders([])
->attach( 'file', file_get_contents( $chunk->getRealPath() ), $fileUUID )
->post( $server['upload_chunk'], [
'filepath' => $filepath,
'filename' => $filename,
'current_chunk' => $currentChunk,
'total_chunks' => $totalChunks,
// TODO : Must replace User ID
2026-06-02 20:54:10 +02:00
'zeus' => $this->generateZeusToken( \Auth::user()->user_id, $server['base_url'], "Uploadchunk" ),
2026-05-20 18:25:15 +02:00
]);
if (!$response->successful()) {
throw new \RuntimeException( $response->body() );
}
$data = $response->json();
if( isset( $data['file'] ) && $data['file'] !== false ){
Cache::forget( "favorite_server_{$fileUUID}" );
}
$data['favorite_server'] = $serverKey;
$data['file_uuid'] = $fileUUID;
$data['file_path'] = $filepath;
return $data;
}
}