-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add V4Environment and Documentation to the graph. Pre-req for moving …
…state-machine components into the graph.
- Loading branch information
1 parent
465f220
commit 45d155e
Showing
6 changed files
with
196 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
src/commonMain/kotlin/exchange.dydx.abacus/state/manager/ConfigsLoader.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package exchange.dydx.abacus.state.manager | ||
|
||
import exchange.dydx.abacus.di.DeploymentUri | ||
import exchange.dydx.abacus.protocols.FileLocation | ||
import exchange.dydx.abacus.protocols.readCachedTextFile | ||
import exchange.dydx.abacus.state.v2.supervisor.AppConfigsV2 | ||
import exchange.dydx.abacus.utils.IOImplementations | ||
import me.tatarka.inject.annotations.Inject | ||
|
||
@Inject | ||
class ConfigFileLoader( | ||
private val deploymentUri: DeploymentUri, | ||
private val appConfigs: AppConfigsV2, | ||
private val ioImplementations: IOImplementations, | ||
) { | ||
fun <T> load(configFile: ConfigFile, parse: (String) -> Result<T>): Result<T> { | ||
val config = if (appConfigs.loadRemote) { | ||
loadFromCachedConfigFile(configFile).also { | ||
fetchRemoteConfigFile(configFile, parse) | ||
} | ||
} else { | ||
loadFromBundledLocalConfigFile(configFile) | ||
} | ||
return config?.let { parse(it) } ?: Result.failure(RuntimeException("Could not parse config file.")) | ||
} | ||
|
||
private fun <T> fetchRemoteConfigFile(configFile: ConfigFile, parse: (String) -> Result<T>) { | ||
val path = configFile.path | ||
val configFileUrl = "$deploymentUri$path" | ||
ioImplementations.rest?.get(configFileUrl, null, callback = { response, httpCode, _ -> | ||
if (httpCode in 200..299 && response != null) { | ||
if (parse(response).isSuccess) { | ||
writeToLocalFile(response, path) | ||
} | ||
} | ||
}) | ||
} | ||
|
||
private fun loadFromCachedConfigFile(configFile: ConfigFile): String? { | ||
return ioImplementations.fileSystem?.readCachedTextFile( | ||
configFile.path, | ||
) | ||
} | ||
|
||
private fun loadFromBundledLocalConfigFile(configFile: ConfigFile): String? { | ||
return ioImplementations.fileSystem?.readTextFile( | ||
FileLocation.AppBundle, | ||
configFile.path, | ||
) | ||
} | ||
|
||
private fun writeToLocalFile(response: String, file: String) { | ||
ioImplementations.fileSystem?.writeTextFile( | ||
file, | ||
response, | ||
) | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/commonMain/kotlin/exchange.dydx.abacus/state/manager/DocumentationLoader.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package exchange.dydx.abacus.state.manager | ||
|
||
import exchange.dydx.abacus.di.AbacusScope | ||
import exchange.dydx.abacus.output.Documentation | ||
import kotlinx.serialization.json.Json | ||
import me.tatarka.inject.annotations.Inject | ||
import kotlin.js.JsExport | ||
|
||
@JsExport | ||
@AbacusScope | ||
@Inject | ||
class DocumentationLoader internal constructor( | ||
configFileLoader: ConfigFileLoader | ||
) { | ||
|
||
val documentation: Documentation? = | ||
// This is a blocking disk-read. Would be better to access this asynchronously, | ||
// but that is a larger refactor and this is fairly low prio (not shown on a main screen). | ||
// We don't need lazy here, because kotlin-inject accessors are handled lazily already. | ||
configFileLoader.load(ConfigFile.DOCUMENTATION) { | ||
runCatching { Json.decodeFromString<Documentation>(it) } | ||
}.getOrNull() // Not the end of the world if we fail to read. | ||
} |
97 changes: 97 additions & 0 deletions
97
src/commonMain/kotlin/exchange.dydx.abacus/state/manager/EnvironmentLoader.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package exchange.dydx.abacus.state.manager | ||
|
||
import exchange.dydx.abacus.di.AbacusScope | ||
import exchange.dydx.abacus.di.Deployment | ||
import exchange.dydx.abacus.di.DeploymentUri | ||
import exchange.dydx.abacus.di.EnvironmentId | ||
import exchange.dydx.abacus.di.EnvironmentIdParameter | ||
import exchange.dydx.abacus.utils.Parser | ||
import exchange.dydx.abacus.utils.UIImplementations | ||
import kollections.iMutableListOf | ||
import me.tatarka.inject.annotations.Inject | ||
|
||
data class EnvAndAppSettings( | ||
val environmentId: EnvironmentId, | ||
val environments: List<V4Environment>, | ||
val appSettings: AppSettings?, | ||
) | ||
|
||
@AbacusScope | ||
@Inject | ||
class EnvironmentLoader( | ||
private val environmentParser: EnvironmentParser, | ||
configFileLoader: ConfigFileLoader, | ||
) { | ||
val envAndAppSettings: EnvAndAppSettings = | ||
// This is a blocking disk-read call. | ||
// Since this is only at startup, and environment info is absolutely critical, we are okay with this. | ||
// It would be far more complex to provide the final environment to the graph asynchronously, as all downstream consumers would | ||
// need to become reactive, and literally everything depends on the environment. | ||
configFileLoader.load(ConfigFile.ENV, environmentParser::parse).getOrThrow() | ||
} | ||
|
||
@Inject | ||
class EnvironmentParser( | ||
private val deploymentUri: DeploymentUri, | ||
private val deployment: Deployment, | ||
private val environmentIdParameter: EnvironmentIdParameter?, | ||
private val uiImplementations: UIImplementations, | ||
) { | ||
|
||
fun parse(environmentsJson: String): Result<EnvAndAppSettings> { | ||
val parser = Parser() | ||
val items = parser.decodeJsonObject(environmentsJson) | ||
val deployments = parser.asMap(items?.get("deployments")) ?: return Result.failure(RuntimeException("Failure to parse deployments")) | ||
val target = parser.asMap(deployments[deployment]) ?: return Result.failure(RuntimeException("Failure to parse deployment: $deployment")) | ||
val targetEnvironments = parser.asList(target["environments"]) ?: return Result.failure(RuntimeException("Failure to parse target environments")) | ||
val targetDefault = parser.asString(target["default"]) | ||
|
||
val tokensData = parser.asNativeMap(items?.get("tokens")) | ||
val linksData = parser.asNativeMap(items?.get("links")) | ||
val walletsData = parser.asNativeMap(items?.get("wallets")) | ||
val governanceData = parser.asNativeMap(items?.get("governance")) | ||
|
||
if (items != null) { | ||
val environmentsData = parser.asMap(items["environments"]) ?: return Result.failure(RuntimeException("Failure to parse environments")) | ||
val parsedEnvironments = mutableMapOf<String, V4Environment>() | ||
for ((key, value) in environmentsData) { | ||
val data = parser.asMap(value) ?: continue | ||
val dydxChainId = parser.asString(data["dydxChainId"]) ?: continue | ||
val environment = V4Environment.parse( | ||
key, | ||
data, | ||
parser, | ||
deploymentUri, | ||
uiImplementations.localizer, | ||
parser.asNativeMap(tokensData?.get(dydxChainId)), | ||
parser.asNativeMap(linksData?.get(dydxChainId)), | ||
parser.asNativeMap(walletsData?.get(dydxChainId)), | ||
parser.asNativeMap(governanceData?.get(dydxChainId)), | ||
) ?: continue | ||
parsedEnvironments[environment.id] = environment | ||
} | ||
if (parsedEnvironments.isEmpty()) { | ||
return Result.failure(RuntimeException("Parsed environments was empty.")) | ||
} | ||
val environments = iMutableListOf<V4Environment>() | ||
for (environmentId in targetEnvironments) { | ||
val environment = parsedEnvironments[parser.asString(environmentId)!!] | ||
if (environment != null) { | ||
environments.add(environment) | ||
} | ||
} | ||
|
||
val appSettings = parser.asMap(items["apps"])?.let { AppSettings.parse(it, parser) } | ||
|
||
return Result.success( | ||
EnvAndAppSettings( | ||
environmentId = requireNotNull(environmentIdParameter ?: targetDefault) { "environmentId was null and no target default defined." }, | ||
environments = environments, | ||
appSettings = appSettings, | ||
), | ||
) | ||
} else { | ||
return Result.failure(RuntimeException("Failure to env json.")) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters