Skip to content

Conversation

@loveFeng
Copy link

@loveFeng loveFeng commented Nov 14, 2025

codex 编码修复

Summary by CodeRabbit

  • New Features

    • Backup restoration now displays detailed counts of restored repositories, releases, and custom categories
    • Automatic file upload retry mechanism with exponential backoff on network failures
    • Server information retrieval for WebDAV connections
    • Configuration validation for WebDAV settings
  • Bug Fixes

    • Improved sensitive data preservation (API keys, passwords) during backup restoration
    • Enhanced timeout handling for large file uploads

@coderabbitai
Copy link

coderabbitai bot commented Nov 14, 2025

Walkthrough

The pull request enhances backup restoration logic and WebDAV service resilience. SettingsPanel now restores repositories, releases, and custom categories with smart configuration merging that preserves existing credentials when backup data is masked. WebDAVService gains compression utilities, exponential backoff retry logic, file size analysis, improved XML parsing with fallbacks, and configuration validation.

Changes

Cohort / File(s) Summary
Backup Restoration Logic
src/components/SettingsPanel.tsx
Expanded store action wiring (setRepositories, setReleases, addCustomCategory, deleteCustomCategory). Implemented granular data restoration for repositories, releases, and custom categories with try/catch blocks per entity. Added smart merge logic for AI and WebDAV configs that preserves existing credentials when backup data contains masks (***). Updated success message to display counts of restored entities.
WebDAV Service Enhancements
src/services/webdavService.ts
Added private utilities: compressData() for JSON re-serialization, analyzeFileSize() for size classification and optimization suggestions, retryUpload() with exponential backoff for selective retry on timeouts. Enhanced uploadFile and testConnection with file size analysis and dynamic timeout adaptation. Improved ensureDirectoryExists for progressive MKCOL-based directory creation. Refactored listFiles with DOMParser-based XML parsing and regex fallback. Added public validateConfig() for URL/credentials/path validation and getServerInfo() to expose server metadata. Enhanced error handling for HTTP statuses and abort scenarios.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant SettingsPanel as SettingsPanel
    participant Store as useAppStore
    participant WebDAV as WebDAVService

    User->>SettingsPanel: Trigger restore from backup
    
    rect rgb(220, 240, 255)
        note over SettingsPanel: Data Restoration Phase
        SettingsPanel->>Store: setRepositories(backupRepos)
        Store-->>SettingsPanel: ✓
        SettingsPanel->>Store: setReleases(backupReleases)
        Store-->>SettingsPanel: ✓
        SettingsPanel->>Store: deleteCustomCategory(each)
        SettingsPanel->>Store: addCustomCategory(each)
        Store-->>SettingsPanel: ✓
    end
    
    rect rgb(240, 220, 255)
        note over SettingsPanel: Smart Config Merge Phase
        SettingsPanel->>SettingsPanel: Merge AI configs<br/>(preserve existing keys if backup masked)
        SettingsPanel->>SettingsPanel: Merge WebDAV configs<br/>(preserve existing passwords if backup masked)
        SettingsPanel->>Store: updateAIConfigs(merged)
        SettingsPanel->>Store: updateWebDAVConfigs(merged)
        Store-->>SettingsPanel: ✓
    end
    
    SettingsPanel->>User: Display: "Restored N repos, M releases, K categories"
Loading
sequenceDiagram
    participant Client as Client Code
    participant WebDAV as WebDAVService
    participant Compress as compressData()
    participant Analyze as analyzeFileSize()
    participant Retry as retryUpload()
    participant Server as WebDAV Server

    Client->>WebDAV: uploadFile(config, filename, content)
    
    rect rgb(255, 240, 220)
        note over WebDAV: Pre-processing
        WebDAV->>Analyze: analyzeFileSize(content)
        Analyze-->>WebDAV: {sizeKB, isLarge, suggestions}
        WebDAV->>WebDAV: Log size insights & suggestions
        WebDAV->>Compress: compressData(content)
        Compress-->>WebDAV: compressed content
    end
    
    rect rgb(240, 255, 240)
        note over WebDAV: Upload with Retry
        WebDAV->>Retry: retryUpload(uploadOperation, maxRetries=3)
        loop Exponential Backoff on Timeout/Network Error
            Retry->>Server: PUT /path/file.json
            alt Success
                Server-->>Retry: 201/204
                Retry-->>WebDAV: ✓ result
            else Timeout/Network Error
                Server--xRetry: error
                Retry->>Retry: delay (exponential)
                Retry->>Server: Retry...
            end
        end
    end
    
    WebDAV-->>Client: Upload result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • SettingsPanel.tsx: Smart merge logic for AI and WebDAV configs requires careful verification that existing credentials are correctly preserved when backup data contains masks (***). Multiple try/catch blocks and entity-specific restoration paths need validation for correct error handling and state consistency.
  • webdavService.ts: New retry mechanism with exponential backoff needs review for correctness. compressData() and analyzeFileSize() utilities require validation. DOMParser-based XML parsing with regex fallback needs testing against various WebDAV server response formats. Dynamic timeout adaptation logic tied to file size warrants careful analysis.

Poem

🐰 Backups now restore with care and grace,
Credentials preserved in their rightful place,
WebDAV retries through timeouts and strife,
Compressed files zip through digital life—
A hoppy update brings resilience and might! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'fix:修复webdav备份恢复问题' claims to fix WebDAV backup/restore issues, but the changeset includes major enhancements to WebDAV service (compression, retry logic, server info), SettingsPanel restoration logic, and new public store methods—substantially more than a simple fix. Clarify the title to reflect the scope: either narrow it to actual bug fixes or expand it to 'feat/refactor: enhance WebDAV backup restoration with compression and retry logic' to accurately represent the comprehensive changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/services/webdavService.ts (1)

136-158: Bug: PROPFIND in testConnection has no timeout

You create an AbortController and 10s timeout, clear it after the HEAD request, then reuse the same controller for PROPFIND. This means PROPFIND can hang indefinitely with no timeout.

Consider keeping the timer active for the whole block or using a separate controller/timeout for PROPFIND, e.g.:

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);

try {
  const headResponse = await fetch(dirUrl, { method: 'HEAD', headers: { Authorization: this.getAuthHeader() }, signal: controller.signal });

  if (headResponse.ok) return true;

  const propfindResponse = await fetch(dirUrl, {
    method: 'PROPFIND',
    headers: { Authorization: this.getAuthHeader(), Depth: '0' },
    signal: controller.signal,
  });

  return propfindResponse.ok || propfindResponse.status === 207;
} catch (fetchError) {
  if ((fetchError as any).name === 'AbortError') {
    throw new Error('连接超时。请检查WebDAV服务器是否可访问。');
  }
  throw fetchError;
} finally {
  clearTimeout(timeoutId);
}

This preserves a bounded wait time for both requests.

🧹 Nitpick comments (7)
src/components/SettingsPanel.tsx (3)

305-334: Custom category restore is correct but could be more atomic

The "clear then re-add" logic fully replaces custom categories as the confirmation text promises, and the defensive try/catch is good. If the list becomes large, consider exposing a setCustomCategories in the store to replace the entire list in one update instead of many delete calls, which would be both simpler and more efficient.


335-367: AI config merge logic preserves secrets but may over‑write optional fields

The merge correctly:

  • Preserves existing apiKey when backup is masked with ***.
  • Keeps the existing isActive flag.
  • Seeds new configs with isActive: false and empty key when masked.

Two minor improvements you might consider:

  • Pass the id field through to updateAIConfig to keep usage consistent with handleSaveAI (unless the store intentionally treats the second arg as a partial).
  • When cfg.concurrency is undefined (old backups), fall back to existing.concurrency or a default (e.g. 1) instead of overwriting with undefined.

369-399: WebDAV config merge semantics look good, with a small UX opportunity

The WebDAV merge correctly:

  • Preserves existing passwords when the backup is masked (***).
  • Avoids activating newly imported configs and leaves passwords blank when restoring sanitized backups on a new device.

This is functionally sound; the only thing you might add elsewhere is a gentle UI hint after restore that some WebDAV entries were imported without passwords and require re-entry, to avoid silent connection failures later.

src/services/webdavService.ts (4)

10-35: JSON compression and size analysis are reasonable; consider more accurate size calculation

compressData is a safe minifier for JSON payloads, and analyzeFileSize gives useful heuristics for logging and tuning. If you ever need a closer approximation to actual bytes on the wire (especially with non‑ASCII content), new Blob([content]).size would be more accurate than content.length / 1024, though the current approach is fine for rough thresholds.


37-72: retryUpload works but assumes an Error‑like object

The retry logic with exponential backoff looks good for PUT uploads. The only fragility is assuming error.message is always a string; if operation ever throws a non‑Error, error.message.includes(...) could itself throw. You can harden this by normalizing the message first, e.g.:

const message = (error as any)?.message ?? String(error);
const shouldRetry =
  message.includes('超时') ||
  message.toLowerCase().includes('timeout') ||
  message.includes('NetworkError') ||
  message.includes('fetch');

and then log message instead of error.message.


381-460: listFiles XML parsing is robust; small fallback tweak possible

The new PROPFIND handling with a DOMParser first and regex fallbacks for displayname/href covers a wide range of WebDAV server quirks and correctly filters down to .json files. One small enhancement would be to invoke the regex fallback not only when DOMParser throws, but also when it parses successfully yet yields zero <DAV:response> matches, so that malformed but parseable XML still gets a second chance at extraction.


512-533: getServerInfo is useful; consider adding a timeout

Exposing Server and DAV headers via an OPTIONS request is handy for diagnostics. To align with the rest of the service and avoid hanging indefinitely on misbehaving servers, you may want to wrap this in an AbortController with a modest timeout (e.g. 10–15s), similar to fileExists and listFiles.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 094db26 and 56453a7.

📒 Files selected for processing (2)
  • src/components/SettingsPanel.tsx (2 hunks)
  • src/services/webdavService.ts (8 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/SettingsPanel.tsx (1)
src/types/index.ts (2)
  • AIConfig (69-79)
  • WebDAVConfig (81-89)
🔇 Additional comments (5)
src/components/SettingsPanel.tsx (2)

52-55: Store wiring for restore looks correct

Wiring setRepositories, setReleases, addCustomCategory, and deleteCustomCategory into the panel matches the new restore flow and keeps responsibilities in the store instead of local state. No issues here.


402-403: Restore success message is informative and safe

The new message that reports counts for repositories, releases, and custom categories is a nice UX improvement and uses optional chaining/?? 0 defensively, so it won’t explode on older backups missing those fields.

src/services/webdavService.ts (3)

187-250: Upload pre‑processing and retry are solid

The upload pipeline—size analysis, JSON minification, directory creation, dynamic timeout based on compressed size, and a wrapped PUT with structured HTTP error messages plus retry—is well thought out and should significantly improve resilience for large backups. I don’t see functional issues here.


271-296: Progressive MKCOL for nested paths is a good improvement

Creating each path segment with MKCOL and treating 201/405/409 as success makes directory provisioning much more robust across different servers. If you start seeing odd behaviors with redirects or other status codes, you might later expand the “already exists” set, but the current logic is a clear improvement over a single MKCOL.


485-510: validateConfig provides clear, actionable errors

The static validateConfig covers URL scheme, presence of username/password, and the leading / on path, which matches how the rest of the service builds URLs. This gives the UI concrete messages without coupling it to implementation details.

@AmintaCCCP AmintaCCCP merged commit 1a2e61b into AmintaCCCP:main Nov 15, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants