@@ -20,6 +20,7 @@ import okhttp3.logging.HttpLoggingInterceptor
2020import java.io.BufferedInputStream
2121import java.io.BufferedReader
2222import java.io.File
23+ import java.io.RandomAccessFile
2324import java.io.IOException
2425import java.security.SecureRandom
2526import java.security.cert.X509Certificate
@@ -219,7 +220,7 @@ class Client @JvmOverloads constructor(
219220 headers : Map <String , String > = mapOf(),
220221 params : Map <String , Any ?> = mapOf(),
221222 responseType : Class <T >,
222- convert : ((Map <String , Any ,>) -> T )? = null
223+ converter : ((Map <String , Any ,>) -> T )? = null
223224 ): T {
224225 val filteredParams = params.filterValues { it != null }
225226
@@ -255,7 +256,7 @@ class Client @JvmOverloads constructor(
255256 .get()
256257 .build()
257258
258- return awaitResponse(request, responseType, convert )
259+ return awaitResponse(request, responseType, converter )
259260 }
260261
261262 val body = if (MultipartBody .FORM .toString() == headers[" content-type" ]) {
@@ -292,7 +293,7 @@ class Client @JvmOverloads constructor(
292293 .method(method, body)
293294 .build()
294295
295- return awaitResponse(request, responseType, convert )
296+ return awaitResponse(request, responseType, converter )
296297 }
297298
298299 /* *
@@ -310,8 +311,9 @@ class Client @JvmOverloads constructor(
310311 headers : MutableMap <String , String >,
311312 params : MutableMap <String , Any ?>,
312313 responseType : Class <T >,
313- convert : ((Map <String , Any ,>) -> T ),
314+ converter : ((Map <String , Any ,>) -> T ),
314315 paramName : String ,
316+ idParamName : String? = null,
315317 onProgress : ((UploadProgress ) -> Unit )? = null,
316318 ): T {
317319 val file = params[paramName] as File
@@ -324,74 +326,84 @@ class Client @JvmOverloads constructor(
324326 file.asRequestBody()
325327 )
326328 return call(
327- " POST" ,
329+ method = " POST" ,
328330 path,
329331 headers,
330332 params,
331333 responseType,
332- convert
334+ converter
333335 )
334336 }
335337
336- val input = file.inputStream().buffered( )
338+ val input = RandomAccessFile (file, " r " )
337339 val buffer = ByteArray (CHUNK_SIZE )
338340 var offset = 0L
339341 var result: Map <* , * >? = null
340342
341- generateSequence {
342- val readBytes = input.read(buffer)
343- if (readBytes >= 0 ) {
344- buffer.copyOf(readBytes)
345- } else {
346- input.close()
347- null
348- }
349- }.forEach {
343+ if (idParamName?.isNotEmpty() == true && params[idParamName] != " unique()" ) {
344+ // Make a request to check if a file already exists
345+ val current = call(
346+ method = " GET" ,
347+ path = " $path /${params[idParamName]} " ,
348+ headers = headers,
349+ params = emptyMap(),
350+ responseType = Map ::class .java,
351+ )
352+ val chunksUploaded = current[" chunksUploaded" ] as Long
353+ offset = (chunksUploaded * CHUNK_SIZE ).coerceAtMost(size)
354+ }
355+
356+ while (offset < size) {
357+ input.seek(offset)
358+ input.read(buffer)
359+
350360 params[paramName] = MultipartBody .Part .createFormData(
351361 paramName,
352362 file.name,
353- it .toRequestBody()
363+ buffer .toRequestBody()
354364 )
355365
356366 headers[" Content-Range" ] =
357367 " bytes $offset -${((offset + CHUNK_SIZE ) - 1 ).coerceAtMost(size)} /$size "
358368
359369 result = call(
360- " POST" ,
370+ method = " POST" ,
361371 path,
362372 headers,
363373 params,
364- Map ::class .java
374+ responseType = Map ::class .java
365375 )
366376
367377 offset + = CHUNK_SIZE
368378 headers[" x-appwrite-id" ] = result!! [" \$ id" ].toString()
369- onProgress?.invoke(UploadProgress (
370- id = result!! [" \$ id" ].toString(),
371- progress = offset.coerceAtMost(size).toDouble()/ size * 100 ,
372- sizeUploaded = offset.coerceAtMost(size),
373- chunksTotal = result!! [" chunkTotal" ].toString().toInt(),
374- chunksUploaded = result!! [" chunkUploaded" ].toString().toInt(),
375- ))
379+ onProgress?.invoke(
380+ UploadProgress (
381+ id = result!! [" \$ id" ].toString(),
382+ progress = offset.coerceAtMost(size).toDouble() / size * 100 ,
383+ sizeUploaded = offset.coerceAtMost(size),
384+ chunksTotal = result!! [" chunksTotal" ].toString().toInt(),
385+ chunksUploaded = result!! [" chunksUploaded" ].toString().toInt(),
386+ )
387+ )
376388 }
377389
378- return convert (result as Map <String , Any >)
390+ return converter (result as Map <String , Any >)
379391 }
380392
381393 /* *
382394 * Await Response
383395 *
384396 * @param request
385397 * @param responseType
386- * @param convert
398+ * @param converter
387399 *
388400 * @return [T]
389401 */
390402 @Throws(AppwriteException ::class )
391403 private suspend fun <T > awaitResponse (
392404 request : Request ,
393405 responseType : Class <T >,
394- convert : ((Map <String , Any ,>) -> T )? = null
406+ converter : ((Map <String , Any ,>) -> T )? = null
395407 ) = suspendCancellableCoroutine<T > {
396408 http.newCall(request).enqueue(object : Callback {
397409 override fun onFailure (call : Call , e : IOException ) {
@@ -457,7 +469,7 @@ class Client @JvmOverloads constructor(
457469 object : TypeToken <Map <String , Any >>(){}.type
458470 )
459471 it.resume(
460- convert ?.invoke(map) ? : map as T
472+ converter ?.invoke(map) ? : map as T
461473 )
462474 }
463475 })
0 commit comments