Skip to content

Latest commit

 

History

History
224 lines (187 loc) · 12.3 KB

File metadata and controls

224 lines (187 loc) · 12.3 KB

OxiCloud App Architecture

This document describes the architecture of the OxiCloud desktop/mobile sync client.

Overview

OxiCloud App is a cross-platform sync client built with:

  • Flutter for the user interface (5 platforms: Windows, macOS, Linux, Android, iOS)
  • Rust for the core sync engine (performance-critical operations)
  • flutter_rust_bridge for FFI communication between Flutter and Rust

Architecture Pattern

The application follows Clean Architecture principles, ensuring:

  • Separation of concerns
  • Testability
  • Independence from frameworks
  • Independence from UI
┌─────────────────────────────────────────────────────────────────┐
│                      FLUTTER (Dart)                             │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │              PRESENTATION LAYER                          │   │
│  │  ┌─────────┐  ┌─────────┐  ┌──────────┐               │   │
│  │  │  Pages  │  │  BLoCs  │  │ Widgets  │               │   │
│  │  └────┬────┘  └────┬────┘  └────┬─────┘               │   │
│  └───────┼────────────┼────────────┼──────────────────────┘   │
│          │            │            │                            │
│  ┌───────┴────────────┴────────────┴──────────────────────┐   │
│  │                  DOMAIN LAYER                           │   │
│  │  ┌──────────┐  ┌──────────────┐  ┌─────────────┐      │   │
│  │  │ Entities │  │ Repositories │  │  Use Cases  │      │   │
│  │  │  (pure)  │  │  (abstract)  │  │ (optional)  │      │   │
│  │  └──────────┘  └──────────────┘  └─────────────┘      │   │
│  └───────────────────────┬────────────────────────────────┘   │
│                          │                                      │
│  ┌───────────────────────┴────────────────────────────────┐   │
│  │                    DATA LAYER                           │   │
│  │  ┌─────────────────────┐  ┌────────────────────────┐   │   │
│  │  │  Repository Impls   │  │  Rust Bridge Source    │   │   │
│  │  └─────────────────────┘  └───────────┬────────────┘   │   │
│  └───────────────────────────────────────┼────────────────┘   │
└──────────────────────────────────────────┼──────────────────────┘
                                           │ FFI
┌──────────────────────────────────────────┼──────────────────────┐
│                      RUST CORE                                  │
│  ┌───────────────────────────────────────┴──────────────────┐   │
│  │                      API Layer                            │   │
│  │                  (flutter_rust_bridge)                    │   │
│  └───────────────────────────────────────┬──────────────────┘   │
│                                          │                       │
│  ┌───────────────────────────────────────┴──────────────────┐   │
│  │                  APPLICATION LAYER                        │   │
│  │  ┌──────────────┐  ┌────────────────┐  ┌──────────────┐  │   │
│  │  │ SyncService  │  │  AuthService   │  │ FileWatcher  │  │   │
│  │  └──────────────┘  └────────────────┘  └──────────────┘  │   │
│  └───────────────────────────────────────┬──────────────────┘   │
│                                          │                       │
│  ┌───────────────────────────────────────┴──────────────────┐   │
│  │                    DOMAIN LAYER                           │   │
│  │  ┌──────────┐  ┌──────────────────┐                     │   │
│  │  │ Entities │  │  Ports (Traits)  │                     │   │
│  │  └──────────┘  └──────────────────┘                     │   │
│  └───────────────────────────────────────┬──────────────────┘   │
│                                          │                       │
│  ┌───────────────────────────────────────┴──────────────────┐   │
│  │                 INFRASTRUCTURE LAYER                      │   │
│  │  ┌──────────────┐  ┌────────────────┐  ┌──────────────┐  │   │
│  │  │ WebDAV Client│  │ SQLite Storage │  │ File Watcher │  │   │
│  │  └──────────────┘  └────────────────┘  └──────────────┘  │   │
│  └──────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

Layer Responsibilities

Flutter Layers

Presentation Layer

  • Pages: Full screen UI components (LoginPage, HomePage, SettingsPage)
  • BLoCs: Business Logic Components for state management
  • Widgets: Reusable UI components

Domain Layer (Flutter)

  • Entities: Core business objects (User, SyncFolder, SyncStatus)
  • Repositories: Abstract interfaces (ports) for data operations
  • Use Cases: Optional application-specific business rules

Data Layer

  • Repository Implementations: Concrete implementations of domain interfaces
  • RustBridgeDataSource: FFI calls to native Rust code

Rust Layers

API Layer

  • FFI bindings generated by flutter_rust_bridge
  • OxiCloudApi struct exposing safe Rust functions to Dart

Application Layer

  • SyncService: Orchestrates file synchronization
  • AuthService: Handles authentication flows
  • FileWatcherService: Monitors filesystem for changes

Domain Layer (Rust)

  • Entities: SyncItem, SyncStatus, AuthCredentials, SyncConfig
  • Ports: Trait definitions (SyncPort, StoragePort, AuthPort)

Infrastructure Layer

  • WebDavClient: HTTP client for WebDAV server communication
  • SqliteStorage: Local database for sync state persistence
  • NotifyFileWatcher: File system event monitoring

Data Flow

Login Flow

LoginPage → AuthBloc → AuthRepository → RustBridgeDataSource
                                              ↓
                                         Rust API
                                              ↓
                                        AuthService
                                              ↓
                                        WebDavClient → Server

Sync Flow

HomePage → SyncBloc → SyncRepository → RustBridgeDataSource
                                              ↓
                                         Rust API
                                              ↓
                                        SyncService
                                     ↙          ↘
                              SqliteStorage   WebDavClient
                                   ↓               ↓
                             Local DB          Server

State Management

The app uses BLoC (Business Logic Component) pattern:

  • AuthBloc: Authentication state
  • SyncBloc: Synchronization state and operations
  • SettingsBloc: Application settings

Events flow in, states flow out:

UI → Event → BLoC → Repository → State → UI

Dependency Injection

Dependencies are managed with GetIt:

// Register
getIt.registerLazySingleton<AuthRepository>(() => AuthRepositoryImpl(...));

// Resolve
final authRepo = getIt<AuthRepository>();

File Structure

lib/
├── main.dart                  # Entry point
├── injection.dart             # DI configuration
├── core/
│   ├── entities/              # Domain entities
│   ├── repositories/          # Repository interfaces
│   └── usecases/              # Use cases (optional)
├── data/
│   ├── datasources/           # Data sources
│   └── repositories/          # Repository implementations
└── presentation/
    ├── app.dart               # App widget & routing
    ├── blocs/                 # BLoC classes
    ├── pages/                 # Screen widgets
    └── widgets/               # Reusable components

rust/
├── Cargo.toml
└── src/
    ├── lib.rs
    ├── api.rs                 # FFI API
    ├── domain/
    │   ├── entities/          # Rust entities
    │   └── ports/             # Trait definitions
    ├── application/           # Services
    └── infrastructure/        # Concrete implementations

Error Handling

Errors are represented using the Either type from dartz:

Future<Either<AuthFailure, User>> login(AuthCredentials credentials);

Failure types are sealed classes:

sealed class AuthFailure {}
class InvalidCredentialsFailure implements AuthFailure {}
class ServerUnreachableFailure implements AuthFailure {
  final String message;
  ServerUnreachableFailure(this.message);
}

Testing Strategy

  1. Unit Tests: Test individual classes in isolation
  2. Widget Tests: Test UI components
  3. Integration Tests: Test Flutter ↔ Rust communication
  4. E2E Tests: Full application flows

Mock repositories for testing:

class MockAuthRepository extends Mock implements AuthRepository {}