SON KARAR — Kesinleşen Mimari
Dosyalar hem sunucuda hem Bunny'de tutulacak. Sunucu = Master, Bunny = CDN Kopyası
Sunucudaki dosyalar HER ZAMAN kalacak. Asla silinmeyecek. Bunny sadece kopya.
Mevcut AES-128 encryption sistemi değişmeyecek. Key endpoint aynen kalacak.
Kesinleşen Veri Akışı
Şifreleme Sistemi — Değişiklik YOK
Mevcut Sistem (Aynen Kalacak)
- AES-128 Encryption: Her şarkı için unique key
-
Key Storage:
enc.bindosyası local'de -
Key Endpoint:
/hls-key/muzibu/songs/{id} -
DB Field:
encryption_key(hex, 32 char)
Bunny Entegrasyonunda
- enc.bin Bunny'e YÜKLENMEZ — Güvenlik için local'de kalır
- Key endpoint değişmez — Sunucudan serve edilmeye devam
- HLS.js key request — Aynen çalışır
- CORS ayarları — Mevcut config yeterli
Bunny'e Yüklenecek vs Yüklenmeyecek
- • playlist.m3u8 (ana playlist)
- • master.m3u8 (ABR master)
- • segment-*.ts (tüm chunk'lar)
- • ultralow/, low/, mid/ klasörleri
- • mp3_128/*.mp3, mp3_64/*.mp3
- • enc.bin (encryption key)
- • enc.keyinfo (key metadata)
- • Orijinal şarkı dosyaları (opsiyonel)
HLS.js → Bunny'den .m3u8 çeker → Key URI görür → /hls-key/... endpoint'ine istek →
Sunucu DB'den key döner → HLS.js decrypt eder → Şarkı çalar
Maliyet Karşılaştırması
Hibrit modda dosyalar iki yerde tutulsa bile Cloudflare'a göre çok daha ucuz.
Mevcut Sistem Mimarisi
Dosya Yapısı
storage/tenant1001/app/public/muzibu/
├── songs/ # Orijinal dosyalar
│ ├── song_xxx.mp3
│ ├── mp3_128/ # Fallback 128k
│ │ └── {song_id}.mp3
│ └── mp3_64/ # Fallback 64k
│ └── {song_id}.mp3
└── hls/ # HLS Streaming
└── {song_id}/
├── playlist.m3u8 # Ana playlist
├── master.m3u8 # ABR master
├── segment-*.ts # 4sn chunk'lar
├── enc.bin # AES-128 key ⚠️
├── enc.keyinfo # Key metadata ⚠️
├── ultralow/ # 32 kbps
├── low/ # 64 kbps
└── mid/ # 128 kbps
enc.bin ve enc.keyinfo Bunny'e yüklenmez!
Dosya Boyutları (Per Song)
Değişecek Dosyalar (8 Dosya)
Modules/Muzibu/App/Jobs/ConvertToHLSJob.php
HLS dönüşümü sonrası dosyaları Bunny'e yükle (enc.bin HARİÇ).
// MEVCUT: Sadece local storage'a yazıyor
$hlsPath = $this->convertToHLS($song);
// YENİ: Local + Bunny'e yaz (enc.bin HARİÇ)
$hlsPath = $this->convertToHLS($song);
app(BunnyStorageService::class)->uploadDirectory(
$localHlsPath,
"hls/{$song->song_id}",
['exclude' => ['enc.bin', 'enc.keyinfo']] // Şifreleme dosyaları hariç!
);
app/Services/Muzibu/HLSService.php
MP3 fallback üretimi sonrası Bunny'e yükleme ekle.
// generateMp3() fonksiyonuna ekle:
public function generateMp3($song, $bitrate)
{
// Mevcut FFmpeg kodu...
// YENİ: Bunny'e de yükle
if (config('services.bunny.enabled')) {
app(BunnyStorageService::class)->upload(
$localPath,
"songs/mp3_{$bitrate}/{$song->song_id}.mp3"
);
}
}
Modules/Muzibu/App/Observers/SongObserver.php
forceDeleted() event'inde Bunny'den de silme ekle. Local dosyalar da silinir (mevcut davranış).
protected function cleanupAudioFiles(Song $song): void
{
// Mevcut local silme kodu (AYNEN KALIR)...
// YENİ: Bunny'den de sil
if (config('services.bunny.enabled')) {
$bunny = app(BunnyStorageService::class);
$bunny->deleteDirectory("hls/{$song->song_id}");
$bunny->delete("songs/mp3_128/{$song->song_id}.mp3");
$bunny->delete("songs/mp3_64/{$song->song_id}.mp3");
}
}
Modules/Muzibu/App/Http/Controllers/Api/SongStreamController.php
Stream endpoint'inde Bunny CDN URL'lerini döndür. Key endpoint DEĞİŞMEZ!
// stream() response'unda URL'leri değiştir:
// HLS URL → Bunny'den
'hls' => config('services.bunny.enabled')
? "https://muzibu-audio.b-cdn.net/hls/{$id}/master.m3u8"
: "/storage/tenant1001/public/muzibu/hls/{$id}/master.m3u8",
// Key URL → LOCAL'DEN (DEĞİŞMEZ!)
'key' => "/hls-key/muzibu/songs/{$id}", // ⚠️ Aynen kalır!
Modules/Muzibu/App/Http/Livewire/Admin/SongManageComponent.php
Değişiklik minimal — HLS job zaten Bunny'e yükleyecek. Opsiyonel: Orijinal dosya da yüklenebilir.
public function updatedAudioFile()
{
// Mevcut validasyon ve local kayıt (AYNEN KALIR)...
// OPSİYONEL: Orijinal dosyayı da Bunny'e yükle
if (config('services.bunny.upload_originals')) {
app(BunnyStorageService::class)->upload(
$this->audioFile->getRealPath(),
"songs/originals/{$filename}"
);
}
}
Modules/Muzibu/App/Models/Song.php
getHlsUrl() ve benzeri metodlarda Bunny URL desteği.
public function getHlsUrl(): ?string
{
if (!$this->hls_path) return null;
// YENİ: Bunny URL kontrolü
if (config('services.bunny.enabled')) {
return config('services.bunny.cdn_url') . '/' . $this->hls_path;
}
return $this->getStorageUrl($this->hls_path);
}
config/filesystems.php
Bunny Storage disk driver'ı ekle.
'disks' => [
// Mevcut diskler...
'bunny' => [
'driver' => 'bunny',
'api_key' => env('BUNNY_STORAGE_API_KEY'),
'storage_zone' => env('BUNNY_STORAGE_ZONE'),
'region' => env('BUNNY_STORAGE_REGION', 'de'),
],
],
config/services.php
Bunny servis ayarları.
'bunny' => [
'enabled' => env('BUNNY_STORAGE_ENABLED', false),
'mode' => 'hybrid', // Local her zaman master!
'api_key' => env('BUNNY_STORAGE_API_KEY'),
'storage_zone' => env('BUNNY_STORAGE_ZONE'),
'cdn_url' => env('BUNNY_CDN_URL'),
'upload_originals' => env('BUNNY_UPLOAD_ORIGINALS', false),
'fallback_to_local' => true, // Bunny fail → Local
],
Yeni Oluşturulacak Dosyalar (3 Dosya)
app/Services/Bunny/BunnyStorageService.php
Bunny Storage API wrapper servisi.
class BunnyStorageService
{
public function upload($localPath, $remotePath): bool;
public function uploadDirectory($localDir, $remoteDir, $exclude = []): bool;
public function delete($remotePath): bool;
public function deleteDirectory($remoteDir): bool;
public function exists($remotePath): bool;
public function getUrl($remotePath): string;
}
app/Console/Commands/MigrateToBunnyCommand.php
Mevcut dosyaları Bunny'e migrate eden artisan komutu. enc.bin dosyalarını ATLAR!
// Kullanım:
php artisan muzibu:migrate-to-bunny --all # Tüm şarkılar
php artisan muzibu:migrate-to-bunny --song=123 # Tek şarkı
php artisan muzibu:migrate-to-bunny --chunk=100 # 100'lük gruplar
php artisan muzibu:migrate-to-bunny --dry-run # Test modu
// ⚠️ enc.bin ve enc.keyinfo dosyaları otomatik olarak hariç tutulur!
app/Providers/BunnyServiceProvider.php
Bunny servislerini register eden provider.
class BunnyServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(BunnyStorageService::class);
}
public function boot()
{
// Custom filesystem driver
Storage::extend('bunny', function($app, $config) {
return new BunnyStorageAdapter($config);
});
}
}
Yeni ENV Değişkenleri
# Bunny Storage Zone
BUNNY_STORAGE_ENABLED=false
BUNNY_STORAGE_API_KEY=your-storage-api-key
BUNNY_STORAGE_ZONE=muzibu-audio
BUNNY_STORAGE_REGION=de
# Bunny CDN (Pull Zone)
BUNNY_CDN_URL=https://muzibu-audio.b-cdn.net
# Hibrit Mod Ayarları
BUNNY_MODE=hybrid # hybrid | bunny_only | local_only
BUNNY_UPLOAD_ORIGINALS=false # Orijinal MP3'leri de yükle?
BUNNY_FALLBACK_TO_LOCAL=true # Bunny fail → Local'e düş
Migration Stratejisi (Hibrit Mod)
Hazırlık (Gün 1)
- Bunny Storage Zone oluştur
- API key al
- BunnyStorageService kodunu yaz
- ENV değişkenlerini ekle
Dual-Write Aktif Et (Gün 1-2)
- ConvertToHLSJob'u güncelle (local + Bunny, enc.bin HARİÇ)
- HLSService MP3 fallback'ları güncelle
- SongObserver silme işlemlerini güncelle
- Test: Yeni şarkı yükle, Bunny'de görün
Batch Migration (Gün 2-3)
- MigrateToBunnyCommand yaz
- --dry-run ile test et
- Chunk chunk migrate et (100'lük gruplar)
- ~280 GB transfer (~4-8 saat)
- enc.bin dosyaları yüklenmez!
Cutover (Gün 3)
- SongStreamController URL'leri Bunny'e çevir
- BUNNY_STORAGE_ENABLED=true yap
- Cache temizle
- Test: Şarkı çal, Bunny'den geldiğini doğrula
- Key endpoint'in local'den çalıştığını doğrula
İzleme (Sonraki Hafta)
- Bunny Statistics'i izle
- Cache HIT oranını kontrol et
- Hata loglarını takip et
- Local dosyalar yerinde kalır (silinmez!)
Özet — Kesinleşen Plan
Sunucu
- ✅ Tüm dosyalar kalır
- ✅ Master kopya
- ✅ enc.bin burada
- ✅ Key endpoint burada
Bunny
- ✅ HLS dosyaları (enc.bin hariç)
- ✅ MP3 fallback'lar
- ✅ CDN öncelikli serve
- ❌ Şifreleme dosyaları yok
Şifreleme
- ✅ AES-128 aynen
- ✅ Key endpoint aynen
- ✅ enc.bin local'de
- ✅ Kod değişikliği yok
Sonuç: Hibrit mod ile hem güvenlik hem performans. Sunucudaki dosyalar her zaman yedek olarak kalır, Bunny sadece CDN katmanı. Şifreleme sistemi hiç değişmez, enc.bin asla Bunny'e yüklenmez.