All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.pubnub.internal.endpoints.files.UploadFileEndpoint.kt Maven / Gradle / Ivy
package com.pubnub.internal.endpoints.files
import com.pubnub.api.PubNubError
import com.pubnub.api.PubNubException
import com.pubnub.api.endpoints.remoteaction.ExtendedRemoteAction
import com.pubnub.api.enums.PNOperationType
import com.pubnub.api.v2.callbacks.Result
import com.pubnub.internal.PubNubCore
import com.pubnub.internal.models.server.files.FileUploadRequestDetails
import com.pubnub.internal.models.server.files.FormField
import com.pubnub.internal.services.S3Service
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.slf4j.LoggerFactory
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.IOException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.util.function.Consumer
import javax.net.ssl.SSLException
import javax.xml.parsers.DocumentBuilderFactory
internal class UploadFileEndpoint(
private val s3Service: S3Service,
private val fileName: String,
private val content: ByteArray,
private val key: FormField,
private val formParams: List,
private val baseUrl: String,
) : ExtendedRemoteAction {
private var call: Call? = null
@Throws(PubNubException::class)
private fun prepareCall(): Call {
val builder = MultipartBody.Builder().setType(MultipartBody.FORM)
addFormParamsWithKeyFirst(key, formParams, builder)
val mediaType = getMediaType(formParams.findContentType())
builder.addFormDataPart(FILE_PART_MULTIPART, fileName, content.toRequestBody(mediaType, 0, content.size))
return s3Service.upload(baseUrl, builder.build())
}
private fun List.findContentType(): String? {
return find { (key, _) ->
key.equals(CONTENT_TYPE_HEADER, ignoreCase = true)
}?.value
}
private fun getMediaType(contentType: String?): MediaType {
return if (contentType == null) {
APPLICATION_OCTET_STREAM
} else {
try {
contentType.toMediaType()
} catch (t: Throwable) {
log.warn("Content-Type: $contentType was not recognized by MediaType.get", t)
APPLICATION_OCTET_STREAM
}
}
}
@Throws(PubNubException::class)
override fun sync() {
call = prepareCall()
val serverResponse =
try {
call!!.execute()
} catch (e: IOException) {
throw PubNubException(
errorMessage = e.message,
affectedCall = call,
pubnubError = PubNubError.PARSING_ERROR,
cause = e,
)
}
if (!serverResponse.isSuccessful) {
throw createException(serverResponse)
}
}
override fun async(callback: Consumer>) {
try {
call = prepareCall()
call!!.enqueue(
object : Callback {
override fun onResponse(
performedCall: Call,
response: Response,
) {
if (!response.isSuccessful) {
val ex = createException(response)
callback.accept(Result.failure(ex))
return
}
callback.accept(Result.success(Unit))
}
override fun onFailure(
performedCall: Call,
throwable: Throwable,
) {
if (call!!.isCanceled) {
return
}
val error =
when (throwable) {
is UnknownHostException, is SocketException, is SSLException -> PubNubError.CONNECT_EXCEPTION
is SocketTimeoutException -> PubNubError.SUBSCRIBE_TIMEOUT
else ->
if (performedCall.isCanceled) {
PubNubError.HTTP_ERROR
} else {
PubNubError.HTTP_ERROR
}
}
callback.accept(
Result.failure(
PubNubException(error).copy(
errorMessage = throwable.message ?: error.message,
cause = throwable,
),
),
)
}
},
)
} catch (e: Throwable) {
callback.accept(Result.failure(PubNubException.from(e)))
}
}
override fun retry() {}
override fun silentCancel() {
if (!call!!.isCanceled) {
call!!.cancel()
}
}
private fun createException(response: Response): PubNubException {
return try {
PubNubException(
errorMessage = response.readErrorMessage(),
affectedCall = call,
statusCode = response.code(),
)
} catch (e: Exception) {
PubNubException(
errorMessage = e.message,
affectedCall = call,
statusCode = response.code(),
)
}
}
private fun Response.readErrorMessage(): String {
val dbFactory = DocumentBuilderFactory.newInstance()
dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)
dbFactory.isXIncludeAware = false
val dBuilder = dbFactory.newDocumentBuilder()
val doc = dBuilder.parse(errorBody()!!.byteStream())
doc.documentElement.normalize()
val elements = doc.getElementsByTagName("Message")
return elements.item(0)?.firstChild?.nodeValue ?: "N/A"
}
internal class Factory(private val pubNub: PubNubCore) {
fun create(
fileName: String,
content: ByteArray,
fileUploadRequestDetails: FileUploadRequestDetails,
): ExtendedRemoteAction {
return UploadFileEndpoint(
pubNub.retrofitManager.s3Service,
fileName,
content,
fileUploadRequestDetails.keyFormField,
fileUploadRequestDetails.formFields,
fileUploadRequestDetails.url,
)
}
}
companion object {
private val APPLICATION_OCTET_STREAM = "application/octet-stream".toMediaType()
private const val CONTENT_TYPE_HEADER = "Content-Type"
private const val FILE_PART_MULTIPART = "file"
private val log = LoggerFactory.getLogger(UploadFileEndpoint::class.java)
private fun addFormParamsWithKeyFirst(
keyValue: FormField,
formParams: List,
builder: MultipartBody.Builder,
) {
builder.addFormDataPart(keyValue.key, keyValue.value)
formParams
.filter { it.key != keyValue.key }
.forEach { builder.addFormDataPart(it.key, it.value) }
}
}
override fun operationType(): PNOperationType = PNOperationType.FileOperation
}