Source: tc-ids.service.js



(function() {
    'use strict';

    var app = angular.module('topcat');

    app.service('tcIds', function($q, $interval, helpers, tcCache){

    	this.create = function(facility, url){
    		return new Ids(facility, url);
    	};

      /**
       * @interface IDS
       */
    	function Ids(facility, url){
        var that = this;
        var cache;

        this.facility = function(){
          return facility;
        };

        this.cache = function(){
          if(!cache) cache = tcCache.create('ids:' + facility.config().name);
          return cache;
        };


        /**
         * Returns the version of the IDS server
         *
         * @method
         * @name IDS#version
         * @return {Promise<string>}
         */
    		this.version = function(){
    			var out = $q.defer();
    			this.get('getApiVersion').then(function(version){
    				out.resolve(version);
    			}, function(){ out.reject(); });
    			return out.promise;
    		};

        this.isTwoLevel = helpers.overload({
          /**
           * Returns whether or not the IDS is two level.
           *
           * @method
           * @name IDS#isTwoLevel
           * @param {object} options {@link https://docs.angularjs.org/api/ng/service/$http#usage|as specified in the Angular documentation}
           * @return {Promise<boolean>}
           */
          'object': function(options){
            return this.get('isTwoLevel', {}, options).then(function(isTwoLevel){
              return isTwoLevel == 'true';
            });
          },

          /**
           * Returns whether or not the IDS is two level.
           *
           * @method
           * @name IDS#isTwoLevel
           * @param {Promise} timeout if resolved will cancel the request
           * @return {Promise<boolean>}
           */
          'promise': function(timeout){
            return this.isTwoLevel({timeout: timeout});
          },

          /**
           * Returns whether or not the IDS is two level.
           *
           * @method
           * @name IDS#isTwoLevel
           * @return {Promise<boolean>}
           */
          '': function(){
            return this.isTwoLevel({});
          }
        });


        var chunkSize = 100000;
        if(FileReader && !(new FileReader()).readAsBinaryString) chunkSize = 1000;

        /**
         * Uploads files to a dataset.
         *
         * @method
         * @name IDS#upload
         * @param {number} datasetId the id of the dataset you wish to upload to 
         * @param {File[]} files the files to be uploaded
         * @return {Promise}
         */
        this.upload = function(datasetId, files){
          var defered = $q.defer();

          files = _.clone(files);

          var queryParams = {
            idsUrl: url,
            sessionId: facility.icat().session().sessionId,
            datasetId: datasetId,
            datafileFormatId: facility.config().idsUploadDatafileFormatId,
          };


          var datafileIds = [];

          function upload(){
            if(files.length > 0){
              var file = files.shift();
              var dataUploaded = 0;

              _.each(files, function(file){
                file.percentageUploaded = 0;
              });

              queryParams.name = file.name;
              queryParams.contentLength = file.size;

              var topcatUrl = facility.tc().config().topcatUrl;
              if(topcatUrl.match(/^https:\/\//)){
                topcatUrl = "wss://" + topcatUrl.replace(/^https:\/\//, '');
              } else {
                topcatUrl = "ws://" + topcatUrl.replace(/^http:\/\//, '');
              }

              var currentUrl = topcatUrl + "/topcat/user/upload?" + _.map(queryParams, function(v, k){ return encodeURIComponent(k) + "=" + encodeURIComponent(v) }).join('&');

              var connection = new WebSocket(currentUrl);

              var chunkIndex = 0;

              function readChunk(){
                if(chunkIndex * chunkSize > file.size){
                  return;
                }

                var from = chunkIndex * chunkSize;
                var to = (chunkIndex + 1) * chunkSize;
                if(to > file.size) to = file.size;
                var chunk = file.slice(from, to);

                var reader = new FileReader();
    
                reader.onload = function(e) {
                  var binary;
                  if(reader.readAsBinaryString){
                    binary = reader.result;
                  } else {
                    binary = "";
                    var bytes = new Uint8Array(reader.result);
                    var length = bytes.byteLength;
                    for (var i = 0; i < length; i++) {
                      binary += String.fromCharCode(bytes[i]);
                    }
                  }
                  connection.send(binary);
                  dataUploaded += binary.length;
                  file.percentageUploaded = _.round(dataUploaded / (file.size / 100), 2);
                  chunkIndex++;
                  readChunk();
                };
                
                if(reader.readAsBinaryString){
                  reader.readAsBinaryString(chunk);
                } else {
                  reader.readAsArrayBuffer(chunk);
                }
  
              }

              connection.onmessage = function(response){
                datafileIds.push(JSON.parse(response.data).id);
                connection.close();
                upload();
              };

              connection.onopen = function(){
                readChunk();
              };

            } else {
              defered.resolve(datafileIds);
            }
          }
          upload();
          
          return defered.promise;
        };


    		helpers.generateRestMethods(this, url + '/ids/');

        helpers.mixinPluginMethods('ids', this);
    	}
		

	});

})();