cordova-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Gregor Gabriel (JIRA)" <j...@apache.org>
Subject [jira] [Comment Edited] (CB-2787) PhoneGap FileTransfer.Download more than 300 files
Date Tue, 22 Oct 2013 08:03:47 GMT

    [ https://issues.apache.org/jira/browse/CB-2787?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13683354#comment-13683354
] 

Gregor Gabriel edited comment on CB-2787 at 10/22/13 8:02 AM:
--------------------------------------------------------------

This is the Java code for =downloader.js=

{code:javascript}
cordova.define("cordova/plugin/downloader",
  function(require, exports, module) {
    var exec = require("cordova/exec");

    var Downloader = function() {};

    /**
    * 
    */
    Downloader.prototype.downloadFile = function(fileUrl, params, win, fail) {

    	function base64Encode(str) {
    	    var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    	    var out = "", i = 0, len = str.length, c1, c2, c3;
    	    while (i < len) {
    	        c1 = str.charCodeAt(i++) & 0xff;
    	        if (i == len) {
    	            out += CHARS.charAt(c1 >> 2);
    	            out += CHARS.charAt((c1 & 0x3) << 4);
    	            out += "==";
    	            break;
    	        }
    	        c2 = str.charCodeAt(i++);
    	        if (i == len) {
    	            out += CHARS.charAt(c1 >> 2);
    	            out += CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >>
4));
    	            out += CHARS.charAt((c2 & 0xF) << 2);
    	            out += "=";
    	            break;
    	        }
    	        c3 = str.charCodeAt(i++);
    	        out += CHARS.charAt(c1 >> 2);
    	        out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
    	        out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
    	        out += CHARS.charAt(c3 & 0x3F);
    	    }
    	    return out;
    	}
    	
    	function load_binary_resource(url) {
    		var req = new XMLHttpRequest();
    		req.open('GET', url, false);
    		//XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
    		req.overrideMimeType('text\/plain; charset=x-user-defined');
    		req.send(null);
    		if (req.status != 200) {
    			console.log("unable to load " + fileUrl);
    			fail();
    			return null;
    		}
    		if (req.response === null) {
    			fail();
    			return null;
    		}
    		return req.response;
    	}

    	console.log("start loading " + fileUrl);
    	
    	var base64File = base64Encode(load_binary_resource(fileUrl));
    	
    	//Make params hash optional.
    	if (!fail) win = params;
    	PhoneGap.exec(win, fail, "Downloader", "downloadFile", [base64File, params]);

    	fileUrl = null;
		base64File = null;

    };
    

    var downloader = new Downloader();
    module.exports = downloader;
});


if (!window.plugins) {
    window.plugins = {};
}
if (!window.plugins.downloader) {
    window.plugins.downloader = cordova.require("cordova/plugin/downloader");
}

{code}

And this is the Java code of Downloader.java

{code:java}
package com.phonegap.plugins.downloader;

import java.io.File;
import java.io.FileOutputStream;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
import org.apache.cordova.api.PluginResult;

import android.util.Base64;


public class Downloader extends CordovaPlugin {
	
    private CallbackContext context;

    /**
     * Executes the request and returns PluginResult.
     *
     * @param action        The action to execute.
     * @param args          JSONArry of arguments for the plugin.
     * @param callbackId    The callback id used when calling back into JavaScript.
     * @return              A PluginResult object with a status and message.
     */
    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext)
throws JSONException {

    	this.context = callbackContext;
    	
		if (!action.equals("downloadFile")) {
            this.context.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION,
"Plugin Downloader cannot handle action "+action));
        	return true;
		}
		try {
			
			//String fileUrl = args.getString(0);
			//byte[] fileContent = Base64.decode( params.getString("fileUrl"), Base64.DEFAULT );
			byte[] fileContent = Base64.decode( args.getString(0), Base64.DEFAULT );
			
			JSONObject params = args.getJSONObject(1);
			
			String fileName = params.getString("fileName");
			
			String dirName =params.getString("dirName");
			
			Boolean overwrite = params.has("overwrite") ? params.getBoolean("overwrite") : false;
			
			this.context.sendPluginResult(this.downloadUrl(fileContent, dirName, fileName, overwrite));
			fileContent = null;
			params = null;
            return true;
			
		} catch (JSONException e) {

			e.printStackTrace();
			
			this.context.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage()));
        	return true;

		} catch (InterruptedException e) {
			e.printStackTrace();
			
			this.context.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, e.getMessage()));
			return true;
		}
	
	}

	private PluginResult downloadUrl(byte[] fileUrl, String dirName, String fileName, Boolean
overwrite) throws InterruptedException, JSONException {
	
		try {
			System.gc();

			Log.d("Downloader", "write file " + dirName + "/" + fileName);
			
			dirName = dirName.replace("file:///", "/");
			
			File dir = new File(dirName);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			
			File file = new File(dirName, fileName);
			
			if (!overwrite && file.exists()) {
				Log.d("Downloader", "File already exist");
				
				JSONObject obj = new JSONObject();
				obj.put("status", 1);
				obj.put("total", 0);
				obj.put("file", fileName);
				obj.put("dir", dirName);
				obj.put("progress", 100);
				
				return new PluginResult(PluginResult.Status.OK, obj);
			}
			
			int progress = 0;
			int fileSize = 0;
		
			FileOutputStream fos = null;
				
			try {
				// Log.d("Downloader", "Download starts, connection is open ...");

				fos = new FileOutputStream(file);
				fos.write(fileUrl);
				//fos.close();
				//fos = null;
				//fileUrl = null;
				
			} catch (Exception e){
				Log.e("Downloader", e.getMessage());
			} finally {
				try {
					fos.close();
					fos = null;
					fileUrl = null;
				    //Log.d("Downloader","closed input stream output stream and connection");
				    
					JSONObject obj = new JSONObject();
					obj.put("status", 1);
					obj.put("total", fileSize);
					obj.put("file", fileName);
					obj.put("dir", dirName);
					obj.put("progress", progress);
					
					return new PluginResult(PluginResult.Status.OK, obj);
				    
				} catch ( Exception e) {
					fos = null;
					fileUrl = null;
					Log.w("Downloader","Fehler beim Aufraeumen - "+e.getStackTrace().toString() );
				}
            }

			//Log.d("Downloader", "Download finished");

			JSONObject obj = new JSONObject();
			obj.put("status", 1);
			obj.put("total", fileSize);
			obj.put("file", fileName);
			obj.put("dir", dirName);
			obj.put("progress", progress);
			
			return new PluginResult(PluginResult.Status.OK, obj);
			
		}
		finally {
			// do nothing		
		}
	}

}
{code}

the usage ot the plugin is:

{code:javascript}
		try {
                        dir="/a/path/to/a/directory/no/ending/slash";
                        file="a_file.name";
                        window.onLoaded=function(){
                            console.log("do something here, when download succeded");
                        }
                        window.onError=function(){
                            console.log("do something here, when download failed");
                        }
			url = "https://issues.apache.org/jira/secure/projectavatar?pid=12312420&avatarId=15888&size=large";
			window.plugins.downloader.downloadFile(
				url,
				{overwrite: true,
				dirName: dir,
				fileName: file}, 
				onLoaded,
				onError
			);
		}
		catch (e) {
			// do some error handling
		}
{code}



was (Author: ggabriel):
This is the Java code for =downloader.js=

{code:javascript}
cordova.define("cordova/plugin/downloader",
  function(require, exports, module) {
    var exec = require("cordova/exec");

    var Downloader = function() {};

    /**
    * 
    */
    Downloader.prototype.downloadFile = function(fileUrl, params, win, fail) {

    	function base64Encode(str) {
    	    var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    	    var out = "", i = 0, len = str.length, c1, c2, c3;
    	    while (i < len) {
    	        c1 = str.charCodeAt(i++) & 0xff;
    	        if (i == len) {
    	            out += CHARS.charAt(c1 >> 2);
    	            out += CHARS.charAt((c1 & 0x3) << 4);
    	            out += "==";
    	            break;
    	        }
    	        c2 = str.charCodeAt(i++);
    	        if (i == len) {
    	            out += CHARS.charAt(c1 >> 2);
    	            out += CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >>
4));
    	            out += CHARS.charAt((c2 & 0xF) << 2);
    	            out += "=";
    	            break;
    	        }
    	        c3 = str.charCodeAt(i++);
    	        out += CHARS.charAt(c1 >> 2);
    	        out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
    	        out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
    	        out += CHARS.charAt(c3 & 0x3F);
    	    }
    	    return out;
    	}
    	
    	function load_binary_resource(url) {
    		var req = new XMLHttpRequest();
    		req.open('GET', url, false);
    		//XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
    		req.overrideMimeType('text\/plain; charset=x-user-defined');
    		req.send(null);
    		if (req.status != 200) {
    			console.log("unable to load " + fileUrl);
    			fail();
    			return null;
    		}
    		if (req.response === null) {
    			fail();
    			return null;
    		}
    		return req.response;
    	}

    	console.log("start loading " + fileUrl);
    	
    	var base64File = base64Encode(load_binary_resource(fileUrl));
    	
    	//Make params hash optional.
    	if (!fail) win = params;
    	PhoneGap.exec(win, fail, "Downloader", "downloadFile", [base64File, params]);

    	fileUrl = null;
		base64File = null;

    };
    

    var downloader = new Downloader();
    module.exports = downloader;
});


if (!window.plugins) {
    window.plugins = {};
}
if (!window.plugins.downloader) {
    window.plugins.downloader = cordova.require("cordova/plugin/downloader");
}

{code}

And this is the Java code of Downloader.java

{code:java}
package com.phonegap.plugins.downloader;

import java.io.File;
import java.io.FileOutputStream;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
import org.apache.cordova.api.PluginResult;

import android.util.Base64;


public class Downloader extends CordovaPlugin {
	
    private CallbackContext context;

    /**
     * Executes the request and returns PluginResult.
     *
     * @param action        The action to execute.
     * @param args          JSONArry of arguments for the plugin.
     * @param callbackId    The callback id used when calling back into JavaScript.
     * @return              A PluginResult object with a status and message.
     */
    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext)
throws JSONException {

    	this.context = callbackContext;
    	
		if (!action.equals("downloadFile")) {
            this.context.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION,
"Plugin Downloader cannot handle action "+action));
        	return true;
		}
		try {
			
			//String fileUrl = args.getString(0);
			//byte[] fileContent = Base64.decode( params.getString("fileUrl"), Base64.DEFAULT );
			byte[] fileContent = Base64.decode( args.getString(0), Base64.DEFAULT );
			
			JSONObject params = args.getJSONObject(1);
			
			String fileName = params.getString("fileName");
			
			String dirName =params.getString("dirName");
			
			Boolean overwrite = params.has("overwrite") ? params.getBoolean("overwrite") : false;
			
			this.context.sendPluginResult(this.downloadUrl(fileContent, dirName, fileName, overwrite));
			fileContent = null;
			params = null;
            return true;
			
		} catch (JSONException e) {

			e.printStackTrace();
			
			this.context.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage()));
        	return true;

		} catch (InterruptedException e) {
			e.printStackTrace();
			
			this.context.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, e.getMessage()));
			return true;
		}
	
	}

	private PluginResult downloadUrl(byte[] fileUrl, String dirName, String fileName, Boolean
overwrite) throws InterruptedException, JSONException {
	
		try {
			System.gc();

			Log.d("Downloader", "write file " + dirName + "/" + fileName);
			
			dirName = dirName.replace("file:///", "/");
			
			File dir = new File(dirName);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			
			File file = new File(dirName, fileName);
			
			if (!overwrite && file.exists()) {
				Log.d("Downloader", "File already exist");
				
				JSONObject obj = new JSONObject();
				obj.put("status", 1);
				obj.put("total", 0);
				obj.put("file", fileName);
				obj.put("dir", dirName);
				obj.put("progress", 100);
				
				return new PluginResult(PluginResult.Status.OK, obj);
			}
			
			int progress = 0;
			int fileSize = 0;
		
			FileOutputStream fos = null;
				
			try {
				// Log.d("Downloader", "Download starts, connection is open ...");

				fos = new FileOutputStream(file);
				fos.write(fileUrl);
				//fos.close();
				//fos = null;
				//fileUrl = null;
				
			} catch (Exception e){
				Log.e("Downloader", e.getMessage());
			} finally {
				try {
					fos.close();
					fos = null;
					fileUrl = null;
				    //Log.d("Downloader","closed input stream output stream and connection");
				    
					JSONObject obj = new JSONObject();
					obj.put("status", 1);
					obj.put("total", fileSize);
					obj.put("file", fileName);
					obj.put("dir", dirName);
					obj.put("progress", progress);
					
					return new PluginResult(PluginResult.Status.OK, obj);
				    
				} catch ( Exception e) {
					fos = null;
					fileUrl = null;
					Log.w("Downloader","Fehler beim Aufraeumen - "+e.getStackTrace().toString() );
				}
            }

			//Log.d("Downloader", "Download finished");

			JSONObject obj = new JSONObject();
			obj.put("status", 1);
			obj.put("total", fileSize);
			obj.put("file", fileName);
			obj.put("dir", dirName);
			obj.put("progress", progress);
			
			return new PluginResult(PluginResult.Status.OK, obj);
			
		}
		finally {
			// do nothing		
		}
	}

}
{code}

the usage ot the plugin is:

{code:javascript}
		try {
                        dir="/a/path/to/a/directory/no/ending/slash";
                        file"a_file.name";
                        window.onLoaded=function(){
                            console.log("do something here, when download succeded");
                        }
                        window.onError=function(){
                            console.log("do something here, when download failed");
                        }
			url = "https://issues.apache.org/jira/secure/projectavatar?pid=12312420&avatarId=15888&size=large";
			window.plugins.downloader.downloadFile(
				url,
				{overwrite: true,
				dirName: dir,
				fileName: file}, 
				onLoaded,
				onError
			);
		}
		catch (e) {
			// do some error handling
		}
{code}


> PhoneGap FileTransfer.Download more than 300 files
> --------------------------------------------------
>
>                 Key: CB-2787
>                 URL: https://issues.apache.org/jira/browse/CB-2787
>             Project: Apache Cordova
>          Issue Type: Bug
>          Components: Android
>    Affects Versions: 2.5.0
>            Reporter: Cho
>            Assignee: Ian Clelland
>
> I had tried to download more than 300 files and then it hit error after that. Seems like
some IO Connection was not properly closed. I wrote a small code to test it out. 
> Any idea? How to file a report or get a source of phonegap to check the real cause?
> {code}
> var counter = 500;
> function DownloadFile() {
>         if (counter == 0) {
>             DownloadComplete();
>             return;
>         }
>         var ft = new FileTransfer();
>         var downloadUrl = "<source>";
>         var dlPath = "<target>"
>         ft.download(downloadUrl, dlPath, function(entry) {
>             counter--;
>             UpdateProgress();
>             DownloadFile();
>         }, function(error) {
>             DownloadFailed();
>         }, true);
>     }
> {code}
> note: <target> and <source> is alright because it was it failed when the
counter goes until 300+.
> {code}
> 03-14 08:35:09.706: E/FileTransfer(24867): {"target":"<target>","source":"<source>","http_status":200,"code":1}
> 03-14 08:35:09.706: E/FileTransfer(24867): java.io.FileNotFoundException: <source>:
open failed: EMFILE (Too many open files)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at libcore.io.IoBridge.open(IoBridge.java:416)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at java.io.FileOutputStream.<init>(FileOutputStream.java:73)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at org.apache.cordova.FileTransfer$4.run(FileTransfer.java:685)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at java.lang.Thread.run(Thread.java:856)
> 03-14 08:35:09.706: E/FileTransfer(24867): Caused by: libcore.io.ErrnoException: open
failed: EMFILE (Too many open files)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at libcore.io.Posix.open(Native Method)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
> 03-14 08:35:09.706: E/FileTransfer(24867):     at libcore.io.IoBridge.open(IoBridge.java:400)
> 03-14 08:35:09.706: E/FileTransfer(24867):     ... 6 more
> {code}



--
This message was sent by Atlassian JIRA
(v6.1#6144)

Mime
View raw message