4 * Copyright 2016 RIFT.IO Inc
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 import _
from 'lodash'
22 import alt
from '../alt'
23 import guid
from '../libraries/guid'
24 import numeral
from 'numeral'
25 import moment
from 'moment'
26 import utils
from '../libraries/utils'
27 import CatalogPackageManagerSource
from '../sources/CatalogPackageManagerSource'
28 import CatalogPackageManagerActions
from '../actions/CatalogPackageManagerActions'
29 import CatalogDataSource
from '../sources/CatalogDataSource'
31 import imgDownload
from '../../../node_modules/open-iconic/svg/cloud-download.svg'
32 import imgOnboard
from '../../../node_modules/open-iconic/svg/cloud-upload.svg'
33 import imgUpdate
from '../../../node_modules/open-iconic/svg/data-transfer-upload.svg'
43 message
: 'Requesting catalog package export...',
50 checkStatusDelayInSeconds
: 2,
51 downloadUrlTimeToLiveInMinutes
: 5
54 const exception
= function ignoreException() {};
56 const packagePropertyNames
= Object
.keys(defaults
.downloadPackage
);
58 function getCatalogPackageManagerServerOrigin() {
59 return utils
.getSearchParams(window
.location
).upload_server
+ ':4567';
62 function delayStatusCheck(statusCheckFunction
, catalogPackage
) {
63 if (!catalogPackage
.checkStatusTimeoutId
) {
64 const delayCallback = function () {
65 delete catalogPackage
.checkStatusTimeoutId
;
66 statusCheckFunction(catalogPackage
).catch(exception
);
68 catalogPackage
.checkStatusTimeoutId
= _
.delay(delayCallback
, defaults
.checkStatusDelayInSeconds
* 1000);
72 class CatalogPackageManagerStore
{
78 this.registerAsync(CatalogDataSource
);
79 this.registerAsync(CatalogPackageManagerSource
);
80 this.bindAction(CatalogPackageManagerActions
.REMOVE_CATALOG_PACKAGE
, this.removeCatalogPackage
);
81 this.bindAction(CatalogPackageManagerActions
.DOWNLOAD_CATALOG_PACKAGE
, this.downloadCatalogPackage
);
82 this.bindAction(CatalogPackageManagerActions
.DOWNLOAD_CATALOG_PACKAGE_STATUS_UPDATED
, this.onDownloadCatalogPackageStatusUpdated
);
83 this.bindAction(CatalogPackageManagerActions
.DOWNLOAD_CATALOG_PACKAGE_ERROR
, this.onDownloadCatalogPackageError
);
84 this.bindAction(CatalogPackageManagerActions
.UPLOAD_CATALOG_PACKAGE
, this.uploadCatalogPackage
);
85 this.bindAction(CatalogPackageManagerActions
.UPLOAD_CATALOG_PACKAGE_STATUS_UPDATED
, this.onUploadCatalogPackageStatusUpdated
);
86 this.bindAction(CatalogPackageManagerActions
.UPLOAD_CATALOG_PACKAGE_ERROR
, this.onUploadCatalogPackageError
);
90 addPackage(catalogPackage
) {
91 const packages
= [catalogPackage
].concat(this.packages
);
92 this.setState({packages
: packages
});
95 updatePackage(catalogPackage
) {
96 const packages
= this.packages
.map(d
=> {
97 if (d
.id
=== catalogPackage
.id
) {
98 return Object
.assign({}, d
, catalogPackage
);
102 this.setState({packages
: packages
});
105 removeCatalogPackage(catalogPackage
) {
106 const packages
= this.packages
.filter(d
=> d
.id
!== catalogPackage
.id
);
107 this.setState({packages
: packages
});
110 uploadCatalogPackage(file
) {
111 file
.id
= file
.id
|| guid();
112 const catalogPackage
= _
.pick(file
, packagePropertyNames
);
113 catalogPackage
.icon
= file
.riftAction
=== 'onboard' ? imgOnboard
: imgUpdate
;
114 catalogPackage
.type
= 'upload';
115 this.addPackage(catalogPackage
);
116 // note DropZone.js handles the async upload so we don't have to invoke any async action creators
119 onUploadCatalogPackageStatusUpdated(response
) {
120 const upload
= updateStatusInfo(response
);
121 this.updatePackage(upload
);
122 // if pending with no transaction id - do nothing
123 // bc DropZone.js will notify upload progress
124 if (upload
.pending
&& upload
.transactionId
) {
125 delayStatusCheck(this.getInstance().requestCatalogPackageUploadStatus
, upload
);
126 } else if (upload
.success
) {
127 this.getInstance().loadCatalogs();
131 onUploadCatalogPackageError(response
) {
132 console
.warn('onUploadCatalogPackageError', response
);
133 const catalogPackage
= updateStatusInfo(response
);
134 this.updatePackage(catalogPackage
);
137 downloadCatalogPackage(data
) {
138 let catalogItems
= data
['selectedItems'] || [];
139 let schema
= data
['selectedFormat'] || 'mano';
140 let grammar
= data
['selectedGrammar'] || 'osm';
142 if (catalogItems
.length
) {
143 const catalogPackage
= Object
.assign({}, defaults
.downloadPackage
, {id
: guid()});
144 catalogPackage
.name
= catalogItems
[0].name
;
145 catalogPackage
.type
= 'download';
146 if (catalogItems
.length
> 1) {
147 catalogPackage
.name
+= ' (' + catalogItems
.length
+ ' items)';
149 catalogPackage
.ids
= catalogItems
.map(d
=> d
.id
).sort().toString();
150 catalogPackage
.catalogItems
= catalogItems
;
151 this.addPackage(catalogPackage
);
152 this.getInstance().requestCatalogPackageDownload(catalogPackage
, format
, grammar
, schema
).catch(exception
);
156 onDownloadCatalogPackageStatusUpdated(response
) {
157 const download
= updateStatusInfo(response
);
158 this.updatePackage(download
);
159 if (download
.pending
) {
160 delayStatusCheck(this.getInstance().requestCatalogPackageDownloadStatus
, download
);
164 onDownloadCatalogPackageError(response
) {
165 console
.warn('onDownloadCatalogPackageError', response
);
166 const catalogPackage
= updateStatusInfo(response
);
167 this.updatePackage(catalogPackage
);
172 function calculateUploadProgressMessage(size
= 0, progress
= 0, bytesSent
= 0) {
173 const amount
= parseFloat(progress
) || 0;
174 const loaded
= amount
=== 100 ? size
: size
* amount
/ 100;
176 if (amount
=== 100) {
177 progressText
= numeral(loaded
).format('0.0b') + ' loaded ';
178 } else if (typeof amount
=== 'number' && amount
!= 0) {
179 progressText
= numeral(bytesSent
).format('0.0b') + ' out of ' + numeral(size
).format('0.0b');
181 progressText
= progress
;
186 function updateStatusInfo(response
) {
187 // returns the catalogPackage object with the status fields updated based on the server response
193 const responseData
= (response
.data
.output
) ? response
.data
.output
: response
.data
;
194 const catalogPackage
= response
.state
;
195 switch(response
.data
.status
) {
196 case 'upload-progress':
197 statusInfo
.pending
= true;
198 statusInfo
.progress
= parseFloat(responseData
.progress
) || 0;
199 statusInfo
.message
= calculateUploadProgressMessage(catalogPackage
.size
, responseData
.progress
, responseData
.bytesSent
);
201 case 'upload-success':
202 statusInfo
.pending
= true;
203 statusInfo
.progress
= 100;
204 statusInfo
.message
= 'Upload completed.';
205 statusInfo
.transactionId
= responseData
['transaction-id'] || catalogPackage
.transactionId
;
208 statusInfo
.error
= true;
209 statusInfo
.message
= responseData
.message
;
211 case 'download-requested':
212 statusInfo
.pending
= true;
213 statusInfo
.progress
= 25;
214 statusInfo
.transactionId
= responseData
['transaction-id'] || catalogPackage
.transactionId
;
217 statusInfo
.pending
= true;
218 statusInfo
.progress
= 50;
219 statusInfo
.message
= responseData
.events
[responseData
.events
.length
- 1].text
;
222 statusInfo
.success
= true;
223 statusInfo
.progress
= 100;
224 statusInfo
.message
= responseData
.events
[responseData
.events
.length
- 1].text
;
225 if (catalogPackage
.type
=== 'download') {
226 statusInfo
.urlValidUntil
= moment().add(defaults
.downloadUrlTimeToLiveInMinutes
, 'minutes').toISOString();
227 if (responseData
.filename
) {
228 statusInfo
.url
= getCatalogPackageManagerServerOrigin() + '/api/export/' + responseData
.filename
;
230 statusInfo
.url
= getCatalogPackageManagerServerOrigin() + '/api/export/' + catalogPackage
.transactionId
+ '.tar.gz';
235 statusInfo
.error
= true;
236 statusInfo
.message
= responseData
.errors
[0].value
;
239 throw new ReferenceError('a status of "request", "success", "failure", "pending", "upload-completed", "upload-error", "download-requested", "upload-progress", "upload-action" is required');
241 return Object
.assign({}, catalogPackage
, statusInfo
);
244 export default alt
.createStore(CatalogPackageManagerStore
, 'CatalogPackageManagerStore');