Files
SilverDROID/app/src/main/kotlin/uk/silverlabs/silverdroid/config/RemoteConfigLoader.kt
SysAdmin ba9bba1503 Remove companion object from RemoteConfigLoader
Objects cannot have companion objects in Kotlin. Moved TAG constant
to top-level instead.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 20:10:13 +01:00

113 lines
3.6 KiB
Kotlin

package uk.silverlabs.silverdroid.config
import android.content.Context
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import java.net.HttpURLConnection
import java.net.URL
private const val TAG = "RemoteConfigLoader"
/**
* Loads configuration from remote AppStore server
*/
object RemoteConfigLoader {
private val json = Json {
ignoreUnknownKeys = true
isLenient = true
}
/**
* Fetch configuration from remote URL with optional authentication
*/
suspend fun fetchConfig(
remoteSettings: RemoteConfigSettings,
userId: String? = null
): kotlin.Result<AppConfig> = withContext(Dispatchers.IO) {
try {
val url = buildConfigUrl(remoteSettings, userId)
Log.i(TAG, "Fetching config from: $url")
val connection = URL(url).openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 10000
connection.readTimeout = 10000
// Add authentication if provided
remoteSettings.authToken?.let {
connection.setRequestProperty("Authorization", "Bearer $it")
}
// Add user ID if user-specific config
userId?.let {
connection.setRequestProperty("X-User-ID", it)
}
val responseCode = connection.responseCode
if (responseCode == HttpURLConnection.HTTP_OK) {
val response = connection.inputStream.bufferedReader().use { it.readText() }
val config = json.decodeFromString<AppConfig>(response)
Log.i(TAG, "Successfully loaded remote config for: ${config.appName}")
kotlin.Result.success(config)
} else {
val error = "HTTP $responseCode: ${connection.responseMessage}"
Log.e(TAG, "Failed to fetch config: $error")
kotlin.Result.failure(Exception(error))
}
} catch (e: Exception) {
Log.e(TAG, "Error fetching remote config", e)
kotlin.Result.failure(e)
}
}
private fun buildConfigUrl(settings: RemoteConfigSettings, userId: String?): String {
var url = settings.url
// Add user parameter if user-specific
if (settings.userSpecific && userId != null) {
url = if (url.contains("?")) {
"$url&userId=$userId"
} else {
"$url?userId=$userId"
}
}
return url
}
/**
* Load config with remote fallback
* 1. Try to load local config
* 2. If remote is configured, fetch from server
* 3. Merge remote with local (remote takes precedence)
*/
suspend fun loadConfigWithRemote(
context: Context,
userId: String? = null
): AppConfig {
// Load local config first
val localConfig = ConfigLoader.loadConfig(context)
// Check if remote config is enabled
val remoteSettings = localConfig.remoteConfig
if (remoteSettings == null || !remoteSettings.enabled) {
Log.i(TAG, "Remote config disabled, using local config")
return localConfig
}
// Fetch remote config
return fetchConfig(remoteSettings, userId).getOrElse { error ->
Log.w(TAG, "Remote config failed, falling back to local", error)
localConfig
}.also {
if (it != localConfig) {
Log.i(TAG, "Using remote configuration")
}
}
}
}