UNPKG

@rsweeten/dropbox-sync

Version:

Reusable Dropbox synchronization module with framework adapters

245 lines (221 loc) 8.66 kB
// Angular service implementation for Dropbox sync import { Injectable } from '@angular/core' import { BehaviorSubject, Observable, of, fromEvent } from 'rxjs' import { catchError, map, tap } from 'rxjs/operators' import { HttpClient } from '@angular/common/http' // For a private module, you would import from your private registry or local path // import { DropboxSyncService, getCredentialsFromEnvironment } from '@yourcompany/dropbox-sync'; import { DropboxSyncService, getCredentialsFromEnvironment } from 'dropbox-sync' import { environment } from '../environments/environment' @Injectable({ providedIn: 'root', }) export class DropboxService { // State observables private _connected = new BehaviorSubject<boolean>(false) private _syncing = new BehaviorSubject<boolean>(false) private _progress = new BehaviorSubject<number>(0) private _message = new BehaviorSubject<string>('') private _error = new BehaviorSubject<string | null>(null) // Public observable properties readonly connected$ = this._connected.asObservable() readonly syncing$ = this._syncing.asObservable() readonly progress$ = this._progress.asObservable() readonly message$ = this._message.asObservable() readonly error$ = this._error.asObservable() private syncStats = { total: 0, uploads: 0, downloads: 0, completed: 0, } constructor( private http: HttpClient, private dropboxSyncService: DropboxSyncService ) { // Initialize the Dropbox sync client this.initialize() } /** * Initialize the Dropbox sync client and check connection status */ initialize(): void { // Get credentials from environment and localStorage const credentials = getCredentialsFromEnvironment(environment) // Initialize the service this.dropboxSyncService.initialize(credentials) // Check connection status this.checkConnection().subscribe() // Set up socket event listeners this.setupSocketEventListeners() } /** * Check if connected to Dropbox */ checkConnection(): Observable<boolean> { return this.http .get<{ connected: boolean }>('/api/dropbox/status') .pipe( map((response) => response.connected), tap((connected) => this._connected.next(connected)), catchError((error) => { console.error('Error checking Dropbox connection:', error) this._connected.next(false) return of(false) }) ) } /** * Start the OAuth flow to connect to Dropbox */ connect(): void { window.location.href = '/api/dropbox/auth/start' } /** * Disconnect from Dropbox */ disconnect(): Observable<boolean> { return this.http .post<{ success: boolean }>('/api/dropbox/logout', {}) .pipe( tap((response) => { if (response.success) { this._connected.next(false) localStorage.removeItem('dropbox_access_token') localStorage.removeItem('dropbox_refresh_token') localStorage.removeItem('dropbox_connected') } }), map((response) => response.success), catchError((error) => { console.error('Error disconnecting from Dropbox:', error) return of(false) }) ) } /** * Start syncing files with Dropbox */ startSync(options?: { localDir?: string; dropboxDir?: string }): void { try { // Reset state this._syncing.next(true) this._progress.next(0) this._message.next('Initializing Dropbox sync...') this._error.next(null) // Get socket from the sync service and emit sync event const client = this.dropboxSyncService.getClient() client.socket.connect() client.socket.emit('dropbox:sync', options) } catch (error: any) { console.error('Error starting Dropbox sync:', error) this._error.next(error.message || 'Error starting synchronization') this._syncing.next(false) } } /** * Cancel ongoing sync process */ cancelSync(): void { try { const client = this.dropboxSyncService.getClient() client.sync.cancelSync() this._syncing.next(false) this._message.next('Sync cancelled by user') } catch (error: any) { console.error('Error cancelling sync:', error) } } /** * Check which files need to be synced without performing sync */ checkSyncNeeded(options?: { localDir?: string dropboxDir?: string }): Observable<{ upload: number; download: number }> { try { const client = this.dropboxSyncService.getClient() return this.dropboxSyncService.createSyncQueue(options).pipe( map(({ uploadQueue, downloadQueue }) => ({ upload: uploadQueue.length, download: downloadQueue.length, })), catchError((error) => { console.error('Error checking sync status:', error) return of({ upload: 0, download: 0 }) }) ) } catch (error) { console.error('Error creating sync queue:', error) return of({ upload: 0, download: 0 }) } } /** * Set up socket event listeners for real-time sync updates */ private setupSocketEventListeners(): void { try { const client = this.dropboxSyncService.getClient() const socketProgress = this.dropboxSyncService.setupSocketListeners() // Subscribe to the socket events observable socketProgress.subscribe({ next: (data: any) => { switch (data.type) { case 'progress': this._progress.next(data.data.progress) this._message.next(data.data.message) break case 'queue': this.syncStats = { total: data.data.total, uploads: data.data.totalUploads, downloads: data.data.totalDownloads, completed: 0, } break case 'complete': this._progress.next(100) this._message.next(data.data.message) this._syncing.next(false) if (data.data.stats) { this.syncStats.completed = this.syncStats.total } break case 'error': this._error.next(data.data.message) if (!data.data.continue) { this._syncing.next(false) } break } }, error: (error) => { this._error.next( typeof error === 'string' ? error : 'An error occurred during synchronization' ) this._syncing.next(false) }, complete: () => { // Sync process completed successfully console.log('Dropbox sync process completed') }, }) } catch (error) { console.error('Error setting up socket listeners:', error) } } /** * Get current sync statistics */ getSyncStats(): { total: number uploads: number downloads: number completed: number } { return { ...this.syncStats } } }