fchaty/FIXES-FOR-CODEX.md
2026-07-27 23:41:27 +02:00

6.5 KiB

Fchaty — الإصلاحات المطلوبة

ثلاث مشاكل أساسية تحتاج إصلاح. لكل مشكلة: الملف المعني، السطر، وصف المشكلة، والحل المطلوب.


Fix 1: حذف الرسائل المحلية عند فك الاقتران (unpair)

المشكلة: عند unpair() الرسائل القديمة تبقى محفوظة بملف messages.json المحلي. عند إعادة الاقتران مع شخص جديد، المحادثة القديمة تظهر.

الملف: FchatyApp/Sources/FchatyApp/Session/AppSession.swift

السطر: 115-124 — دالة unpair()

الكود الحالي:

func unpair() {
    incomingMessagesTask?.cancel()
    incomingMessagesTask = nil
    KeychainStore.clearAll()
    let webSocket = webSocket
    Task {
        await webSocket.disconnect()
    }
    state = .unpaired
}

المطلوب:

  1. إضافة دالة deleteAll() في MessageStore تحذف ملف messages.json من الدسك.
  2. استدعاء deleteAll() ومسح messages array في unpair().

الملف الإضافي: FchatyApp/Sources/FchatyApp/Storage/MessageStore.swift

أضف هذه الدالة في MessageStore:

func deleteAll() throws {
    let url = try messagesURL()
    if fileManager.fileExists(atPath: url.path) {
        try fileManager.removeItem(at: url)
    }
}

وعدّل unpair() في AppSession.swift:

func unpair() {
    incomingMessagesTask?.cancel()
    incomingMessagesTask = nil
    messages = []
    Task {
        try? await messageStore.deleteAll()
    }
    KeychainStore.clearAll()
    let webSocket = webSocket
    Task {
        await webSocket.disconnect()
    }
    state = .unpaired
}

Fix 2: جعل WebSocket reconnect لانهائي

المشكلة: الـ reconnect يحاول 5 مرات فقط (2, 4, 8, 16, 32 ثانية) ثم يتوقف نهائياً بدون إبلاغ المستخدم. رفيقك يشوف loading لانهائي لأن التطبيق توقف عن المحاولة.

الملف: FchatyApp/Sources/FchatyApp/Networking/WSClient.swift

السطر: 243-273 — دالة reconnect()

الكود الحالي:

private func reconnect(using token: String, id: UUID) async {
    let delays: [UInt64] = [2, 4, 8, 16, 32]

    for delay in delays {
        do {
            try await Task.sleep(nanoseconds: delay * 1_000_000_000)
        } catch {
            return
        }

        guard reconnectID == id, !isDisconnecting else {
            return
        }

        do {
            try await establishConnection(token: token)
            if reconnectID == id {
                reconnectID = nil
                reconnectTask = nil
            }
            return
        } catch {
            continue
        }
    }

    if reconnectID == id {
        reconnectID = nil
        reconnectTask = nil
    }
}

المطلوب: تغيير الدالة لتحاول بشكل لانهائي مع exponential backoff بحد أقصى 60 ثانية:

private func reconnect(using token: String, id: UUID) async {
    var delay: UInt64 = 2

    while !Task.isCancelled {
        do {
            try await Task.sleep(nanoseconds: delay * 1_000_000_000)
        } catch {
            return
        }

        guard reconnectID == id, !isDisconnecting else {
            return
        }

        do {
            try await establishConnection(token: token)
            if reconnectID == id {
                reconnectID = nil
                reconnectTask = nil
            }
            return
        } catch {
            delay = min(delay * 2, 60)
            continue
        }
    }
}

Fix 3: تحميل fileRegistry من الدسك عند بدء السيرفر

المشكلة: fileRegistry هو Map في الذاكرة فقط. بعد إعادة تشغيل السيرفر (deploy جديد مثلاً)، كل الملفات المرفوعة تصبح 404 رغم إنها موجودة على الدسك.

الملف: relay-server/src/index.js

السطر: 42 — تعريف fileRegistry

المطلوب: إضافة دالة تقرأ الملفات الموجودة بمجلد /data/files/ وتعبّي الـ fileRegistry عند بدء السيرفر.

أضف هذه الدالة بعد سطر 42 (const fileRegistry = new Map();):

function loadFileRegistryFromDisk() {
  if (!fs.existsSync(UPLOADS_DIR)) return;

  for (const entry of fs.readdirSync(UPLOADS_DIR, { withFileTypes: true })) {
    if (!entry.isFile()) continue;

    const diskPath = path.join(UPLOADS_DIR, entry.name);
    try {
      const stats = fs.statSync(diskPath);
      fileRegistry.set(entry.name, {
        diskPath,
        originalName: entry.name, // الاسم الأصلي ضايع — نستخدم الـ UUID كفولباك
        size: stats.size,
      });
    } catch (_) {}
  }
}

loadFileRegistryFromDisk();
console.log(`[files] loaded ${fileRegistry.size} files from disk`);

ملاحظة مهمة: الاسم الأصلي للملف (originalName) لا يُحفظ على الدسك حالياً — multer يحفظ الملف باسم UUID فقط. هذا الإصلاح يسترجع الملفات لكن بدون أسمائها الأصلية. لحل كامل، يجب حفظ metadata الملف (اسمه الأصلي وحجمه) بملف .meta.json بجانب كل ملف عند الرفع. هذا تحسين إضافي وليس ضرورياً الآن.


ملخص سريع

# الملف المشكلة الأولوية
1 AppSession.swift + MessageStore.swift الرسائل القديمة تظهر بعد unpair عالية
2 WSClient.swift الاتصال يفشل نهائياً بعد 5 محاولات عالية
3 relay-server/src/index.js الملفات 404 بعد restart السيرفر عالية

الاختبارات

بعد تنفيذ الإصلاحات:

  1. swift test --package-path FchatyApp — لازم كل الاختبارات تنجح
  2. تأكد إنو unpair() يمسح الرسائل — عمل pairing، أرسل رسائل، عمل unpair، تأكد إنو المحادثة فاضية
  3. تأكد إنو الـ reconnect ما بيوقف — شغّل التطبيق، أوقف السيرفر، شغله بعد دقيقة، لازم يتصل تلقائياً
  4. تأكد إنو الملفات تتحمل — أرسل ملف، أعد تشغيل السيرفر، حاول حمّل الملف