mirror of
https://github.com/apache/cordova-plugin-file-transfer.git
synced 2024-10-06 07:42:20 +08:00
[CB-4118] remove dupe code
This commit is contained in:
parent
de38d4a2c8
commit
aedea91307
@ -51,7 +51,7 @@
|
||||
</feature>
|
||||
</config-file>
|
||||
|
||||
<source-file src="src/wp7/FileTransfer.cs" />
|
||||
<source-file src="src/wp/FileTransfer.cs" />
|
||||
|
||||
<js-module src="www/wp/FileTransfer.js" name="FileTransfer1">
|
||||
<clobbers target="window.FileTransfer" />
|
||||
@ -67,7 +67,7 @@
|
||||
</feature>
|
||||
</config-file>
|
||||
|
||||
<source-file src="src/wp8/FileTransfer.cs" />
|
||||
<source-file src="src/wp/FileTransfer.cs" />
|
||||
|
||||
<js-module src="www/wp/FileTransfer.js" name="FileTransfer1">
|
||||
<clobbers target="window.FileTransfer" />
|
||||
|
@ -1,526 +0,0 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.IsolatedStorage;
|
||||
using System.Net;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Windows;
|
||||
using System.Security;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace WPCordovaClassLib.Cordova.Commands
|
||||
{
|
||||
public class FileTransfer : BaseCommand
|
||||
{
|
||||
public class DownloadRequestState
|
||||
{
|
||||
// This class stores the State of the request.
|
||||
public HttpWebRequest request;
|
||||
public DownloadOptions options;
|
||||
|
||||
public DownloadRequestState()
|
||||
{
|
||||
request = null;
|
||||
options = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boundary symbol
|
||||
/// </summary>
|
||||
private string Boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
|
||||
|
||||
// Error codes
|
||||
public const int FileNotFoundError = 1;
|
||||
public const int InvalidUrlError = 2;
|
||||
public const int ConnectionError = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Options for downloading file
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public class DownloadOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// File path to download to
|
||||
/// </summary>
|
||||
[DataMember(Name = "filePath", IsRequired = true)]
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Server address to the file to download
|
||||
/// </summary>
|
||||
[DataMember(Name = "url", IsRequired = true)]
|
||||
public string Url { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options for uploading file
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public class UploadOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// File path to upload
|
||||
/// </summary>
|
||||
[DataMember(Name = "filePath", IsRequired = true)]
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Server address
|
||||
/// </summary>
|
||||
[DataMember(Name = "server", IsRequired = true)]
|
||||
public string Server { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File key
|
||||
/// </summary>
|
||||
[DataMember(Name = "fileKey")]
|
||||
public string FileKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File name on the server
|
||||
/// </summary>
|
||||
[DataMember(Name = "fileName")]
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File Mime type
|
||||
/// </summary>
|
||||
[DataMember(Name = "mimeType")]
|
||||
public string MimeType { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Additional options
|
||||
/// </summary>
|
||||
[DataMember(Name = "params")]
|
||||
public string Params { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flag to recognize if we should trust every host (only in debug environments)
|
||||
/// </summary>
|
||||
[DataMember(Name = "debug")]
|
||||
public bool Debug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates options object with default parameters
|
||||
/// </summary>
|
||||
public UploadOptions()
|
||||
{
|
||||
this.SetDefaultValues(new StreamingContext());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes default values for class fields.
|
||||
/// Implemented in separate method because default constructor is not invoked during deserialization.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
[OnDeserializing()]
|
||||
public void SetDefaultValues(StreamingContext context)
|
||||
{
|
||||
this.FileKey = "file";
|
||||
this.FileName = "image.jpg";
|
||||
this.MimeType = "image/jpeg";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uploading response info
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public class FileUploadResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Amount of sent bytes
|
||||
/// </summary>
|
||||
[DataMember(Name = "bytesSent")]
|
||||
public long BytesSent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Server response code
|
||||
/// </summary>
|
||||
[DataMember(Name = "responseCode")]
|
||||
public long ResponseCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Server response
|
||||
/// </summary>
|
||||
[DataMember(Name = "response", EmitDefaultValue = false)]
|
||||
public string Response { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates FileUploadResult object with response values
|
||||
/// </summary>
|
||||
/// <param name="bytesSent">Amount of sent bytes</param>
|
||||
/// <param name="responseCode">Server response code</param>
|
||||
/// <param name="response">Server response</param>
|
||||
public FileUploadResult(long bytesSent, long responseCode, string response)
|
||||
{
|
||||
this.BytesSent = bytesSent;
|
||||
this.ResponseCode = responseCode;
|
||||
this.Response = response;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents transfer error codes for callback
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public class FileTransferError
|
||||
{
|
||||
/// <summary>
|
||||
/// Error code
|
||||
/// </summary>
|
||||
[DataMember(Name = "code", IsRequired = true)]
|
||||
public int Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The source URI
|
||||
/// </summary>
|
||||
[DataMember(Name = "source", IsRequired = true)]
|
||||
public string Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The target URI
|
||||
/// </summary>
|
||||
[DataMember(Name = "target", IsRequired = true)]
|
||||
public string Target { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The http status code response from the remote URI
|
||||
/// </summary>
|
||||
[DataMember(Name = "http_status", IsRequired = true)]
|
||||
public int HttpStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates FileTransferError object
|
||||
/// </summary>
|
||||
/// <param name="errorCode">Error code</param>
|
||||
public FileTransferError(int errorCode)
|
||||
{
|
||||
this.Code = errorCode;
|
||||
this.Source = null;
|
||||
this.Target = null;
|
||||
this.HttpStatus = 0;
|
||||
}
|
||||
public FileTransferError(int errorCode, string source, string target, int status)
|
||||
{
|
||||
this.Code = errorCode;
|
||||
this.Source = source;
|
||||
this.Target = target;
|
||||
this.HttpStatus = status;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upload options
|
||||
/// </summary>
|
||||
private UploadOptions uploadOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Bytes sent
|
||||
/// </summary>
|
||||
private long bytesSent;
|
||||
|
||||
/// <summary>
|
||||
/// sends a file to a server
|
||||
/// </summary>
|
||||
/// <param name="options">Upload options</param>
|
||||
public void upload(string options)
|
||||
{
|
||||
Debug.WriteLine("options = " + options);
|
||||
options = options.Replace("{}", "null");
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
|
||||
uploadOptions = JSON.JsonHelper.Deserialize<UploadOptions>(args[0]);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
|
||||
return;
|
||||
}
|
||||
|
||||
Uri serverUri;
|
||||
try
|
||||
{
|
||||
serverUri = new Uri(uploadOptions.Server);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(InvalidUrlError, uploadOptions.Server, null, 0)));
|
||||
return;
|
||||
}
|
||||
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(serverUri);
|
||||
webRequest.ContentType = "multipart/form-data;boundary=" + Boundary;
|
||||
webRequest.Method = "POST";
|
||||
webRequest.BeginGetRequestStream(WriteCallback, webRequest);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)));
|
||||
}
|
||||
}
|
||||
|
||||
public void download(string options)
|
||||
{
|
||||
DownloadOptions downloadOptions = null;
|
||||
HttpWebRequest webRequest = null;
|
||||
|
||||
try
|
||||
{
|
||||
string[] optionStrings = JSON.JsonHelper.Deserialize<string[]>(options);
|
||||
|
||||
downloadOptions = new DownloadOptions();// JSON.JsonHelper.Deserialize<DownloadOptions>(options);
|
||||
downloadOptions.Url = optionStrings[0];
|
||||
downloadOptions.FilePath = optionStrings[1];
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
webRequest = (HttpWebRequest)WebRequest.Create(downloadOptions.Url);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(InvalidUrlError, downloadOptions.Url, null, 0)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (downloadOptions != null && webRequest != null)
|
||||
{
|
||||
DownloadRequestState state = new DownloadRequestState();
|
||||
state.options = downloadOptions;
|
||||
state.request = webRequest;
|
||||
webRequest.BeginGetResponse(new AsyncCallback(downloadCallback), state);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="asynchronousResult"></param>
|
||||
private void downloadCallback(IAsyncResult asynchronousResult)
|
||||
{
|
||||
DownloadRequestState reqState = (DownloadRequestState)asynchronousResult.AsyncState;
|
||||
HttpWebRequest request = reqState.request;
|
||||
|
||||
try
|
||||
{
|
||||
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
|
||||
|
||||
using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
|
||||
{
|
||||
// create the file if not exists
|
||||
if (!isoFile.FileExists(reqState.options.FilePath))
|
||||
{
|
||||
var file = isoFile.CreateFile(reqState.options.FilePath);
|
||||
file.Close();
|
||||
}
|
||||
|
||||
using (FileStream fileStream = new IsolatedStorageFileStream(reqState.options.FilePath, FileMode.Open, FileAccess.Write, isoFile))
|
||||
{
|
||||
long totalBytes = response.ContentLength;
|
||||
int bytesRead = 0;
|
||||
using (BinaryReader reader = new BinaryReader(response.GetResponseStream()))
|
||||
{
|
||||
|
||||
using (BinaryWriter writer = new BinaryWriter(fileStream))
|
||||
{
|
||||
int BUFFER_SIZE = 1024;
|
||||
byte[] buffer;
|
||||
|
||||
while (true)
|
||||
{
|
||||
buffer = reader.ReadBytes(BUFFER_SIZE);
|
||||
// fire a progress event ?
|
||||
bytesRead += buffer.Length;
|
||||
if (buffer.Length > 0)
|
||||
{
|
||||
writer.Write(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Close();
|
||||
reader.Close();
|
||||
fileStream.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
WPCordovaClassLib.Cordova.Commands.File.FileEntry entry = new WPCordovaClassLib.Cordova.Commands.File.FileEntry(reqState.options.FilePath);
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry));
|
||||
}
|
||||
catch (IsolatedStorageException)
|
||||
{
|
||||
// Trying to write the file somewhere within the IsoStorage.
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)));
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
// Trying to write the file somewhere not allowed.
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)));
|
||||
}
|
||||
catch (WebException webex)
|
||||
{
|
||||
// TODO: probably need better work here to properly respond with all http status codes back to JS
|
||||
// Right now am jumping through hoops just to detect 404.
|
||||
if ((webex.Status == WebExceptionStatus.ProtocolError && ((HttpWebResponse)webex.Response).StatusCode == HttpStatusCode.NotFound) || webex.Status == WebExceptionStatus.UnknownError)
|
||||
{
|
||||
// Weird MSFT detection of 404... seriously... just give us the f(*&#$@ status code as a number ffs!!!
|
||||
// "Numbers for HTTP status codes? Nah.... let's create our own set of enums/structs to abstract that stuff away."
|
||||
// FACEPALM
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError, null, null, 404)));
|
||||
}
|
||||
else
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)));
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Read file from Isolated Storage and sends it to server
|
||||
/// </summary>
|
||||
/// <param name="asynchronousResult"></param>
|
||||
private void WriteCallback(IAsyncResult asynchronousResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
|
||||
using (Stream requestStream = (webRequest.EndGetRequestStream(asynchronousResult)))
|
||||
{
|
||||
string lineStart = "--";
|
||||
string lineEnd = Environment.NewLine;
|
||||
byte[] boundaryBytes = System.Text.Encoding.UTF8.GetBytes(lineStart + Boundary + lineEnd);
|
||||
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"" + lineEnd + lineEnd + "{1}" + lineEnd;
|
||||
|
||||
if (uploadOptions.Params != null)
|
||||
{
|
||||
|
||||
string[] arrParams = uploadOptions.Params.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (string param in arrParams)
|
||||
{
|
||||
string[] split = param.Split('=');
|
||||
string key = split[0];
|
||||
string val = split[1];
|
||||
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
|
||||
string formItem = string.Format(formdataTemplate, key, val);
|
||||
byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(formItem);
|
||||
requestStream.Write(formItemBytes, 0, formItemBytes.Length);
|
||||
}
|
||||
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
|
||||
}
|
||||
using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
|
||||
{
|
||||
if (!isoFile.FileExists(uploadOptions.FilePath))
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError, uploadOptions.Server, uploadOptions.FilePath, 0)));
|
||||
return;
|
||||
}
|
||||
|
||||
using (FileStream fileStream = new IsolatedStorageFileStream(uploadOptions.FilePath, FileMode.Open, isoFile))
|
||||
{
|
||||
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + lineEnd + "Content-Type: {2}" + lineEnd + lineEnd;
|
||||
string header = string.Format(headerTemplate, uploadOptions.FileKey, uploadOptions.FileName, uploadOptions.MimeType);
|
||||
byte[] headerBytes = System.Text.Encoding.UTF8.GetBytes(header);
|
||||
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
|
||||
requestStream.Write(headerBytes, 0, headerBytes.Length);
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead = 0;
|
||||
|
||||
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
|
||||
{
|
||||
requestStream.Write(buffer, 0, bytesRead);
|
||||
bytesSent += bytesRead;
|
||||
}
|
||||
}
|
||||
byte[] endRequest = System.Text.Encoding.UTF8.GetBytes(lineEnd + lineStart + Boundary + lineStart + lineEnd);
|
||||
requestStream.Write(endRequest, 0, endRequest.Length);
|
||||
}
|
||||
}
|
||||
webRequest.BeginGetResponse(ReadCallback, webRequest);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Deployment.Current.Dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads response into FileUploadResult
|
||||
/// </summary>
|
||||
/// <param name="asynchronousResult"></param>
|
||||
private void ReadCallback(IAsyncResult asynchronousResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
|
||||
using (HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult))
|
||||
{
|
||||
using (Stream streamResponse = response.GetResponseStream())
|
||||
{
|
||||
using (StreamReader streamReader = new StreamReader(streamResponse))
|
||||
{
|
||||
string responseString = streamReader.ReadToEnd();
|
||||
Deployment.Current.Dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileUploadResult(bytesSent, (long)response.StatusCode, responseString)));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Deployment.Current.Dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
FileTransferError transferError = new FileTransferError(ConnectionError, uploadOptions.Server, uploadOptions.FilePath, 403);
|
||||
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, transferError));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user