@@ -23,6 +23,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
2323import java.io.BufferedInputStream
2424import java.io.BufferedReader
2525import java.io.File
26+ import java.io.RandomAccessFile
2627import java.io.IOException
2728import java.net.CookieManager
2829import java.net.CookiePolicy
@@ -225,7 +226,7 @@ class Client @JvmOverloads constructor(
225226 headers: Map<String , String > = mapOf(),
226227 params: Map<String , Any ?> = mapOf(),
227228 responseType: Class<T >,
228- convert : ((Map<String , Any ,>) -> T)? = null
229+ converter : ((Map<String , Any ,>) -> T)? = null
229230 ): T {
230231 val filteredParams = params.filterValues { it != null }
231232
@@ -261,7 +262,7 @@ class Client @JvmOverloads constructor(
261262 .get()
262263 .build()
263264
264- return awaitResponse(request, responseType, convert )
265+ return awaitResponse(request, responseType, converter )
265266 }
266267
267268 val body = if (MultipartBody.FORM.toString() == headers["content-type"]) {
@@ -298,7 +299,7 @@ class Client @JvmOverloads constructor(
298299 .method(method, body)
299300 .build()
300301
301- return awaitResponse(request, responseType, convert )
302+ return awaitResponse(request, responseType, converter )
302303 }
303304
304305 /**
@@ -316,8 +317,9 @@ class Client @JvmOverloads constructor(
316317 headers: MutableMap<String , String >,
317318 params: MutableMap<String , Any ?>,
318319 responseType: Class<T >,
319- convert : ((Map<String , Any ,>) -> T),
320+ converter : ((Map<String , Any ,>) -> T),
320321 paramName: String,
322+ idParamName: String? = null,
321323 onProgress: ((UploadProgress) -> Unit)? = null,
322324 ): T {
323325 val file = params[paramName] as File
@@ -330,74 +332,84 @@ class Client @JvmOverloads constructor(
330332 file.asRequestBody()
331333 )
332334 return call(
333- "POST",
335+ method = "POST",
334336 path,
335337 headers,
336338 params,
337339 responseType,
338- convert
340+ converter
339341 )
340342 }
341343
342- val input = file.inputStream().buffered( )
344+ val input = RandomAccessFile(file, "r" )
343345 val buffer = ByteArray(CHUNK_SIZE)
344346 var offset = 0L
345347 var result: Map< *, *>? = null
346348
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+
356366 params[paramName] = MultipartBody.Part.createFormData(
357367 paramName,
358368 file.name,
359- it .toRequestBody()
369+ buffer .toRequestBody()
360370 )
361371
362372 headers["Content-Range"] =
363373 "bytes $offset-${((offset + CHUNK_SIZE) - 1).coerceAtMost(size)}/$size"
364374
365375 result = call(
366- "POST",
376+ method = "POST",
367377 path,
368378 headers,
369379 params,
370- Map::class.java
380+ responseType = Map::class.java
371381 )
372382
373383 offset += CHUNK_SIZE
374384 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- ))
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+ )
382394 }
383395
384- return convert (result as Map<String , Any >)
396+ return converter (result as Map<String , Any >)
385397 }
386398
387399 /**
388400 * Await Response
389401 *
390402 * @param request
391403 * @param responseType
392- * @param convert
404+ * @param converter
393405 *
394406 * @return [T]
395407 */
396408 @Throws({{ spec .title | caseUcfirst }}Exception::class)
397409 private suspend fun <T > awaitResponse(
398410 request: Request,
399411 responseType: Class<T >,
400- convert : ((Map<String , Any ,>) -> T)? = null
412+ converter : ((Map<String , Any ,>) -> T)? = null
401413 ) = suspendCancellableCoroutine<T > {
402414 http.newCall(request).enqueue(object : Callback {
403415 override fun onFailure(call: Call, e: IOException) {
@@ -463,7 +475,7 @@ class Client @JvmOverloads constructor(
463475 object : TypeToken<Map <String , Any >>(){}.type
464476 )
465477 it.resume(
466- convert ?.invoke(map) ?: map as T
478+ converter ?.invoke(map) ?: map as T
467479 )
468480 }
469481 })
0 commit comments