Add ability to download icons

This commit is contained in:
ligi 2022-06-13 06:26:41 +02:00
parent 33b37d0113
commit 8bd6563b9a
No known key found for this signature in database
GPG Key ID: 8E81894010ABF23D
3 changed files with 74 additions and 34 deletions

View File

@ -18,5 +18,7 @@ dependencies {
testImplementation "org.jetbrains.kotlin:kotlin-test:${KOTLIN_VERSION}" testImplementation "org.jetbrains.kotlin:kotlin-test:${KOTLIN_VERSION}"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:${KOTLIN_VERSION}" testImplementation "org.jetbrains.kotlin:kotlin-test-junit:${KOTLIN_VERSION}"
implementation 'com.github.ligi:ipfs-api-kotlin:0.15'
} }

View File

@ -2,29 +2,43 @@ package org.ethereum.lists.chains
import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import io.ipfs.kotlin.IPFS
import io.ipfs.kotlin.IPFSConfiguration
import okhttp3.OkHttpClient
import org.ethereum.lists.chains.model.Chain import org.ethereum.lists.chains.model.Chain
import java.time.Duration
val mandatory_fields = listOf( val mandatory_fields = listOf(
"name", "name",
"shortName", "shortName",
"chain", "chain",
"chainId", "chainId",
"networkId", "networkId",
"rpc", "rpc",
"faucets", "faucets",
"infoURL", "infoURL",
"nativeCurrency" "nativeCurrency"
) )
val optionalFields = listOf( val optionalFields = listOf(
"slip44", "slip44",
"ens", "ens",
"icon", "icon",
"explorers", "explorers",
"title", "title",
"network", "network",
"parent", "parent",
"status" "status"
) )
val moshi: Moshi = Moshi.Builder().build() val moshi: Moshi = Moshi.Builder().build()
val chainAdapter: JsonAdapter<Chain> = moshi.adapter(Chain::class.java) val chainAdapter: JsonAdapter<Chain> = moshi.adapter(Chain::class.java)
val ipfs by lazy {
IPFS(
IPFSConfiguration(
"http://127.0.0.1:5001/api/v0/",
OkHttpClient.Builder().readTimeout(Duration.ofMinutes(1)).build(),
Moshi.Builder().build()
)
)
}

View File

@ -4,10 +4,15 @@ import com.beust.klaxon.JsonArray
import java.io.File import java.io.File
import com.beust.klaxon.JsonObject import com.beust.klaxon.JsonObject
import com.beust.klaxon.Klaxon import com.beust.klaxon.Klaxon
import com.squareup.moshi.Moshi
import io.ipfs.kotlin.IPFS
import io.ipfs.kotlin.IPFSConfiguration
import okhttp3.OkHttpClient
import org.ethereum.lists.chains.model.* import org.ethereum.lists.chains.model.*
import org.kethereum.erc55.isValid import org.kethereum.erc55.isValid
import org.kethereum.model.Address import org.kethereum.model.Address
import org.kethereum.rpc.HttpEthereumRPC import org.kethereum.rpc.HttpEthereumRPC
import java.time.Duration
val parsedShortNames = mutableSetOf<String>() val parsedShortNames = mutableSetOf<String>()
val parsedNames = mutableSetOf<String>() val parsedNames = mutableSetOf<String>()
@ -15,6 +20,7 @@ val parsedNames = mutableSetOf<String>()
val basePath = File("..") val basePath = File("..")
val dataPath = File(basePath, "_data") val dataPath = File(basePath, "_data")
val iconsPath = File(dataPath, "icons") val iconsPath = File(dataPath, "icons")
val iconsDownloadPath = File(dataPath, "iconsDownload")
val chainsPath = File(dataPath, "chains") val chainsPath = File(dataPath, "chains")
private val allFiles = chainsPath.listFiles() ?: error("${chainsPath.absolutePath} must contain the chain json files - but it does not") private val allFiles = chainsPath.listFiles() ?: error("${chainsPath.absolutePath} must contain the chain json files - but it does not")
@ -22,8 +28,7 @@ private val allChainFiles = allFiles.filter { !it.isDirectory }
fun main(args: Array<String>) { fun main(args: Array<String>) {
doChecks(doRPCConnect = args.contains("rpcConnect")) doChecks(doRPCConnect = args.contains("rpcConnect"), doIconDownload = args.contains("iconDownload"))
createOutputFiles() createOutputFiles()
} }
@ -83,14 +88,14 @@ private fun createOutputFiles() {
File(buildPath, "CNAME").writeText("chainid.network") File(buildPath, "CNAME").writeText("chainid.network")
} }
private fun doChecks(doRPCConnect: Boolean) { private fun doChecks(doRPCConnect: Boolean, doIconDownload: Boolean) {
allChainFiles.forEach { allChainFiles.forEach {
checkChain(it, doRPCConnect) checkChain(it, doRPCConnect)
} }
val allIcons = iconsPath.listFiles() ?: return val allIcons = iconsPath.listFiles() ?: return
allIcons.forEach { allIcons.forEach {
checkIcon(it) checkIcon(it, doIconDownload)
} }
allFiles.filter { it.isDirectory }.forEach { _ -> allFiles.filter { it.isDirectory }.forEach { _ ->
@ -98,7 +103,7 @@ private fun doChecks(doRPCConnect: Boolean) {
} }
} }
fun checkIcon(icon: File) { fun checkIcon(icon: File, withIconDownload: Boolean) {
println("checking Icon " + icon.name) println("checking Icon " + icon.name)
val obj: JsonArray<*> = Klaxon().parseJsonArray(icon.reader()) val obj: JsonArray<*> = Klaxon().parseJsonArray(icon.reader())
println("found variants " + obj.size) println("found variants " + obj.size)
@ -113,6 +118,25 @@ fun checkIcon(icon: File) {
error("url must start with ipfs://") error("url must start with ipfs://")
} }
if (withIconDownload) {
val iconCID = url.removePrefix("ipfs://")
try {
println("fetching Icon from IPFS $iconCID")
val iconBytes = ipfs.get.catBytes(iconCID)
println("Icon size" + iconBytes.size)
val outFile = File(iconsDownloadPath, iconCID)
outFile.createNewFile()
outFile.writeBytes(iconBytes)
} catch (e: Exception) {
println("could not fetch icon from IPFS")
}
}
val width = it["width"] val width = it["width"]
val height = it["height"] val height = it["height"]
if (width != null || height != null) { if (width != null || height != null) {
@ -143,14 +167,14 @@ fun checkChain(chainFile: File, connectRPC: Boolean) {
if (chainFile.nameWithoutExtension.startsWith("eip155-")) { if (chainFile.nameWithoutExtension.startsWith("eip155-")) {
if (chainAsLong != chainFile.nameWithoutExtension.replace("eip155-", "").toLongOrNull()) { if (chainAsLong != chainFile.nameWithoutExtension.replace("eip155-", "").toLongOrNull()) {
throw(FileNameMustMatchChainId()) throw (FileNameMustMatchChainId())
} }
} else { } else {
throw(UnsupportedNamespace()) throw (UnsupportedNamespace())
} }
if (chainFile.extension != "json") { if (chainFile.extension != "json") {
throw(ExtensionMustBeJSON()) throw (ExtensionMustBeJSON())
} }
getNumber(jsonObject, "networkId") getNumber(jsonObject, "networkId")
@ -183,7 +207,7 @@ fun checkChain(chainFile: File, connectRPC: Boolean) {
if (symbol.length >= 7) { if (symbol.length >= 7) {
throw NativeCurrencySymbolMustHaveLessThan7Chars() throw NativeCurrencySymbolMustHaveLessThan7Chars()
} }
if (it.keys != setOf("symbol","decimals","name")) { if (it.keys != setOf("symbol", "decimals", "name")) {
throw NativeCurrencyCanOnlyHaveSymbolNameAndDecimals() throw NativeCurrencyCanOnlyHaveSymbolNameAndDecimals()
} }
if (it["decimals"] !is Int) { if (it["decimals"] !is Int) {
@ -205,20 +229,20 @@ fun checkChain(chainFile: File, connectRPC: Boolean) {
} }
if (explorer["name"] == null) { if (explorer["name"] == null) {
throw(ExplorerMustHaveName()) throw (ExplorerMustHaveName())
} }
val url = explorer["url"] val url = explorer["url"]
if (url == null || url !is String || !url.startsWith("https://")) { if (url == null || url !is String || !url.startsWith("https://")) {
throw(ExplorerMustWithHttps()) throw (ExplorerMustWithHttps())
} }
if (url.endsWith("/")) { if (url.endsWith("/")) {
throw(ExplorerCannotEndInSlash()) throw (ExplorerCannotEndInSlash())
} }
if (explorer["standard"] != "EIP3091" && explorer["standard"] != "none") { if (explorer["standard"] != "EIP3091" && explorer["standard"] != "none") {
throw(ExplorerStandardMustBeEIP3091OrNone()) throw (ExplorerStandardMustBeEIP3091OrNone())
} }
} }
} }
@ -239,7 +263,7 @@ fun checkChain(chainFile: File, connectRPC: Boolean) {
if (it !is String) { if (it !is String) {
throw StatusMustBeString() throw StatusMustBeString()
} }
if (!setOf("incubating","active","deprecated").contains(it)) { if (!setOf("incubating", "active", "deprecated").contains(it)) {
throw StatusMustBeIncubatingActiveOrDeprecated() throw StatusMustBeIncubatingActiveOrDeprecated()
} }
} }
@ -286,7 +310,7 @@ fun checkChain(chainFile: File, connectRPC: Boolean) {
if (jsonObject["rpc"] is List<*>) { if (jsonObject["rpc"] is List<*>) {
(jsonObject["rpc"] as List<*>).forEach { (jsonObject["rpc"] as List<*>).forEach {
if (it !is String) { if (it !is String) {
throw(RPCMustBeListOfStrings()) throw (RPCMustBeListOfStrings())
} else { } else {
println("connecting to $it") println("connecting to $it")
val ethereumRPC = HttpEthereumRPC(it) val ethereumRPC = HttpEthereumRPC(it)
@ -297,7 +321,7 @@ fun checkChain(chainFile: File, connectRPC: Boolean) {
} }
println() println()
} else { } else {
throw(RPCMustBeList()) throw (RPCMustBeList())
} }
} }
} }
@ -328,6 +352,6 @@ private fun getNumber(jsonObject: JsonObject, field: String): Long {
return when (val chainId = jsonObject[field]) { return when (val chainId = jsonObject[field]) {
is Int -> chainId.toLong() is Int -> chainId.toLong()
is Long -> chainId is Long -> chainId
else -> throw(Exception("chain_id must be a number")) else -> throw (Exception("chain_id must be a number"))
} }
} }