class PouchDBService constructor: (options = {}) -> { @localDbName = 'braer_color_cache' @remoteDbUrl = 'http://localhost:5984/braer_color_shop' @userFilter = { userId: null } @appVersion = '1.0.0' } = options @localDb = null @remoteDb = null @initialized = false @syncHandler = null # Основная инициализация init: -> return Promise.resolve() if @initialized try debug.log '🚀 Инициализация PouchDB сервиса...' # Создание локальной базы @localDb = new PouchDB(@localDbName) debug.log '📁 Локальная база создана:', @localDbName # Создание/подключение удаленной базы await @ensureRemoteDatabase() # Загрузка design документов await @ensureDesignDocs() # Настройка синхронизации await @setupSync() @initialized = true debug.log '✅ PouchDB сервис инициализирован' return Promise.resolve() catch error console.error '❌ Ошибка инициализации PouchDB:', error return Promise.reject(error) # Создание удаленной базы если не существует ensureRemoteDatabase: -> try @remoteDb = new PouchDB(@remoteDbUrl) # Проверка существования базы info = await @remoteDb.info() debug.log '🌐 Удаленная база подключена:', info.db_name catch error if error.status == 404 debug.log '📦 Создание новой удаленной базы...' # В браузере создание БД происходит автоматически при первом обращении @remoteDb = new PouchDB(@remoteDbUrl) info = await @remoteDb.info() debug.log '✅ Удаленная база создана:', info.db_name else throw error # Создание design документов ensureDesignDocs: -> try # Загрузка design документов adminDesign = require 'app/design/admin.coffee' siteDesign = require 'app/design/site.coffee' # Сохранение design документов await @saveDesignDoc(adminDesign) await @saveDesignDoc(siteDesign) debug.log '📝 Design документы загружены' catch error console.error 'Ошибка загрузки design документов:', error throw error # Сохранение design документа с проверкой версий saveDesignDoc: (designDoc) -> try existingDoc = await @remoteDb.get(designDoc._id) # Проверка необходимости обновления if existingDoc.hash != designDoc.hash || existingDoc.version != designDoc.version designDoc._rev = existingDoc._rev await @remoteDb.put(designDoc) debug.log "🔄 Design документ обновлен: #{designDoc._id}" else debug.log "✅ Design документ актуален: #{designDoc._id}" catch error if error.status == 404 # Документ не существует, создаем новый await @remoteDb.put(designDoc) debug.log "✅ Design документ создан: #{designDoc._id}" else throw error # Настройка синхронизации setupSync: -> @syncHandler = PouchDB.sync(@remoteDb, @localDb, { live: true, retry: true, filter: (doc) => @shouldSyncDocument(doc) }) @syncHandler .on('change', (info) => debug.log '🔄 Синхронизация:', info) .on('paused', (err) => debug.log '⏸️ Синхронизация приостановлена') .on('active', => debug.log '🔄 Синхронизация активна') .on('error', (err) => console.error '❌ Ошибка синхронизации:', err) debug.log '🔁 Синхронизация настроена' # Проверка необходимости синхронизации документа shouldSyncDocument: (doc) -> return false if doc._id?.startsWith('_design/') # Всегда синхронизируем общие данные if doc.type in ['product', 'category', 'settings', 'hero_slide', 'blog_article', 'route', 'domain_settings'] return true # Для пользовательских данных проверяем принадлежность if doc.type in ['order', 'user_data', 'cart'] return doc.userId == @userFilter?.userId # Для мультидоменности проверяем принадлежность к домену if doc.domains return @userFilter?.currentDomain in doc.domains return false # Умное получение документа getDocument: (docId) -> @ensureInit() try # Сначала пробуем локально doc = await @localDb.get(docId) debug.log '📄 Документ получен из локального кэша:', docId return doc catch localError if localError.status == 404 try # Затем пробуем удаленно doc = await @remoteDb.get(docId) # Сохраняем в кэш для будущих запросов await @localDb.put(doc) debug.log '📄 Документ получен из удаленной БД и закэширован:', docId return doc catch remoteError console.error '❌ Документ не найден:', docId throw remoteError else throw localError # Сохранение документа (только в удаленную БД) saveToRemote: (doc) -> @ensureInit() try # Проверяем существование документа existingDoc = await @remoteDb.get(doc._id) doc._rev = existingDoc._rev result = await @remoteDb.put(doc) debug.log '💾 Документ обновлен в удаленной БД:', doc._id return result catch error if error.status == 404 # Документ не существует, создаем новый result = await @remoteDb.put(doc) debug.log '💾 Документ создан в удаленной БД:', doc._id return result else console.error '❌ Ошибка сохранения документа:', error throw error # Пакетное сохранение bulkDocs: (docs) -> @ensureInit() await @remoteDb.bulkDocs(docs) # Выполнение view запроса queryView: (designDoc, viewName, options = {}) -> @ensureInit() await @remoteDb.query("#{designDoc}/#{viewName}", options) # Получение вложений getAttachment: (docId, attachmentName) -> @ensureInit() await @remoteDb.getAttachment(docId, attachmentName) # Сохранение вложения putAttachment: (docId, attachmentName, attachment, type) -> @ensureInit() try doc = await @remoteDb.get(docId) await @remoteDb.putAttachment(docId, attachmentName, doc._rev, attachment, type) debug.log '📎 Вложение сохранено:', "#{docId}/#{attachmentName}" catch error if error.status == 404 # Документ не существует, создаем сначала базовый документ await @remoteDb.put({ _id: docId, type: 'with_attachments' }) await @remoteDb.putAttachment(docId, attachmentName, attachment, type) else throw error # Вспомогательные методы ensureInit: -> if !@initialized throw new Error 'PouchDBService не инициализирован. Вызовите init() сначала.' destroy: -> if @syncHandler @syncHandler.cancel() @initialized = false debug.log '🧹 PouchDBService уничтожен' # Создание и экспорт синглтона module.exports = new PouchDBService({ localDbName: 'braer_color_cache' remoteDbUrl: 'https://oleg:631074@couchdb.favt.ru.net/braer_color_shop' userFilter: { userId: 'current_user_id' } appVersion: '1.0.0' })