@@ -23,6 +23,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
23
23
import java.io.BufferedInputStream
24
24
import java.io.BufferedReader
25
25
import java.io.File
26
+ import java.io.RandomAccessFile
26
27
import java.io.IOException
27
28
import java.net.CookieManager
28
29
import java.net.CookiePolicy
@@ -225,7 +226,7 @@ class Client @JvmOverloads constructor(
225
226
headers: Map<String , String > = mapOf(),
226
227
params: Map<String , Any ?> = mapOf(),
227
228
responseType: Class<T >,
228
- convert : ((Map<String , Any ,>) -> T)? = null
229
+ converter : ((Map<String , Any ,>) -> T)? = null
229
230
): T {
230
231
val filteredParams = params.filterValues { it != null }
231
232
@@ -261,7 +262,7 @@ class Client @JvmOverloads constructor(
261
262
.get()
262
263
.build()
263
264
264
- return awaitResponse(request, responseType, convert )
265
+ return awaitResponse(request, responseType, converter )
265
266
}
266
267
267
268
val body = if (MultipartBody.FORM.toString() == headers["content-type"]) {
@@ -298,7 +299,7 @@ class Client @JvmOverloads constructor(
298
299
.method(method, body)
299
300
.build()
300
301
301
- return awaitResponse(request, responseType, convert )
302
+ return awaitResponse(request, responseType, converter )
302
303
}
303
304
304
305
/**
@@ -316,8 +317,9 @@ class Client @JvmOverloads constructor(
316
317
headers: MutableMap<String , String >,
317
318
params: MutableMap<String , Any ?>,
318
319
responseType: Class<T >,
319
- convert : ((Map<String , Any ,>) -> T),
320
+ converter : ((Map<String , Any ,>) -> T),
320
321
paramName: String,
322
+ idParamName: String? = null,
321
323
onProgress: ((UploadProgress) -> Unit)? = null,
322
324
): T {
323
325
val file = params[paramName] as File
@@ -330,74 +332,84 @@ class Client @JvmOverloads constructor(
330
332
file.asRequestBody()
331
333
)
332
334
return call(
333
- "POST",
335
+ method = "POST",
334
336
path,
335
337
headers,
336
338
params,
337
339
responseType,
338
- convert
340
+ converter
339
341
)
340
342
}
341
343
342
- val input = file.inputStream().buffered( )
344
+ val input = RandomAccessFile(file, "r" )
343
345
val buffer = ByteArray(CHUNK_SIZE)
344
346
var offset = 0L
345
347
var result: Map< *, *>? = null
346
348
347
- generateSequence {
348
- val readBytes = input.read(buffer)
349
- if (readBytes >= 0) {
350
- buffer.copyOf(readBytes)
351
- } else {
352
- input.close()
353
- null
354
- }
355
- }.forEach {
349
+ if (idParamName?.isNotEmpty() == true && params[idParamName] != "unique()") {
350
+ // Make a request to check if a file already exists
351
+ val current = call(
352
+ method = "GET",
353
+ path = "$path/${params[idParamName]}",
354
+ headers = headers,
355
+ params = emptyMap(),
356
+ responseType = Map::class.java,
357
+ )
358
+ val chunksUploaded = current["chunksUploaded"] as Long
359
+ offset = (chunksUploaded * CHUNK_SIZE).coerceAtMost(size)
360
+ }
361
+
362
+ while (offset < size) {
363
+ input.seek(offset)
364
+ input.read(buffer)
365
+
356
366
params[paramName] = MultipartBody.Part.createFormData(
357
367
paramName,
358
368
file.name,
359
- it .toRequestBody()
369
+ buffer .toRequestBody()
360
370
)
361
371
362
372
headers["Content-Range"] =
363
373
"bytes $offset-${((offset + CHUNK_SIZE) - 1).coerceAtMost(size)}/$size"
364
374
365
375
result = call(
366
- "POST",
376
+ method = "POST",
367
377
path,
368
378
headers,
369
379
params,
370
- Map::class.java
380
+ responseType = Map::class.java
371
381
)
372
382
373
383
offset += CHUNK_SIZE
374
- headers["x-{{ spec .title | caseLower }}-id"] = result!!["\$id"].toString()
375
- onProgress?.invoke(UploadProgress(
376
- id = result!!["\$id"].toString(),
377
- progress = offset.coerceAtMost(size).toDouble()/size * 100,
378
- sizeUploaded = offset.coerceAtMost(size),
379
- chunksTotal = result!!["chunksTotal"].toString().toInt(),
380
- chunksUploaded = result!!["chunksUploaded"].toString().toInt(),
381
- ))
384
+ headers["x-appwrite-id"] = result!!["\$id"].toString()
385
+ onProgress?.invoke(
386
+ UploadProgress(
387
+ id = result!!["\$id"].toString(),
388
+ progress = offset.coerceAtMost(size).toDouble() / size * 100,
389
+ sizeUploaded = offset.coerceAtMost(size),
390
+ chunksTotal = result!!["chunksTotal"].toString().toInt(),
391
+ chunksUploaded = result!!["chunksUploaded"].toString().toInt(),
392
+ )
393
+ )
382
394
}
383
395
384
- return convert (result as Map<String , Any >)
396
+ return converter (result as Map<String , Any >)
385
397
}
386
398
387
399
/**
388
400
* Await Response
389
401
*
390
402
* @param request
391
403
* @param responseType
392
- * @param convert
404
+ * @param converter
393
405
*
394
406
* @return [T]
395
407
*/
396
408
@Throws({{ spec .title | caseUcfirst }}Exception::class)
397
409
private suspend fun <T > awaitResponse(
398
410
request: Request,
399
411
responseType: Class<T >,
400
- convert : ((Map<String , Any ,>) -> T)? = null
412
+ converter : ((Map<String , Any ,>) -> T)? = null
401
413
) = suspendCancellableCoroutine<T > {
402
414
http.newCall(request).enqueue(object : Callback {
403
415
override fun onFailure(call: Call, e: IOException) {
@@ -463,7 +475,7 @@ class Client @JvmOverloads constructor(
463
475
object : TypeToken<Map <String , Any >>(){}.type
464
476
)
465
477
it.resume(
466
- convert ?.invoke(map) ?: map as T
478
+ converter ?.invoke(map) ?: map as T
467
479
)
468
480
}
469
481
})
0 commit comments