Add version interceptor.
This interceptor add version param to request and peeks into response to parse server version. Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>
This commit is contained in:
parent
1c56d6459b
commit
c76d25e1ba
|
@ -0,0 +1,74 @@
|
|||
package org.moire.ultrasonic.api.subsonic.interceptors
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import org.amshove.kluent.`should contain`
|
||||
import org.amshove.kluent.`should equal`
|
||||
import org.junit.Test
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
|
||||
import org.moire.ultrasonic.api.subsonic.enqueueResponse
|
||||
import kotlin.LazyThreadSafetyMode.NONE
|
||||
|
||||
/**
|
||||
* Integration test for [VersionInterceptor].
|
||||
*/
|
||||
class VersionInterceptorTest : BaseInterceptorTest() {
|
||||
private val initialProtocolVersion = SubsonicAPIVersions.V1_1_0
|
||||
private var updatedProtocolVersion = SubsonicAPIVersions.V1_1_0
|
||||
|
||||
override val interceptor: Interceptor by lazy(NONE) {
|
||||
VersionInterceptor(initialProtocolVersion) {
|
||||
updatedProtocolVersion = it
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should add initial protocol version to request`() {
|
||||
mockWebServerRule.enqueueResponse("ping_ok.json")
|
||||
val request = createRequest {}
|
||||
|
||||
client.newCall(request).execute()
|
||||
|
||||
val requestLine = mockWebServerRule.mockWebServer.takeRequest().requestLine
|
||||
|
||||
requestLine `should contain` "v=${initialProtocolVersion.restApiVersion}"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should update version from response`() {
|
||||
mockWebServerRule.enqueueResponse("ping_ok.json")
|
||||
|
||||
client.newCall(createRequest {}).execute()
|
||||
|
||||
(interceptor as VersionInterceptor).protocolVersion `should equal` SubsonicAPIVersions.V1_13_0
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should not update version if response json doesn't contain version`() {
|
||||
mockWebServerRule.enqueueResponse("non_subsonic_response.json")
|
||||
|
||||
client.newCall(createRequest {}).execute()
|
||||
|
||||
(interceptor as VersionInterceptor).protocolVersion `should equal` initialProtocolVersion
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should not update version on non-json response`() {
|
||||
mockWebServerRule.mockWebServer.enqueue(MockResponse()
|
||||
.setBody("asdqwnekjnqwkjen")
|
||||
.setHeader("Content-Type", "application/octet-stream"))
|
||||
|
||||
client.newCall(createRequest {}).execute()
|
||||
|
||||
(interceptor as VersionInterceptor).protocolVersion `should equal` initialProtocolVersion
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should notify notifier on version change`() {
|
||||
mockWebServerRule.enqueueResponse("ping_ok.json")
|
||||
|
||||
client.newCall(createRequest {}).execute()
|
||||
|
||||
updatedProtocolVersion `should equal` SubsonicAPIVersions.V1_13_0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"none" : "some"
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
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 okhttp3.Interceptor
|
||||
import okhttp3.Interceptor.Chain
|
||||
import okhttp3.Response
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
|
||||
import java.io.IOException
|
||||
|
||||
private const val DEFAULT_PEEK_BYTE_COUNT = 100L
|
||||
|
||||
/**
|
||||
* 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().bufferedReader().readText()
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue