condo 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/README.textile +133 -133
  3. data/app/assets/javascripts/condo.js +9 -6
  4. data/app/assets/javascripts/condo/amazon.js +403 -406
  5. data/app/assets/javascripts/condo/condo.js +184 -0
  6. data/app/assets/javascripts/condo/config.js +69 -80
  7. data/app/assets/javascripts/condo/google.js +338 -255
  8. data/app/assets/javascripts/condo/md5/hash.worker.emulator.js +23 -23
  9. data/app/assets/javascripts/condo/md5/hash.worker.js +11 -11
  10. data/app/assets/javascripts/condo/md5/hasher.js +119 -100
  11. data/app/assets/javascripts/condo/md5/spark-md5.js +276 -161
  12. data/app/assets/javascripts/condo/rackspace.js +326 -329
  13. data/app/assets/javascripts/condo/{abstract-md5.js.erb → services/abstract-md5.js.erb} +86 -93
  14. data/app/assets/javascripts/condo/{base64.js → services/base64.js} +2 -10
  15. data/app/assets/javascripts/condo/services/broadcaster.js +26 -0
  16. data/app/assets/javascripts/condo/services/uploader.js +302 -0
  17. data/app/assets/javascripts/core/core.js +4 -0
  18. data/app/assets/javascripts/core/services/1-safe-apply.js +17 -0
  19. data/app/assets/javascripts/core/services/2-messaging.js +171 -0
  20. data/lib/condo.rb +269 -269
  21. data/lib/condo/configuration.rb +137 -139
  22. data/lib/condo/errors.rb +8 -8
  23. data/lib/condo/strata/amazon_s3.rb +301 -301
  24. data/lib/condo/strata/google_cloud_storage.rb +315 -314
  25. data/lib/condo/strata/rackspace_cloud_files.rb +245 -223
  26. data/lib/condo/version.rb +1 -1
  27. metadata +21 -44
  28. data/app/assets/javascripts/condo/broadcaster.js +0 -60
  29. data/app/assets/javascripts/condo/controller.js +0 -194
  30. data/app/assets/javascripts/condo/uploader.js +0 -310
  31. data/test/dummy/db/test.sqlite3 +0 -0
  32. data/test/dummy/log/test.log +0 -25
@@ -1,329 +1,326 @@
1
- /**
2
- * CoTag Condo Rackspace Cloud Files Strategy
3
- * Direct to cloud resumable uploads for Rackspace Cloud Files
4
- *
5
- * Copyright (c) 2012 CoTag Media.
6
- *
7
- * @author Stephen von Takach <steve@cotag.me>
8
- * @copyright 2012 cotag.me
9
- *
10
- *
11
- * References:
12
- * * https://github.com/umdjs/umd
13
- * * https://github.com/addyosmani/jquery-plugin-patterns
14
- * *
15
- *
16
- **/
17
-
18
- (function (factory) {
19
- if (typeof define === 'function' && define.amd) {
20
- // AMD
21
- define(['jquery', 'condo-uploader'], factory);
22
- } else {
23
- // Browser globals
24
- factory(jQuery);
25
- }
26
- }(function ($) {
27
- 'use strict';
28
-
29
- angular.module('CondoRackspaceProvider', ['CondoUploader', 'CondoAbstractMd5']).run(['$q', 'Condo.Registrar', 'Condo.Md5', function($q, registrar, md5) {
30
- var PENDING = 0,
31
- STARTED = 1,
32
- PAUSED = 2,
33
- UPLOADING = 3,
34
- COMPLETED = 4,
35
- ABORTED = 5,
36
-
37
-
38
- Rackspace = function (api, file) {
39
- var self = this,
40
- strategy = null,
41
- part_size = 2097152, // Multi-part uploads should be bigger then this
42
- pausing = false,
43
- defaultError = function(reason) {
44
- self.error = !pausing;
45
- pausing = false;
46
- self.pause(reason);
47
- },
48
-
49
- restart = function() {
50
- strategy = null;
51
- },
52
-
53
-
54
- completeUpload = function() {
55
- api.update().then(function(data) {
56
- self.state = COMPLETED;
57
- }, defaultError);
58
- },
59
-
60
-
61
- //
62
- // We need to sign our uploads so rackspace can confirm they are valid for us
63
- //
64
- build_request = function(part_number) {
65
- var current_part;
66
-
67
- if (file.size > part_size) { // If file bigger then 5mb we expect a chunked upload
68
- var endbyte = part_number * part_size;
69
- if (endbyte > file.size)
70
- endbyte = file.size;
71
- current_part = file.slice((part_number - 1) * part_size, endbyte);
72
- } else {
73
- current_part = file;
74
- }
75
-
76
- return md5.hash(current_part).then(function(val) {
77
- return {
78
- data: current_part,
79
- data_id: val,
80
- part_number: part_number
81
- }
82
- }, function(reason){
83
- return $q.reject(reason);
84
- });
85
- },
86
-
87
- //
88
- // Direct file upload strategy
89
- //
90
- RackspaceDirect = function(data) {
91
- //
92
- // resume
93
- // abort
94
- // pause
95
- //
96
- var $this = this,
97
- finalising = false;
98
-
99
- //
100
- // Update the parent
101
- //
102
- self.state = UPLOADING;
103
-
104
-
105
- //
106
- // This will only be called when the upload has finished and we need to inform the application
107
- //
108
- this.resume = function() {
109
- self.state = UPLOADING;
110
- completeUpload();
111
- }
112
-
113
- this.pause = function() {
114
- api.abort();
115
-
116
- if(!finalising) {
117
- restart(); // Should occur before events triggered
118
- self.progress = 0;
119
- }
120
- };
121
-
122
-
123
- //
124
- // AJAX for upload goes here
125
- //
126
- data['data'] = file;
127
- api.process_request(data, function(progress) {
128
- self.progress = progress;
129
- }).then(function(result) {
130
- finalising = true;
131
- $this.resume(); // Resume informs the application that the upload is complete
132
- }, function(reason) {
133
- self.progress = 0;
134
- defaultError(reason);
135
- });
136
- }, // END DIRECT
137
-
138
-
139
- //
140
- // Chunked upload strategy--------------------------------------------------
141
- //
142
- RackspaceChunked = function (data, first_chunk) {
143
- //
144
- // resume
145
- // abort
146
- // pause
147
- //
148
- var last_part = 0,
149
-
150
- //
151
- // Get the next part signature
152
- //
153
- next_part = function(part_number) {
154
- //
155
- // Check if we are past the end of the file
156
- //
157
- if ((part_number - 1) * part_size < file.size) {
158
- build_request(part_number).then(function(result) {
159
- if (self.state != UPLOADING)
160
- return; // upload was paused or aborted as we were reading the file
161
-
162
- api.update({
163
- resumable_id: part_number,
164
- file_id: result.data_id,
165
- part: part_number
166
- }).then(function(data) {
167
- set_part(data, result);
168
- }, defaultError);
169
-
170
- }, defaultError); // END BUILD_REQUEST
171
-
172
- } else {
173
- //
174
- // We're after the final commit
175
- //
176
- api.edit('finish').
177
- then(function(request) {
178
- api.process_request(request).then(completeUpload, defaultError);
179
- }, defaultError);
180
- }
181
- },
182
-
183
-
184
- //
185
- // Send a part to amazon
186
- //
187
- set_part = function(request, part_info) {
188
- request['data'] = part_info.data;
189
- api.process_request(request, function(progress) {
190
- self.progress = (part_info.part_number - 1) * part_size + progress;
191
- }).then(function(result) {
192
- last_part = part_info.part_number;
193
- next_part(last_part + 1);
194
- }, function(reason) {
195
- self.progress = (part_info.part_number - 1) * part_size;
196
- defaultError(reason);
197
- });
198
- };
199
-
200
-
201
- self.state = UPLOADING;
202
-
203
- this.resume = function() {
204
- self.state = UPLOADING;
205
- next_part(last_part + 1);
206
- };
207
-
208
- this.pause = function() {
209
- api.abort();
210
- };
211
-
212
-
213
- //
214
- // We need to check if we are resuming or starting an upload
215
- //
216
- if(data.type == 'parts') {
217
- next_part(data.current_part);
218
- } else {
219
- set_part(data, first_chunk);
220
- }
221
- }; // END CHUNKED
222
-
223
-
224
- //
225
- // Variables required for all drivers
226
- //
227
- this.state = PENDING;
228
- this.progress = 0;
229
- this.message = 'pending';
230
- this.name = file.name;
231
- this.size = file.size;
232
- this.error = false;
233
-
234
-
235
- //
236
- // Support file slicing
237
- //
238
- if (typeof(file.slice) != 'function')
239
- file.slice = file.webkitSlice || file.mozSlice;
240
-
241
-
242
- this.start = function(){
243
- if(strategy == null) { // We need to create the upload
244
-
245
- pausing = false;
246
- this.error = false;
247
- this.message = null;
248
- this.state = STARTED;
249
- strategy = {}; // This function shouldn't be called twice so we need a state (TODO:: fix this)
250
-
251
- build_request(1).then(function(result) {
252
- if (self.state != STARTED)
253
- return; // upload was paused or aborted as we were reading the file
254
-
255
- api.create({file_id: result.data_id}).
256
- then(function(data) {
257
- if(data.type == 'direct_upload') {
258
- strategy = new RackspaceDirect(data);
259
- } else {
260
- strategy = new RackspaceChunked(data, result);
261
- }
262
- }, defaultError);
263
-
264
- }, defaultError); // END BUILD_REQUEST
265
-
266
-
267
- } else if (this.state == PAUSED) { // We need to resume the upload if it is paused
268
-
269
- pausing = false;
270
- this.error = false;
271
- this.message = null;
272
- strategy.resume();
273
- }
274
- };
275
-
276
- this.pause = function(reason) {
277
- if(strategy != null && this.state == UPLOADING) { // Check if the upload is uploading
278
- this.state = PAUSED;
279
- pausing = true;
280
- strategy.pause();
281
- } else if (this.state <= STARTED) {
282
- this.state = PAUSED;
283
- restart();
284
- }
285
- if(this.state == PAUSED)
286
- this.message = reason;
287
- };
288
-
289
- this.abort = function(reason) {
290
- if(strategy != null && this.state < COMPLETED) { // Check the upload has not finished
291
- var old_state = this.state;
292
-
293
- this.state = ABORTED;
294
- api.abort();
295
-
296
-
297
- //
298
- // As we may not have successfully deleted the upload
299
- // or we aborted before we received a response from create
300
- //
301
- restart(); // nullifies strategy
302
-
303
-
304
- //
305
- // if we have an upload_id then we should destroy the upload
306
- // we won't worry if this fails as it should be automatically cleaned up by the back end
307
- //
308
- if(old_state > STARTED) {
309
- api.destroy();
310
- }
311
-
312
- this.message = reason;
313
- }
314
- };
315
- }; // END RACKSPACE
316
-
317
-
318
- //
319
- // Register the residence with the API
320
- // Dependency injection succeeded
321
- //
322
- registrar.register('RackspaceCloudFiles', {
323
- new_upload: function(api, file) {
324
- return new Rackspace(api, file);
325
- }
326
- });
327
- }]);
328
-
329
- }));
1
+ /**
2
+ * CoTag Condo Rackspace Cloud Files Strategy
3
+ * Direct to cloud resumable uploads for Rackspace Cloud Files
4
+ *
5
+ * Copyright (c) 2012 CoTag Media.
6
+ *
7
+ * @author Stephen von Takach <steve@cotag.me>
8
+ * @copyright 2012 cotag.me
9
+ *
10
+ *
11
+ * References:
12
+ * *
13
+ *
14
+ **/
15
+
16
+
17
+ (function(angular, undefined) {
18
+ 'use strict';
19
+
20
+ angular.module('Condo').
21
+
22
+ factory('Condo.Rackspace', ['$q', 'Condo.Md5', function($q, md5) {
23
+ var PENDING = 0,
24
+ STARTED = 1,
25
+ PAUSED = 2,
26
+ UPLOADING = 3,
27
+ COMPLETED = 4,
28
+ ABORTED = 5,
29
+
30
+
31
+ Rackspace = function (api, file) {
32
+ var self = this,
33
+ strategy = null,
34
+ part_size = 2097152, // Multi-part uploads should be bigger then this
35
+ pausing = false,
36
+ defaultError = function(reason) {
37
+ self.error = !pausing;
38
+ pausing = false;
39
+ self.pause(reason);
40
+ },
41
+
42
+ restart = function() {
43
+ strategy = null;
44
+ },
45
+
46
+
47
+ completeUpload = function() {
48
+ api.update().then(function(data) {
49
+ self.progress = self.size; // Update to 100%
50
+ self.state = COMPLETED;
51
+ }, defaultError);
52
+ },
53
+
54
+
55
+ //
56
+ // We need to sign our uploads so rackspace can confirm they are valid for us
57
+ //
58
+ build_request = function(part_number) {
59
+ var current_part;
60
+
61
+ if (file.size > part_size) { // If file bigger then 5mb we expect a chunked upload
62
+ var endbyte = part_number * part_size;
63
+ if (endbyte > file.size)
64
+ endbyte = file.size;
65
+ current_part = file.slice((part_number - 1) * part_size, endbyte);
66
+ } else {
67
+ current_part = file;
68
+ }
69
+
70
+ return md5.hash(current_part).then(function(val) {
71
+ return {
72
+ data: current_part,
73
+ data_id: val,
74
+ part_number: part_number
75
+ }
76
+ }, function(reason){
77
+ return $q.reject(reason);
78
+ });
79
+ },
80
+
81
+ //
82
+ // Direct file upload strategy
83
+ //
84
+ RackspaceDirect = function(data) {
85
+ //
86
+ // resume
87
+ // abort
88
+ // pause
89
+ //
90
+ var $this = this,
91
+ finalising = false;
92
+
93
+ //
94
+ // Update the parent
95
+ //
96
+ self.state = UPLOADING;
97
+
98
+
99
+ //
100
+ // This will only be called when the upload has finished and we need to inform the application
101
+ //
102
+ this.resume = function() {
103
+ self.state = UPLOADING;
104
+ completeUpload();
105
+ }
106
+
107
+ this.pause = function() {
108
+ api.abort();
109
+
110
+ if(!finalising) {
111
+ restart(); // Should occur before events triggered
112
+ self.progress = 0;
113
+ }
114
+ };
115
+
116
+
117
+ //
118
+ // AJAX for upload goes here
119
+ //
120
+ data['data'] = file;
121
+ api.process_request(data, function(progress) {
122
+ self.progress = progress;
123
+ }).then(function(result) {
124
+ finalising = true;
125
+ $this.resume(); // Resume informs the application that the upload is complete
126
+ }, function(reason) {
127
+ self.progress = 0;
128
+ defaultError(reason);
129
+ });
130
+ }, // END DIRECT
131
+
132
+
133
+ //
134
+ // Chunked upload strategy--------------------------------------------------
135
+ //
136
+ RackspaceChunked = function (data, first_chunk) {
137
+ //
138
+ // resume
139
+ // abort
140
+ // pause
141
+ //
142
+ var last_part = 0,
143
+
144
+ //
145
+ // Get the next part signature
146
+ //
147
+ next_part = function(part_number) {
148
+ //
149
+ // Check if we are past the end of the file
150
+ //
151
+ if ((part_number - 1) * part_size < file.size) {
152
+
153
+ self.progress = (part_number - 1) * part_size; // Update the progress
154
+
155
+ build_request(part_number).then(function(result) {
156
+ if (self.state != UPLOADING)
157
+ return; // upload was paused or aborted as we were reading the file
158
+
159
+ api.update({
160
+ resumable_id: part_number,
161
+ file_id: result.data_id,
162
+ part: part_number
163
+ }).then(function(data) {
164
+ set_part(data, result);
165
+ }, defaultError);
166
+
167
+ }, defaultError); // END BUILD_REQUEST
168
+
169
+ } else {
170
+ //
171
+ // We're after the final commit
172
+ //
173
+ api.edit('finish').
174
+ then(function(request) {
175
+ api.process_request(request).then(completeUpload, defaultError);
176
+ }, defaultError);
177
+ }
178
+ },
179
+
180
+
181
+ //
182
+ // Send a part to rackspace
183
+ //
184
+ set_part = function(request, part_info) {
185
+ request['data'] = part_info.data;
186
+ api.process_request(request, function(progress) {
187
+ self.progress = (part_info.part_number - 1) * part_size + progress;
188
+ }).then(function(result) {
189
+ last_part = part_info.part_number;
190
+ next_part(last_part + 1);
191
+ }, function(reason) {
192
+ self.progress = (part_info.part_number - 1) * part_size;
193
+ defaultError(reason);
194
+ });
195
+ };
196
+
197
+
198
+ self.state = UPLOADING;
199
+
200
+ this.resume = function() {
201
+ self.state = UPLOADING;
202
+ next_part(last_part + 1);
203
+ };
204
+
205
+ this.pause = function() {
206
+ api.abort();
207
+ };
208
+
209
+
210
+ //
211
+ // We need to check if we are resuming or starting an upload
212
+ //
213
+ if(data.type == 'parts') {
214
+ next_part(data.current_part);
215
+ } else {
216
+ set_part(data, first_chunk);
217
+ }
218
+ }; // END CHUNKED
219
+
220
+
221
+ //
222
+ // Variables required for all drivers
223
+ //
224
+ this.state = PENDING;
225
+ this.progress = 0;
226
+ this.message = 'pending';
227
+ this.name = file.name;
228
+ this.size = file.size;
229
+ this.error = false;
230
+
231
+
232
+ //
233
+ // Support file slicing
234
+ //
235
+ if (typeof(file.slice) != 'function')
236
+ file.slice = file.webkitSlice || file.mozSlice;
237
+
238
+
239
+ this.start = function(){
240
+ if(strategy == null) { // We need to create the upload
241
+
242
+ pausing = false;
243
+ this.error = false;
244
+ this.message = null;
245
+ this.state = STARTED;
246
+ strategy = {}; // This function shouldn't be called twice so we need a state (TODO:: fix this)
247
+
248
+ build_request(1).then(function(result) {
249
+ if (self.state != STARTED)
250
+ return; // upload was paused or aborted as we were reading the file
251
+
252
+ api.create({file_id: result.data_id}).
253
+ then(function(data) {
254
+ if(data.type == 'direct_upload') {
255
+ strategy = new RackspaceDirect(data);
256
+ } else {
257
+ strategy = new RackspaceChunked(data, result);
258
+ }
259
+ }, defaultError);
260
+
261
+ }, defaultError); // END BUILD_REQUEST
262
+
263
+
264
+ } else if (this.state == PAUSED) { // We need to resume the upload if it is paused
265
+
266
+ pausing = false;
267
+ this.error = false;
268
+ this.message = null;
269
+ strategy.resume();
270
+ }
271
+ };
272
+
273
+ this.pause = function(reason) {
274
+ if(strategy != null && this.state == UPLOADING) { // Check if the upload is uploading
275
+ this.state = PAUSED;
276
+ pausing = true;
277
+ strategy.pause();
278
+ } else if (this.state <= STARTED) {
279
+ this.state = PAUSED;
280
+ restart();
281
+ }
282
+ if(this.state == PAUSED)
283
+ this.message = reason;
284
+ };
285
+
286
+ this.abort = function(reason) {
287
+ if(strategy != null && this.state < COMPLETED) { // Check the upload has not finished
288
+ var old_state = this.state;
289
+
290
+ this.state = ABORTED;
291
+ api.abort();
292
+
293
+
294
+ //
295
+ // As we may not have successfully deleted the upload
296
+ // or we aborted before we received a response from create
297
+ //
298
+ restart(); // nullifies strategy
299
+
300
+
301
+ //
302
+ // if we have an upload_id then we should destroy the upload
303
+ // we won't worry if this fails as it should be automatically cleaned up by the back end
304
+ //
305
+ if(old_state > STARTED) {
306
+ api.destroy();
307
+ }
308
+
309
+ this.message = reason;
310
+ }
311
+ };
312
+ }; // END RACKSPACE
313
+
314
+
315
+ return {
316
+ new_upload: function(api, file) {
317
+ return new Rackspace(api, file);
318
+ }
319
+ };
320
+ }]).
321
+
322
+ config(['Condo.ApiProvider', function (ApiProvider) {
323
+ ApiProvider.register('RackspaceCloudFiles', 'Condo.Rackspace');
324
+ }]);
325
+
326
+ })(angular);