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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|