| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- # 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'
- })
|