UNPKG

5.29 kBtext/coffeescriptView Raw
1CACHE_RETRY_TIMEOUT = 60000 # one minute
2
3module.exports = (providerParams, $q) ->
4 {$log} = providerParams
5 ResourceCacheEntry = require('./resource_cache_entry')(providerParams)
6 Cache = require('./cache')(providerParams)
7
8 # this could be a lot nicer with ES6 WeakMaps
9 # (http://www.nczonline.net/blog/2014/01/21/private-instance-members-with-weakmaps-in-javascript/)
10 # but till then this is to maintain private instance members
11 flushQueueDeferreds = {}
12 resetDeferred = (queue) ->
13 deferred = $q.defer()
14 flushQueueDeferreds[queue.key] = deferred
15 queue.promise = deferred.promise
16 deferred
17 resolveDeferred = (queue) ->
18 flushQueueDeferreds[queue.key].resolve()
19
20 class ResourceWriteQueue
21 logStatusOfRequest: (status, action, params, data) ->
22 $log.debug("#{action} for #{@key} #{angular.toJson(params)} #{status} (queue length: #{@queue.length})", data)
23
24 constructor: (@CachedResource, @$timeout) ->
25 @key = "#{@CachedResource.$key}/write"
26 @queue = Cache.getItem(@key, [])
27 write.busy = false for write in @queue
28 resetDeferred(@)
29 if @queue.length is 0
30 resolveDeferred(@) # initialize the queue with a resolved promise
31
32 enqueue: (params, resourceData, action, deferred) ->
33 resetDeferred(@) if @queue.length is 0
34 resourceParams = if angular.isArray(resourceData)
35 resourceData.map((resource) -> resource.$params())
36 else
37 resourceData.$params()
38
39 write = @findWrite {params, action}
40 if not write?
41 @queue.push {params, resourceParams, action, deferred}
42 @_update()
43 else
44 write.deferred?.promise.then (response) ->
45 deferred.resolve response
46 write.deferred?.promise.catch (error) ->
47 deferred.reject error
48 @logStatusOfRequest('enqueued', action, params, resourceData)
49
50 findWrite: ({action, params}) ->
51 for write in @queue
52 return write if action is write.action and angular.equals(params, write.params)
53
54 removeWrite: ({action, params}) ->
55 newQueue = []
56 for entry in @queue
57 newQueue.push entry unless action is entry.action and angular.equals(params, entry.params)
58 @queue = newQueue
59
60 if @queue.length is 0 and @timeoutPromise
61 @$timeout.cancel @timeoutPromise
62 delete @timeoutPromise
63
64 @_update()
65
66 resolveDeferred @ if @queue.length is 0
67
68 flush: (done) ->
69 @promise.then done if angular.isFunction(done)
70 @_setFlushTimeout()
71 @_processWrite(write) for write in @queue
72
73 processResource: (params, done) ->
74 notDone = true
75 for write in @_writesForResource(params)
76 @_processWrite write, =>
77 if notDone and @_writesForResource(params).length is 0
78 notDone = false
79 done()
80
81 _writesForResource: (params) ->
82 # TODO FIX FIX FIXME this should compare against individual write.resourceParams, which could be a nested array
83 write for write in @queue when angular.equals(params, write.params)
84
85 _processWrite: (write, done) ->
86 return if write.busy
87 write.busy = true
88
89 if angular.isArray(write.resourceParams)
90 cacheEntries = write.resourceParams.map (resourceParams) =>
91 new ResourceCacheEntry(@CachedResource.$key, resourceParams).load()
92 writeData = cacheEntries.map (cacheEntry) -> cacheEntry.value
93 else
94 cacheEntries = [new ResourceCacheEntry(@CachedResource.$key, write.resourceParams).load()]
95 writeData = cacheEntries[0].value
96
97 onSuccess = (value) =>
98 @removeWrite write
99 write.deferred?.resolve value
100 @logStatusOfRequest('succeeded', write.action, write.resourceParams, writeData)
101 done() if angular.isFunction(done)
102 onFailure = (error) =>
103 if error and error.status >= 400 and error.status < 500
104 @removeWrite write
105 $log.error "#{write.action} to #{@CachedResource.$key} failed with error #{error.status}",
106 { method: error.config.method, url: error.config.url, writeData }
107 else
108 write.busy = false
109 @logStatusOfRequest("failed with error #{angular.toJson error}; still in queue", write.action, write.resourceParams, writeData)
110 write.deferred?.reject error
111
112 @CachedResource.$resource[write.action](write.params, writeData, onSuccess, onFailure).$promise.then (savedResources) =>
113 savedResources = if angular.isArray(savedResources) then savedResources else [savedResources]
114 for resource in savedResources
115 resourceInstance = new @CachedResource(resource)
116 cacheEntry = new ResourceCacheEntry(@CachedResource.$key, resourceInstance.$params()).load()
117 cacheEntry.set(resource, false)
118
119 @logStatusOfRequest('processed', write.action, write.resourceParams, writeData)
120
121 _setFlushTimeout: ->
122 if @queue.length > 0 and not @timeoutPromise
123 @timeoutPromise = @$timeout angular.bind(@, @flush), CACHE_RETRY_TIMEOUT
124 @timeoutPromise.then =>
125 delete @timeoutPromise
126 @_setFlushTimeout()
127
128 _update: ->
129 savableQueue = @queue.map (write) ->
130 params: write.params
131 resourceParams: write.resourceParams
132 action: write.action
133 Cache.setItem @key, savableQueue