UNPKG

8.71 kBJavaScriptView Raw
1function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
3function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
4
5var io = requireSocketIo;
6
7var Emitter = require('component-emitter');
8
9var has = require('@uppy/utils/lib/hasProperty');
10
11var parseUrl = require('./parseUrl');
12
13var NetworkError = require('@uppy/utils/lib/NetworkError');
14
15var fetchWithNetworkError = require('@uppy/utils/lib/fetchWithNetworkError'); // Lazy load socket.io to avoid a console error
16// in IE 10 when the Transloadit plugin is not used.
17// (The console.error call comes from `buffer`. I
18// think we actually don't use that part of socket.io
19// at all…)
20
21
22var socketIo;
23
24function requireSocketIo() {
25 if (!socketIo) {
26 socketIo = require('socket.io-client');
27 }
28
29 return socketIo;
30}
31
32var ASSEMBLY_UPLOADING = 'ASSEMBLY_UPLOADING';
33var ASSEMBLY_EXECUTING = 'ASSEMBLY_EXECUTING';
34var ASSEMBLY_COMPLETED = 'ASSEMBLY_COMPLETED';
35var statusOrder = [ASSEMBLY_UPLOADING, ASSEMBLY_EXECUTING, ASSEMBLY_COMPLETED];
36/**
37 * Check that an assembly status is equal to or larger than some desired status.
38 * It checks for things that are larger so that a comparison like this works,
39 * when the old assembly status is UPLOADING but the new is FINISHED:
40 *
41 * !isStatus(oldStatus, ASSEMBLY_EXECUTING) && isStatus(newState, ASSEMBLY_EXECUTING)
42 *
43 * …so that we can emit the 'executing' event even if the execution step was so
44 * fast that we missed it.
45 */
46
47function isStatus(status, test) {
48 return statusOrder.indexOf(status) >= statusOrder.indexOf(test);
49}
50
51var TransloaditAssembly = /*#__PURE__*/function (_Emitter) {
52 _inheritsLoose(TransloaditAssembly, _Emitter);
53
54 function TransloaditAssembly(assembly) {
55 var _this;
56
57 _this = _Emitter.call(this) || this; // The current assembly status.
58
59 _this.status = assembly; // The socket.io connection.
60
61 _this.socket = null; // The interval timer for full status updates.
62
63 _this.pollInterval = null; // Whether this assembly has been closed (finished or errored)
64
65 _this.closed = false;
66 return _this;
67 }
68
69 var _proto = TransloaditAssembly.prototype;
70
71 _proto.connect = function connect() {
72 this._connectSocket();
73
74 this._beginPolling();
75 };
76
77 _proto._onFinished = function _onFinished() {
78 this.emit('finished');
79 this.close();
80 };
81
82 _proto._connectSocket = function _connectSocket() {
83 var _this2 = this;
84
85 var parsed = parseUrl(this.status.websocket_url);
86 var socket = io().connect(parsed.origin, {
87 transports: ['websocket'],
88 path: parsed.pathname
89 });
90 socket.on('connect', function () {
91 socket.emit('assembly_connect', {
92 id: _this2.status.assembly_id
93 });
94
95 _this2.emit('connect');
96 });
97 socket.on('connect_failed', function () {
98 _this2._onError(new NetworkError('Transloadit Socket.io connection error'));
99
100 _this2.socket = null;
101 });
102 socket.on('error', function () {
103 socket.disconnect();
104 _this2.socket = null;
105 });
106 socket.on('assembly_finished', function () {
107 _this2._onFinished();
108 });
109 socket.on('assembly_upload_finished', function (file) {
110 _this2.emit('upload', file);
111
112 _this2.status.uploads.push(file);
113 });
114 socket.on('assembly_uploading_finished', function () {
115 _this2.emit('executing');
116 });
117 socket.on('assembly_upload_meta_data_extracted', function () {
118 _this2.emit('metadata');
119
120 _this2._fetchStatus({
121 diff: false
122 });
123 });
124 socket.on('assembly_result_finished', function (stepName, result) {
125 _this2.emit('result', stepName, result);
126
127 if (!_this2.status.results[stepName]) {
128 _this2.status.results[stepName] = [];
129 }
130
131 _this2.status.results[stepName].push(result);
132 });
133 socket.on('assembly_error', function (err) {
134 _this2._onError(err); // Refetch for updated status code
135
136
137 _this2._fetchStatus({
138 diff: false
139 });
140 });
141 this.socket = socket;
142 };
143
144 _proto._onError = function _onError(err) {
145 this.emit('error', _extends(new Error(err.message), err));
146 }
147 /**
148 * Begin polling for assembly status changes. This sends a request to the
149 * assembly status endpoint every so often, if the socket is not connected.
150 * If the socket connection fails or takes a long time, we won't miss any
151 * events.
152 */
153 ;
154
155 _proto._beginPolling = function _beginPolling() {
156 var _this3 = this;
157
158 this.pollInterval = setInterval(function () {
159 if (!_this3.socket || !_this3.socket.connected) {
160 _this3._fetchStatus();
161 }
162 }, 2000);
163 }
164 /**
165 * Reload assembly status. Useful if the socket doesn't work.
166 *
167 * Pass `diff: false` to avoid emitting diff events, instead only emitting
168 * 'status'.
169 */
170 ;
171
172 _proto._fetchStatus = function _fetchStatus(_temp) {
173 var _this4 = this;
174
175 var _ref = _temp === void 0 ? {} : _temp,
176 _ref$diff = _ref.diff,
177 diff = _ref$diff === void 0 ? true : _ref$diff;
178
179 return fetchWithNetworkError(this.status.assembly_ssl_url).then(function (response) {
180 return response.json();
181 }).then(function (status) {
182 // Avoid updating if we closed during this request's lifetime.
183 if (_this4.closed) return;
184
185 _this4.emit('status', status);
186
187 if (diff) {
188 _this4.updateStatus(status);
189 } else {
190 _this4.status = status;
191 }
192 }).catch(function (err) {
193 return _this4._onError(err);
194 });
195 };
196
197 _proto.update = function update() {
198 return this._fetchStatus({
199 diff: true
200 });
201 }
202 /**
203 * Update this assembly's status with a full new object. Events will be
204 * emitted for status changes, new files, and new results.
205 *
206 * @param {object} next The new assembly status object.
207 */
208 ;
209
210 _proto.updateStatus = function updateStatus(next) {
211 this._diffStatus(this.status, next);
212
213 this.status = next;
214 }
215 /**
216 * Diff two assembly statuses, and emit the events necessary to go from `prev`
217 * to `next`.
218 *
219 * @param {object} prev The previous assembly status.
220 * @param {object} next The new assembly status.
221 */
222 ;
223
224 _proto._diffStatus = function _diffStatus(prev, next) {
225 var _this5 = this;
226
227 var prevStatus = prev.ok;
228 var nextStatus = next.ok;
229
230 if (next.error && !prev.error) {
231 return this._onError(next);
232 } // Desired emit order:
233 // - executing
234 // - (n × upload)
235 // - metadata
236 // - (m × result)
237 // - finished
238 // The below checks run in this order, that way even if we jump from
239 // UPLOADING straight to FINISHED all the events are emitted as expected.
240
241
242 var nowExecuting = isStatus(nextStatus, ASSEMBLY_EXECUTING) && !isStatus(prevStatus, ASSEMBLY_EXECUTING);
243
244 if (nowExecuting) {
245 // Without WebSockets, this is our only way to tell if uploading finished.
246 // Hence, we emit this just before the 'upload's and before the 'metadata'
247 // event for the most intuitive ordering, corresponding to the _usual_
248 // ordering (if not guaranteed) that you'd get on the WebSocket.
249 this.emit('executing');
250 } // Find new uploaded files.
251
252
253 Object.keys(next.uploads).filter(function (upload) {
254 return !has(prev.uploads, upload);
255 }).map(function (upload) {
256 return next.uploads[upload];
257 }).forEach(function (upload) {
258 _this5.emit('upload', upload);
259 });
260
261 if (nowExecuting) {
262 this.emit('metadata');
263 } // Find new results.
264
265
266 Object.keys(next.results).forEach(function (stepName) {
267 var nextResults = next.results[stepName];
268 var prevResults = prev.results[stepName];
269 nextResults.filter(function (n) {
270 return !prevResults || !prevResults.some(function (p) {
271 return p.id === n.id;
272 });
273 }).forEach(function (result) {
274 _this5.emit('result', stepName, result);
275 });
276 });
277
278 if (isStatus(nextStatus, ASSEMBLY_COMPLETED) && !isStatus(prevStatus, ASSEMBLY_COMPLETED)) {
279 this.emit('finished');
280 }
281 }
282 /**
283 * Stop updating this assembly.
284 */
285 ;
286
287 _proto.close = function close() {
288 this.closed = true;
289
290 if (this.socket) {
291 this.socket.disconnect();
292 this.socket = null;
293 }
294
295 clearInterval(this.pollInterval);
296 };
297
298 return TransloaditAssembly;
299}(Emitter);
300
301module.exports = TransloaditAssembly;
\No newline at end of file