condo 1.0.4 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
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);