Node.js İle Socket.io Kullanarak Paylaşımlı Canlı Dosya Yönetim Paneli Nasıl Yapılır?

Node.js İle Socket.io Kullanarak Paylaşımlı Canlı Dosya Yönetim Paneli Nasıl Yapılır?
Node.js İle Socket.io Kullanarak Paylaşımlı Canlı Dosya Yönetim Paneli Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Projenize başlamadan önce sisteminizde Node.js (LTS sürümü 20.x veya üzeri önerilir) kurulu olmalıdır. Ayrıca paket yönetimi için npm veya pnpm kullanabilirsiniz. Çalışma ortamınızı hazırlamak için aşağıdaki adımları takip edin:

  • Node.js ve npm kurulumunu kontrol edin: node -v ve npm -v komutlarını çalıştırın.
  • Proje klasörünü oluşturun ve içine girin: mkdir dosya-paneli && cd dosya-paneli
  • Gerekli paketleri kurun: npm init -y komutuyla package.json oluşturun.
  • Bağımlılıkları yükleyin: npm install express socket.io chokidar

Burada chokidar kütüphanesini kullanmamızın sebebi, Node.js'in yerel fs.watch metoduna göre çok daha kararlı ve platformlar arası uyumlu bir dosya izleme deneyimi sunmasıdır.

Sunucu Tarafı Kurulumu ve Socket.io Yapılandırması

Node.js sunucusu, hem HTTP isteklerini karşılamalı hem de WebSocket bağlantılarını yönetmelidir. Socket.io, bağlantı koptuğunda otomatik yeniden bağlanma ve düşük gecikmeli iletişim sağlar. İlk olarak temel sunucu yapısını kuruyoruz.

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');

const app = express();
const server = http.createServer(app);
const io = new Server(server);

io.on('connection', (socket) => {
    console.log('Bir kullanıcı bağlandı: ' + socket.id);
    
    socket.on('disconnect', () => {
        console.log('Kullanıcı ayrıldı');
    });
});

server.listen(3000, () => {
    console.log('Sunucu http://localhost:3000 adresinde çalışıyor.');
});

Bu kod bloğu, temel bir HTTP sunucusu oluşturur ve üzerine Socket.io katmanını ekler. io.on('connection') bloğu, her yeni istemci bağlantısında tetiklenir ve bağlantı yönetimini sağlar.

Dosya Sistemi İzleme ve Canlı Güncellemeler

Dosya yönetim panelinin "canlı" olması için, sunucudaki bir klasörde gerçekleşen değişiklikleri (dosya ekleme, silme, isim değiştirme) anında istemcilere bildirmemiz gerekir. Bunun için chokidar kütüphanesini kullanacağız.

const chokidar = require('chokidar');
const path = require('path');

const watcher = chokidar.watch(path.join(__dirname, 'files'), {
    persistent: true
});

watcher.on('all', (event, filePath) => {
    const fileName = path.basename(filePath);
    io.emit('file-update', { event, fileName });
});

Bu kod, files klasörünü sürekli izler. Bir dosya eklendiğinde veya silindiğinde file-update olayı tüm bağlı istemcilere yayınlanır. io.emit metodu, sunucuya bağlı olan tüm kullanıcılara mesaj gönderilmesini sağlar.

İstemci Tarafı: Socket.io Entegrasyonu

İstemci tarafında, sunucudan gelen canlı güncellemeleri dinlemeli ve DOM (Document Object Model) üzerinde gerekli güncellemeleri yapmalıyız. Basit bir HTML yapısı ile bu verileri listeleyelim.



    const socket = io();
    const fileList = document.getElementById('file-list');

    socket.on('file-update', (data) => {
        console.log('Güncelleme geldi:', data);
        // Burada gelen veriye göre DOM güncellenir
        const li = document.createElement('li');
        li.textContent = `${data.event}: ${data.fileName}`;
        fileList.appendChild(li);
    });

Bu kod, sunucudan gelen file-update olayını dinler. Olay geldiğinde, sayfadaki liste öğesine yeni bir satır ekleyerek kullanıcının sayfayı yenilemesine gerek kalmadan değişikliği görmesini sağlar.

Dosya İşlemleri ve Güvenlik Önlemleri

Kullanıcıların panel üzerinden dosya oluşturmasına veya silmesine izin verirken, dizin geçişi (directory traversal) gibi saldırılara karşı dikkatli olmalıyız. Kullanıcıdan gelen dosya isimlerini doğrudan fs modülüne geçirmek güvenlik açığı yaratır.

const fs = require('fs');

socket.on('delete-file', (fileName) => {
    // Güvenlik: Sadece dosya ismini al, yolu kısıtla
    const safePath = path.join(__dirname, 'files', path.basename(fileName));
    
    if (fs.existsSync(safePath)) {
        fs.unlinkSync(safePath);
    }
});

Yukarıdaki örnekte path.basename() kullanımı, kullanıcının ../../etc/passwd gibi yollarla sistem dosyalarına erişmesini engellemek için kritik bir güvenlik önlemidir.

Kritik Güvenlik Uyarısı: Üretim ortamında (production) dosya sistemine doğrudan erişim sağlayan API'ler oluştururken mutlaka kullanıcı yetkilendirmesi (JWT veya Session tabanlı) kullanın. Asla kullanıcıdan gelen veriyi doğrudan sistem komutu olarak çalıştırmayın.

Performans ve Yöntem Karşılaştırması

Canlı dosya yönetimi için kullanılan farklı yaklaşımların karşılaştırması aşağıdadır:

Yöntem Avantaj Dezavantaj
Socket.io Düşük gecikme, çift yönlü iletişim Sunucu kaynak tüketimi yüksektir
Polling (setInterval) Basit uygulama Yüksek ağ trafiği, gecikmeli veri
Server-Sent Events Hafif, tek yönlü Sadece sunucudan istemciye veri

Sıkça Sorulan Sorular

Socket.io bağlantısı neden sürekli kopuyor?

Bu durum genellikle ağ yapılandırması veya sunucu tarafındaki "heartbeat" (kalp atışı) zaman aşımı ayarlarıyla ilgilidir. İstemci ve sunucu arasındaki bağlantının kararlılığı için proxy (Nginx vb.) kullanıyorsanız, WebSocket desteğinin açık olduğundan emin olun.

Birden fazla sunucu (cluster) kullanırsam ne olur?

Socket.io, varsayılan olarak tek bir sunucu örneğinde çalışır. Eğer uygulamanızı ölçeklendirip birden fazla sunucuya yayarsanız, @socket.io/redis-adapter kullanarak mesajların sunucular arasında iletilmesini sağlamalısınız.

Dosya yükleme (upload) işlemini nasıl eklerim?

Dosya yükleme için multer kütüphanesini kullanabilirsiniz. Dosya başarıyla yüklendikten sonra io.emit ile tüm istemcilere yeni dosyanın geldiğini bildirebilirsiniz.

Büyük dosyalar için WebSocket uygun mudur?

Hayır, WebSocket büyük binary verilerin iletimi için tasarlanmamıştır. Büyük dosyalar için geleneksel HTTP POST isteklerini kullanmalı, sadece dosya durumu güncellemelerini Socket.io üzerinden yapmalısınız.

XSS saldırılarına karşı nasıl önlem alırım?

İstemci tarafında DOM'a veri eklerken innerHTML yerine textContent kullanın. Bu, gelen dosya isimlerinin HTML olarak yorumlanmasını engelleyerek XSS saldırılarını önler.

Kod güvenliği sorumluluk reddi: Bu rehberdeki örnekler eğitim amaçlıdır. Uygulamanızı canlıya almadan önce tüm girdi doğrulamalarını (input validation) ve yetkilendirme mekanizmalarını (authentication/authorization) profesyonel standartlara göre yapılandırın.

Dağıtık Sistemlerde Ölçeklenebilirlik: Redis Adaptörü Kullanımı

Uygulamanız büyüdükçe ve kullanıcı sayısı arttıkça, tek bir Node.js sunucusu trafiği karşılamakta yetersiz kalabilir. Socket.io, çoklu sunucu (cluster) yapılarında mesajların tüm istemcilere ulaşmasını sağlamak için @socket.io/redis-adapter kütüphanesini kullanır. Bu sayede bir sunucuya bağlı olan istemci, diğer sunucudaki bir dosya değişikliğinden haberdar olabilir.

Redis adaptörünü kurmak için şu adımları izleyin:

npm install @socket.io/redis-adapter redis

Sunucu yapılandırmanızda Redis bağlantısını şu şekilde entegre edebilirsiniz:

const { createClient } = require("redis");
const { createAdapter } = require("@socket.io/redis-adapter");

const pubClient = createClient({ url: "redis://localhost:6379" });
const subClient = pubClient.duplicate();

Promise.all([pubClient.connect(), subClient.connect()]).then(() => {
  io.adapter(createAdapter(pubClient, subClient));
});

Canlı Dosya Yönetiminde Hata Ayıklama (Debugging) Stratejileri

Gerçek zamanlı uygulamalarda hata ayıklamak, geleneksel HTTP isteklerine göre daha karmaşıktır. Bağlantı kopmaları, paket kayıpları veya dosya izleme (watch) hatalarını tespit etmek için izlemeniz gereken yöntemler şunlardır:

  • Socket.io Debug Modu: Sunucu tarafında DEBUG=socket.io* node app.js komutunu kullanarak tüm paket trafiğini konsolda görebilirsiniz.
  • Dosya Sistemi Olaylarını İzleme: fs.watch veya chokidar kullanırken, işletim sistemi seviyesindeki kısıtlamaları (inotify limitleri) kontrol edin. Linux sistemlerde çok fazla dosya izlendiğinde ENOSPC hatası alabilirsiniz.
  • Bağlantı Durumunu İzleme: İstemci tarafında bağlantı kesintilerini yakalamak için connect_error olayını dinleyin.
// İstemci tarafı hata ayıklama örneği
socket.on("connect_error", (err) => {
  console.error("Bağlantı hatası:", err.message);
  // Kullanıcıya görsel bildirim gönderin
  showToast("Sunucu ile bağlantı kesildi, tekrar deneniyor...");
});

// Sunucu tarafı dosya izleme hata yönetimi
const watcher = fs.watch('./uploads', (eventType, filename) => {
  if (!filename) return;
  console.log(`Dosya değişikliği: ${eventType} - ${filename}`);
});

watcher.on('error', (error) => {
  console.error("Dosya izleyici hatası:", error);
});

Performans İpuçları ve Optimizasyon

Dosya yönetim panelinizin performansını artırmak için şu teknikleri uygulayın:

Teknik Açıklama
Debouncing Dosya değişikliklerini anlık göndermek yerine 300ms'lik bir gecikme ekleyerek sunucu yükünü azaltın.
Binary Veri Büyük dosya içeriklerini metin olarak değil, Buffer veya Blob formatında gönderin.
Namespace Kullanımı Tüm olayları ana kanalda tutmak yerine io.of('/files') gibi namespace'ler kullanarak trafiği segmente edin.

Özellikle chokidar gibi kütüphaneler kullanırken, awaitWriteFinish seçeneğini aktif ederek dosya yazma işlemi tamamen bitmeden tetiklenmesini engelleyebilir ve hatalı veri gönderiminin önüne geçebilirsiniz.

Sonuç

Node.js ve Socket.io kullanarak canlı bir dosya yönetim paneli oluşturmak, gerçek zamanlı web uygulamalarının temellerini anlamak için harika bir projedir. Bu rehberde dosya izleme, sunucu-istemci iletişimi ve temel güvenlik pratiklerini ele aldık. Bir sonraki adım olarak, bu yapıya kullanıcı yetkilendirme sistemi ekleyebilir veya dosya içeriklerini anlık olarak düzenleyebilecek bir "editör" modülü geliştirmeyi deneyebilirsiniz. Başarılar dileriz.

Bu yazıya tepkinizi paylaşın:
Mert Özdemir

Teknoloji ve dijital dünyadaki karmaşık süreçleri adım adım rehberlerle sadeleştiriyorum. Kullanıcıların dijital araçlardan en yüksek verimi alması için anlaşılır ve öğretici içerikler yazıyorum.

Yorumlar (0)

Yorum Yaz