1 | CACHE_RETRY_TIMEOUT = 60000
|
2 |
|
3 | module.exports = (providerParams, $q) ->
|
4 | {$log} = providerParams
|
5 | ResourceCacheEntry = require('./resource_cache_entry')(providerParams)
|
6 | Cache = require('./cache')(providerParams)
|
7 |
|
8 |
|
9 |
|
10 |
|
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(@)
|
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 |
|
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
|