spine-couch-changes.coffee 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. Spine = require('spine/core')
  2. db = require('db')
  3. duality = require('duality/core')
  4. session = require('session')
  5. feeds = {} # Cache `_changes` feeds by their url
  6. Spine.Model.CouchChanges = (opts = {})->
  7. opts.url = opts.url or duality.getDBURL()
  8. opts.handler = Spine.Model.CouchChanges.Changes unless opts.handler
  9. feeds[opts.url] or feeds[opts.url] =
  10. changes: new opts.handler opts
  11. extended: ->
  12. # need to keep _rev around to support changes feed processing
  13. @attributes.push "_rev" unless @attributes[ "_rev" ]
  14. @changes.subscribe @className, @
  15. Spine.Model.CouchChanges.Changes = class Changes
  16. subscribers: {}
  17. query: include_docs: yes
  18. constructor: (options = {})->
  19. @url = options.url
  20. @startListening()
  21. subscribe: (classname, klass) =>
  22. @subscribers[classname.toLowerCase()] = klass
  23. startListening: =>
  24. db.use(@url).changes @query, @handler()
  25. # returns handler which you may disable by setting handler.disabled flag `true`
  26. handler: -> self = (err, resp) =>
  27. if self.disabled then false
  28. else if err then false # TODO? @trigger error
  29. else
  30. @acceptChanges resp?.results
  31. true
  32. acceptChanges: (changes)->
  33. return unless changes
  34. Spine.CouchAjax.disable =>
  35. for doc in changes
  36. if type = doc.doc?.type
  37. klass = @subscribers[type]
  38. unless klass
  39. console.warn "changes: can't find subscriber for #{doc.doc.type}"
  40. continue
  41. atts = doc.doc
  42. atts.id = atts._id unless atts.id
  43. try
  44. obj = klass.find atts.id
  45. if doc.deleted
  46. obj.destroy()
  47. else
  48. unless obj._rev is atts._rev
  49. obj.updateAttributes atts
  50. catch e
  51. klass.create atts unless doc.deleted
  52. # Start listening for _changes only when user is authenticated
  53. # and stop listening for changes when he logged out
  54. Spine.Model.CouchChanges.PrivateChanges = class PrivateChanges extends Changes
  55. startListening: =>
  56. session.on "change", @authChanged
  57. authChanged: (userCtx)=>
  58. if userCtx.name
  59. @currentHandler.disabled = true if @currentHandler
  60. @currentHandler = @handler()
  61. db.use(@url).changes @query, @currentHandler
  62. else
  63. @currentHandler.disabled = true if @currentHandler