Skip to content

Commit f4e2450

Browse files
authored
Adding the Call object when upload media wo the Kotlin wrapperto allow cancel it (#817)
* Adding the Call object when upload media to allow cancell it * Adding some documentation * Adding cancellable wrapper
1 parent 7aafe5e commit f4e2450

File tree

1 file changed

+53
-6
lines changed

1 file changed

+53
-6
lines changed

native/kotlin/api/kotlin/src/main/kotlin/rs/wordpress/api/kotlin/WpRequestExecutor.kt

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import kotlinx.coroutines.CoroutineDispatcher
44
import kotlinx.coroutines.Dispatchers
55
import kotlinx.coroutines.delay
66
import kotlinx.coroutines.withContext
7+
import okhttp3.Call
78
import okhttp3.HttpUrl
89
import okhttp3.MediaType.Companion.toMediaType
910
import okhttp3.MultipartBody
@@ -35,7 +36,7 @@ class WpRequestExecutor(
3536
private val httpClient: WpHttpClient = WpHttpClient.DefaultHttpClient(),
3637
private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
3738
private val fileResolver: FileResolver = DefaultFileResolver(),
38-
private val uploadProgressListener: ((uploadedBytes: Long, totalBytes: Long) -> Unit)? = null
39+
private val uploadListener: UploadListener? = null
3940
) : RequestExecutor {
4041
override suspend fun execute(request: WpNetworkRequest): WpNetworkResponse =
4142
withContext(dispatcher) {
@@ -95,7 +96,7 @@ class WpRequestExecutor(
9596
if (file == null || !file.canBeUploaded()) {
9697
throw MediaUploadRequestExecutionException.MediaFileNotFound(mediaUploadRequest.filePath())
9798
}
98-
val progressRequestBody = getRequestBody(file, mediaUploadRequest, uploadProgressListener)
99+
val progressRequestBody = getRequestBody(file, mediaUploadRequest, uploadListener)
99100
multipartBodyBuilder.addFormDataPart(
100101
name = "file",
101102
filename = file.name,
@@ -111,7 +112,10 @@ class WpRequestExecutor(
111112
}
112113
}
113114

114-
httpClient.getClient().newCall(requestBuilder.build()).execute().use { response ->
115+
val call = httpClient.getClient().newCall(requestBuilder.build())
116+
// Notify about the call creation so it can be cancelled if needed
117+
uploadListener?.onUploadStarted(CancellableCall(call))
118+
call.execute().use { response ->
115119
return@withContext WpNetworkResponse(
116120
body = response.body?.bytes() ?: ByteArray(0),
117121
statusCode = response.code.toUShort(),
@@ -125,15 +129,15 @@ class WpRequestExecutor(
125129
private fun getRequestBody(
126130
file: File,
127131
mediaUploadRequest: MediaUploadRequest,
128-
uploadProgressListener: ((uploadedBytes: Long, totalBytes: Long) -> Unit)?
132+
uploadListener: UploadListener?
129133
): RequestBody {
130134
val fileRequestBody = file.asRequestBody(mediaUploadRequest.fileContentType().toMediaType())
131-
return if (uploadProgressListener != null) {
135+
return if (uploadListener != null) {
132136
ProgressRequestBody(
133137
delegate = fileRequestBody,
134138
progressListener = object : ProgressRequestBody.ProgressListener {
135139
override fun onProgress(bytesWritten: Long, contentLength: Long) {
136-
uploadProgressListener.invoke(bytesWritten, contentLength)
140+
uploadListener.onProgressUpdate(bytesWritten, contentLength)
137141
}
138142
}
139143
)
@@ -147,6 +151,49 @@ class WpRequestExecutor(
147151
}
148152

149153
private fun File.canBeUploaded() = exists() && isFile && canRead()
154+
155+
/**
156+
* Interface for monitoring the progress and status of a media upload.
157+
*/
158+
interface UploadListener {
159+
/**
160+
* Called to report the progress of the upload.
161+
*
162+
* @param uploadedBytes The number of bytes that have been uploaded so far.
163+
* @param totalBytes The total number of bytes to be uploaded.
164+
*/
165+
fun onProgressUpdate(uploadedBytes: Long, totalBytes: Long)
166+
167+
/**
168+
* Called when the upload starts.
169+
*
170+
* @param cancellableUpload The [CancellableUpload] object representing the upload request. This can be used
171+
* to cancel the upload if needed by calling [cancellableUpload.cancel].
172+
*
173+
* This method is invoked at the beginning of the upload process, allowing the caller
174+
* to monitor or control the upload operation.
175+
*/
176+
fun onUploadStarted(cancellableUpload: CancellableUpload)
177+
}
178+
179+
/**
180+
* Represents a cancellable upload operation.
181+
*/
182+
interface CancellableUpload {
183+
/**
184+
* Cancels the upload operation.
185+
*/
186+
fun cancel()
187+
}
188+
189+
/**
190+
* Implementation of [CancellableUpload] that delegates to an OkHttp [Call].
191+
*/
192+
class CancellableCall(private val call: Call) : CancellableUpload {
193+
override fun cancel() {
194+
call.cancel()
195+
}
196+
}
150197
}
151198

152199
private fun RequestExecutionErrorReason.Companion.unknownHost(e: UnknownHostException) =

0 commit comments

Comments
 (0)