pouch.coffee 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. # app/utils/pouch.coffee
  2. class PouchDBService
  3. constructor: (options = {}) ->
  4. {@localDbName, @remoteDbUrl, @appVersion} = options
  5. @localDb = null
  6. @remoteDb = null
  7. @syncHandler = null
  8. @initialized = false
  9. @syncStatus = 'disconnected'
  10. init: ->
  11. return Promise.resolve() if @initialized
  12. try
  13. log '🔄 Инициализация PouchDB сервиса'
  14. # Инициализация локальной базы
  15. @localDb = new PouchDB(@localDbName or 'braer_color_cache')
  16. log '✅ Локальная PouchDB инициализирована'
  17. # Инициализация удаленной базы
  18. @remoteDb = new PouchDB(@remoteDbUrl, {
  19. skip_setup: false
  20. fetch: (url, opts) =>
  21. opts.credentials = 'include'
  22. # Добавляем заголовки аутентификации
  23. opts.headers ?= {}
  24. # Здесь будут добавляться токены аутентификации
  25. PouchDB.fetch(url, opts)
  26. })
  27. log '✅ Удаленная CouchDB подключена'
  28. # Настройка непрерывной синхронизации
  29. @setupSync()
  30. @initialized = true
  31. log '🎉 PouchDB сервис полностью инициализирован'
  32. return Promise.resolve()
  33. catch error
  34. log '❌ Критическая ошибка инициализации PouchDB:', error
  35. return Promise.reject(error)
  36. setupSync: ->
  37. @syncHandler = PouchDB.sync(@localDb, @remoteDb, {
  38. live: true,
  39. retry: true,
  40. batch_size: 50,
  41. batches_limit: 10,
  42. filter: (doc) => @shouldSyncDocument(doc)
  43. })
  44. .on 'change', (info) =>
  45. log '📡 Синхронизация: данные изменены', info
  46. @syncStatus = 'syncing'
  47. .on 'paused', (err) =>
  48. log '⏸️ Синхронизация приостановлена'
  49. @syncStatus = 'paused'
  50. .on 'active', ->
  51. log '🔄 Синхронизация активна'
  52. @syncStatus = 'active'
  53. .on 'denied', (err) =>
  54. log '🚫 Доступ запрещен:', err
  55. @syncStatus = 'denied'
  56. .on 'complete', (info) =>
  57. log '✅ Синхронизация завершена', info
  58. @syncStatus = 'complete'
  59. .on 'error', (err) =>
  60. log '❌ Ошибка синхронизации:', err
  61. @syncStatus = 'error'
  62. @handleSyncError(err)
  63. shouldSyncDocument: (doc) ->
  64. # Фильтрация по доменам и типам документов
  65. return true if doc.type in ['product', 'category', 'domain_settings', 'hero_slide']
  66. return true if doc.type in ['blog_article', 'route', 'user_settings']
  67. # Для заказов и пользовательских данных проверяем принадлежность
  68. if doc.type in ['order', 'user_data', 'cart']
  69. return doc.userId == @getCurrentUserId()
  70. # По умолчанию не синхронизируем
  71. return false
  72. getCurrentUserId: ->
  73. # Получение ID текущего пользователя
  74. userData = localStorage.getItem('user')
  75. if userData
  76. try
  77. user = JSON.parse(userData)
  78. return user.id
  79. catch
  80. return 'anonymous'
  81. return 'anonymous'
  82. handleSyncError: (error) ->
  83. log '🔄 Обработка ошибки синхронизации:', error
  84. # Автоматический повтор при временных ошибках
  85. if error.status in [408, 429, 500, 502, 503, 504]
  86. log '⏳ Временная ошибка, повтор через 5 секунд...'
  87. setTimeout (=>
  88. @setupSync()
  89. ), 5000
  90. else if error.status == 401
  91. log '🔐 Ошибка аутентификации, требуется перелогин'
  92. # Триггер события для приложения
  93. document.dispatchEvent(new CustomEvent('auth-required'))
  94. # Основные методы работы с данными
  95. getDocument: (docId) ->
  96. @ensureInit()
  97. try
  98. # Пробуем получить из локальной базы
  99. doc = await @localDb.get(docId)
  100. log '📄 Документ получен из локальной базы:', docId
  101. return doc
  102. catch localError
  103. if localError.status == 404
  104. try
  105. # Получаем из удаленной базы и сохраняем локально
  106. doc = await @remoteDb.get(docId)
  107. await @localDb.put(doc)
  108. log '📄 Документ получен из удаленной базы и сохранен локально:', docId
  109. return doc
  110. catch remoteError
  111. log '❌ Документ не найден в удаленной базе:', docId
  112. throw remoteError
  113. else
  114. log '❌ Ошибка получения документа из локальной базы:', localError
  115. throw localError
  116. saveDocument: (doc) ->
  117. @ensureInit()
  118. try
  119. # Сохраняем в локальную базу
  120. result = await @localDb.put(doc)
  121. log '💾 Документ сохранен локально:', doc._id
  122. return result
  123. catch error
  124. log '❌ Ошибка сохранения документа:', error
  125. throw error
  126. bulkDocs: (docs) ->
  127. @ensureInit()
  128. try
  129. result = await @localDb.bulkDocs(docs)
  130. log '📦 Пакетное сохранение документов:', docs.length
  131. return result
  132. catch error
  133. log '❌ Ошибка пакетного сохранения:', error
  134. throw error
  135. queryView: (designDoc, viewName, options = {}) ->
  136. @ensureInit()
  137. try
  138. result = await @localDb.query("#{designDoc}/#{viewName}", options)
  139. log '🔍 Выполнен запрос к view:', "#{designDoc}/#{viewName}"
  140. return result
  141. catch error
  142. log '❌ Ошибка запроса к view:', error
  143. throw error
  144. ensureInit: ->
  145. unless @initialized
  146. throw new Error('PouchDB сервис не инициализирован. Вызовите init() сначала.')
  147. destroy: ->
  148. if @syncHandler
  149. @syncHandler.cancel()
  150. if @localDb
  151. await @localDb.close()
  152. @initialized = false
  153. log '🔚 PouchDB сервис остановлен'
  154. module.exports = new PouchDBService({
  155. localDbName: 'braer_color_cache',
  156. remoteDbUrl: 'https://oleg:631074@couchdb.favt.ru.net/braer_color_shop',
  157. appVersion: '1.0.0'
  158. })