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>
113 lines
3.6 KiB
Kotlin
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")
|
|
}
|
|
}
|
|
}
|
|
}
|