IF YOU WOULD LIKE TO GET AN ACCOUNT, please write an email to s dot adaszewski at gmail dot com. User accounts are meant only to report issues and/or generate pull requests. This is a purpose-specific Git hosting for ADARED projects. Thank you for your understanding!
Browse Source

Implemented file download but held back by CORS issues.

pull/1/head
parent
commit
694d8d5a52
7 changed files with 110 additions and 6 deletions
  1. +1
    -0
      frontend/package.json
  2. +2
    -0
      frontend/rollup.config.js
  3. +2
    -0
      frontend/src/html/index.html
  4. +10
    -1
      frontend/src/js/component/wb-collection-content.js
  5. +17
    -5
      frontend/src/js/misc/make-arvados-request.js
  6. +13
    -0
      frontend/src/js/misc/wb-collection-manifest.js
  7. +65
    -0
      frontend/src/js/misc/wb-download-file.js

+ 1
- 0
frontend/package.json View File

@@ -2,6 +2,7 @@
"dependencies": {
"@fortawesome/fontawesome-free": "^5.12.0",
"bootstrap": "^4.4.1",
"crypto-js": "^3.1.9-1",
"filesize": "^6.0.1",
"jquery": "^3.4.1",
"js-uuid": "0.0.6",


+ 2
- 0
frontend/rollup.config.js View File

@@ -43,6 +43,8 @@ export default {
'node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.woff2': 'dist/webfonts/fa-brands-400.woff2',
'node_modules/js-uuid/js-uuid.js': 'dist/js/js-uuid.js',
'node_modules/filesize/lib/filesize.js': 'dist/js/filesize.js',
'node_modules/crypto-js/core.js': 'dist/js/crypto-js/core.js',
'node_modules/crypto-js/md5.js': 'dist/js/crypto-js/md5.js',
verbose: true
}),
buble({jsx: 'h'}),


+ 2
- 0
frontend/src/html/index.html View File

@@ -9,6 +9,8 @@
<script language="javascript" src="/js/fontawesome.min.js"></script>
<script language="javascript" src="/js/js-uuid.js"></script>
<script language="javascript" src="/js/filesize.js"></script>
<script language="javascript" src="/js/crypto-js/core.js"></script>
<script language="javascript" src="/js/crypto-js/md5.js"></script>
</head>
<body>
<script language="javascript" src="/js/app.min.js"></script>


+ 10
- 1
frontend/src/js/component/wb-collection-content.js View File

@@ -3,6 +3,7 @@ import WBTable from 'wb-table';
import WBBreadcrumbs from 'wb-breadcrumbs';
import { WBManifestReader } from 'wb-collection-manifest';
import makeArvadosRequest from 'make-arvados-request';
import wbDownloadFile from 'wb-download-file';
class WBCollectionContent extends Component {
constructor(...args) {
@@ -41,6 +42,7 @@ class WBCollectionContent extends Component {
prepareRows() {
let { manifestReader } = this.state;
let { collectionPath } = this.props;
let { arvHost, arvToken } = this.props.app.state;
//path = path.split('/');
//path = [ '.' ].concat(path);
@@ -58,7 +60,14 @@ class WBCollectionContent extends Component {
(<a href={ this.getUrl({ 'collectionPath': collectionPath + '/' + item[1] }) }>{ item[1] }</a>),
'File',
filesize(item[2]),
(<div></div>)
(<div>
<button class="btn btn-outline-primary mx-1" title="Download"
onclick={ () => wbDownloadFile(arvHost, arvToken, manifestReader,
'.' + collectionPath + '/' + item[1]) }><i class="fas fa-download"></i></button>
<button class="btn btn-outline-primary mx-1" title="View"
onclick={ () => wbDownloadFile(arvHost, arvToken, manifestReader,
'.' + collectionPath + '/' + item[1]) }><i class="far fa-eye"></i></button>
</div>)
]
))
});


+ 17
- 5
frontend/src/js/misc/make-arvados-request.js View File

@@ -1,13 +1,25 @@
function makeArvadosRequest(arvHost, arvToken, endpoint, method='GET', data=null,
contentType='application/json;charset=utf-8', responseType='json') {
function makeArvadosRequest(arvHost, arvToken, endpoint, params={}) {
const defaultParams = {
'method': 'GET',
'data': null,
'contentType': 'application/json;charset=utf-8',
'responseType': 'json',
'useSsl': true,
'requireToken': true
};
if (!arvHost || !arvToken)
Object.keys(defaultParams).map(k => (params[k] =
(k in params ? params[k] : defaultParams[k])));
let { method, data, contentType, responseType, useSsl, requireToken } = params;
if (!(arvHost && (arvToken || !requireToken)))
return new Promise((accept, reject) => reject());
let xhr = new XMLHttpRequest();
xhr.open(method, 'https://' + arvHost + endpoint);
xhr.setRequestHeader('Authorization', 'OAuth2 ' + arvToken);
xhr.open(method, (useSsl ? 'https://' : 'http://') + arvHost + endpoint);
if (arvToken)
xhr.setRequestHeader('Authorization', 'OAuth2 ' + arvToken);
if (data !== null)
xhr.setRequestHeader('Content-Type', contentType);
xhr.responseType = responseType;


+ 13
- 0
frontend/src/js/misc/wb-collection-manifest.js View File

@@ -161,6 +161,19 @@ class WBManifestReader {
out = b;
}
}*/
getFile(path) {
if (typeof(path) === 'string')
path = path.split('/');
if (path.length < 2)
throw Error('Invalid file path');
let name = path[path.length - 1];
let dir = this.findDir(path.slice(0, path.length - 1));
if (!(name in dir))
throw Error('File not found');
if (!(dir[name] instanceof Array))
throw Error('Path points to a directory not a file');
return dir[name];
}
}
export { WBManifestReader };

+ 65
- 0
frontend/src/js/misc/wb-download-file.js View File

@@ -0,0 +1,65 @@
import makeArvadosRequest from 'make-arvados-request';
function rdvHash(serviceId, locator) {
let blockHash = /^[0-9a-f]{32}/.exec(locator);
if (!blockHash)
throw Error('Invalid locator');
if (typeof(serviceId) !== 'string')
throw Error('Invalid service ID');
let res = CryptoJS.MD5(serviceId + blockHash).toString();
return res;
}
function wbDownloadFile(arvHost, arvToken,
manifestReader, path) {
const file = manifestReader.getFile(path);
const name = path.split('/').reverse()[0];
const blockRefs = file[0];
let services;
let prom = makeArvadosRequest(arvHost, arvToken,
'/arvados/v1/keep_services/accessible');
prom = prom.then(xhr => (services = xhr.response['items']));
const blocks = [];
for (let i = 0; i < blockRefs.length; i++) {
prom = prom.then(() => {
const [ locator, position, size ] = blockRefs[i];
const weights = services.map(s => rdvHash(s['uuid'], locator));
const order = Object.keys(services).sort((a, b) => weights[b].localeCompare(weights[a]));
const orderedServices = order.map(i => services[i]);
let k = 0;
const cb = () => {
if (k >= orderedServices.length)
throw Error('Block not found');
const svc = orderedServices[k];
k++;
let prom_1 = makeArvadosRequest(svc.service_host +
':' + svc.service_port, arvToken,
'/' + locator, { 'useSsl': svc.service_ssl_flag,
'responseType': 'arraybuffer' });
//prom_1 = prom_1.then(xhr => xhr.response);
prom_1 = prom_1.catch(cb);
return prom_1;
};
return cb().then(xhr => (blocks.append(xhr.response.slice(position, size))));
});
}
prom = prom.then(() => {
const blob = new Blob(blocks);
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = name;
});
}
export default wbDownloadFile;

Loading…
Cancel
Save