UNPKG

@rsweeten/dropbox-sync

Version:

Reusable Dropbox synchronization module with framework adapters

218 lines (188 loc) 6.67 kB
import { Injectable } from '@angular/core' import { HttpClient, HttpHeaders } from '@angular/common/http' import { Observable, from, of } from 'rxjs' import { catchError, map, switchMap, tap } from 'rxjs/operators' import { createDropboxSyncClient } from '../core/client' import type { DropboxCredentials, DropboxSyncClient, SyncOptions, SyncResult, TokenResponse, } from '../core/types' @Injectable({ providedIn: 'root', }) export class DropboxSyncService { private client: DropboxSyncClient | null = null constructor(private http: HttpClient) {} /** * Initialize the Dropbox sync client with credentials */ initialize(credentials: DropboxCredentials): DropboxSyncClient { this.client = createDropboxSyncClient(credentials) return this.client } /** * Get the current Dropbox sync client instance, or initialize with credentials if not exists */ getClient(credentials?: DropboxCredentials): DropboxSyncClient { if (!this.client && credentials) { return this.initialize(credentials) } if (!this.client) { throw new Error( 'DropboxSyncService not initialized. Call initialize() first.' ) } return this.client } /** * Check the connection status with Dropbox */ checkConnection(): Observable<boolean> { return this.http .get<{ connected: boolean }>('/api/dropbox/status') .pipe( map((response: any) => response.connected), catchError(() => of(false)) ) } /** * Start the OAuth flow to connect to Dropbox */ connectDropbox(): void { window.location.href = '/api/dropbox/auth/start' } /** * Disconnect from Dropbox */ disconnectDropbox(): Observable<boolean> { return this.http .post<{ success: boolean }>('/api/dropbox/logout', {}) .pipe( map((response: any) => response.success), catchError(() => of(false)) ) } /** * Start the sync process */ startSync(options?: Partial<SyncOptions>): Observable<SyncResult> { if (!this.client) { throw new Error( 'DropboxSyncService not initialized. Call initialize() first.' ) } // Connect to socket before starting sync this.client.socket.connect() // Setup socket listeners for sync events this.setupSocketListeners() return from(this.client.sync.syncFiles(options)) } /** * Cancel an ongoing sync process */ cancelSync(): void { if (!this.client) { return } this.client.sync.cancelSync() } /** * Set up socket listeners for sync events * Returns an RxJS Observable that emits sync progress events */ setupSocketListeners(): Observable<any> { if (!this.client) { throw new Error( 'DropboxSyncService not initialized. Call initialize() first.' ) } // Create observable for sync progress events return new Observable((observer: any) => { // Listen for progress updates this.client!.socket.on('sync:progress', (data: any) => { observer.next({ type: 'progress', data }) }) // Listen for queue information this.client!.socket.on('sync:queue', (data: any) => { observer.next({ type: 'queue', data }) }) // Listen for sync completion this.client!.socket.on('sync:complete', (data: any) => { observer.next({ type: 'complete', data }) observer.complete() }) // Listen for sync errors this.client!.socket.on('sync:error', (data: any) => { if (!data.continue) { observer.error(data.message) } else { observer.next({ type: 'error', data }) } }) // Cleanup function - remove event listeners when subscription is disposed return () => { this.client!.socket.off('sync:progress') this.client!.socket.off('sync:queue') this.client!.socket.off('sync:complete') this.client!.socket.off('sync:error') } }) } /** * Handle OAuth callback on the client side */ handleOAuthCallback(code: string): Observable<TokenResponse> { if (!this.client) { throw new Error( 'DropboxSyncService not initialized. Call initialize() first.' ) } const redirectUri = window.location.origin + '/api/dropbox/auth/callback' return from( this.client.auth.exchangeCodeForToken(code, redirectUri) ).pipe( tap((tokens: any) => { // Store tokens in local storage for client-side access localStorage.setItem('dropbox_access_token', tokens.accessToken) if (tokens.refreshToken) { localStorage.setItem( 'dropbox_refresh_token', tokens.refreshToken ) } localStorage.setItem('dropbox_connected', 'true') }) ) } /** * Create a sync queue to determine which files need to be uploaded/downloaded */ createSyncQueue( options?: Partial<SyncOptions> ): Observable<{ uploadQueue: string[]; downloadQueue: string[] }> { if (!this.client) { throw new Error( 'DropboxSyncService not initialized. Call initialize() first.' ) } return from(this.client.sync.createSyncQueue(options)) } } /** * Function to extract credentials from Angular environment */ export function getCredentialsFromEnvironment( environment: any ): DropboxCredentials { return { clientId: environment.dropboxAppKey || '', clientSecret: environment.dropboxAppSecret, accessToken: localStorage.getItem('dropbox_access_token') || undefined, refreshToken: localStorage.getItem('dropbox_refresh_token') || undefined, } }