ultrasonic-app-subsonic-and.../core/subsonic-api/src/main/kotlin/org/moire/ultrasonic/api/subsonic/interceptors/VersionInterceptor.kt

82 lines
2.6 KiB
Kotlin

package org.moire.ultrasonic.api.subsonic.interceptors
import com.fasterxml.jackson.core.JsonFactory
import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.core.JsonToken
import java.io.IOException
import okhttp3.Interceptor
import okhttp3.Interceptor.Chain
import okhttp3.Response
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
private const val DEFAULT_PEEK_BYTE_COUNT = 1000L
/**
* Special [Interceptor] that adds client supported version to request and tries to update it
* from server response.
*
* Optionally [notifier] will be invoked on version change.
*
* @author Yahor Berdnikau
*/
internal class VersionInterceptor(
internal var protocolVersion: SubsonicAPIVersions,
private val notifier: (SubsonicAPIVersions) -> Unit = {}
) : Interceptor {
private val jsonFactory = JsonFactory()
override fun intercept(chain: Chain): okhttp3.Response {
val originalRequest = chain.request()
val newRequest = originalRequest.newBuilder()
.url(
originalRequest
.url()
.newBuilder()
.addQueryParameter("v", protocolVersion.restApiVersion)
.build()
)
.build()
val response = chain.proceed(newRequest)
if (response.isSuccessful) {
val isJson = response.body()?.contentType()?.subtype()?.equals("json", true) ?: false
if (isJson) {
tryUpdateProtocolVersion(response)
}
}
return response
}
private fun tryUpdateProtocolVersion(response: Response) {
val content = response.peekBody(DEFAULT_PEEK_BYTE_COUNT).byteStream()
try {
val jsonReader = jsonFactory.createParser(content)
jsonReader.nextToken()
if (jsonReader.currentToken == JsonToken.START_OBJECT) {
while (
jsonReader.currentName != "version" &&
jsonReader.currentToken != null
) {
jsonReader.nextToken()
}
val versionStr = jsonReader.nextTextValue()
if (versionStr != null) {
try {
protocolVersion = SubsonicAPIVersions.fromApiVersion(versionStr)
notifier(protocolVersion)
} catch (e: IllegalArgumentException) {
// no-op
}
}
}
} catch (io: IOException) {
// no-op
} catch (parse: JsonParseException) {
// no-op
}
}
}