mirror of
				https://github.com/owncloud/android-library.git
				synced 2025-10-31 02:17:41 +00:00 
			
		
		
		
	Basic upload with chunks [WIP]
This commit is contained in:
		
							parent
							
								
									366459699e
								
							
						
					
					
						commit
						153c0a10ff
					
				| @ -56,7 +56,7 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres | |||||||
|     private final File mFile; |     private final File mFile; | ||||||
|     private long mOffset; |     private long mOffset; | ||||||
|     private long mTransferred; |     private long mTransferred; | ||||||
|     Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>(); |     Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>(); | ||||||
|     private ByteBuffer mBuffer = ByteBuffer.allocate(4096); |     private ByteBuffer mBuffer = ByteBuffer.allocate(4096); | ||||||
| 
 | 
 | ||||||
|     public ChunkFromFileChannelRequestEntity( |     public ChunkFromFileChannelRequestEntity( | ||||||
| @ -120,8 +120,8 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres | |||||||
|      |      | ||||||
|      |      | ||||||
|     public void writeRequest(final OutputStream out) throws IOException { |     public void writeRequest(final OutputStream out) throws IOException { | ||||||
|         int readCount = 0; |         int readCount; | ||||||
|         Iterator<OnDatatransferProgressListener> it = null; |         Iterator<OnDatatransferProgressListener> it; | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             mChannel.position(mOffset); |             mChannel.position(mOffset); | ||||||
| @ -161,7 +161,5 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres | |||||||
|         } catch (FileRequestEntity.WriteException we) { |         } catch (FileRequestEntity.WriteException we) { | ||||||
|             throw we.getWrapped(); |             throw we.getWrapped(); | ||||||
|         } |         } | ||||||
|              |  | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
| @ -0,0 +1,100 @@ | |||||||
|  | /* ownCloud Android Library is available under MIT license | ||||||
|  |  *   Copyright (C) 2018 ownCloud GmbH. | ||||||
|  |  * | ||||||
|  |  *   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  *   of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  *   in the Software without restriction, including without limitation the rights | ||||||
|  |  *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  *   copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  *   furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  *   The above copyright notice and this permission notice shall be included in | ||||||
|  |  *   all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  |  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
|  |  *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|  |  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||||||
|  |  *   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||||||
|  |  *   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||||
|  |  *   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  |  *   THE SOFTWARE. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package com.owncloud.android.lib.common.network; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  | import java.nio.channels.FileChannel; | ||||||
|  | import java.util.Iterator; | ||||||
|  | 
 | ||||||
|  | import okhttp3.MediaType; | ||||||
|  | import okio.BufferedSink; | ||||||
|  | 
 | ||||||
|  | public class ChunkFromFileRequestBody extends FileRequestBody { | ||||||
|  | 
 | ||||||
|  |     private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName(); | ||||||
|  | 
 | ||||||
|  |     //private final File mFile; | ||||||
|  |     private final FileChannel mChannel; | ||||||
|  |     private final long mChunkSize; | ||||||
|  |     private long mOffset; | ||||||
|  |     private long mTransferred; | ||||||
|  |     private ByteBuffer mBuffer = ByteBuffer.allocate(4096); | ||||||
|  | 
 | ||||||
|  |     public ChunkFromFileRequestBody(File file, MediaType contentType, FileChannel channel, long chunkSize) { | ||||||
|  |         super(file, contentType); | ||||||
|  |         if (channel == null) { | ||||||
|  |             throw new IllegalArgumentException("File may not be null"); | ||||||
|  |         } | ||||||
|  |         if (chunkSize <= 0) { | ||||||
|  |             throw new IllegalArgumentException("Chunk size must be greater than zero"); | ||||||
|  |         } | ||||||
|  |         this.mChannel = channel; | ||||||
|  |         this.mChunkSize = chunkSize; | ||||||
|  |         mOffset = 0; | ||||||
|  |         mTransferred = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void writeTo(BufferedSink sink) { | ||||||
|  |         int readCount; | ||||||
|  |         Iterator<OnDatatransferProgressListener> it; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             mChannel.position(mOffset); | ||||||
|  |             long size = mFile.length(); | ||||||
|  |             if (size == 0) size = -1; | ||||||
|  |             long maxCount = Math.min(mOffset + mChunkSize, mChannel.size()); | ||||||
|  |             while (mChannel.position() < maxCount) { | ||||||
|  |                 readCount = mChannel.read(mBuffer); | ||||||
|  |                 sink.write(mBuffer.array(), 0 ,readCount); | ||||||
|  |                 mBuffer.clear(); | ||||||
|  |                 if (mTransferred < maxCount) {  // condition to avoid accumulate progress for repeated chunks | ||||||
|  |                     mTransferred += readCount; | ||||||
|  |                 } | ||||||
|  |                 synchronized (mDataTransferListeners) { | ||||||
|  |                     it = mDataTransferListeners.iterator(); | ||||||
|  |                     while (it.hasNext()) { | ||||||
|  |                         it.next().onTransferProgress(readCount, mTransferred, size, mFile.getAbsolutePath()); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             sink.flush(); | ||||||
|  | 
 | ||||||
|  |         } catch (IOException io) { | ||||||
|  | //            // any read problem will be handled as if the file is not there | ||||||
|  | //            if (io instanceof FileNotFoundException) { | ||||||
|  | //                throw io; | ||||||
|  | //            } else { | ||||||
|  | //                FileNotFoundException fnf = new FileNotFoundException("Exception reading source file"); | ||||||
|  | //                fnf.initCause(io); | ||||||
|  | //                throw fnf; | ||||||
|  | //            } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -43,7 +43,7 @@ import okio.Source; | |||||||
|  */ |  */ | ||||||
| public class FileRequestBody extends RequestBody implements ProgressiveDataTransferer { | public class FileRequestBody extends RequestBody implements ProgressiveDataTransferer { | ||||||
| 
 | 
 | ||||||
|     private File mFile; |     protected File mFile; | ||||||
|     private MediaType mContentType; |     private MediaType mContentType; | ||||||
|     Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>(); |     Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>(); | ||||||
| 
 | 
 | ||||||
| @ -71,7 +71,7 @@ public class FileRequestBody extends RequestBody implements ProgressiveDataTrans | |||||||
|             long transferred = 0; |             long transferred = 0; | ||||||
|             long read; |             long read; | ||||||
| 
 | 
 | ||||||
|             while ((read = source.read(sink.buffer(), 2048)) != -1) { |             while ((read = source.read(sink.buffer(), 4096)) != -1) { | ||||||
|                 transferred += read; |                 transferred += read; | ||||||
|                 sink.flush(); |                 sink.flush(); | ||||||
|                 synchronized (mDataTransferListeners) { |                 synchronized (mDataTransferListeners) { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| /* ownCloud Android Library is available under MIT license | /* ownCloud Android Library is available under MIT license | ||||||
|  *   Copyright (C) 2016 ownCloud GmbH. |  *   Copyright (C) 2018 ownCloud GmbH. | ||||||
|  *    |  *    | ||||||
|  *   Permission is hereby granted, free of charge, to any person obtaining a copy |  *   Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  *   of this software and associated documentation files (the "Software"), to deal |  *   of this software and associated documentation files (the "Software"), to deal | ||||||
| @ -26,14 +26,28 @@ package com.owncloud.android.lib.resources.files; | |||||||
| 
 | 
 | ||||||
| import com.owncloud.android.lib.common.OwnCloudClient; | import com.owncloud.android.lib.common.OwnCloudClient; | ||||||
| import com.owncloud.android.lib.common.http.HttpUtils; | import com.owncloud.android.lib.common.http.HttpUtils; | ||||||
| import com.owncloud.android.lib.common.http.methods.webdav.MkColMethod; | import com.owncloud.android.lib.common.http.methods.webdav.PutMethod; | ||||||
| import com.owncloud.android.lib.common.network.WebdavUtils; | import com.owncloud.android.lib.common.network.ChunkFromFileRequestBody; | ||||||
| import com.owncloud.android.lib.common.operations.RemoteOperationResult; | import com.owncloud.android.lib.common.operations.RemoteOperationResult; | ||||||
|  | import com.owncloud.android.lib.common.utils.Log_OC; | ||||||
| 
 | 
 | ||||||
|  | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.RandomAccessFile; | import java.io.RandomAccessFile; | ||||||
| import java.nio.channels.FileChannel; | import java.nio.channels.FileChannel; | ||||||
| 
 | 
 | ||||||
|  | import okhttp3.MediaType; | ||||||
|  | 
 | ||||||
|  | import static com.owncloud.android.lib.common.http.HttpConstants.IF_MATCH_HEADER; | ||||||
|  | import static com.owncloud.android.lib.common.http.HttpConstants.OC_TOTAL_LENGTH_HEADER; | ||||||
|  | import static com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Remote operation performing the chunked upload of a remote file to the ownCloud server. | ||||||
|  |  * | ||||||
|  |  * @author David A. Velasco | ||||||
|  |  * @author David González Verdugo | ||||||
|  |  */ | ||||||
| public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation { | public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation { | ||||||
| 
 | 
 | ||||||
|     private static final int LAST_CHUNK_TIMEOUT = 900000; //15 mins. |     private static final int LAST_CHUNK_TIMEOUT = 900000; //15 mins. | ||||||
| @ -46,11 +60,6 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation | |||||||
| 
 | 
 | ||||||
|     private long mTransferId; |     private long mTransferId; | ||||||
| 
 | 
 | ||||||
|     public ChunkedUploadRemoteFileOperation(String storagePath, String remotePath, String mimeType, |  | ||||||
|                                             String fileLastModifTimestamp) { |  | ||||||
|         super(storagePath, remotePath, mimeType, fileLastModifTimestamp); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public ChunkedUploadRemoteFileOperation(long transferId, String storagePath, String remotePath, String mimeType, |     public ChunkedUploadRemoteFileOperation(long transferId, String storagePath, String remotePath, String mimeType, | ||||||
|                                             String requiredEtag, String fileLastModifTimestamp) { |                                             String requiredEtag, String fileLastModifTimestamp) { | ||||||
|         super(storagePath, remotePath, mimeType, requiredEtag, fileLastModifTimestamp); |         super(storagePath, remotePath, mimeType, requiredEtag, fileLastModifTimestamp); | ||||||
| @ -65,80 +74,84 @@ public class ChunkedUploadRemoteFileOperation extends UploadRemoteFileOperation | |||||||
|         FileChannel channel = null; |         FileChannel channel = null; | ||||||
|         RandomAccessFile raf = null; |         RandomAccessFile raf = null; | ||||||
| 
 | 
 | ||||||
|         //TODO |         try { | ||||||
| //        try { |             File fileToUpload = new File(mLocalPath); | ||||||
| //            File file = new File(mLocalPath); |             MediaType mediaType = MediaType.parse(mMimeType); | ||||||
| //            raf = new RandomAccessFile(file, "r"); | 
 | ||||||
| //            channel = raf.getChannel(); |             raf = new RandomAccessFile(fileToUpload, "r"); | ||||||
| //            mEntity = new ChunkFromFileChannelRequestEntity(channel, mMimeType, CHUNK_SIZE, file); |             channel = raf.getChannel(); | ||||||
| //            synchronized (mDataTransferListeners) { | 
 | ||||||
| //                ((ProgressiveDataTransferer) mEntity) |             mFileRequestBody = new ChunkFromFileRequestBody(fileToUpload, mediaType, channel, CHUNK_SIZE); | ||||||
| //                    .addDatatransferProgressListeners(mDataTransferListeners); | 
 | ||||||
| //            } |             synchronized (mDataTransferListeners) { | ||||||
| // |                 mFileRequestBody.addDatatransferProgressListeners(mDataTransferListeners); | ||||||
| //            long offset = 0; |             } | ||||||
| //            String uriPrefix = client.getOldWebdavUri() + WebdavUtils.encodePath(mRemotePath) + | 
 | ||||||
| //                "-chunking-" + Math.abs((new Random()).nextInt(9000) + 1000) + "-"; |             long offset = 0; | ||||||
| //            long totalLength = file.length(); |             String uriPrefix = client.getNewUploadsWebDavUri() + FileUtils.PATH_SEPARATOR + String.valueOf(mTransferId); | ||||||
| //            long chunkCount = (long) Math.ceil((double) totalLength / CHUNK_SIZE); |             long totalLength = fileToUpload.length(); | ||||||
| //            String chunkSizeStr = String.valueOf(CHUNK_SIZE); |             long chunkCount = (long) Math.ceil((double) totalLength / CHUNK_SIZE); | ||||||
| //            String totalLengthStr = String.valueOf(file.length()); |             String chunkSizeStr = String.valueOf(CHUNK_SIZE); | ||||||
| //            for (int chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++, offset += CHUNK_SIZE) { |             String totalLengthStr = String.valueOf(fileToUpload.length()); | ||||||
| //                if (chunkIndex == chunkCount - 1) { | 
 | ||||||
| //                    chunkSizeStr = String.valueOf(CHUNK_SIZE * chunkCount - totalLength); |             for (int chunkIndex = 0; chunkIndex < chunkCount; chunkIndex++, offset += CHUNK_SIZE) { | ||||||
| //                } |                 if (chunkIndex == chunkCount - 1) { | ||||||
| //                if (mPutMethod != null) { |                     chunkSizeStr = String.valueOf(CHUNK_SIZE * chunkCount - totalLength); | ||||||
| //                    mPutMethod.releaseConnection();     // let the connection available |                 } | ||||||
| //                    // for other methods | 
 | ||||||
| //                } |                 mPutMethod = new PutMethod( | ||||||
| //                mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex); |                         HttpUtils.stringUrlToHttpUrl(uriPrefix + FileUtils.PATH_SEPARATOR + chunkIndex) | ||||||
| //                if (mRequiredEtag != null && mRequiredEtag.length() > 0) { |                 ); | ||||||
| //                    mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\""); | 
 | ||||||
| //                } |                 if (mRequiredEtag != null && mRequiredEtag.length() > 0) { | ||||||
|  |                     mPutMethod.addRequestHeader(IF_MATCH_HEADER, "\"" + mRequiredEtag + "\""); | ||||||
|  |                 } | ||||||
| //                mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER); | //                mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER); | ||||||
| //                mPutMethod.addRequestHeader(OC_CHUNK_SIZE_HEADER, chunkSizeStr); | //                mPutMethod.addRequestHeader(OC_CHUNK_SIZE_HEADER, chunkSizeStr); | ||||||
| //                mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, totalLengthStr); |                 mPutMethod.addRequestHeader(OC_TOTAL_LENGTH_HEADER, totalLengthStr); | ||||||
| // | 
 | ||||||
| //                mPutMethod.addRequestHeader(OC_CHUNK_X_OC_MTIME_HEADER, mFileLastModifTimestamp); |                 mPutMethod.addRequestHeader(OC_CHUNK_X_OC_MTIME_HEADER, mFileLastModifTimestamp); | ||||||
| // | 
 | ||||||
| //                ((ChunkFromFileChannelRequestEntity) mEntity).setOffset(offset); | //                ((ChunkFromFileChannelRequestEntity) mEntity).setOffset(offset); | ||||||
| //                mPutMethod.setRequestEntity(mEntity); | //                mPutMethod.setRequestEntity(mEntity); | ||||||
| //                if (mCancellationRequested.get()) { | //                if (mCancellationRequested.get()) { | ||||||
| //                    mPutMethod.abort(); | //                    mPutMethod.abort(); | ||||||
| //                    // next method will throw an exception | //                    // next method will throw an exception | ||||||
| //                } | //                } | ||||||
| // | 
 | ||||||
| //                if (chunkIndex == chunkCount - 1) { | //                if (chunkIndex == chunkCount - 1) { | ||||||
| //                    // Added a high timeout to the last chunk due to when the last chunk | //                    // Added a high timeout to the last chunk due to when the last chunk | ||||||
| //                    // arrives to the server with the last PUT, all chunks get assembled | //                    // arrives to the server with the last PUT, all chunks get assembled | ||||||
| //                    // within that PHP request, so last one takes longer. | //                    // within that PHP request, so last one takes longer. | ||||||
| //                    mPutMethod.getParams().setSoTimeout(LAST_CHUNK_TIMEOUT); | //                    mPutMethod.getParams().setSoTimeout(LAST_CHUNK_TIMEOUT); | ||||||
| //                } | //                } | ||||||
| // | 
 | ||||||
| //                status = client.executeMethod(mPutMethod); |                 mPutMethod.setRequestBody(mFileRequestBody); | ||||||
| // | 
 | ||||||
| //                result = new RemoteOperationResult( |                 status = client.executeHttpMethod(mPutMethod); | ||||||
| //                    isSuccess(status), | 
 | ||||||
| //                    mPutMethod |                 Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + | ||||||
| //                ); |                         ", chunk index " + chunkIndex + ", count " + chunkCount + | ||||||
| // |                         ", HTTP result status " + status); | ||||||
| //                client.exhaustResponse(mPutMethod.getResponseBodyAsStream()); | 
 | ||||||
| //                Log_OC.d(TAG, "Upload of " + mLocalPath + " to " + mRemotePath + |                 if (isSuccess(status)) { | ||||||
| //                    ", chunk index " + chunkIndex + ", count " + chunkCount + |                     result = new RemoteOperationResult(OK); | ||||||
| //                    ", HTTP result status " + status); |                 } else { | ||||||
| // |                     result = new RemoteOperationResult(mPutMethod); | ||||||
| //                if (!isSuccess(status)) |                     break; | ||||||
| //                    break; |                 } | ||||||
| //            } |             } | ||||||
| // | 
 | ||||||
| //        } finally { |         } catch (Exception e) { | ||||||
| //            if (channel != null) |             e.printStackTrace(); | ||||||
| //                channel.close(); |         } finally { | ||||||
| //            if (raf != null) |             if (channel != null) | ||||||
| //                raf.close(); |                 channel.close(); | ||||||
|  |             if (raf != null) | ||||||
|  |                 raf.close(); | ||||||
| //            if (mPutMethod != null) | //            if (mPutMethod != null) | ||||||
| //                mPutMethod.releaseConnection();    // let the connection available for other methods | //                mPutMethod.releaseConnection();    // let the connection available for other methods | ||||||
| //        } |         } | ||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
| } | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user