@@ -20,6 +20,7 @@ import okhttp3.logging.HttpLoggingInterceptor
20
20
import java.io.BufferedInputStream
21
21
import java.io.BufferedReader
22
22
import java.io.File
23
+ import java.io.RandomAccessFile
23
24
import java.io.IOException
24
25
import java.security.SecureRandom
25
26
import java.security.cert.X509Certificate
@@ -219,7 +220,7 @@ class Client @JvmOverloads constructor(
219
220
headers : Map <String , String > = mapOf(),
220
221
params : Map <String , Any ?> = mapOf(),
221
222
responseType : Class <T >,
222
- convert : ((Map <String , Any ,>) -> T )? = null
223
+ converter : ((Map <String , Any ,>) -> T )? = null
223
224
): T {
224
225
val filteredParams = params.filterValues { it != null }
225
226
@@ -255,7 +256,7 @@ class Client @JvmOverloads constructor(
255
256
.get()
256
257
.build()
257
258
258
- return awaitResponse(request, responseType, convert )
259
+ return awaitResponse(request, responseType, converter )
259
260
}
260
261
261
262
val body = if (MultipartBody .FORM .toString() == headers[" content-type" ]) {
@@ -292,7 +293,7 @@ class Client @JvmOverloads constructor(
292
293
.method(method, body)
293
294
.build()
294
295
295
- return awaitResponse(request, responseType, convert )
296
+ return awaitResponse(request, responseType, converter )
296
297
}
297
298
298
299
/* *
@@ -310,8 +311,9 @@ class Client @JvmOverloads constructor(
310
311
headers : MutableMap <String , String >,
311
312
params : MutableMap <String , Any ?>,
312
313
responseType : Class <T >,
313
- convert : ((Map <String , Any ,>) -> T ),
314
+ converter : ((Map <String , Any ,>) -> T ),
314
315
paramName : String ,
316
+ idParamName : String? = null,
315
317
onProgress : ((UploadProgress ) -> Unit )? = null,
316
318
): T {
317
319
val file = params[paramName] as File
@@ -324,74 +326,84 @@ class Client @JvmOverloads constructor(
324
326
file.asRequestBody()
325
327
)
326
328
return call(
327
- " POST" ,
329
+ method = " POST" ,
328
330
path,
329
331
headers,
330
332
params,
331
333
responseType,
332
- convert
334
+ converter
333
335
)
334
336
}
335
337
336
- val input = file.inputStream().buffered( )
338
+ val input = RandomAccessFile (file, " r " )
337
339
val buffer = ByteArray (CHUNK_SIZE )
338
340
var offset = 0L
339
341
var result: Map <* , * >? = null
340
342
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
+
350
360
params[paramName] = MultipartBody .Part .createFormData(
351
361
paramName,
352
362
file.name,
353
- it .toRequestBody()
363
+ buffer .toRequestBody()
354
364
)
355
365
356
366
headers[" Content-Range" ] =
357
367
" bytes $offset -${((offset + CHUNK_SIZE ) - 1 ).coerceAtMost(size)} /$size "
358
368
359
369
result = call(
360
- " POST" ,
370
+ method = " POST" ,
361
371
path,
362
372
headers,
363
373
params,
364
- Map ::class .java
374
+ responseType = Map ::class .java
365
375
)
366
376
367
377
offset + = CHUNK_SIZE
368
378
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
+ )
376
388
}
377
389
378
- return convert (result as Map <String , Any >)
390
+ return converter (result as Map <String , Any >)
379
391
}
380
392
381
393
/* *
382
394
* Await Response
383
395
*
384
396
* @param request
385
397
* @param responseType
386
- * @param convert
398
+ * @param converter
387
399
*
388
400
* @return [T]
389
401
*/
390
402
@Throws(AppwriteException ::class )
391
403
private suspend fun <T > awaitResponse (
392
404
request : Request ,
393
405
responseType : Class <T >,
394
- convert : ((Map <String , Any ,>) -> T )? = null
406
+ converter : ((Map <String , Any ,>) -> T )? = null
395
407
) = suspendCancellableCoroutine<T > {
396
408
http.newCall(request).enqueue(object : Callback {
397
409
override fun onFailure (call : Call , e : IOException ) {
@@ -457,7 +469,7 @@ class Client @JvmOverloads constructor(
457
469
object : TypeToken <Map <String , Any >>(){}.type
458
470
)
459
471
it.resume(
460
- convert ?.invoke(map) ? : map as T
472
+ converter ?.invoke(map) ? : map as T
461
473
)
462
474
}
463
475
})
0 commit comments