# app/utils/pouch.coffee class PouchDBService constructor: (options = {}) -> {@localDbName, @remoteDbUrl, @appVersion} = options @localDb = null @remoteDb = null @syncHandler = null @initialized = false @syncStatus = 'disconnected' init: -> return Promise.resolve() if @initialized try log 'πŸ”„ Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ PouchDB сСрвиса' # Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ локальной Π±Π°Π·Ρ‹ @localDb = new PouchDB(@localDbName or 'braer_color_cache') log 'βœ… Π›ΠΎΠΊΠ°Π»ΡŒΠ½Π°Ρ PouchDB ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π°' # Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ Π±Π°Π·Ρ‹ @remoteDb = new PouchDB(@remoteDbUrl, { skip_setup: false fetch: (url, opts) => opts.credentials = 'include' # ДобавляСм Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ opts.headers ?= {} # Π—Π΄Π΅ΡΡŒ Π±ΡƒΠ΄ΡƒΡ‚ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒΡΡ Ρ‚ΠΎΠΊΠ΅Π½Ρ‹ Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ PouchDB.fetch(url, opts) }) log 'βœ… УдалСнная CouchDB ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½Π°' # Настройка Π½Π΅ΠΏΡ€Π΅Ρ€Ρ‹Π²Π½ΠΎΠΉ синхронизации @setupSync() @initialized = true log 'πŸŽ‰ PouchDB сСрвис ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½' return Promise.resolve() catch error log '❌ ΠšΡ€ΠΈΡ‚ΠΈΡ‡Π΅ΡΠΊΠ°Ρ ошибка ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ PouchDB:', error return Promise.reject(error) setupSync: -> @syncHandler = PouchDB.sync(@localDb, @remoteDb, { live: true, retry: true, batch_size: 50, batches_limit: 10, filter: (doc) => @shouldSyncDocument(doc) }) .on 'change', (info) => log 'πŸ“‘ Бинхронизация: Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½Ρ‹', info @syncStatus = 'syncing' .on 'paused', (err) => log '⏸️ Бинхронизация приостановлСна' @syncStatus = 'paused' .on 'active', -> log 'πŸ”„ Бинхронизация Π°ΠΊΡ‚ΠΈΠ²Π½Π°' @syncStatus = 'active' .on 'denied', (err) => log '🚫 Доступ Π·Π°ΠΏΡ€Π΅Ρ‰Π΅Π½:', err @syncStatus = 'denied' .on 'complete', (info) => log 'βœ… Бинхронизация Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½Π°', info @syncStatus = 'complete' .on 'error', (err) => log '❌ Ошибка синхронизации:', err @syncStatus = 'error' @handleSyncError(err) shouldSyncDocument: (doc) -> # Π€ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΡ ΠΏΠΎ Π΄ΠΎΠΌΠ΅Π½Π°ΠΌ ΠΈ Ρ‚ΠΈΠΏΠ°ΠΌ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² return true if doc.type in ['product', 'category', 'domain_settings', 'hero_slide'] return true if doc.type in ['blog_article', 'route', 'user_settings'] # Для Π·Π°ΠΊΠ°Π·ΠΎΠ² ΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… Π΄Π°Π½Π½Ρ‹Ρ… провСряСм ΠΏΡ€ΠΈΠ½Π°Π΄Π»Π΅ΠΆΠ½ΠΎΡΡ‚ΡŒ if doc.type in ['order', 'user_data', 'cart'] return doc.userId == @getCurrentUserId() # По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π½Π΅ синхронизируСм return false getCurrentUserId: -> # ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ID Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ userData = localStorage.getItem('user') if userData try user = JSON.parse(userData) return user.id catch return 'anonymous' return 'anonymous' handleSyncError: (error) -> log 'πŸ”„ ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибки синхронизации:', error # АвтоматичСский ΠΏΠΎΠ²Ρ‚ΠΎΡ€ ΠΏΡ€ΠΈ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ… if error.status in [408, 429, 500, 502, 503, 504] log '⏳ ВрСмСнная ошибка, ΠΏΠΎΠ²Ρ‚ΠΎΡ€ Ρ‡Π΅Ρ€Π΅Π· 5 сСкунд...' setTimeout (=> @setupSync() ), 5000 else if error.status == 401 log 'πŸ” Ошибка Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ, трСбуСтся ΠΏΠ΅Ρ€Π΅Π»ΠΎΠ³ΠΈΠ½' # Π’Ρ€ΠΈΠ³Π³Π΅Ρ€ события для прилоТСния document.dispatchEvent(new CustomEvent('auth-required')) # ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ getDocument: (docId) -> @ensureInit() try # ΠŸΡ€ΠΎΠ±ΡƒΠ΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΈΠ· локальной Π±Π°Π·Ρ‹ doc = await @localDb.get(docId) log 'πŸ“„ Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ ΠΈΠ· локальной Π±Π°Π·Ρ‹:', docId return doc catch localError if localError.status == 404 try # ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΈΠ· ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ Π±Π°Π·Ρ‹ ΠΈ сохраняСм локально doc = await @remoteDb.get(docId) await @localDb.put(doc) log 'πŸ“„ Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ ΠΈΠ· ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ Π±Π°Π·Ρ‹ ΠΈ сохранСн локально:', docId return doc catch remoteError log '❌ Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ Π² ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ Π±Π°Π·Π΅:', docId throw remoteError else log '❌ Ошибка получСния Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° ΠΈΠ· локальной Π±Π°Π·Ρ‹:', localError throw localError saveDocument: (doc) -> @ensureInit() try # БохраняСм Π² Π»ΠΎΠΊΠ°Π»ΡŒΠ½ΡƒΡŽ Π±Π°Π·Ρƒ result = await @localDb.put(doc) log 'πŸ’Ύ Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ сохранСн локально:', doc._id return result catch error log '❌ Ошибка сохранСния Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°:', error throw error bulkDocs: (docs) -> @ensureInit() try result = await @localDb.bulkDocs(docs) log 'πŸ“¦ ΠŸΠ°ΠΊΠ΅Ρ‚Π½ΠΎΠ΅ сохранСниС Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²:', docs.length return result catch error log '❌ Ошибка ΠΏΠ°ΠΊΠ΅Ρ‚Π½ΠΎΠ³ΠΎ сохранСния:', error throw error queryView: (designDoc, viewName, options = {}) -> @ensureInit() try result = await @localDb.query("#{designDoc}/#{viewName}", options) log 'πŸ” Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ запрос ΠΊ view:', "#{designDoc}/#{viewName}" return result catch error log '❌ Ошибка запроса ΠΊ view:', error throw error ensureInit: -> unless @initialized throw new Error('PouchDB сСрвис Π½Π΅ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½. Π’Ρ‹Π·ΠΎΠ²ΠΈΡ‚Π΅ init() сначала.') destroy: -> if @syncHandler @syncHandler.cancel() if @localDb await @localDb.close() @initialized = false log 'πŸ”š PouchDB сСрвис остановлСн' module.exports = new PouchDBService({ localDbName: 'braer_color_cache', remoteDbUrl: 'https://oleg:631074@couchdb.favt.ru.net/braer_color_shop', appVersion: '1.0.0' })