Skip to content

Commit 1b77a69

Browse files
authored
Merge pull request #593 from namehillsoftware/feature/experimental-ktor-http-client
[Feature] Experimental Ktor HTTP client
2 parents 4037597 + 6a09a4a commit 1b77a69

File tree

127 files changed

+2268
-653
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+2268
-653
lines changed

gradle/libs.versions.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,20 @@ handoff = "0.30.1"
1515
jodaTime = "2.14.0"
1616
jsoup = "1.21.2"
1717
junit = "4.13.2"
18-
junitJupiterApi = "6.0.0"
18+
junitJupiterApi = "6.0.1"
1919
junitKtx = "1.3.0"
2020
kotlinxCoroutinesRx3 = "1.10.2"
2121
kotlin = "2.2.21"
22+
ktorVersion = "3.3.1"
2223
lazyJ = "0.11.0"
2324
lifecycle = "2.9.4"
2425
logbackAndroid = "3.0.0"
25-
markdownRenderer = "0.37.0"
26+
markdownRenderer = "0.38.1"
2627
material = "1.13.0"
2728
media = "1.7.1"
2829
media3 = "1.8.0"
2930
mockk = "1.14.6"
30-
okhttp = "5.2.1"
31+
okhttp = "5.3.0"
3132
okio = "3.16.2"
3233
paletteKtx = "1.0.0"
3334
preferenceKtx = "1.2.1"
@@ -79,6 +80,8 @@ junit-vintage-engine = { module = "org.junit.vintage:junit-vintage-engine" }
7980
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" }
8081
kotlinx-coroutines-rx3 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx3", version.ref = "kotlinxCoroutinesRx3" }
8182
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesRx3" }
83+
ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktorVersion" }
84+
ktor-client = { module = "io.ktor:ktor-client-cio", version.ref = "ktorVersion" }
8285
lazy-j = { module = "com.namehillsoftware:lazy-j", version.ref = "lazyJ" }
8386
logback-android = { module = "com.github.tony19:logback-android", version.ref = "logbackAndroid" }
8487
material = { module = "com.google.android.material:material", version.ref = "material" }

projectBlueWater/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ dependencies {
208208
implementation libs.joda.time
209209
implementation libs.commons.io
210210
implementation libs.slf4j.api
211+
implementation libs.ktor.client
212+
implementation libs.ktor.core
211213
implementation libs.logback.android
212214
implementation libs.handoff
213215
implementation libs.rxjava

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/ApplicationDependencies.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import com.lasthopesoftware.bluewater.client.connection.MediaCenterConnectionDet
1515
import com.lasthopesoftware.bluewater.client.connection.SubsonicConnectionDetails
1616
import com.lasthopesoftware.bluewater.client.connection.libraries.ProvideLibraryConnections
1717
import com.lasthopesoftware.bluewater.client.connection.libraries.ProvideProgressingLibraryConnections
18-
import com.lasthopesoftware.bluewater.client.connection.okhttp.OkHttpFactory
18+
import com.lasthopesoftware.bluewater.client.connection.requests.ProvideHttpPromiseClients
1919
import com.lasthopesoftware.bluewater.client.connection.requests.ProvideHttpPromiseServerClients
2020
import com.lasthopesoftware.bluewater.client.connection.session.ManageConnectionSessions
2121
import com.lasthopesoftware.bluewater.client.connection.settings.LookupConnectionSettings
@@ -64,7 +64,7 @@ interface ApplicationDependencies {
6464
val audioFileCache: DiskFileCache
6565
val connectionSettingsLookup: LookupConnectionSettings
6666
val audioCacheStreamSupplier: DiskFileCacheStreamSupplier
67-
val okHttpClients: OkHttpFactory
67+
val httpClients: ProvideHttpPromiseClients
6868
val libraryNameLookup: LibraryNameLookup
6969
val exceptionAnnouncer: AnnounceExceptions
7070
val mediaCenterHttpClients: ProvideHttpPromiseServerClients<MediaCenterConnectionDetails>

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/ApplicationDependenciesContainer.kt

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,16 @@ import com.lasthopesoftware.bluewater.client.browsing.library.settings.access.Ca
2626
import com.lasthopesoftware.bluewater.client.browsing.library.settings.access.LibrarySettingsAccess
2727
import com.lasthopesoftware.bluewater.client.browsing.library.settings.access.StoreLibrarySettings
2828
import com.lasthopesoftware.bluewater.client.connection.PacketSender
29+
import com.lasthopesoftware.bluewater.client.connection.http.ApplicationSettingsHttpClient
30+
import com.lasthopesoftware.bluewater.client.connection.http.ApplicationSettingsMediaCenterClient
31+
import com.lasthopesoftware.bluewater.client.connection.http.ApplicationSettingsSubsonicClient
32+
import com.lasthopesoftware.bluewater.client.connection.http.KtorFactory
33+
import com.lasthopesoftware.bluewater.client.connection.http.OkHttpFactory
2934
import com.lasthopesoftware.bluewater.client.connection.libraries.LibraryConnectionProvider
3035
import com.lasthopesoftware.bluewater.client.connection.libraries.ProvideProgressingLibraryConnections
3136
import com.lasthopesoftware.bluewater.client.connection.live.LiveServerConnectionProvider
3237
import com.lasthopesoftware.bluewater.client.connection.lookup.ServerInfoXmlRequest
3338
import com.lasthopesoftware.bluewater.client.connection.lookup.ServerLookup
34-
import com.lasthopesoftware.bluewater.client.connection.okhttp.OkHttpFactory
3539
import com.lasthopesoftware.bluewater.client.connection.session.ConnectionSessionManager
3640
import com.lasthopesoftware.bluewater.client.connection.session.PromisedConnectionsRepository
3741
import com.lasthopesoftware.bluewater.client.connection.settings.ConnectionSettingsLookup
@@ -66,6 +70,7 @@ import com.lasthopesoftware.resources.strings.Base64Encoder
6670
import com.lasthopesoftware.resources.strings.JsonEncoderDecoder
6771
import com.lasthopesoftware.resources.strings.StringResources
6872

73+
@OptIn(UnstableApi::class)
6974
object ApplicationDependenciesContainer {
7075

7176
private val connectionsRepository by lazy { PromisedConnectionsRepository() }
@@ -74,7 +79,6 @@ object ApplicationDependenciesContainer {
7479

7580
@SuppressLint("StaticFieldLeak")
7681
@Volatile
77-
@OptIn(UnstableApi::class)
7882
private var attachedDependencies: AttachedDependencies? = null
7983

8084
val Context.applicationDependencies: ApplicationDependencies
@@ -108,24 +112,45 @@ object ApplicationDependenciesContainer {
108112

109113
private val audioCacheFilesProvider by lazy { CachedFilesProvider(context, AudioCacheConfiguration) }
110114

111-
override val okHttpClients by lazy { OkHttpFactory(context) }
115+
private val okHttpClients by lazy { OkHttpFactory(context) }
116+
private val ktorClients by lazy { KtorFactory(context) }
112117

113-
override val mediaCenterHttpClients by lazy { okHttpClients.MediaCenterHttpPromiseServerClient() }
118+
override val httpClients by lazy {
119+
ApplicationSettingsHttpClient(
120+
applicationFeatureConfiguration,
121+
okHttpClients,
122+
ktorClients
123+
)
124+
}
125+
126+
override val mediaCenterHttpClients by lazy {
127+
ApplicationSettingsMediaCenterClient(
128+
applicationFeatureConfiguration,
129+
okHttpClients.MediaCenterClient(),
130+
ktorClients.MediaCenterClient()
131+
)
132+
}
114133

115134
override val mediaCenterDataFactories by lazy {
116135
ServerHttpDataSourceProvider(
117136
mediaCenterHttpClients,
118-
mediaCenterHttpClients,
137+
okHttpClients.MediaCenterClient(),
119138
applicationFeatureConfiguration
120139
)
121140
}
122141

123-
override val subsonicHttpClients by lazy { okHttpClients.SubsonicHttpPromiseServerClient() }
142+
override val subsonicHttpClients by lazy {
143+
ApplicationSettingsSubsonicClient(
144+
applicationFeatureConfiguration,
145+
okHttpClients.SubsonicClient(),
146+
ktorClients.SubsonicClient()
147+
)
148+
}
124149

125150
override val subsonicDataFactories by lazy {
126151
ServerHttpDataSourceProvider(
127152
subsonicHttpClients,
128-
subsonicHttpClients,
153+
okHttpClients.SubsonicClient(),
129154
applicationFeatureConfiguration
130155
)
131156
}
@@ -232,7 +257,7 @@ object ApplicationDependenciesContainer {
232257
override val connectionSessions by lazy {
233258
val serverLookup = ServerLookup(
234259
connectionSettingsLookup,
235-
ServerInfoXmlRequest(connectionSettingsLookup, okHttpClients),
260+
ServerInfoXmlRequest(connectionSettingsLookup, httpClients),
236261
)
237262

238263
val activeNetwork = ActiveNetworkFinder(context)

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/HandheldApplication.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ import com.lasthopesoftware.promises.extensions.toPromise
8181
import com.namehillsoftware.handoff.promises.Promise
8282
import dev.olshevski.navigation.reimagined.NavHost
8383
import dev.olshevski.navigation.reimagined.rememberNavController
84-
import kotlinx.coroutines.ExperimentalCoroutinesApi
8584
import kotlinx.coroutines.async
8685
import org.slf4j.LoggerFactory
8786

@@ -90,7 +89,6 @@ private val logger by lazy { LoggerFactory.getLogger("HandheldApplication") }
9089
private val bottomAppBarHeight = Dimensions.appBarHeight
9190
private val bottomSheetElevation = 16.dp
9291

93-
@OptIn(ExperimentalCoroutinesApi::class)
9492
@Composable
9593
private fun BrowserLibraryDestination.Navigate(
9694
browserViewDependencies: ScopedViewModelDependencies,

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/access/RemoteLibraryAccess.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import com.lasthopesoftware.bluewater.client.browsing.items.ItemId
77
import com.lasthopesoftware.bluewater.client.browsing.items.KeyedIdentifier
88
import com.lasthopesoftware.bluewater.client.browsing.items.playlists.PlaylistId
99
import com.lasthopesoftware.bluewater.client.servers.version.SemanticVersion
10+
import com.lasthopesoftware.resources.io.PromisingReadableStream
1011
import com.namehillsoftware.handoff.promises.Promise
11-
import java.io.InputStream
1212

1313
interface RemoteLibraryAccess {
1414
fun promiseFileProperties(serviceFile: ServiceFile): Promise<LookupFileProperties>
@@ -25,7 +25,7 @@ interface RemoteLibraryAccess {
2525
fun promiseIsReadOnly(): Promise<Boolean>
2626
fun promiseServerVersion(): Promise<SemanticVersion?>
2727
fun promiseRevision(): Promise<Long?>
28-
fun promiseFile(serviceFile: ServiceFile): Promise<InputStream>
28+
fun promiseFile(serviceFile: ServiceFile): Promise<PromisingReadableStream>
2929
fun promisePlaystatsUpdate(serviceFile: ServiceFile): Promise<*>
3030
fun promiseFiles(): Promise<List<ServiceFile>>
3131
fun promiseFiles(query: String): Promise<List<ServiceFile>>

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/browsing/files/cached/DiskFileCache.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import com.lasthopesoftware.bluewater.client.browsing.files.cached.configuration
77
import com.lasthopesoftware.bluewater.client.browsing.files.cached.disk.ProvideDiskCacheDirectory
88
import com.lasthopesoftware.bluewater.client.browsing.files.cached.persistence.UpdateDiskFileAccessTime
99
import com.lasthopesoftware.bluewater.client.browsing.files.cached.repository.CachedFile
10-
import com.lasthopesoftware.bluewater.client.browsing.files.cached.stream.CacheOutputStream
10+
import com.lasthopesoftware.bluewater.client.browsing.files.cached.stream.CacheWritableStream
1111
import com.lasthopesoftware.bluewater.client.browsing.files.cached.stream.supplier.SupplyCacheStreams
1212
import com.lasthopesoftware.bluewater.client.browsing.library.repository.LibraryId
1313
import com.lasthopesoftware.bluewater.repository.RepositoryAccessHelper
@@ -47,12 +47,12 @@ class DiskFileCache(
4747
return putPromise
4848
}
4949

50-
private fun writeCachedFileWithRetries(libraryId: LibraryId, uniqueKey: String, cachedFileOutputStream: CacheOutputStream, fileData: ByteArray): Promise<CachedFile?> {
50+
private fun writeCachedFileWithRetries(libraryId: LibraryId, uniqueKey: String, cachedFileOutputStream: CacheWritableStream, fileData: ByteArray): Promise<CachedFile?> {
5151
return cachedFileOutputStream
5252
.promiseWrite(fileData, 0, fileData.size)
53-
.eventually { obj -> obj.flush() }
53+
.eventually { cachedFileOutputStream.promiseFlush() }
5454
.eventually(
55-
{ fos -> fos.commitToCache() },
55+
{ cachedFileOutputStream.commitToCache() },
5656
{ e ->
5757
logger.error("Unable to write to file!", e)
5858

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/browsing/files/cached/stream/CacheOutputStream.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.lasthopesoftware.bluewater.client.browsing.files.cached.stream
2+
3+
import com.lasthopesoftware.bluewater.client.browsing.files.cached.repository.CachedFile
4+
import com.lasthopesoftware.resources.io.PromisingWritableStream
5+
import com.namehillsoftware.handoff.promises.Promise
6+
7+
interface CacheWritableStream : PromisingWritableStream {
8+
fun commitToCache(): Promise<CachedFile?>
9+
}

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/browsing/files/cached/stream/CachedFileOutputStream.kt renamed to projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/browsing/files/cached/stream/CachedFileWritableStream.kt

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@ import com.lasthopesoftware.promises.extensions.guaranteedUnitResponse
77
import com.lasthopesoftware.promises.extensions.preparePromise
88
import com.lasthopesoftware.resources.executors.ThreadPools
99
import com.namehillsoftware.handoff.promises.Promise
10-
import okio.BufferedSource
11-
import okio.sink
1210
import java.io.File
1311
import java.io.FileOutputStream
1412

15-
class CachedFileOutputStream(
13+
class CachedFileWritableStream(
1614
private val libraryId: LibraryId,
1715
private val uniqueKey: String,
1816
private val file: File,
1917
private val diskFileCachePersistence: IDiskFileCachePersistence
20-
) : CacheOutputStream {
18+
) : CacheWritableStream {
2119

2220
@Volatile
2321
private var isClosed = false
@@ -28,26 +26,18 @@ class CachedFileOutputStream(
2826
buffer: ByteArray,
2927
offset: Int,
3028
length: Int
31-
): Promise<CacheOutputStream> {
29+
): Promise<Int> {
3230
return ThreadPools.io.preparePromise {
33-
if (!isClosed)
34-
lazyFileOutputStream.value.write(buffer, offset, length)
35-
this
31+
if (!isClosed) {
32+
lazyFileOutputStream.value.write(buffer, offset, length)
33+
length
34+
} else 0
3635
}
3736
}
3837

39-
override fun promiseTransfer(bufferedSource: BufferedSource): Promise<CacheOutputStream> {
40-
return ThreadPools.io.preparePromise {
41-
if (!isClosed)
42-
bufferedSource.readAll(lazyFileOutputStream.value.sink())
43-
this
44-
}
45-
}
46-
47-
override fun flush(): Promise<CacheOutputStream> {
38+
override fun promiseFlush(): Promise<Unit> {
4839
return ThreadPools.io.preparePromise {
4940
if (!isClosed && lazyFileOutputStream.isInitialized()) lazyFileOutputStream.value.flush()
50-
this
5141
}
5242
}
5343

@@ -56,7 +46,7 @@ class CachedFileOutputStream(
5646
else Promise.empty()
5747

5848
override fun promiseClose(): Promise<Unit> {
59-
return flush().must { _ ->
49+
return promiseFlush().must { _ ->
6050
isClosed = true
6151
if (lazyFileOutputStream.isInitialized()) lazyFileOutputStream.value.close()
6252
}.guaranteedUnitResponse()

0 commit comments

Comments
 (0)