From 96bcc4d228c68c84c792dedd5c3e612bc9959553 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 May 2022 09:57:57 +0000 Subject: [PATCH 01/38] Bump mockk from 1.12.0 to 1.12.4 Bumps [mockk](https://github.com/mockk/mockk) from 1.12.0 to 1.12.4. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/compare/v1.12.0...1.12.4) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index c535211..53b168e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -46,7 +46,7 @@ subprojects { "testRuntime"("org.junit.jupiter:junit-jupiter-engine:${Versions.jupiter}") "testImplementation"("org.jetbrains.kotlin:kotlin-test") - "testImplementation"("io.mockk:mockk:1.12.0") + "testImplementation"("io.mockk:mockk:1.12.4") } From 1330fcddf38dda250afa95dadbca7d27471e61d7 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 02:29:01 -0400 Subject: [PATCH 02/38] update to kotlin 1.6.21 with multiplatform plugin for lib --- build.gradle.kts | 98 ++++++++----------- buildSrc/src/main/kotlin/Versions.kt | 3 +- example/build.gradle.kts | 3 +- gradle/wrapper/gradle-wrapper.properties | 2 +- lib/build.gradle | 40 -------- lib/build.gradle.kts | 34 +++++++ .../kotlin/io/ipfs/kotlin/IPFS.kt | 0 .../kotlin/io/ipfs/kotlin/IPFSConnection.kt | 2 +- .../kotlin/io/ipfs/kotlin/commands/Add.kt | 13 ++- .../kotlin/io/ipfs/kotlin/commands/Get.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Info.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Name.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Pins.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Repo.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Stats.kt | 0 .../io/ipfs/kotlin/defaults/Defaults.kt | 0 .../io/ipfs/kotlin/defaults/InfuraIPFS.kt | 0 .../io/ipfs/kotlin/defaults/LocalIPFS.kt | 0 .../io/ipfs/kotlin/model/BandWidthInfo.kt | 0 .../kotlin/io/ipfs/kotlin/model/Key.kt | 0 .../kotlin/io/ipfs/kotlin/model/KeyV2.kt | 0 .../io/ipfs/kotlin/model/MessageWithCode.kt | 0 .../kotlin/io/ipfs/kotlin/model/NameValue.kt | 0 .../kotlin/io/ipfs/kotlin/model/NamedHash.kt | 0 .../kotlin/io/ipfs/kotlin/model/Path.kt | 0 .../io/ipfs/kotlin/model/VersionInfo.kt | 0 .../io/ipfs/kotlin/BaseIPFSWebserverTest.kt | 0 .../kotlin/io/ipfs/kotlin/TestAdd.kt | 0 .../kotlin/io/ipfs/kotlin/TestGet.kt | 0 .../kotlin/io/ipfs/kotlin/TestInfo.kt | 0 .../kotlin/io/ipfs/kotlin/TestName.kt | 0 .../kotlin/io/ipfs/kotlin/TestPins.kt | 0 .../kotlin/io/ipfs/kotlin/TestRepo.kt | 0 .../kotlin/io/ipfs/kotlin/TestStats.kt | 0 settings.gradle | 4 - settings.gradle.kts | 24 +++++ 36 files changed, 113 insertions(+), 110 deletions(-) delete mode 100644 lib/build.gradle create mode 100644 lib/build.gradle.kts rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/IPFS.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/IPFSConnection.kt (99%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/commands/Add.kt (81%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/commands/Get.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/commands/Info.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/commands/Name.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/commands/Pins.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/commands/Repo.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/commands/Stats.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/defaults/Defaults.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/model/Key.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/model/KeyV2.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/model/NameValue.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/model/NamedHash.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/model/Path.kt (100%) rename lib/src/{main => jvmMain}/kotlin/io/ipfs/kotlin/model/VersionInfo.kt (100%) rename lib/src/{test => jvmTest}/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt (100%) rename lib/src/{test => jvmTest}/kotlin/io/ipfs/kotlin/TestAdd.kt (100%) rename lib/src/{test => jvmTest}/kotlin/io/ipfs/kotlin/TestGet.kt (100%) rename lib/src/{test => jvmTest}/kotlin/io/ipfs/kotlin/TestInfo.kt (100%) rename lib/src/{test => jvmTest}/kotlin/io/ipfs/kotlin/TestName.kt (100%) rename lib/src/{test => jvmTest}/kotlin/io/ipfs/kotlin/TestPins.kt (100%) rename lib/src/{test => jvmTest}/kotlin/io/ipfs/kotlin/TestRepo.kt (100%) rename lib/src/{test => jvmTest}/kotlin/io/ipfs/kotlin/TestStats.kt (100%) delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts index 53b168e..05e6a75 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,57 +1,41 @@ -apply { - from("https://raw.githubusercontent.com/ligi/gradle-common/master/versions_plugin_stable_only.gradle") -} - -buildscript { - repositories { - jcenter() - maven("https://jitpack.io") - } - - dependencies { - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}") - classpath("com.github.ben-manes:gradle-versions-plugin:${Versions.versions_plugin}") - } -} - - -subprojects { - repositories { - jcenter() - maven("https://jitpack.io") - maven("https://kotlin.bintray.com/kotlinx") - } - - apply(plugin = "jacoco") - apply(plugin = "maven") - apply(plugin = "kotlin") - - tasks.withType { - useJUnitPlatform() - } - - configure { - withSourcesJar() - withJavadocJar() - } - - afterEvaluate { - - dependencies { - "implementation"("org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}") - - "testImplementation"("org.assertj:assertj-core:3.22.0") - "testImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.jupiter}") - "testImplementation"("org.junit.jupiter:junit-jupiter-params:${Versions.jupiter}") - "testRuntime"("org.junit.jupiter:junit-jupiter-engine:${Versions.jupiter}") - - "testImplementation"("org.jetbrains.kotlin:kotlin-test") - "testImplementation"("io.mockk:mockk:1.12.4") - } - - - } - val compileTestKotlin by tasks.getting(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class) { - kotlinOptions.jvmTarget = "1.8" - } -} +//apply { +// from("https://raw.githubusercontent.com/ligi/gradle-common/master/versions_plugin_stable_only.gradle") +//} + + +//subprojects { +// repositories { +// mavenCentral() +// maven("https://jitpack.io") +// maven("https://kotlin.bintray.com/kotlinx") +// } +// +// tasks.withType { +// useJUnitPlatform() +// } +// +// configure { +// withSourcesJar() +// withJavadocJar() +// } +// +// afterEvaluate { +// +// dependencies { +// "implementation"("org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}") +// +// "testImplementation"("org.assertj:assertj-core:3.22.0") +// "testImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.jupiter}") +// "testImplementation"("org.junit.jupiter:junit-jupiter-params:${Versions.jupiter}") +// "testImplementation"("org.junit.jupiter:junit-jupiter-engine:${Versions.jupiter}") +// +// "testImplementation"("org.jetbrains.kotlin:kotlin-test") +// "testImplementation"("io.mockk:mockk:1.12.4") +// } +// +// +// } +//// val compileTestKotlin by tasks.getting(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class) { +//// kotlinOptions.jvmTarget = "1.8" +//// } +//} diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 37cb9ba..e60bd7d 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,5 +1,6 @@ object Versions { - const val kotlin = "1.3.72" + const val kotlin = "1.6.21" const val versions_plugin = "0.28.0" const val jupiter = "5.6.2" + const val okhttp = "4.9.3" } \ No newline at end of file diff --git a/example/build.gradle.kts b/example/build.gradle.kts index ae9f178..31d6b55 100644 --- a/example/build.gradle.kts +++ b/example/build.gradle.kts @@ -1,9 +1,10 @@ plugins { + kotlin("jvm") application } application { - mainClassName = "org.kethereum.example_cli.ExampleCLIKt" + mainClass.set("io.ipfs.example_cli.ExampleCLIKt") } dependencies { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fd0c5a3..aa991fc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/lib/build.gradle b/lib/build.gradle deleted file mode 100644 index 83af898..0000000 --- a/lib/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.72' - ext.okhttp_version = '3.11.0' - - repositories { - jcenter() - } - - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0' - } -} - -plugins { - id 'jacoco' -} - - -apply plugin: "kotlin" -apply plugin: 'maven' -apply plugin: 'com.github.ben-manes.versions' - -group = 'com.github.ligi' - -repositories { - jcenter() -} - -dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}" - // we can't yet use moshi 1.5.0 as we need @Json https://github.com/square/moshi/issues/315 - compile 'com.squareup.moshi:moshi:1.4.0' - compile "com.squareup.okhttp3:okhttp:${okhttp_version}" - - testCompile 'junit:junit:4.13' - testCompile 'org.mockito:mockito-core:3.3.3' - testCompile "com.squareup.okhttp3:mockwebserver:${okhttp_version}" - testCompile 'org.assertj:assertj-core:3.10.0' -} diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts new file mode 100644 index 0000000..51a98f0 --- /dev/null +++ b/lib/build.gradle.kts @@ -0,0 +1,34 @@ +plugins { + kotlin("multiplatform") + id("jacoco") + id("com.github.ben-manes.versions") +} + +group = "com.github.ligi" + +repositories { + mavenCentral() +} + +kotlin { + jvm() + + sourceSets { + val jvmMain by getting { + dependencies { + // we can't yet use moshi 1.5.0 as we need @Json https://github.com/square/moshi/issues/315 + api("com.squareup.moshi:moshi:1.4.0") + api("com.squareup.okhttp3:okhttp:${Versions.okhttp}") + } + } + + val jvmTest by getting { + dependencies { + implementation(kotlin("test")) + implementation("org.mockito:mockito-core:3.3.3") + implementation("com.squareup.okhttp3:mockwebserver:${Versions.okhttp}") + implementation("org.assertj:assertj-core:3.10.0") + } + } + } +} diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/IPFS.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/IPFS.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/IPFSConnection.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt similarity index 99% rename from lib/src/main/kotlin/io/ipfs/kotlin/IPFSConnection.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt index a787aa8..73f972e 100644 --- a/lib/src/main/kotlin/io/ipfs/kotlin/IPFSConnection.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt @@ -20,7 +20,7 @@ open class IPFSConnection(val config: IPFSConfiguration) { .url(config.base_url + cmd) .build() - return config.okHttpClient.newCall(request).execute().body()!! + return config.okHttpClient.newCall(request).execute().body!! } fun setErrorByJSON(jsonString: String) { diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/commands/Add.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt similarity index 81% rename from lib/src/main/kotlin/io/ipfs/kotlin/commands/Add.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 63da417..463ed6a 100644 --- a/lib/src/main/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -4,6 +4,9 @@ import com.squareup.moshi.JsonAdapter import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.NamedHash import okhttp3.* +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.RequestBody.Companion.asRequestBody +import okhttp3.RequestBody.Companion.toRequestBody import java.io.File import java.net.URLEncoder @@ -34,16 +37,16 @@ class Add(val ipfs: IPFSConnection) { private fun addFile(builder: MultipartBody.Builder, file: File, name: String, filename: String) { val encodedFileName = URLEncoder.encode(filename, "UTF-8") - val headers = Headers.of("Content-Disposition", "file; filename=\"$encodedFileName\"", "Content-Transfer-Encoding", "binary") + val headers = Headers.headersOf("Content-Disposition", "file; filename=\"$encodedFileName\"", "Content-Transfer-Encoding", "binary") if (file.isDirectory) { // add directory - builder.addPart(headers, RequestBody.create(MediaType.parse("application/x-directory"), "")) + builder.addPart(headers, "".toRequestBody("application/x-directory".toMediaType())) // add files and subdirectories for (f: File in file.listFiles()) { addFile(builder, f, f.name, filename + "/" + f.name) } } else { - builder.addPart(headers, RequestBody.create(MediaType.parse("application/octet-stream"), file)) + builder.addPart(headers, file.asRequestBody("application/octet-stream".toMediaType())) } } @@ -51,7 +54,7 @@ class Add(val ipfs: IPFSConnection) { fun string(text: String, name: String = "string", filename: String = name): NamedHash { return addGeneric { - val body = RequestBody.create(MediaType.parse("application/octet-stream"), text) + val body = RequestBody.create("application/octet-stream".toMediaType(), text) it.addFormDataPart(name, filename, body) }.last() // there can be only one @@ -69,7 +72,7 @@ class Add(val ipfs: IPFSConnection) { .post(requestBody) .build() - val response = ipfs.config.okHttpClient.newCall(request).execute().body() + val response = ipfs.config.okHttpClient.newCall(request).execute().body response.use { responseBody -> return responseBody!!.charStream().readLines().asSequence().map { diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/commands/Get.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/commands/Get.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/commands/Info.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/commands/Info.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/commands/Name.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/commands/Name.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/commands/Pins.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Pins.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/commands/Pins.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Pins.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/commands/Repo.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/commands/Repo.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/commands/Stats.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/commands/Stats.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/defaults/Defaults.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/defaults/Defaults.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/model/Key.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Key.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/model/Key.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Key.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/model/KeyV2.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/model/KeyV2.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/model/NameValue.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NameValue.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/model/NameValue.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NameValue.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/model/NamedHash.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/model/NamedHash.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/model/Path.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Path.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/model/Path.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Path.kt diff --git a/lib/src/main/kotlin/io/ipfs/kotlin/model/VersionInfo.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt similarity index 100% rename from lib/src/main/kotlin/io/ipfs/kotlin/model/VersionInfo.kt rename to lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt diff --git a/lib/src/test/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt similarity index 100% rename from lib/src/test/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt rename to lib/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt diff --git a/lib/src/test/kotlin/io/ipfs/kotlin/TestAdd.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt similarity index 100% rename from lib/src/test/kotlin/io/ipfs/kotlin/TestAdd.kt rename to lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt diff --git a/lib/src/test/kotlin/io/ipfs/kotlin/TestGet.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt similarity index 100% rename from lib/src/test/kotlin/io/ipfs/kotlin/TestGet.kt rename to lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt diff --git a/lib/src/test/kotlin/io/ipfs/kotlin/TestInfo.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt similarity index 100% rename from lib/src/test/kotlin/io/ipfs/kotlin/TestInfo.kt rename to lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt diff --git a/lib/src/test/kotlin/io/ipfs/kotlin/TestName.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt similarity index 100% rename from lib/src/test/kotlin/io/ipfs/kotlin/TestName.kt rename to lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt diff --git a/lib/src/test/kotlin/io/ipfs/kotlin/TestPins.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt similarity index 100% rename from lib/src/test/kotlin/io/ipfs/kotlin/TestPins.kt rename to lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt diff --git a/lib/src/test/kotlin/io/ipfs/kotlin/TestRepo.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt similarity index 100% rename from lib/src/test/kotlin/io/ipfs/kotlin/TestRepo.kt rename to lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt diff --git a/lib/src/test/kotlin/io/ipfs/kotlin/TestStats.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt similarity index 100% rename from lib/src/test/kotlin/io/ipfs/kotlin/TestStats.kt rename to lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index d1ca3ba..0000000 --- a/settings.gradle +++ /dev/null @@ -1,4 +0,0 @@ -include 'example' -include 'lib' - -rootProject.name = 'ipfs-api-kotlin' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..7fc46db --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,24 @@ +rootProject.name = "ipfs-api-kotlin" + +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + } + + plugins { + kotlin("multiplatform") version "1.6.21" + kotlin("jvm") version "1.6.21" + kotlin("plugin.serialization") version "1.6.21" + id("com.github.ben-manes.versions") version "0.42.0" + } +} + +dependencyResolutionManagement { + repositories { + mavenCentral() + } +} + +include("example") +include("lib") From bb70d3b811b5f0f59abc17f1ae84c7b00b4cd9df Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 02:56:12 -0400 Subject: [PATCH 03/38] remove moshi. use kotlinx serialization --- lib/build.gradle.kts | 4 ++-- lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt | 5 +---- .../kotlin/io/ipfs/kotlin/IPFSConnection.kt | 9 +++------ .../jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt | 9 +++------ .../kotlin/io/ipfs/kotlin/commands/Info.kt | 7 +++++-- .../kotlin/io/ipfs/kotlin/commands/Name.kt | 15 ++++----------- .../kotlin/io/ipfs/kotlin/commands/Repo.kt | 11 +++++------ .../kotlin/io/ipfs/kotlin/commands/Stats.kt | 5 +++-- .../kotlin/io/ipfs/kotlin/defaults/Defaults.kt | 5 ----- .../kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt | 2 +- .../kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt | 2 +- .../kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt | 1 + .../jvmMain/kotlin/io/ipfs/kotlin/model/Key.kt | 1 + .../jvmMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt | 6 ++++-- .../io/ipfs/kotlin/model/MessageWithCode.kt | 1 + .../kotlin/io/ipfs/kotlin/model/NameValue.kt | 1 + .../kotlin/io/ipfs/kotlin/model/NamedHash.kt | 1 + .../jvmMain/kotlin/io/ipfs/kotlin/model/Path.kt | 1 + .../kotlin/io/ipfs/kotlin/model/VersionInfo.kt | 1 + 19 files changed, 39 insertions(+), 48 deletions(-) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 51a98f0..3701378 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -1,5 +1,6 @@ plugins { kotlin("multiplatform") + kotlin("plugin.serialization") id("jacoco") id("com.github.ben-manes.versions") } @@ -16,8 +17,7 @@ kotlin { sourceSets { val jvmMain by getting { dependencies { - // we can't yet use moshi 1.5.0 as we need @Json https://github.com/square/moshi/issues/315 - api("com.squareup.moshi:moshi:1.4.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") api("com.squareup.okhttp3:okhttp:${Versions.okhttp}") } } diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt index 1f35cca..fe4d297 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt @@ -1,15 +1,12 @@ package io.ipfs.kotlin -import com.squareup.moshi.Moshi import io.ipfs.kotlin.commands.* -import io.ipfs.kotlin.defaults.createMoshi import io.ipfs.kotlin.defaults.createOKHTTP import io.ipfs.kotlin.model.MessageWithCode import okhttp3.OkHttpClient data class IPFSConfiguration(val base_url: String = "http://127.0.0.1:5001/api/v0/", - val okHttpClient: OkHttpClient = createOKHTTP(), - val moshi: Moshi = createMoshi()) + val okHttpClient: OkHttpClient = createOKHTTP()) open class IPFS(configuration: IPFSConfiguration) { diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt index 73f972e..3465ff2 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt @@ -1,7 +1,8 @@ package io.ipfs.kotlin -import com.squareup.moshi.JsonAdapter import io.ipfs.kotlin.model.MessageWithCode +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json import okhttp3.Request import okhttp3.RequestBody import okhttp3.ResponseBody @@ -10,10 +11,6 @@ open class IPFSConnection(val config: IPFSConfiguration) { var lastError: MessageWithCode? = null - private val errorAdapter: JsonAdapter by lazy { - config.moshi.adapter(MessageWithCode::class.java) - } - fun callCmd(cmd: String): ResponseBody { val request = Request.Builder() .post(RequestBody.create(null, "")) @@ -24,6 +21,6 @@ open class IPFSConnection(val config: IPFSConfiguration) { } fun setErrorByJSON(jsonString: String) { - lastError = errorAdapter.fromJson(jsonString) + lastError = Json.decodeFromString(jsonString) } } \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 463ed6a..e6b036d 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -1,8 +1,9 @@ package io.ipfs.kotlin.commands -import com.squareup.moshi.JsonAdapter import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.NamedHash +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json import okhttp3.* import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.asRequestBody @@ -12,10 +13,6 @@ import java.net.URLEncoder class Add(val ipfs: IPFSConnection) { - private val adapter: JsonAdapter by lazy { - ipfs.config.moshi.adapter(NamedHash::class.java) - } - // Accepts a single file or directory and returns the named hash. // For directories we return the hash of the enclosing // directory because that makes the most sense, also for @@ -76,7 +73,7 @@ class Add(val ipfs: IPFSConnection) { response.use { responseBody -> return responseBody!!.charStream().readLines().asSequence().map { - adapter.fromJson(it) + Json.decodeFromString(it) }.filterNotNull().toList() } } diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt index e6b2e98..2fef10f 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt @@ -1,15 +1,18 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection +import io.ipfs.kotlin.model.NamedHash import io.ipfs.kotlin.model.VersionInfo +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream class Info(val ipfs: IPFSConnection) { - private val versionAdapter= ipfs.config.moshi.adapter(VersionInfo::class.java) fun version(): VersionInfo? { val response = ipfs.callCmd("version") - return response.use { versionAdapter.fromJson(it.source()) } + return response.use { Json.decodeFromStream(it.byteStream()) } } } \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt index 32ded05..5739e64 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt @@ -1,20 +1,13 @@ package io.ipfs.kotlin.commands -import com.squareup.moshi.JsonAdapter import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.NameValue import io.ipfs.kotlin.model.Path +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json class Name(val ipfs: IPFSConnection) { - private val adapter: JsonAdapter by lazy { - ipfs.config.moshi.adapter(NameValue::class.java) - } - - private val pathAdapter: JsonAdapter by lazy { - ipfs.config.moshi.adapter(Path::class.java) - } - fun publish(hash: String): String? { val resultString = ipfs.callCmd("name/publish/$hash").use { it.string() } val resultBoolean = resultString.contains(hash) @@ -22,7 +15,7 @@ class Name(val ipfs: IPFSConnection) { ipfs.setErrorByJSON(resultString) return null } - return adapter.fromJson(resultString)?.Name + return Json.decodeFromString(resultString).Name } fun resolve(hash: String): String? { @@ -30,7 +23,7 @@ class Name(val ipfs: IPFSConnection) { return when { resultString == null -> null - resultString.contains("Path") -> pathAdapter.fromJson(resultString)?.Path + resultString.contains("Path") -> Json.decodeFromString(resultString).Path else -> { ipfs.setErrorByJSON(resultString) null diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt index 89fcbf0..bcacbcb 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt @@ -1,9 +1,10 @@ package io.ipfs.kotlin.commands -import com.squareup.moshi.JsonDataException import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.Key import io.ipfs.kotlin.model.KeyV2 +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json import okio.BufferedSource class Repo(val ipfs: IPFSConnection) { @@ -13,11 +14,9 @@ class Repo(val ipfs: IPFSConnection) { fun listFromNDJson(source: BufferedSource): List { val jsonString = source.readUtf8() return try { - val keyV2Adapter = ipfs.config.moshi.adapter(KeyV2::class.java) - jsonString.parseNDJSON { keyV2Adapter.fromJson(it)?.Key?.hash } - } catch (e: JsonDataException) { - val keyAdapter = ipfs.config.moshi.adapter(Key::class.java) - jsonString.parseNDJSON { keyAdapter.fromJson(it)?.Key } + jsonString.parseNDJSON { it?.let { Json.decodeFromString(it).Key.hash } } + } catch (e: Throwable) { + jsonString.parseNDJSON { Json.decodeFromString(it!!).Key } } } diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt index 9a87348..ca2b8fb 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt @@ -2,14 +2,15 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.BandWidthInfo +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream class Stats(val ipfs: IPFSConnection) { - private val bandWidthAdapter = ipfs.config.moshi.adapter(BandWidthInfo::class.java) fun bandWidth(): BandWidthInfo? { val response = ipfs.callCmd("stats/bw") - return response.use { bandWidthAdapter.fromJson(it.source()) } + return response.use { Json.decodeFromStream(it.byteStream()) } } } \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt index 04ab679..43dd275 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt @@ -1,10 +1,5 @@ package io.ipfs.kotlin.defaults -import com.squareup.moshi.Moshi -import io.ipfs.kotlin.commands.* -import io.ipfs.kotlin.model.MessageWithCode import okhttp3.OkHttpClient internal fun createOKHTTP() = OkHttpClient.Builder().build() - -internal fun createMoshi() = Moshi.Builder().build() \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt index 6434431..64b55a4 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt @@ -4,7 +4,7 @@ import io.ipfs.kotlin.IPFS import io.ipfs.kotlin.IPFSConfiguration val infuraIPFSConfig by lazy { - IPFSConfiguration("https://ipfs.infura.io:5001/api/v0/", createOKHTTP(), createMoshi()) + IPFSConfiguration("https://ipfs.infura.io:5001/api/v0/", createOKHTTP()) } open class InfuraIPFS : IPFS(infuraIPFSConfig) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt index 611e32c..edfd1ab 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt @@ -4,7 +4,7 @@ import io.ipfs.kotlin.IPFS import io.ipfs.kotlin.IPFSConfiguration val localIPFSConfig by lazy { - IPFSConfiguration("http://127.0.0.1:5001/api/v0/", createOKHTTP(), createMoshi()) + IPFSConfiguration("http://127.0.0.1:5001/api/v0/", createOKHTTP()) } open class LocalIPFS : IPFS(localIPFSConfig) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt index bb46d3b..8cdad84 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt @@ -1,5 +1,6 @@ package io.ipfs.kotlin.model +@kotlinx.serialization.Serializable data class BandWidthInfo(val TotalIn: Int, val TotalOut: Int, val RateIn: Double, diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Key.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Key.kt index bc94369..61cb0a7 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Key.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Key.kt @@ -1,3 +1,4 @@ package io.ipfs.kotlin.model +@kotlinx.serialization.Serializable data class Key(val Key: String) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt index e808d94..7d79394 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt @@ -1,6 +1,8 @@ package io.ipfs.kotlin.model -import com.squareup.moshi.Json +import kotlinx.serialization.SerialName -data class KeyV2Content(@Json(name = "/") val hash: String) +@kotlinx.serialization.Serializable +data class KeyV2Content(@SerialName("/") val hash: String) +@kotlinx.serialization.Serializable data class KeyV2(val Key: KeyV2Content) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt index 5a3bf4e..2777738 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt @@ -1,4 +1,5 @@ package io.ipfs.kotlin.model +@kotlinx.serialization.Serializable data class MessageWithCode(val Message: String, val Code: Int) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NameValue.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NameValue.kt index bb52a5e..62cdfe9 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NameValue.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NameValue.kt @@ -1,4 +1,5 @@ package io.ipfs.kotlin.model +@kotlinx.serialization.Serializable data class NameValue(val Name: String, val Value: String) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt index 54b99b2..2702278 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt @@ -1,4 +1,5 @@ package io.ipfs.kotlin.model +@kotlinx.serialization.Serializable data class NamedHash(val Name: String, val Hash: String) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Path.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Path.kt index 22bc4fa..83af1ad 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Path.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Path.kt @@ -1,3 +1,4 @@ package io.ipfs.kotlin.model +@kotlinx.serialization.Serializable data class Path(val Path: String) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt index 28b347a..014771c 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt @@ -1,5 +1,6 @@ package io.ipfs.kotlin.model +@kotlinx.serialization.Serializable data class VersionInfo(val Version: String, val Commit: String, val Repo: String) \ No newline at end of file From 271d3126f8a3758986c83187a20e16052c52aa2d Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 16:29:06 -0400 Subject: [PATCH 04/38] update dependencies --- lib/build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 3701378..3bdcb7e 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -26,8 +26,9 @@ kotlin { dependencies { implementation(kotlin("test")) implementation("org.mockito:mockito-core:3.3.3") + implementation("org.mockito:mockito-core:4.5.1") implementation("com.squareup.okhttp3:mockwebserver:${Versions.okhttp}") - implementation("org.assertj:assertj-core:3.10.0") + implementation("org.assertj:assertj-core:3.22.0") } } } From 802d57bec8a895c559ae86b41fdc95aa3bde88a0 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 16:32:18 -0400 Subject: [PATCH 05/38] port callCmd to ktor for tests set responses serving json to have a header of setHeader("Content-Type", ContentType.Application.Json) --- .../kotlin/io/ipfs/example_cli/ExampleCLI.kt | 2 +- gradle.properties | 1 + lib/build.gradle.kts | 8 ++++- lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt | 6 +++- .../kotlin/io/ipfs/kotlin/IPFSConnection.kt | 18 +++++----- .../kotlin/io/ipfs/kotlin/commands/Get.kt | 12 ++++--- .../kotlin/io/ipfs/kotlin/commands/Info.kt | 11 +++++-- .../kotlin/io/ipfs/kotlin/commands/Name.kt | 9 ++--- .../kotlin/io/ipfs/kotlin/commands/Pins.kt | 5 +-- .../kotlin/io/ipfs/kotlin/commands/Repo.kt | 8 ++--- .../kotlin/io/ipfs/kotlin/commands/Stats.kt | 15 ++++++--- .../io/ipfs/kotlin/defaults/Defaults.kt | 19 ++++++++++- .../io/ipfs/kotlin/BaseIPFSWebserverTest.kt | 1 + .../jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt | 24 ++++++++++---- .../jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt | 3 +- .../jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt | 9 +++-- .../jvmTest/kotlin/io/ipfs/kotlin/TestName.kt | 30 ++++++++++++----- .../jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt | 16 ++++++--- .../jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt | 33 ++++++++++++------- .../kotlin/io/ipfs/kotlin/TestStats.kt | 9 +++-- 20 files changed, 168 insertions(+), 71 deletions(-) create mode 100644 gradle.properties diff --git a/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt b/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt index 115994c..038eb98 100644 --- a/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt +++ b/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt @@ -3,6 +3,6 @@ package io.ipfs.example_cli import io.ipfs.kotlin.IPFS import io.ipfs.kotlin.IPFSConfiguration -fun main() { +suspend fun main() { println(IPFS(IPFSConfiguration()).info.version()) } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..7fc6f1f --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +kotlin.code.style=official diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 3bdcb7e..c935e47 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -18,6 +18,11 @@ kotlin { val jvmMain by getting { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") + api("io.ktor:ktor-client-core:2.0.0") + implementation("io.ktor:ktor-client-okhttp:2.0.0") + implementation("io.ktor:ktor-client-content-negotiation:2.0.0") + implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0") + implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.21") api("com.squareup.okhttp3:okhttp:${Versions.okhttp}") } } @@ -25,7 +30,8 @@ kotlin { val jvmTest by getting { dependencies { implementation(kotlin("test")) - implementation("org.mockito:mockito-core:3.3.3") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1") implementation("org.mockito:mockito-core:4.5.1") implementation("com.squareup.okhttp3:mockwebserver:${Versions.okhttp}") implementation("org.assertj:assertj-core:3.22.0") diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt index fe4d297..8d74154 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt @@ -1,12 +1,16 @@ package io.ipfs.kotlin import io.ipfs.kotlin.commands.* +import io.ipfs.kotlin.defaults.createKTOR import io.ipfs.kotlin.defaults.createOKHTTP import io.ipfs.kotlin.model.MessageWithCode +import io.ktor.client.* import okhttp3.OkHttpClient data class IPFSConfiguration(val base_url: String = "http://127.0.0.1:5001/api/v0/", - val okHttpClient: OkHttpClient = createOKHTTP()) + val okHttpClient: OkHttpClient = createOKHTTP(), + val ktorClient: HttpClient = createKTOR(), +) open class IPFS(configuration: IPFSConfiguration) { diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt index 3465ff2..977e4fb 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt @@ -1,23 +1,23 @@ package io.ipfs.kotlin import io.ipfs.kotlin.model.MessageWithCode +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import okhttp3.Request -import okhttp3.RequestBody -import okhttp3.ResponseBody open class IPFSConnection(val config: IPFSConfiguration) { var lastError: MessageWithCode? = null - fun callCmd(cmd: String): ResponseBody { - val request = Request.Builder() - .post(RequestBody.create(null, "")) - .url(config.base_url + cmd) - .build() + suspend fun callCmd(cmd: String): HttpResponse { + val request = HttpRequestBuilder().apply { + url(config.base_url + cmd) + contentType(ContentType.Any) + } - return config.okHttpClient.newCall(request).execute().body!! + return config.ktorClient.post(request) } fun setErrorByJSON(jsonString: String) { diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt index 9056d6f..18b3dce 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt @@ -1,6 +1,8 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection +import io.ktor.client.statement.* +import io.ktor.utils.io.jvm.javaio.* import okhttp3.ResponseBody import java.io.InputStream @@ -11,14 +13,14 @@ class Get(val ipfs: IPFSConnection) { * * @param hash The hash of the content in base58. */ - fun cat(hash: String): String = ipfs.callCmd("cat/$hash").use(ResponseBody::string) + suspend fun cat(hash: String): String = ipfs.callCmd("cat/$hash").bodyAsText() /** * Cat IPFS content and return it as ByteArray. * * @param hash The hash of the content in base58. */ - fun catBytes(hash: String): ByteArray = ipfs.callCmd("cat/$hash").use(ResponseBody::bytes) + suspend fun catBytes(hash: String): ByteArray = ipfs.callCmd("cat/$hash").readBytes() /** * Cat IPFS content and process it using InputStream. @@ -26,9 +28,9 @@ class Get(val ipfs: IPFSConnection) { * @param hash The hash of the content in base58. * @param handler Callback which handle processing the input stream. When the callback return the stream and the request body will be closed. */ - fun catStream(hash: String, handler: (stream: InputStream) -> Unit): Unit = - ipfs.callCmd("cat/$hash").use { body -> - val inputStream = body.byteStream() + suspend fun catStream(hash: String, handler: (stream: InputStream) -> Unit): Unit = + ipfs.callCmd("cat/$hash").let { response -> + val inputStream = response.bodyAsChannel().toInputStream() inputStream.use(handler) } diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt index 2fef10f..64535f3 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt @@ -1,8 +1,10 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection +import io.ipfs.kotlin.model.BandWidthInfo import io.ipfs.kotlin.model.NamedHash import io.ipfs.kotlin.model.VersionInfo +import io.ktor.client.call.* import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream @@ -10,9 +12,12 @@ import kotlinx.serialization.json.decodeFromStream class Info(val ipfs: IPFSConnection) { - fun version(): VersionInfo? { - val response = ipfs.callCmd("version") - return response.use { Json.decodeFromStream(it.byteStream()) } + suspend fun version(): VersionInfo? { + return try { + ipfs.callCmd("version").body() as VersionInfo + } catch (_: Throwable){ + null + } } } \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt index 5739e64..7fcc998 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt @@ -3,13 +3,14 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.NameValue import io.ipfs.kotlin.model.Path +import io.ktor.client.statement.* import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json class Name(val ipfs: IPFSConnection) { - fun publish(hash: String): String? { - val resultString = ipfs.callCmd("name/publish/$hash").use { it.string() } + suspend fun publish(hash: String): String? { + val resultString = ipfs.callCmd("name/publish/$hash").let { it.bodyAsText() } val resultBoolean = resultString.contains(hash) if (!resultBoolean) { ipfs.setErrorByJSON(resultString) @@ -18,8 +19,8 @@ class Name(val ipfs: IPFSConnection) { return Json.decodeFromString(resultString).Name } - fun resolve(hash: String): String? { - val resultString = ipfs.callCmd("name/resolve/$hash").use { it.string() } + suspend fun resolve(hash: String): String? { + val resultString = ipfs.callCmd("name/resolve/$hash").let { it.bodyAsText() } return when { resultString == null -> null diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Pins.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Pins.kt index 0d7a900..c18e21e 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Pins.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Pins.kt @@ -1,11 +1,12 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection +import io.ktor.client.statement.* class Pins(val ipfs: IPFSConnection) { - fun add(hash: String): Boolean { - val resultString = ipfs.callCmd("pin/add/$hash").use { it.string() } + suspend fun add(hash: String): Boolean { + val resultString = ipfs.callCmd("pin/add/$hash").let { it.bodyAsText() } val resultBoolean = resultString.contains(hash) if (!resultBoolean) { ipfs.setErrorByJSON(resultString) diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt index bcacbcb..891f47c 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt @@ -3,16 +3,16 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.Key import io.ipfs.kotlin.model.KeyV2 +import io.ktor.client.statement.* import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import okio.BufferedSource class Repo(val ipfs: IPFSConnection) { - fun gc() = ipfs.callCmd("repo/gc").use { listFromNDJson(it.source()) } + suspend fun gc() = ipfs.callCmd("repo/gc").let { listFromNDJson(it) } - fun listFromNDJson(source: BufferedSource): List { - val jsonString = source.readUtf8() + suspend fun listFromNDJson(source: HttpResponse): List { + val jsonString = source.bodyAsText() return try { jsonString.parseNDJSON { it?.let { Json.decodeFromString(it).Key.hash } } } catch (e: Throwable) { diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt index ca2b8fb..3bdf381 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt @@ -2,15 +2,20 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.BandWidthInfo -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream +import io.ktor.client.call.* +import io.ktor.http.* class Stats(val ipfs: IPFSConnection) { - fun bandWidth(): BandWidthInfo? { - val response = ipfs.callCmd("stats/bw") - return response.use { Json.decodeFromStream(it.byteStream()) } + suspend fun bandWidth(): BandWidthInfo? { + return try { + val result : BandWidthInfo = ipfs.callCmd("stats/bw").body() + result + } catch (t : Throwable){ + println(t) + null + } } } \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt index 43dd275..b53b783 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt @@ -1,5 +1,22 @@ package io.ipfs.kotlin.defaults +import io.ktor.client.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.serialization.kotlinx.json.* +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json import okhttp3.OkHttpClient -internal fun createOKHTTP() = OkHttpClient.Builder().build() + +internal fun createOKHTTP() = OkHttpClient.Builder().build() + +@OptIn(ExperimentalSerializationApi::class) +internal fun createKTOR() = HttpClient { + install(ContentNegotiation) { + json(Json { + ignoreUnknownKeys = true + }) + } +} + + diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt index 1a680c7..a52d024 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt @@ -15,6 +15,7 @@ abstract class BaseIPFSWebserverTest { @Before fun runBeforeEveryTest() { server.start() + } @After diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt index ea3e66d..284682d 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt @@ -1,5 +1,6 @@ package io.ipfs.kotlin +import io.ktor.http.* import okhttp3.mockwebserver.MockResponse import org.assertj.core.api.Assertions.assertThat import org.junit.Test @@ -7,12 +8,15 @@ import java.io.File import java.nio.file.Files import java.nio.file.Paths -class TestAdd :BaseIPFSWebserverTest() { +class TestAdd : BaseIPFSWebserverTest() { @Test fun testAddString() { // setup - server.enqueue(MockResponse().setBody("{\"Hash\":\"hashprobe\",\"Name\":\"nameprobe\"}")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Hash\":\"hashprobe\",\"Name\":\"nameprobe\"}") + ) // invoke val addString = ipfs.add.string("foo") @@ -29,7 +33,10 @@ class TestAdd :BaseIPFSWebserverTest() { @Test fun testAddFile() { // setup - server.enqueue(MockResponse().setBody("{\"Hash\":\"hashprobe\",\"Name\":\"nameprobe\"}")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Hash\":\"hashprobe\",\"Name\":\"nameprobe\"}") + ) // invoke val addString = ipfs.add.file(File.createTempFile("temptestfile", null)) @@ -46,19 +53,22 @@ class TestAdd :BaseIPFSWebserverTest() { @Test fun testAddDirectory() { // setup - server.enqueue(MockResponse().setBody("{\"Hash\":\"hashprobe\",\"Name\":\"nameprobe\"}")); + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Hash\":\"hashprobe\",\"Name\":\"nameprobe\"}") + ); // create nested subdirectories val path = Files.createTempDirectory("temptestdir") val dttf = File.createTempFile("dirtemptestfile", null, path.toFile()) dttf.writeText("Contents of temptestdir/dirtemptestfile") - val subdirpath = Files.createDirectory(Paths.get(path.toString()+File.separator+"subdir")) - val sdttf = File.createTempFile("subdirtemptestfile", null,subdirpath.toFile()) + val subdirpath = Files.createDirectory(Paths.get(path.toString() + File.separator + "subdir")) + val sdttf = File.createTempFile("subdirtemptestfile", null, subdirpath.toFile()) sdttf.writeText("Contents of temptestdir/subdir/subdirtemptestfile") val dttf2 = File.createTempFile("dirtemptestfile2", null, path.toFile()) dttf2.writeText("Contents of temptestdir/dirtemptestfile2") - val result = ipfs.add.directory(path.toFile(),path.fileName.toString()) + val result = ipfs.add.directory(path.toFile(), path.fileName.toString()) // assert assertThat(result.first().Hash).isEqualTo("hashprobe") diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt index 70ee146..7fd055a 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt @@ -1,5 +1,6 @@ package io.ipfs.kotlin +import kotlinx.coroutines.test.runTest import okhttp3.mockwebserver.MockResponse import org.assertj.core.api.Assertions.assertThat import org.junit.Test @@ -7,7 +8,7 @@ import org.junit.Test class TestGet : BaseIPFSWebserverTest() { @Test - fun testAddString() { + fun testAddString() = runTest { // setup server.enqueue(MockResponse().setBody("result")) diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt index 92aff54..105fe0a 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt @@ -1,5 +1,7 @@ package io.ipfs.kotlin +import io.ktor.http.* +import kotlinx.coroutines.test.runTest import okhttp3.mockwebserver.MockResponse import org.assertj.core.api.Assertions.assertThat import org.junit.Test @@ -7,9 +9,12 @@ import org.junit.Test class TestInfo : BaseIPFSWebserverTest() { @Test - fun testInfo() { + fun testInfo() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Version\":\"0.4.2\",\"Commit\":\"1654bbf\",\"Repo\":\"3\"}\n")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Version\":\"0.4.2\",\"Commit\":\"1654bbf\",\"Repo\":\"3\"}\n") + ) // invoke val addString = ipfs.info.version() diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt index 4fd63b0..6058660 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt @@ -1,5 +1,7 @@ package io.ipfs.kotlin +import io.ktor.http.* +import kotlinx.coroutines.test.runTest import okhttp3.mockwebserver.MockResponse import org.assertj.core.api.Assertions.assertThat import org.junit.Test @@ -7,9 +9,12 @@ import org.junit.Test class TestName : BaseIPFSWebserverTest() { @Test - fun testPublishSuccess() { + fun testPublishSuccess() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Name\":\"hashname\",\"Value\":\"hashvalue\"}\n")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Name\":\"hashname\",\"Value\":\"hashvalue\"}\n") + ) // invoke val result = ipfs.name.publish("hashvalue") @@ -23,9 +28,12 @@ class TestName : BaseIPFSWebserverTest() { } @Test - fun testPublishFail() { + fun testPublishFail() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Message\":\"invalid ipfs ref path\",\"Code\":0}")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Message\":\"invalid ipfs ref path\",\"Code\":0}") + ) // invoke val result = ipfs.name.publish("hashname") @@ -41,9 +49,12 @@ class TestName : BaseIPFSWebserverTest() { } @Test - fun testResolveSuccess() { + fun testResolveSuccess() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Path\":\"/ipfs/somehash\"}\n")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Path\":\"/ipfs/somehash\"}\n") + ) // invoke val result = ipfs.name.resolve("somehash") @@ -57,9 +68,12 @@ class TestName : BaseIPFSWebserverTest() { } @Test - fun testResolveFail() { + fun testResolveFail() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Message\":\"Could not resolve name.\",\"Code\":0}")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Message\":\"Could not resolve name.\",\"Code\":0}") + ) // invoke val result = ipfs.name.resolve("somehash") diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt index 2da9891..1005447 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt @@ -1,5 +1,7 @@ package io.ipfs.kotlin +import io.ktor.http.* +import kotlinx.coroutines.test.runTest import okhttp3.mockwebserver.MockResponse import org.assertj.core.api.Assertions.assertThat import org.junit.Test @@ -7,9 +9,12 @@ import org.junit.Test class TestPins : BaseIPFSWebserverTest() { @Test - fun testAddPin() { + fun testAddPin() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Pins\":[\"QmPFDyWdL6yjz92jdc6bzWXHKVvydAhgTzhefSmmkDXzSZ\"]}")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Pins\":[\"QmPFDyWdL6yjz92jdc6bzWXHKVvydAhgTzhefSmmkDXzSZ\"]}") + ) // invoke val result = ipfs.pins.add("QmPFDyWdL6yjz92jdc6bzWXHKVvydAhgTzhefSmmkDXzSZ") @@ -23,9 +28,12 @@ class TestPins : BaseIPFSWebserverTest() { } @Test - fun testAddPinFail() { + fun testAddPinFail() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Message\":\"pin: invalid ipfs ref path\",\"Code\":0}")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Message\":\"pin: invalid ipfs ref path\",\"Code\":0}") + ) // invoke val result = ipfs.pins.add("foo") diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt index a573f14..b801fa9 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt @@ -1,13 +1,15 @@ package io.ipfs.kotlin +import io.ktor.http.* +import kotlinx.coroutines.test.runTest import okhttp3.mockwebserver.MockResponse import org.assertj.core.api.Assertions.assertThat import org.junit.Test -class TestRepo :BaseIPFSWebserverTest() { +class TestRepo : BaseIPFSWebserverTest() { @Test - fun testEmptyGC() { + fun testEmptyGC() = runTest { // setup server.enqueue(MockResponse().setBody("")) @@ -23,45 +25,54 @@ class TestRepo :BaseIPFSWebserverTest() { } @Test - fun testGC() { + fun testGC() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Key\":\"k1\"}\n{\"Key\":\"k2\"}\n{\"Key\":\"k3\"}\n")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Key\":\"k1\"}\n{\"Key\":\"k2\"}\n{\"Key\":\"k3\"}\n") + ) // invoke val addString = ipfs.repo.gc() // assert - assertThat(addString).containsExactly("k1","k2","k3") + assertThat(addString).containsExactly("k1", "k2", "k3") val executedRequest = server.takeRequest(); assertThat(executedRequest.path).startsWith("/repo/gc") } @Test - fun testNewGCResponseStyle() { + fun testNewGCResponseStyle() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Key\":{\"/\":\"k1\"}}\n{\"Key\":{\"/\":\"k2\"}}\n{\"Key\":{\"/\":\"k3\"}}\n")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Key\":{\"/\":\"k1\"}}\n{\"Key\":{\"/\":\"k2\"}}\n{\"Key\":{\"/\":\"k3\"}}\n") + ) // invoke val addString = ipfs.repo.gc() // assert - assertThat(addString).containsExactly("k1","k2","k3") + assertThat(addString).containsExactly("k1", "k2", "k3") val executedRequest = server.takeRequest(); assertThat(executedRequest.path).startsWith("/repo/gc") } @Test - fun testDifferentSeparator() { + fun testDifferentSeparator() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"Key\":\"k1\"}\r\n{\"Key\":\"k2\"}\r\n{\"Key\":\"k3\"}")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"Key\":\"k1\"}\r\n{\"Key\":\"k2\"}\r\n{\"Key\":\"k3\"}") + ) // invoke val addString = ipfs.repo.gc() // assert - assertThat(addString).containsExactly("k1","k2","k3") + assertThat(addString).containsExactly("k1", "k2", "k3") val executedRequest = server.takeRequest(); assertThat(executedRequest.path).startsWith("/repo/gc") diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt index 127f23c..33e4272 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt @@ -1,5 +1,7 @@ package io.ipfs.kotlin +import io.ktor.http.* +import kotlinx.coroutines.test.runTest import okhttp3.mockwebserver.MockResponse import org.assertj.core.api.Assertions.assertThat import org.junit.Test @@ -7,9 +9,12 @@ import org.junit.Test class TestStats : BaseIPFSWebserverTest() { @Test - fun testBandWidthStats() { + fun testBandWidthStats() = runTest { // setup - server.enqueue(MockResponse().setBody("{\"TotalIn\":80461165,\"TotalOut\":70998948,\"RateIn\":1103.8830769540511,\"RateOut\":1814.6417381019044}\n")) + server.enqueue( + MockResponse().setHeader("Content-Type", ContentType.Application.Json) + .setBody("{\"TotalIn\":80461165,\"TotalOut\":70998948,\"RateIn\":1103.8830769540511,\"RateOut\":1814.6417381019044}\n") + ) // invoke val statsBandWidth = ipfs.stats.bandWidth() From 5074f4a69b95d7f6d3bc2c68b2dd5a4793798520 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 16:32:40 -0400 Subject: [PATCH 06/38] remove unused import --- lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt index b53b783..4bba7c4 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt @@ -3,14 +3,12 @@ package io.ipfs.kotlin.defaults import io.ktor.client.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* -import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import okhttp3.OkHttpClient internal fun createOKHTTP() = OkHttpClient.Builder().build() -@OptIn(ExperimentalSerializationApi::class) internal fun createKTOR() = HttpClient { install(ContentNegotiation) { json(Json { From 9ae9c4de9c69fb89995448636c225dc6917c5b65 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 16:51:14 -0400 Subject: [PATCH 07/38] remove reflect --- lib/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index c935e47..20cbc45 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -22,7 +22,6 @@ kotlin { implementation("io.ktor:ktor-client-okhttp:2.0.0") implementation("io.ktor:ktor-client-content-negotiation:2.0.0") implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0") - implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.21") api("com.squareup.okhttp3:okhttp:${Versions.okhttp}") } } From 95714ac5fd437915d95cedc8b7447bed2b0e15b3 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 19:55:44 -0400 Subject: [PATCH 08/38] use ktor for add note ktor automatically mulitpart request headers look like: Content-Disposition: form-data; name=""; file; filename="temptestdir7160507879139843984%2Fsubdir" Content-Transfer-Encoding: binary Content-Type: application/x-directory Content-Length: 0 vs Perviously with OkHttp: Content-Disposition: file; filename="temptestdir14927010351886631568%2Fsubdir" Content-Transfer-Encoding: binary Content-Type: application/x-directory; charset=utf-8 Content-Length: 0 --- .../kotlin/io/ipfs/kotlin/commands/Add.kt | 74 +++++++++---------- .../kotlin/io/ipfs/kotlin/commands/Get.kt | 1 - .../kotlin/io/ipfs/kotlin/commands/Info.kt | 5 -- .../kotlin/io/ipfs/kotlin/commands/Stats.kt | 1 - .../jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt | 7 +- 5 files changed, 41 insertions(+), 47 deletions(-) diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt index e6b036d..150416f 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -2,14 +2,11 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.NamedHash -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import okhttp3.* -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.RequestBody.Companion.asRequestBody -import okhttp3.RequestBody.Companion.toRequestBody +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.request.forms.* +import io.ktor.http.* import java.io.File -import java.net.URLEncoder class Add(val ipfs: IPFSConnection) { @@ -17,64 +14,67 @@ class Add(val ipfs: IPFSConnection) { // For directories we return the hash of the enclosing // directory because that makes the most sense, also for // consistency with the java-ipfs-api implementation. - fun file(file: File, name: String = "file", filename: String = name) = addGeneric { - addFile(it, file, name, filename) + suspend fun file(file: File, name: String = "file", filename: String = name) = addGeneric { + addFile(file, name, filename) }.last() // Accepts a single file or directory and returns the named hash. // Returns a collection of named hashes for the containing directory // and all sub-directories. - fun directory(file: File, name: String = "file", filename: String = name) = addGeneric { - addFile(it, file, name, filename) + suspend fun directory(file: File, name: String = "file", filename: String = name) = addGeneric { + addFile(file, name, filename) } // this has to be outside the lambda because it is reentrant to handle subdirectory structures - private fun addFile(builder: MultipartBody.Builder, file: File, name: String, filename: String) { + private fun FormBuilder.addFile(file: File, name: String, filename: String) { + + val encodedFileName = filename.encodeURLParameter() + + val headersBuilder = HeadersBuilder() + + headersBuilder.append(HttpHeaders.ContentDisposition, "file; filename=\"$encodedFileName\"") + headersBuilder.append("Content-Transfer-Encoding", "binary") + - val encodedFileName = URLEncoder.encode(filename, "UTF-8") - val headers = Headers.headersOf("Content-Disposition", "file; filename=\"$encodedFileName\"", "Content-Transfer-Encoding", "binary") if (file.isDirectory) { // add directory - builder.addPart(headers, "".toRequestBody("application/x-directory".toMediaType())) + headersBuilder.append(HttpHeaders.ContentType, ContentType("application", "x-directory")) + append("", "", headersBuilder.build()) + // add files and subdirectories for (f: File in file.listFiles()) { - addFile(builder, f, f.name, filename + "/" + f.name) + addFile(f, f.name, filename + "/" + f.name) } } else { - builder.addPart(headers, file.asRequestBody("application/octet-stream".toMediaType())) + headersBuilder.append(HttpHeaders.ContentType, ContentType.Application.OctetStream) + append(name, file.readBytes(), headersBuilder.build()) } } - fun string(text: String, name: String = "string", filename: String = name): NamedHash { + suspend fun string(text: String, name: String = "string", filename: String = name): NamedHash { return addGeneric { - val body = RequestBody.create("application/octet-stream".toMediaType(), text) - it.addFormDataPart(name, filename, body) + append(name, text, Headers.build { + append(HttpHeaders.ContentType, ContentType.Application.OctetStream) + append(HttpHeaders.ContentDisposition, "filename=$filename") + }) }.last() // there can be only one } - private fun addGeneric(withBuilder: (MultipartBody.Builder) -> Any): List { - - val builder = MultipartBody.Builder().setType(MultipartBody.FORM) - withBuilder(builder) - val requestBody = builder.build() - - val request = Request.Builder() - .url("${ipfs.config.base_url}add?stream-channels=true&progress=false") - .post(requestBody) - .build() - - val response = ipfs.config.okHttpClient.newCall(request).execute().body - - response.use { responseBody -> - return responseBody!!.charStream().readLines().asSequence().map { - Json.decodeFromString(it) - }.filterNotNull().toList() + private suspend fun addGeneric(withBuilder: FormBuilder.() -> Unit): List { + val request = MultiPartFormDataContent(formData(withBuilder)) + val result = ipfs.config.ktorClient.post("${ipfs.config.base_url}add?stream-channels=true&progress=false"){ + setBody(request) + } + return try { + listOf(result.body()) + } catch (_: Throwable){ + result.body() } } } diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt index 18b3dce..760f9fd 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt @@ -3,7 +3,6 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ktor.client.statement.* import io.ktor.utils.io.jvm.javaio.* -import okhttp3.ResponseBody import java.io.InputStream class Get(val ipfs: IPFSConnection) { diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt index 64535f3..06d0892 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt @@ -1,13 +1,8 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection -import io.ipfs.kotlin.model.BandWidthInfo -import io.ipfs.kotlin.model.NamedHash import io.ipfs.kotlin.model.VersionInfo import io.ktor.client.call.* -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream class Info(val ipfs: IPFSConnection) { diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt index 3bdf381..8793404 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt @@ -3,7 +3,6 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.BandWidthInfo import io.ktor.client.call.* -import io.ktor.http.* class Stats(val ipfs: IPFSConnection) { diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt index 284682d..1d763b2 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt @@ -1,6 +1,7 @@ package io.ipfs.kotlin import io.ktor.http.* +import kotlinx.coroutines.test.runTest import okhttp3.mockwebserver.MockResponse import org.assertj.core.api.Assertions.assertThat import org.junit.Test @@ -11,7 +12,7 @@ import java.nio.file.Paths class TestAdd : BaseIPFSWebserverTest() { @Test - fun testAddString() { + fun testAddString() = runTest { // setup server.enqueue( MockResponse().setHeader("Content-Type", ContentType.Application.Json) @@ -31,7 +32,7 @@ class TestAdd : BaseIPFSWebserverTest() { } @Test - fun testAddFile() { + fun testAddFile() = runTest { // setup server.enqueue( MockResponse().setHeader("Content-Type", ContentType.Application.Json) @@ -51,7 +52,7 @@ class TestAdd : BaseIPFSWebserverTest() { } @Test - fun testAddDirectory() { + fun testAddDirectory() = runTest { // setup server.enqueue( MockResponse().setHeader("Content-Type", ContentType.Application.Json) From 7f680c1d3f032360b1dd341357380759b73b0ad5 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 20:09:17 -0400 Subject: [PATCH 09/38] include quotes around filename for string --- lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 150416f..06698d0 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -59,7 +59,7 @@ class Add(val ipfs: IPFSConnection) { return addGeneric { append(name, text, Headers.build { append(HttpHeaders.ContentType, ContentType.Application.OctetStream) - append(HttpHeaders.ContentDisposition, "filename=$filename") + append(HttpHeaders.ContentDisposition, "filename=\"$filename\"") }) }.last() // there can be only one From fc0af5e0694c0af0742aa9f4fa19c06bf1afd9a6 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 21:09:13 -0400 Subject: [PATCH 10/38] move code to common --- .../src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt | 2 +- lib/build.gradle.kts | 9 +++++++-- .../kotlin/io/ipfs/kotlin/IPFS.kt | 3 --- .../kotlin/io/ipfs/kotlin/IPFSConnection.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Add.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Get.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Info.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Name.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Pins.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Repo.kt | 0 .../kotlin/io/ipfs/kotlin/commands/Stats.kt | 0 .../kotlin/io/ipfs/kotlin/defaults/Defaults.kt | 3 --- .../kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt | 2 +- .../kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt | 2 +- .../kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt | 0 .../kotlin/io/ipfs/kotlin/model/Key.kt | 0 .../kotlin/io/ipfs/kotlin/model/KeyV2.kt | 0 .../kotlin/io/ipfs/kotlin/model/MessageWithCode.kt | 0 .../kotlin/io/ipfs/kotlin/model/NameValue.kt | 0 .../kotlin/io/ipfs/kotlin/model/NamedHash.kt | 0 .../kotlin/io/ipfs/kotlin/model/Path.kt | 0 .../kotlin/io/ipfs/kotlin/model/VersionInfo.kt | 0 22 files changed, 10 insertions(+), 11 deletions(-) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/IPFS.kt (84%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/IPFSConnection.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/commands/Add.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/commands/Get.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/commands/Info.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/commands/Name.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/commands/Pins.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/commands/Repo.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/commands/Stats.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/defaults/Defaults.kt (79%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt (70%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt (71%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/model/Key.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/model/KeyV2.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/model/NameValue.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/model/NamedHash.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/model/Path.kt (100%) rename lib/src/{jvmMain => commonMain}/kotlin/io/ipfs/kotlin/model/VersionInfo.kt (100%) diff --git a/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt b/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt index 038eb98..b72dd41 100644 --- a/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt +++ b/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt @@ -3,6 +3,6 @@ package io.ipfs.example_cli import io.ipfs.kotlin.IPFS import io.ipfs.kotlin.IPFSConfiguration -suspend fun main() { +fun main() = runBlocking { println(IPFS(IPFSConfiguration()).info.version()) } \ No newline at end of file diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 20cbc45..2a1340e 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -15,14 +15,19 @@ kotlin { jvm() sourceSets { - val jvmMain by getting { + val commonMain by getting { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") api("io.ktor:ktor-client-core:2.0.0") implementation("io.ktor:ktor-client-okhttp:2.0.0") implementation("io.ktor:ktor-client-content-negotiation:2.0.0") implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0") - api("com.squareup.okhttp3:okhttp:${Versions.okhttp}") + } + } + + val jvmMain by getting { + dependencies { + implementation("io.ktor:ktor-client-okhttp:2.0.0") } } diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt similarity index 84% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt index 8d74154..6ff88fe 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFS.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt @@ -2,13 +2,10 @@ package io.ipfs.kotlin import io.ipfs.kotlin.commands.* import io.ipfs.kotlin.defaults.createKTOR -import io.ipfs.kotlin.defaults.createOKHTTP import io.ipfs.kotlin.model.MessageWithCode import io.ktor.client.* -import okhttp3.OkHttpClient data class IPFSConfiguration(val base_url: String = "http://127.0.0.1:5001/api/v0/", - val okHttpClient: OkHttpClient = createOKHTTP(), val ktorClient: HttpClient = createKTOR(), ) diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Add.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Get.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Info.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Info.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Info.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Name.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Pins.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Pins.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Pins.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Pins.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Repo.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Repo.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Repo.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Stats.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/commands/Stats.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Stats.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt similarity index 79% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt index 4bba7c4..69c8f01 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt @@ -4,11 +4,8 @@ import io.ktor.client.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json -import okhttp3.OkHttpClient -internal fun createOKHTTP() = OkHttpClient.Builder().build() - internal fun createKTOR() = HttpClient { install(ContentNegotiation) { json(Json { diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt similarity index 70% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt index 64b55a4..0616561 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt @@ -4,7 +4,7 @@ import io.ipfs.kotlin.IPFS import io.ipfs.kotlin.IPFSConfiguration val infuraIPFSConfig by lazy { - IPFSConfiguration("https://ipfs.infura.io:5001/api/v0/", createOKHTTP()) + IPFSConfiguration("https://ipfs.infura.io:5001/api/v0/") } open class InfuraIPFS : IPFS(infuraIPFSConfig) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt similarity index 71% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt index edfd1ab..f1ebe5a 100644 --- a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt @@ -4,7 +4,7 @@ import io.ipfs.kotlin.IPFS import io.ipfs.kotlin.IPFSConfiguration val localIPFSConfig by lazy { - IPFSConfiguration("http://127.0.0.1:5001/api/v0/", createOKHTTP()) + IPFSConfiguration("http://127.0.0.1:5001/api/v0/") } open class LocalIPFS : IPFS(localIPFSConfig) \ No newline at end of file diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Key.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/Key.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Key.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/model/Key.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NameValue.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/NameValue.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NameValue.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/model/NameValue.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Path.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/Path.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/Path.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/model/Path.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt rename to lib/src/commonMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt From 38adc4e5f47694f138e1539e5424be1ccf20c68a Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 22:15:34 -0400 Subject: [PATCH 11/38] fix file add --- lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 06698d0..5ace947 100644 --- a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -34,7 +34,7 @@ class Add(val ipfs: IPFSConnection) { val headersBuilder = HeadersBuilder() - headersBuilder.append(HttpHeaders.ContentDisposition, "file; filename=\"$encodedFileName\"") + headersBuilder.append(HttpHeaders.ContentDisposition, "filename=\"$encodedFileName\"") headersBuilder.append("Content-Transfer-Encoding", "binary") From 49dee73c1525ddda3e46c9c97bf8c3c59b4f7015 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Tue, 24 May 2022 22:43:45 -0400 Subject: [PATCH 12/38] move more dependencies to buildsrc versions --- buildSrc/src/main/kotlin/Versions.kt | 3 +++ lib/build.gradle.kts | 16 ++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index e60bd7d..c527bda 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,6 +1,9 @@ object Versions { const val kotlin = "1.6.21" + const val serialization= "1.3.2" const val versions_plugin = "0.28.0" const val jupiter = "5.6.2" const val okhttp = "4.9.3" + const val coroutines = "1.6.1" + const val ktor = "2.0.0" } \ No newline at end of file diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 2a1340e..15d10c9 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -17,25 +17,25 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") - api("io.ktor:ktor-client-core:2.0.0") - implementation("io.ktor:ktor-client-okhttp:2.0.0") - implementation("io.ktor:ktor-client-content-negotiation:2.0.0") - implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.serialization}") + api("io.ktor:ktor-client-core:${Versions.ktor}") + implementation("io.ktor:ktor-client-content-negotiation:${Versions.ktor}") + implementation("io.ktor:ktor-serialization-kotlinx-json:${Versions.ktor}") } } val jvmMain by getting { + dependsOn(commonMain) dependencies { - implementation("io.ktor:ktor-client-okhttp:2.0.0") + implementation("io.ktor:ktor-client-okhttp:${Versions.ktor}") } } val jvmTest by getting { dependencies { implementation(kotlin("test")) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.coroutines}") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.coroutines}") implementation("org.mockito:mockito-core:4.5.1") implementation("com.squareup.okhttp3:mockwebserver:${Versions.okhttp}") implementation("org.assertj:assertj-core:3.22.0") From a6fdb82ea9b0dc58e2533706e599c6cf115fb7fa Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Wed, 25 May 2022 00:09:38 -0400 Subject: [PATCH 13/38] add nearly all the targets ktor supports --- lib/build.gradle.kts | 54 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 15d10c9..1412fec 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -12,8 +12,28 @@ repositories { } kotlin { - jvm() + val darwinTargets = arrayOf( + "macosX64", "macosArm64", + "iosArm32", "iosArm64", "iosX64", "iosSimulatorArm64", + "tvosArm64", "tvosX64", "tvosSimulatorArm64", + "watchosArm32", "watchosArm64", "watchosX86", "watchosX64", "watchosSimulatorArm64", + ) + val linuxTargets = arrayOf("linuxX64", /*"linuxArm64"*/) + val mingwTargets = arrayOf("mingwX64") + val nativeTargets = linuxTargets + darwinTargets + mingwTargets + jvm { + compilations.all { + kotlinOptions.jvmTarget = "11" + } + } + js(IR) { + browser() + nodejs() + } + for (target in nativeTargets) { + targets.add(presets.getByName(target).createTarget(target)) + } sourceSets { val commonMain by getting { dependencies { @@ -31,6 +51,14 @@ kotlin { } } + val jsMain by getting { + dependsOn(commonMain) + dependencies { + implementation("io.ktor:ktor-client-js:${Versions.ktor}") + } + } + + val jvmTest by getting { dependencies { implementation(kotlin("test")) @@ -41,5 +69,29 @@ kotlin { implementation("org.assertj:assertj-core:3.22.0") } } + + val darwinMain by creating { + dependsOn(commonMain) + dependencies { + implementation("io.ktor:ktor-client-darwin:${Versions.ktor}") + } + } + darwinTargets.forEach { target -> + getByName("${target}Main") { + dependsOn(darwinMain) + } + } + val linuxAndMingwMain by creating { + dependsOn(commonMain) + dependencies { + implementation("io.ktor:ktor-client-curl:${Versions.ktor}") + } + } + (mingwTargets + linuxTargets).forEach { target -> + getByName("${target}Main") { + dependsOn(linuxAndMingwMain) + } + } + } } From 774497992c92b6c617066c2b18a625e4803b7941 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Wed, 25 May 2022 01:47:01 -0400 Subject: [PATCH 14/38] port from using jvm file to okio filesystem --- buildSrc/src/main/kotlin/Versions.kt | 1 + kotlin-js-store/yarn.lock | 627 ++++++++++++++++++ lib/build.gradle.kts | 19 +- .../commonMain/kotlin/io/ipfs/kotlin/IPFS.kt | 3 + .../kotlin/io/ipfs/kotlin/commands/Add.kt | 24 +- .../kotlin/io/ipfs/kotlin/commands/Get.kt | 15 +- .../io/ipfs/kotlin/defaults/Defaults.kt | 3 + .../ipfs/kotlin/defaults/createFileSystem.kt | 6 + .../ipfs/kotlin/defaults/createFileSystem.kt | 5 + .../jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt | 5 +- .../ipfs/kotlin/defaults/createFileSystem.kt | 5 + 11 files changed, 688 insertions(+), 25 deletions(-) create mode 100644 kotlin-js-store/yarn.lock create mode 100644 lib/src/jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt create mode 100644 lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt create mode 100644 lib/src/nativeMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index c527bda..0dd7934 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -6,4 +6,5 @@ object Versions { const val okhttp = "4.9.3" const val coroutines = "1.6.1" const val ktor = "2.0.0" + const val okio = "3.1.0" } \ No newline at end of file diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock new file mode 100644 index 0000000..bf8d3ce --- /dev/null +++ b/kotlin-js-store/yarn.lock @@ -0,0 +1,627 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +abort-controller@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +debug@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dukat@0.5.8-rc.4: + version "0.5.8-rc.4" + resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21" + integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA== + dependencies: + google-protobuf "3.12.2" + typescript "3.9.5" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +format-util@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" + integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +google-protobuf@3.12.2: + version "3.12.2" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" + integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +minimatch@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +mocha@9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.1.2.tgz#93f53175b0f0dc4014bd2d612218fccfcf3534d3" + integrity sha512-ta3LtJ+63RIBP03VBjMGtSqbe6cWXRejF9SyM9Zyli1CKZJZ+vfCTj3oW24V7wAphMJdpOFLoMI3hjJ1LWbs0w== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.2" + debug "4.3.2" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.1.7" + growl "1.10.5" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "3.0.4" + ms "2.1.3" + nanoid "3.1.25" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + workerpool "6.1.5" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.1.25: + version "3.1.25" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" + integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== + +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +source-map-support@0.5.20: + version "0.5.20" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + +typescript@3.9.5: + version "3.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" + integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +workerpool@6.1.5: + version "6.1.5" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" + integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 1412fec..550ddc5 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -6,6 +6,7 @@ plugins { } group = "com.github.ligi" +version = "0.16" repositories { mavenCentral() @@ -14,7 +15,7 @@ repositories { kotlin { val darwinTargets = arrayOf( "macosX64", "macosArm64", - "iosArm32", "iosArm64", "iosX64", "iosSimulatorArm64", + "iosArm64", "iosX64", "iosSimulatorArm64", "tvosArm64", "tvosX64", "tvosSimulatorArm64", "watchosArm32", "watchosArm64", "watchosX86", "watchosX64", "watchosSimulatorArm64", ) @@ -28,7 +29,6 @@ kotlin { } } js(IR) { - browser() nodejs() } for (target in nativeTargets) { @@ -41,6 +41,7 @@ kotlin { api("io.ktor:ktor-client-core:${Versions.ktor}") implementation("io.ktor:ktor-client-content-negotiation:${Versions.ktor}") implementation("io.ktor:ktor-serialization-kotlinx-json:${Versions.ktor}") + api("com.squareup.okio:okio:${Versions.okio}") } } @@ -55,6 +56,7 @@ kotlin { dependsOn(commonMain) dependencies { implementation("io.ktor:ktor-client-js:${Versions.ktor}") + implementation("com.squareup.okio:okio-nodefilesystem:${Versions.okio}") } } @@ -69,9 +71,12 @@ kotlin { implementation("org.assertj:assertj-core:3.22.0") } } + val nativeMain by creating { + dependsOn(commonMain) + } val darwinMain by creating { - dependsOn(commonMain) + dependsOn(nativeMain) dependencies { implementation("io.ktor:ktor-client-darwin:${Versions.ktor}") } @@ -82,7 +87,7 @@ kotlin { } } val linuxAndMingwMain by creating { - dependsOn(commonMain) + dependsOn(nativeMain) dependencies { implementation("io.ktor:ktor-client-curl:${Versions.ktor}") } @@ -95,3 +100,9 @@ kotlin { } } + +tasks.withType { + kotlinOptions { + jvmTarget = "11" + } +} \ No newline at end of file diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt index 6ff88fe..a1499ce 100644 --- a/lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt @@ -1,12 +1,15 @@ package io.ipfs.kotlin import io.ipfs.kotlin.commands.* +import io.ipfs.kotlin.defaults.createFileSystem import io.ipfs.kotlin.defaults.createKTOR import io.ipfs.kotlin.model.MessageWithCode import io.ktor.client.* +import okio.FileSystem data class IPFSConfiguration(val base_url: String = "http://127.0.0.1:5001/api/v0/", val ktorClient: HttpClient = createKTOR(), + val fileSystem: FileSystem = createFileSystem() ) open class IPFS(configuration: IPFSConfiguration) { diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 5ace947..a8ff182 100644 --- a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -6,7 +6,7 @@ import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.client.request.forms.* import io.ktor.http.* -import java.io.File +import okio.Path class Add(val ipfs: IPFSConnection) { @@ -14,7 +14,7 @@ class Add(val ipfs: IPFSConnection) { // For directories we return the hash of the enclosing // directory because that makes the most sense, also for // consistency with the java-ipfs-api implementation. - suspend fun file(file: File, name: String = "file", filename: String = name) = addGeneric { + suspend fun file(file: Path, name: String = "file", filename: String = name) = addGeneric { addFile(file, name, filename) }.last() @@ -22,13 +22,13 @@ class Add(val ipfs: IPFSConnection) { // Accepts a single file or directory and returns the named hash. // Returns a collection of named hashes for the containing directory // and all sub-directories. - suspend fun directory(file: File, name: String = "file", filename: String = name) = addGeneric { - addFile(file, name, filename) + suspend fun directory(path: Path, name: String = "file", filename: String = name) = addGeneric { + addFile(path, name, filename) } // this has to be outside the lambda because it is reentrant to handle subdirectory structures - private fun FormBuilder.addFile(file: File, name: String, filename: String) { + private fun FormBuilder.addFile(path: Path, name: String, filename: String) { val encodedFileName = filename.encodeURLParameter() @@ -36,20 +36,22 @@ class Add(val ipfs: IPFSConnection) { headersBuilder.append(HttpHeaders.ContentDisposition, "filename=\"$encodedFileName\"") headersBuilder.append("Content-Transfer-Encoding", "binary") - - - if (file.isDirectory) { + val dirFiles = ipfs.config.fileSystem.listOrNull(path) + val isDir = dirFiles?.isNotEmpty() ?: false + if (isDir) { // add directory headersBuilder.append(HttpHeaders.ContentType, ContentType("application", "x-directory")) append("", "", headersBuilder.build()) // add files and subdirectories - for (f: File in file.listFiles()) { - addFile(f, f.name, filename + "/" + f.name) + for (p: Path in dirFiles!!) { + addFile(p, p.name, filename + "/" + p.name) } } else { headersBuilder.append(HttpHeaders.ContentType, ContentType.Application.OctetStream) - append(name, file.readBytes(), headersBuilder.build()) + ipfs.config.fileSystem.read(path) { + append(name, this.readByteArray(), headersBuilder.build()) + } } } diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt index 760f9fd..15cf6c9 100644 --- a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt @@ -2,8 +2,7 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ktor.client.statement.* -import io.ktor.utils.io.jvm.javaio.* -import java.io.InputStream +import io.ktor.utils.io.* class Get(val ipfs: IPFSConnection) { @@ -22,15 +21,15 @@ class Get(val ipfs: IPFSConnection) { suspend fun catBytes(hash: String): ByteArray = ipfs.callCmd("cat/$hash").readBytes() /** - * Cat IPFS content and process it using InputStream. + * Cat IPFS content and process it using ByteReadChannel. * * @param hash The hash of the content in base58. * @param handler Callback which handle processing the input stream. When the callback return the stream and the request body will be closed. */ - suspend fun catStream(hash: String, handler: (stream: InputStream) -> Unit): Unit = - ipfs.callCmd("cat/$hash").let { response -> - val inputStream = response.bodyAsChannel().toInputStream() - inputStream.use(handler) - } + suspend fun catReadChannel(hash: String, handler: (stream: ByteReadChannel) -> Unit): Unit = + ipfs.callCmd("cat/$hash").let { response -> + val channel = response.bodyAsChannel() + handler.invoke(channel) + } } \ No newline at end of file diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt index 69c8f01..e05a9a5 100644 --- a/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt @@ -4,6 +4,7 @@ import io.ktor.client.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json +import okio.FileSystem internal fun createKTOR() = HttpClient { @@ -14,4 +15,6 @@ internal fun createKTOR() = HttpClient { } } +expect internal fun createFileSystem() : FileSystem + diff --git a/lib/src/jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt b/lib/src/jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt new file mode 100644 index 0000000..eb0567e --- /dev/null +++ b/lib/src/jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt @@ -0,0 +1,6 @@ +package io.ipfs.kotlin.defaults + +import okio.FileSystem +import okio.NodeJsFileSystem + +internal actual fun createFileSystem(): FileSystem = NodeJsFileSystem diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt new file mode 100644 index 0000000..75a1c81 --- /dev/null +++ b/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt @@ -0,0 +1,5 @@ +package io.ipfs.kotlin.defaults + +import okio.FileSystem + +internal actual fun createFileSystem(): FileSystem = FileSystem.SYSTEM diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt index 1d763b2..85df681 100644 --- a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt +++ b/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt @@ -3,6 +3,7 @@ package io.ipfs.kotlin import io.ktor.http.* import kotlinx.coroutines.test.runTest import okhttp3.mockwebserver.MockResponse +import okio.Path.Companion.toOkioPath import org.assertj.core.api.Assertions.assertThat import org.junit.Test import java.io.File @@ -40,7 +41,7 @@ class TestAdd : BaseIPFSWebserverTest() { ) // invoke - val addString = ipfs.add.file(File.createTempFile("temptestfile", null)) + val addString = ipfs.add.file(File.createTempFile("temptestfile", null).toOkioPath()) // assert assertThat(addString.Hash).isEqualTo("hashprobe") @@ -69,7 +70,7 @@ class TestAdd : BaseIPFSWebserverTest() { val dttf2 = File.createTempFile("dirtemptestfile2", null, path.toFile()) dttf2.writeText("Contents of temptestdir/dirtemptestfile2") - val result = ipfs.add.directory(path.toFile(), path.fileName.toString()) + val result = ipfs.add.directory(path.toOkioPath(), path.fileName.toString()) // assert assertThat(result.first().Hash).isEqualTo("hashprobe") diff --git a/lib/src/nativeMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt b/lib/src/nativeMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt new file mode 100644 index 0000000..75a1c81 --- /dev/null +++ b/lib/src/nativeMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt @@ -0,0 +1,5 @@ +package io.ipfs.kotlin.defaults + +import okio.FileSystem + +internal actual fun createFileSystem(): FileSystem = FileSystem.SYSTEM From 19893ed9d17a713f8600e948d16d5681ad4a885d Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 26 May 2022 17:01:57 -0400 Subject: [PATCH 15/38] add function to add file to ipfs using a BufferedSource --- .../kotlin/io/ipfs/kotlin/commands/Add.kt | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index a8ff182..58a2272 100644 --- a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -6,22 +6,38 @@ import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.client.request.forms.* import io.ktor.http.* +import okio.BufferedSource import okio.Path class Add(val ipfs: IPFSConnection) { - // Accepts a single file or directory and returns the named hash. - // For directories we return the hash of the enclosing - // directory because that makes the most sense, also for - // consistency with the java-ipfs-api implementation. + /*** Accepts a single file or directory and returns the named hash. + * For directories, we return the hash of the enclosing + * directory because that makes the most sense, also for + * consistency with the java-ipfs-api implementation. + **/ suspend fun file(file: Path, name: String = "file", filename: String = name) = addGeneric { addFile(file, name, filename) }.last() + /*** + * Accepts a single file's BufferedSource and returns the named hash. + **/ + suspend fun file(source: BufferedSource, name: String = "file", filename: String = name) = addGeneric { + val encodedFileName = filename.encodeURLParameter() + val headersBuilder = HeadersBuilder() + headersBuilder.append(HttpHeaders.ContentDisposition, "filename=\"$encodedFileName\"") + headersBuilder.append("Content-Transfer-Encoding", "binary") + headersBuilder.append(HttpHeaders.ContentType, ContentType.Application.OctetStream) + append(name, source.readByteArray(), headersBuilder.build()) + }.last() - // Accepts a single file or directory and returns the named hash. - // Returns a collection of named hashes for the containing directory - // and all sub-directories. + + /*** + * Accepts a single file or directory and returns the named hash. + * Returns a collection of named hashes for the containing directory + * and all sub-directories. + */ suspend fun directory(path: Path, name: String = "file", filename: String = name) = addGeneric { addFile(path, name, filename) } @@ -29,13 +45,11 @@ class Add(val ipfs: IPFSConnection) { // this has to be outside the lambda because it is reentrant to handle subdirectory structures private fun FormBuilder.addFile(path: Path, name: String, filename: String) { - val encodedFileName = filename.encodeURLParameter() - val headersBuilder = HeadersBuilder() - headersBuilder.append(HttpHeaders.ContentDisposition, "filename=\"$encodedFileName\"") headersBuilder.append("Content-Transfer-Encoding", "binary") + val dirFiles = ipfs.config.fileSystem.listOrNull(path) val isDir = dirFiles?.isNotEmpty() ?: false if (isDir) { @@ -70,12 +84,12 @@ class Add(val ipfs: IPFSConnection) { private suspend fun addGeneric(withBuilder: FormBuilder.() -> Unit): List { val request = MultiPartFormDataContent(formData(withBuilder)) - val result = ipfs.config.ktorClient.post("${ipfs.config.base_url}add?stream-channels=true&progress=false"){ + val result = ipfs.config.ktorClient.post("${ipfs.config.base_url}add?stream-channels=true&progress=false") { setBody(request) } return try { listOf(result.body()) - } catch (_: Throwable){ + } catch (_: Throwable) { result.body() } } From bc237d9d52d07135da7f2b5462aa98909bb8eaa1 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 26 May 2022 17:02:12 -0400 Subject: [PATCH 16/38] use experimental memory model --- gradle.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gradle.properties b/gradle.properties index 7fc6f1f..b8d590b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,3 @@ kotlin.code.style=official + +kotlin.native.binary.memoryModel=experimental From f740b60fb094ae6d4fd6cee4d292f9bf802b7e62 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 2 Jun 2022 04:16:00 -0400 Subject: [PATCH 17/38] change project library folder folder from being named lib to ipfs-api that way the library artifact has an appropriate name when publishing outside of jitpack --- example/build.gradle.kts | 2 +- {lib => ipfs-api}/build.gradle.kts | 2 ++ {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Info.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Pins.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Repo.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Stats.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/model/Key.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt | 0 .../commonMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/model/NameValue.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/model/Path.kt | 0 .../src/commonMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt | 0 .../jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt | 0 .../jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt | 0 .../src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt | 0 {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt | 0 {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt | 0 {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt | 0 {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt | 0 {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt | 0 {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt | 0 .../src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt | 0 .../kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt | 0 settings.gradle.kts | 2 +- 34 files changed, 4 insertions(+), 2 deletions(-) rename {lib => ipfs-api}/build.gradle.kts (99%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/commands/Info.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/commands/Pins.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/commands/Repo.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/commands/Stats.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/model/Key.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/model/NameValue.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/model/Path.kt (100%) rename {lib => ipfs-api}/src/commonMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt (100%) rename {lib => ipfs-api}/src/jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt (100%) rename {lib => ipfs-api}/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt (100%) rename {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt (100%) rename {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt (100%) rename {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt (100%) rename {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt (100%) rename {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt (100%) rename {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt (100%) rename {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt (100%) rename {lib => ipfs-api}/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt (100%) rename {lib => ipfs-api}/src/nativeMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt (100%) diff --git a/example/build.gradle.kts b/example/build.gradle.kts index 31d6b55..e0dcf5c 100644 --- a/example/build.gradle.kts +++ b/example/build.gradle.kts @@ -8,5 +8,5 @@ application { } dependencies { - implementation(project(":lib")) + implementation(project(":ipfs-api")) } diff --git a/lib/build.gradle.kts b/ipfs-api/build.gradle.kts similarity index 99% rename from lib/build.gradle.kts rename to ipfs-api/build.gradle.kts index 550ddc5..dc1e806 100644 --- a/lib/build.gradle.kts +++ b/ipfs-api/build.gradle.kts @@ -3,11 +3,13 @@ plugins { kotlin("plugin.serialization") id("jacoco") id("com.github.ben-manes.versions") + id("maven-publish") } group = "com.github.ligi" version = "0.16" + repositories { mavenCentral() } diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Info.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Info.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Info.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Info.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Pins.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Pins.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Pins.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Pins.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Repo.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Repo.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Repo.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Repo.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Stats.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Stats.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/commands/Stats.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Stats.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/LocalIPFS.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/BandWidthInfo.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/Key.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/Key.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/model/Key.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/Key.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/KeyV2.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/MessageWithCode.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/NameValue.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NameValue.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/model/NameValue.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NameValue.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/Path.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/Path.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/model/Path.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/Path.kt diff --git a/lib/src/commonMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt similarity index 100% rename from lib/src/commonMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt rename to ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/VersionInfo.kt diff --git a/lib/src/jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt b/ipfs-api/src/jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt similarity index 100% rename from lib/src/jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt rename to ipfs-api/src/jsMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt diff --git a/lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt b/ipfs-api/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt similarity index 100% rename from lib/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt rename to ipfs-api/src/jvmMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt similarity index 100% rename from lib/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt rename to ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/BaseIPFSWebserverTest.kt diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt similarity index 100% rename from lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt rename to ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt similarity index 100% rename from lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt rename to ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestGet.kt diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt similarity index 100% rename from lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt rename to ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestInfo.kt diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt similarity index 100% rename from lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt rename to ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestName.kt diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt similarity index 100% rename from lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt rename to ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestPins.kt diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt similarity index 100% rename from lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt rename to ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestRepo.kt diff --git a/lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt similarity index 100% rename from lib/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt rename to ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestStats.kt diff --git a/lib/src/nativeMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt b/ipfs-api/src/nativeMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt similarity index 100% rename from lib/src/nativeMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt rename to ipfs-api/src/nativeMain/kotlin/io/ipfs/kotlin/defaults/createFileSystem.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 7fc46db..a825a67 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,4 +21,4 @@ dependencyResolutionManagement { } include("example") -include("lib") +include("ipfs-api") From 0cb3154156f47b99657f0194b25c92779128f9e3 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 2 Jun 2022 04:16:13 -0400 Subject: [PATCH 18/38] update ktor --- buildSrc/src/main/kotlin/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 0dd7934..5b5ce4a 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -5,6 +5,6 @@ object Versions { const val jupiter = "5.6.2" const val okhttp = "4.9.3" const val coroutines = "1.6.1" - const val ktor = "2.0.0" + const val ktor = "2.0.2" const val okio = "3.1.0" } \ No newline at end of file From 4596b38ab7826009b7f156971481c40b1d87cf3b Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 2 Jul 2022 01:57:42 -0400 Subject: [PATCH 19/38] add an option progress callback for adding files tests broken :/ --- .../kotlin/io/ipfs/kotlin/commands/Add.kt | 78 +++++++++++++++---- .../kotlin/io/ipfs/kotlin/model/NamedHash.kt | 5 -- .../io/ipfs/kotlin/model/NamedResponse.kt | 16 ++++ .../jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt | 12 +-- 4 files changed, 84 insertions(+), 27 deletions(-) delete mode 100644 ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt create mode 100644 ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedResponse.kt diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 58a2272..b95194b 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -1,29 +1,50 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection -import io.ipfs.kotlin.model.NamedHash +import io.ipfs.kotlin.model.NamedResponse import io.ktor.client.call.* +import io.ktor.client.plugins.* import io.ktor.client.request.* import io.ktor.client.request.forms.* +import io.ktor.client.statement.* import io.ktor.http.* +import io.ktor.utils.io.* +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json import okio.BufferedSource import okio.Path +data class AddUploadProgress(val bytesSent: Long, val byteSize: Long) +data class AddProcessedProgress(var bytesProcessed: Long, val byteSize: Long) + +typealias AddProgressCallback = ((AddUploadProgress?, AddProcessedProgress?) -> Unit) + class Add(val ipfs: IPFSConnection) { /*** Accepts a single file or directory and returns the named hash. * For directories, we return the hash of the enclosing * directory because that makes the most sense, also for * consistency with the java-ipfs-api implementation. - **/ - suspend fun file(file: Path, name: String = "file", filename: String = name) = addGeneric { + **/ + suspend fun file( + file: Path, + name: String = "file", + filename: String = name, + progressCallback: AddProgressCallback? = null + ) = addGeneric(progressCallback) { + println(ipfs.config.fileSystem.openReadOnly(file).size()) addFile(file, name, filename) }.last() /*** * Accepts a single file's BufferedSource and returns the named hash. **/ - suspend fun file(source: BufferedSource, name: String = "file", filename: String = name) = addGeneric { + suspend fun file( + source: BufferedSource, + name: String = "file", + filename: String = name, + progressCallback: AddProgressCallback? = null + ) = addGeneric(progressCallback) { val encodedFileName = filename.encodeURLParameter() val headersBuilder = HeadersBuilder() headersBuilder.append(HttpHeaders.ContentDisposition, "filename=\"$encodedFileName\"") @@ -38,7 +59,7 @@ class Add(val ipfs: IPFSConnection) { * Returns a collection of named hashes for the containing directory * and all sub-directories. */ - suspend fun directory(path: Path, name: String = "file", filename: String = name) = addGeneric { + suspend fun directory(path: Path, name: String = "file", filename: String = name) = addGeneric(null) { addFile(path, name, filename) } @@ -70,9 +91,9 @@ class Add(val ipfs: IPFSConnection) { } - suspend fun string(text: String, name: String = "string", filename: String = name): NamedHash { + suspend fun string(text: String, name: String = "string", filename: String = name): NamedResponse { - return addGeneric { + return addGeneric(null) { append(name, text, Headers.build { append(HttpHeaders.ContentType, ContentType.Application.OctetStream) append(HttpHeaders.ContentDisposition, "filename=\"$filename\"") @@ -82,15 +103,40 @@ class Add(val ipfs: IPFSConnection) { } - private suspend fun addGeneric(withBuilder: FormBuilder.() -> Unit): List { + private suspend fun addGeneric( + progressCallback: AddProgressCallback?, + withBuilder: FormBuilder.() -> Unit + ): List { val request = MultiPartFormDataContent(formData(withBuilder)) - val result = ipfs.config.ktorClient.post("${ipfs.config.base_url}add?stream-channels=true&progress=false") { - setBody(request) - } - return try { - listOf(result.body()) - } catch (_: Throwable) { - result.body() - } + val progress = progressCallback != null + val result: List = + ipfs.config.ktorClient.preparePost("${ipfs.config.base_url}add?progress=$progress") { + onUpload { bytesSentTotal, contentLength -> + val uploadProgress = AddUploadProgress(bytesSentTotal, contentLength) + progressCallback?.invoke(uploadProgress, null) + } + setBody(request) + }.execute { httpResponse -> + // todo: figure out how to calculate the total size returned by ipfs before add completion. This isn't really correct to set byteSize with content length. Ipfs returns a slightly larger final number + val processedProgress = + httpResponse.call.request.content.contentLength?.let { AddProcessedProgress(0, it) } + + val channel = httpResponse.bodyAsChannel() + while (!channel.isClosedForRead) { + val progressNamedResponse: NamedResponse? = + channel.readUTF8Line()?.let { Json.decodeFromString(it) } + progressNamedResponse?.size + processedProgress?.bytesProcessed = + progressNamedResponse?.bytes ?: progressNamedResponse?.size?.toLong() ?: 0 + progressCallback?.invoke(null, processedProgress) + } + + return@execute try { + listOf(httpResponse.body()) + } catch (_: Throwable) { + httpResponse.body() + } + } + return result } } diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt deleted file mode 100644 index 2702278..0000000 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedHash.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.ipfs.kotlin.model - -@kotlinx.serialization.Serializable -data class NamedHash(val Name: String, - val Hash: String) \ No newline at end of file diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedResponse.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedResponse.kt new file mode 100644 index 0000000..df8008c --- /dev/null +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/model/NamedResponse.kt @@ -0,0 +1,16 @@ +package io.ipfs.kotlin.model + +import kotlinx.serialization.SerialName + + +@kotlinx.serialization.Serializable +data class NamedResponse( + @SerialName("Name") + val name: String, + @SerialName("Bytes") + val bytes: Long? = null, + @SerialName("Hash") + val hash: String? = null, + @SerialName("Size") + val size: String? = null +) diff --git a/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt index 85df681..f520dd9 100644 --- a/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt +++ b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt @@ -24,8 +24,8 @@ class TestAdd : BaseIPFSWebserverTest() { val addString = ipfs.add.string("foo") // assert - assertThat(addString.Hash).isEqualTo("hashprobe") - assertThat(addString.Name).isEqualTo("nameprobe") + assertThat(addString.hash).isEqualTo("hashprobe") + assertThat(addString.name).isEqualTo("nameprobe") val executedRequest = server.takeRequest(); assertThat(executedRequest.path).startsWith("/add") @@ -44,8 +44,8 @@ class TestAdd : BaseIPFSWebserverTest() { val addString = ipfs.add.file(File.createTempFile("temptestfile", null).toOkioPath()) // assert - assertThat(addString.Hash).isEqualTo("hashprobe") - assertThat(addString.Name).isEqualTo("nameprobe") + assertThat(addString.hash).isEqualTo("hashprobe") + assertThat(addString.name).isEqualTo("nameprobe") val executedRequest = server.takeRequest(); assertThat(executedRequest.path).startsWith("/add"); @@ -73,8 +73,8 @@ class TestAdd : BaseIPFSWebserverTest() { val result = ipfs.add.directory(path.toOkioPath(), path.fileName.toString()) // assert - assertThat(result.first().Hash).isEqualTo("hashprobe") - assertThat(result.first().Name).isEqualTo("nameprobe") + assertThat(result.first().hash).isEqualTo("hashprobe") + assertThat(result.first().name).isEqualTo("nameprobe") val executedRequest = server.takeRequest() val body = executedRequest.body.readUtf8() From a6963d95306992a9511248179efb9f48ec38e6fa Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 7 Jul 2022 14:35:11 -0400 Subject: [PATCH 20/38] update kotlin and dependencies --- buildSrc/src/main/kotlin/Versions.kt | 12 ++++++------ ipfs-api/build.gradle.kts | 10 +++++++--- settings.gradle.kts | 6 +++--- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 5b5ce4a..618ae2d 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,10 +1,10 @@ object Versions { - const val kotlin = "1.6.21" - const val serialization= "1.3.2" + const val kotlin = "1.7.10" + const val serialization= "1.3.3" const val versions_plugin = "0.28.0" const val jupiter = "5.6.2" - const val okhttp = "4.9.3" - const val coroutines = "1.6.1" - const val ktor = "2.0.2" - const val okio = "3.1.0" + const val okhttp = "4.10.0" + const val coroutines = "1.6.3" + const val ktor = "2.0.3" + const val okio = "3.2.0" } \ No newline at end of file diff --git a/ipfs-api/build.gradle.kts b/ipfs-api/build.gradle.kts index dc1e806..ab01d45 100644 --- a/ipfs-api/build.gradle.kts +++ b/ipfs-api/build.gradle.kts @@ -46,6 +46,13 @@ kotlin { api("com.squareup.okio:okio:${Versions.okio}") } } + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.coroutines}") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.coroutines}") + } + } val jvmMain by getting { dependsOn(commonMain) @@ -65,9 +72,6 @@ kotlin { val jvmTest by getting { dependencies { - implementation(kotlin("test")) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.coroutines}") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.coroutines}") implementation("org.mockito:mockito-core:4.5.1") implementation("com.squareup.okhttp3:mockwebserver:${Versions.okhttp}") implementation("org.assertj:assertj-core:3.22.0") diff --git a/settings.gradle.kts b/settings.gradle.kts index a825a67..a78a187 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -7,9 +7,9 @@ pluginManagement { } plugins { - kotlin("multiplatform") version "1.6.21" - kotlin("jvm") version "1.6.21" - kotlin("plugin.serialization") version "1.6.21" + kotlin("multiplatform") version "1.7.10" + kotlin("jvm") version "1.7.10" + kotlin("plugin.serialization") version "1.7.10" id("com.github.ben-manes.versions") version "0.42.0" } } From 281e9a48b7b861b5352d00ad3b7b9c0be9026f9e Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 7 Jul 2022 14:37:59 -0400 Subject: [PATCH 21/38] fix add --- .../kotlin/io/ipfs/kotlin/commands/Add.kt | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index b95194b..0d5b15e 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -14,10 +14,10 @@ import kotlinx.serialization.json.Json import okio.BufferedSource import okio.Path -data class AddUploadProgress(val bytesSent: Long, val byteSize: Long) -data class AddProcessedProgress(var bytesProcessed: Long, val byteSize: Long) +data class UploadProgress(val bytesSent: Long, val byteSize: Long) +data class AddProgress(var bytesProcessed: Long, val byteSize: Long) -typealias AddProgressCallback = ((AddUploadProgress?, AddProcessedProgress?) -> Unit) +typealias UploadAndAddProgressListener = ((UploadProgress?, AddProgress?) -> Unit) class Add(val ipfs: IPFSConnection) { @@ -30,7 +30,7 @@ class Add(val ipfs: IPFSConnection) { file: Path, name: String = "file", filename: String = name, - progressCallback: AddProgressCallback? = null + progressCallback: UploadAndAddProgressListener? = null ) = addGeneric(progressCallback) { println(ipfs.config.fileSystem.openReadOnly(file).size()) addFile(file, name, filename) @@ -43,7 +43,7 @@ class Add(val ipfs: IPFSConnection) { source: BufferedSource, name: String = "file", filename: String = name, - progressCallback: AddProgressCallback? = null + progressCallback: UploadAndAddProgressListener? = null ) = addGeneric(progressCallback) { val encodedFileName = filename.encodeURLParameter() val headersBuilder = HeadersBuilder() @@ -104,7 +104,7 @@ class Add(val ipfs: IPFSConnection) { } private suspend fun addGeneric( - progressCallback: AddProgressCallback?, + progressCallback: UploadAndAddProgressListener?, withBuilder: FormBuilder.() -> Unit ): List { val request = MultiPartFormDataContent(formData(withBuilder)) @@ -112,30 +112,29 @@ class Add(val ipfs: IPFSConnection) { val result: List = ipfs.config.ktorClient.preparePost("${ipfs.config.base_url}add?progress=$progress") { onUpload { bytesSentTotal, contentLength -> - val uploadProgress = AddUploadProgress(bytesSentTotal, contentLength) + val uploadProgress = UploadProgress(bytesSentTotal, contentLength) progressCallback?.invoke(uploadProgress, null) } setBody(request) }.execute { httpResponse -> // todo: figure out how to calculate the total size returned by ipfs before add completion. This isn't really correct to set byteSize with content length. Ipfs returns a slightly larger final number - val processedProgress = - httpResponse.call.request.content.contentLength?.let { AddProcessedProgress(0, it) } - + val ipfsAddProgress = + httpResponse.call.request.content.contentLength?.let { AddProgress(0, it) } + val addResults = mutableListOf() val channel = httpResponse.bodyAsChannel() while (!channel.isClosedForRead) { val progressNamedResponse: NamedResponse? = channel.readUTF8Line()?.let { Json.decodeFromString(it) } - progressNamedResponse?.size - processedProgress?.bytesProcessed = - progressNamedResponse?.bytes ?: progressNamedResponse?.size?.toLong() ?: 0 - progressCallback?.invoke(null, processedProgress) + if (progressNamedResponse?.bytes != null) { + ipfsAddProgress?.bytesProcessed = progressNamedResponse.bytes + } else if (progressNamedResponse?.hash != null) { + ipfsAddProgress?.bytesProcessed = progressNamedResponse.size!!.toLong() + addResults.add(progressNamedResponse) + } + progressCallback?.invoke(null, ipfsAddProgress) } - return@execute try { - listOf(httpResponse.body()) - } catch (_: Throwable) { - httpResponse.body() - } + return@execute addResults } return result } From 93f50a0f41a0bae4fce5eef346ac079ad1b0a00f Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 7 Jul 2022 14:38:13 -0400 Subject: [PATCH 22/38] fix tests --- ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt index f520dd9..29135c2 100644 --- a/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt +++ b/ipfs-api/src/jvmTest/kotlin/io/ipfs/kotlin/TestAdd.kt @@ -17,7 +17,7 @@ class TestAdd : BaseIPFSWebserverTest() { // setup server.enqueue( MockResponse().setHeader("Content-Type", ContentType.Application.Json) - .setBody("{\"Hash\":\"hashprobe\",\"Name\":\"nameprobe\"}") + .setBody("""{"Hash":"hashprobe","Name":"nameprobe", "Size":"1"}""") ) // invoke @@ -37,7 +37,7 @@ class TestAdd : BaseIPFSWebserverTest() { // setup server.enqueue( MockResponse().setHeader("Content-Type", ContentType.Application.Json) - .setBody("{\"Hash\":\"hashprobe\",\"Name\":\"nameprobe\"}") + .setBody("""{"Hash":"hashprobe","Name":"nameprobe", "Size":"1"}""") ) // invoke @@ -57,7 +57,7 @@ class TestAdd : BaseIPFSWebserverTest() { // setup server.enqueue( MockResponse().setHeader("Content-Type", ContentType.Application.Json) - .setBody("{\"Hash\":\"hashprobe\",\"Name\":\"nameprobe\"}") + .setBody("""{"Hash":"hashprobe","Name":"nameprobe", "Size":"1"}""") ); // create nested subdirectories From bc0b4d5b941f6c32bf2cb64a47d50b0bb4eb38d4 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 7 Jul 2022 14:45:49 -0400 Subject: [PATCH 23/38] update example program to add a file --- .../kotlin/io/ipfs/example_cli/ExampleCLI.kt | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt b/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt index b72dd41..4e88b91 100644 --- a/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt +++ b/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt @@ -1,8 +1,20 @@ package io.ipfs.example_cli -import io.ipfs.kotlin.IPFS -import io.ipfs.kotlin.IPFSConfiguration +import io.ipfs.kotlin.commands.AddProgress +import io.ipfs.kotlin.commands.UploadProgress +import io.ipfs.kotlin.defaults.InfuraIPFS +import kotlinx.coroutines.runBlocking +import okio.Path.Companion.toOkioPath +import java.io.File -fun main() = runBlocking { - println(IPFS(IPFSConfiguration()).info.version()) +fun main(args: Array) = runBlocking { + println(InfuraIPFS().info.version()) + println( + InfuraIPFS().add.file( + File(args[0]).toOkioPath() + ) { uploadProgress: UploadProgress?, addProgress: AddProgress? -> + uploadProgress?.let { println(it) } + addProgress?.let { println(it) } + } + ) } \ No newline at end of file From 63458b251b7755401f46cc7d58f949861f6423d2 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 7 Jul 2022 14:53:26 -0400 Subject: [PATCH 24/38] resolve warning --- .../kotlin/io/ipfs/kotlin/commands/Name.kt | 4 +- kotlin-js-store/yarn.lock | 104 ++++++++---------- 2 files changed, 48 insertions(+), 60 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt index 7fcc998..ed25ba9 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Name.kt @@ -20,10 +20,10 @@ class Name(val ipfs: IPFSConnection) { } suspend fun resolve(hash: String): String? { - val resultString = ipfs.callCmd("name/resolve/$hash").let { it.bodyAsText() } + val resultString = ipfs.callCmd("name/resolve/$hash").bodyAsText() return when { - resultString == null -> null + resultString.isBlank() -> null resultString.contains("Path") -> Json.decodeFromString(resultString).Path else -> { ipfs.setErrorByJSON(resultString) diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock index bf8d3ce..44494f1 100644 --- a/kotlin-js-store/yarn.lock +++ b/kotlin-js-store/yarn.lock @@ -62,6 +62,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -92,10 +99,10 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chokidar@3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -133,10 +140,10 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -debug@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== +debug@4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -225,10 +232,10 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -242,11 +249,6 @@ google-protobuf@3.12.2: resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -309,11 +311,6 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - js-yaml@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -336,12 +333,12 @@ log-symbols@4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -minimatch@3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== dependencies: - brace-expansion "^1.1.7" + brace-expansion "^2.0.1" minimatch@^3.0.4: version "3.1.2" @@ -350,32 +347,30 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -mocha@9.1.2: - version "9.1.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.1.2.tgz#93f53175b0f0dc4014bd2d612218fccfcf3534d3" - integrity sha512-ta3LtJ+63RIBP03VBjMGtSqbe6cWXRejF9SyM9Zyli1CKZJZ+vfCTj3oW24V7wAphMJdpOFLoMI3hjJ1LWbs0w== +mocha@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.0.0.tgz#205447d8993ec755335c4b13deba3d3a13c4def9" + integrity sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA== dependencies: "@ungap/promise-all-settled" "1.1.2" ansi-colors "4.1.1" browser-stdout "1.3.1" - chokidar "3.5.2" - debug "4.3.2" + chokidar "3.5.3" + debug "4.3.4" diff "5.0.0" escape-string-regexp "4.0.0" find-up "5.0.0" - glob "7.1.7" - growl "1.10.5" + glob "7.2.0" he "1.2.0" js-yaml "4.1.0" log-symbols "4.1.0" - minimatch "3.0.4" + minimatch "5.0.1" ms "2.1.3" - nanoid "3.1.25" + nanoid "3.3.3" serialize-javascript "6.0.0" strip-json-comments "3.1.1" supports-color "8.1.1" - which "2.0.2" - workerpool "6.1.5" + workerpool "6.2.1" yargs "16.2.0" yargs-parser "20.2.4" yargs-unparser "2.0.0" @@ -390,10 +385,10 @@ ms@2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@3.1.25: - version "3.1.25" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" - integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== node-fetch@2.6.7: version "2.6.7" @@ -474,10 +469,10 @@ serialize-javascript@6.0.0: dependencies: randombytes "^2.1.0" -source-map-support@0.5.20: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== +source-map-support@0.5.21: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -552,17 +547,10 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -workerpool@6.1.5: - version "6.1.5" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" - integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== wrap-ansi@^7.0.0: version "7.0.0" From 4db755c31e20cfbfd3ff824a503117ed52150418 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Fri, 5 Aug 2022 23:40:28 -0400 Subject: [PATCH 25/38] calculate progress percentage of upload and add --- .../kotlin/io/ipfs/kotlin/commands/Add.kt | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 0d5b15e..3cdd913 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -14,8 +14,12 @@ import kotlinx.serialization.json.Json import okio.BufferedSource import okio.Path -data class UploadProgress(val bytesSent: Long, val byteSize: Long) -data class AddProgress(var bytesProcessed: Long, val byteSize: Long) +data class UploadProgress(val bytesSent: Long, val byteSize: Long) { + val percentage = (bytesSent.toDouble() / byteSize.toDouble()) * 100.0 +} +data class AddProgress(var bytesProcessed: Long, val byteSize: Long) { + val percentage = (bytesProcessed.toDouble() / byteSize.toDouble()) * 100.0 +} typealias UploadAndAddProgressListener = ((UploadProgress?, AddProgress?) -> Unit) @@ -30,8 +34,8 @@ class Add(val ipfs: IPFSConnection) { file: Path, name: String = "file", filename: String = name, - progressCallback: UploadAndAddProgressListener? = null - ) = addGeneric(progressCallback) { + progressListener: UploadAndAddProgressListener? = null + ) = addGeneric(progressListener) { println(ipfs.config.fileSystem.openReadOnly(file).size()) addFile(file, name, filename) }.last() @@ -43,8 +47,8 @@ class Add(val ipfs: IPFSConnection) { source: BufferedSource, name: String = "file", filename: String = name, - progressCallback: UploadAndAddProgressListener? = null - ) = addGeneric(progressCallback) { + progressListener: UploadAndAddProgressListener? = null + ) = addGeneric(progressListener) { val encodedFileName = filename.encodeURLParameter() val headersBuilder = HeadersBuilder() headersBuilder.append(HttpHeaders.ContentDisposition, "filename=\"$encodedFileName\"") @@ -104,16 +108,16 @@ class Add(val ipfs: IPFSConnection) { } private suspend fun addGeneric( - progressCallback: UploadAndAddProgressListener?, + progressListener: UploadAndAddProgressListener?, withBuilder: FormBuilder.() -> Unit ): List { val request = MultiPartFormDataContent(formData(withBuilder)) - val progress = progressCallback != null + val progress = progressListener != null val result: List = ipfs.config.ktorClient.preparePost("${ipfs.config.base_url}add?progress=$progress") { onUpload { bytesSentTotal, contentLength -> val uploadProgress = UploadProgress(bytesSentTotal, contentLength) - progressCallback?.invoke(uploadProgress, null) + progressListener?.invoke(uploadProgress, null) } setBody(request) }.execute { httpResponse -> @@ -131,7 +135,7 @@ class Add(val ipfs: IPFSConnection) { ipfsAddProgress?.bytesProcessed = progressNamedResponse.size!!.toLong() addResults.add(progressNamedResponse) } - progressCallback?.invoke(null, ipfsAddProgress) + progressListener?.invoke(null, ipfsAddProgress) } return@execute addResults From 65a18c5cbca3aa11db45a97445577cee4af4fb8b Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Thu, 21 Jul 2022 13:13:57 -0400 Subject: [PATCH 26/38] Add.file: change source from BufferedSource to ByteArray. BufferedSource.readByteArray clears the source buffer. Which was not my intention --- .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 3cdd913..81f0963 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -36,15 +36,14 @@ class Add(val ipfs: IPFSConnection) { filename: String = name, progressListener: UploadAndAddProgressListener? = null ) = addGeneric(progressListener) { - println(ipfs.config.fileSystem.openReadOnly(file).size()) addFile(file, name, filename) }.last() /*** - * Accepts a single file's BufferedSource and returns the named hash. + * Accepts a single file's ByteArray and returns the named hash. **/ suspend fun file( - source: BufferedSource, + source: ByteArray, name: String = "file", filename: String = name, progressListener: UploadAndAddProgressListener? = null @@ -54,7 +53,7 @@ class Add(val ipfs: IPFSConnection) { headersBuilder.append(HttpHeaders.ContentDisposition, "filename=\"$encodedFileName\"") headersBuilder.append("Content-Transfer-Encoding", "binary") headersBuilder.append(HttpHeaders.ContentType, ContentType.Application.OctetStream) - append(name, source.readByteArray(), headersBuilder.build()) + append(name, source, headersBuilder.build()) }.last() From b38f3f3a9721b378ef61184d88f0651dde0e5c3a Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 23 Jul 2022 19:05:07 -0400 Subject: [PATCH 27/38] fix add progress callback --- .../kotlin/io/ipfs/kotlin/commands/Add.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 81f0963..0db04a8 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -17,7 +17,7 @@ import okio.Path data class UploadProgress(val bytesSent: Long, val byteSize: Long) { val percentage = (bytesSent.toDouble() / byteSize.toDouble()) * 100.0 } -data class AddProgress(var bytesProcessed: Long, val byteSize: Long) { +data class AddProgress(val bytesProcessed: Long, val byteSize: Long) { val percentage = (bytesProcessed.toDouble() / byteSize.toDouble()) * 100.0 } @@ -121,18 +121,20 @@ class Add(val ipfs: IPFSConnection) { setBody(request) }.execute { httpResponse -> // todo: figure out how to calculate the total size returned by ipfs before add completion. This isn't really correct to set byteSize with content length. Ipfs returns a slightly larger final number - val ipfsAddProgress = - httpResponse.call.request.content.contentLength?.let { AddProgress(0, it) } + val contentLength = + httpResponse.call.request.content.contentLength val addResults = mutableListOf() val channel = httpResponse.bodyAsChannel() while (!channel.isClosedForRead) { val progressNamedResponse: NamedResponse? = channel.readUTF8Line()?.let { Json.decodeFromString(it) } - if (progressNamedResponse?.bytes != null) { - ipfsAddProgress?.bytesProcessed = progressNamedResponse.bytes + val ipfsAddProgress = if (progressNamedResponse?.bytes != null) { + contentLength?.let { AddProgress(progressNamedResponse.bytes, it) } } else if (progressNamedResponse?.hash != null) { - ipfsAddProgress?.bytesProcessed = progressNamedResponse.size!!.toLong() addResults.add(progressNamedResponse) + contentLength?.let { AddProgress(progressNamedResponse.size!!.toLong(), it) } + } else { + null } progressListener?.invoke(null, ipfsAddProgress) } From 361012a7844cf6276e58ef93fa9ccab55e8744fc Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Fri, 5 Aug 2022 23:42:50 -0400 Subject: [PATCH 28/38] Fix getting bytes --- .../commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt index 15cf6c9..4071a89 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt @@ -2,6 +2,7 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ktor.client.statement.* +import io.ktor.http.* import io.ktor.utils.io.* class Get(val ipfs: IPFSConnection) { @@ -11,14 +12,17 @@ class Get(val ipfs: IPFSConnection) { * * @param hash The hash of the content in base58. */ - suspend fun cat(hash: String): String = ipfs.callCmd("cat/$hash").bodyAsText() + suspend fun cat(hash: String): String = catBytes(hash).decodeToString() /** * Cat IPFS content and return it as ByteArray. * * @param hash The hash of the content in base58. */ - suspend fun catBytes(hash: String): ByteArray = ipfs.callCmd("cat/$hash").readBytes() + suspend fun catBytes(hash: String): ByteArray { + val r = ipfs.callCmd("cat?arg=$hash") + return r.readBytes() + } /** * Cat IPFS content and process it using ByteReadChannel. @@ -27,7 +31,7 @@ class Get(val ipfs: IPFSConnection) { * @param handler Callback which handle processing the input stream. When the callback return the stream and the request body will be closed. */ suspend fun catReadChannel(hash: String, handler: (stream: ByteReadChannel) -> Unit): Unit = - ipfs.callCmd("cat/$hash").let { response -> + ipfs.callCmd("cat?arg=$hash").let { response -> val channel = response.bodyAsChannel() handler.invoke(channel) } From 689707c362152c3ea9f4daf453383d11e23390c1 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 00:46:43 -0400 Subject: [PATCH 29/38] Infuras public gateway does not exist anymore add support for basic auth --- .../{ExampleCLI.kt => ExampleInfuraCLI.kt} | 11 ++++++++--- .../src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt | 15 +++++++++++---- .../kotlin/io/ipfs/kotlin/IPFSConnection.kt | 3 +++ .../kotlin/io/ipfs/kotlin/commands/Add.kt | 3 +++ .../kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt | 12 ++++++++---- 5 files changed, 33 insertions(+), 11 deletions(-) rename example/src/main/kotlin/io/ipfs/example_cli/{ExampleCLI.kt => ExampleInfuraCLI.kt} (65%) diff --git a/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt b/example/src/main/kotlin/io/ipfs/example_cli/ExampleInfuraCLI.kt similarity index 65% rename from example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt rename to example/src/main/kotlin/io/ipfs/example_cli/ExampleInfuraCLI.kt index 4e88b91..c1c64cc 100644 --- a/example/src/main/kotlin/io/ipfs/example_cli/ExampleCLI.kt +++ b/example/src/main/kotlin/io/ipfs/example_cli/ExampleInfuraCLI.kt @@ -8,10 +8,15 @@ import okio.Path.Companion.toOkioPath import java.io.File fun main(args: Array) = runBlocking { - println(InfuraIPFS().info.version()) + require(args.size == 3) + val projectId = args[0] + val projectSecret = args[1] + val filePath = args[2] + val ipfs = InfuraIPFS(projectId, projectSecret) + println(ipfs.info.version()) println( - InfuraIPFS().add.file( - File(args[0]).toOkioPath() + ipfs.add.file( + File(filePath).toOkioPath() ) { uploadProgress: UploadProgress?, addProgress: AddProgress? -> uploadProgress?.let { println(it) } addProgress?.let { println(it) } diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt index a1499ce..df58655 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFS.kt @@ -7,10 +7,17 @@ import io.ipfs.kotlin.model.MessageWithCode import io.ktor.client.* import okio.FileSystem -data class IPFSConfiguration(val base_url: String = "http://127.0.0.1:5001/api/v0/", - val ktorClient: HttpClient = createKTOR(), - val fileSystem: FileSystem = createFileSystem() -) +data class IPFSConfiguration( + val base_url: String = "http://127.0.0.1:5001/api/v0/", + val ktorClient: HttpClient = createKTOR(), + val fileSystem: FileSystem = createFileSystem(), + val basicAuthCredentials: BasicAuth? = null +) { + class BasicAuth( + val username: String, + val password: String + ) +} open class IPFS(configuration: IPFSConfiguration) { diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt index 977e4fb..bf67317 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt @@ -15,6 +15,9 @@ open class IPFSConnection(val config: IPFSConfiguration) { val request = HttpRequestBuilder().apply { url(config.base_url + cmd) contentType(ContentType.Any) + config.basicAuthCredentials?.apply { + basicAuth(username, password) + } } return config.ktorClient.post(request) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index 0db04a8..a81cbc8 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -114,6 +114,9 @@ class Add(val ipfs: IPFSConnection) { val progress = progressListener != null val result: List = ipfs.config.ktorClient.preparePost("${ipfs.config.base_url}add?progress=$progress") { + ipfs.config.basicAuthCredentials?.apply { + basicAuth(username, password) + } onUpload { bytesSentTotal, contentLength -> val uploadProgress = UploadProgress(bytesSentTotal, contentLength) progressListener?.invoke(uploadProgress, null) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt index 0616561..3782d6e 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/InfuraIPFS.kt @@ -3,8 +3,12 @@ package io.ipfs.kotlin.defaults import io.ipfs.kotlin.IPFS import io.ipfs.kotlin.IPFSConfiguration -val infuraIPFSConfig by lazy { - IPFSConfiguration("https://ipfs.infura.io:5001/api/v0/") -} +//https://docs.infura.io/infura/networks/ipfs/how-to/authenticate-requests +fun infuraIPFSConfig(projectId: String, projectSecret: String) = + IPFSConfiguration( + "https://ipfs.infura.io:5001/api/v0/", + basicAuthCredentials = IPFSConfiguration.BasicAuth(projectId, projectSecret) + ) -open class InfuraIPFS : IPFS(infuraIPFSConfig) \ No newline at end of file + +open class InfuraIPFS(projectId: String, projectSecret: String) : IPFS(infuraIPFSConfig(projectId, projectSecret)) \ No newline at end of file From c4c221008be8f0783adfbf478de14926c6e3e4b6 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 01:37:20 -0400 Subject: [PATCH 30/38] gradle and coroutines updates --- buildSrc/src/main/kotlin/Versions.kt | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 618ae2d..fe5b10e 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -4,7 +4,7 @@ object Versions { const val versions_plugin = "0.28.0" const val jupiter = "5.6.2" const val okhttp = "4.10.0" - const val coroutines = "1.6.3" + const val coroutines = "1.6.4" const val ktor = "2.0.3" const val okio = "3.2.0" } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aa991fc..ae04661 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 71ad41e54da2cb8683acc6d033fad38d4a301b3d Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 18:28:23 -0400 Subject: [PATCH 31/38] workaround for SocketTimeoutException https://youtrack.jetbrains.com/issue/KTOR-3840/OkHttp-Socket-timeouts-without-timeout-configured --- .../commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt index e05a9a5..5e39fdc 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/defaults/Defaults.kt @@ -1,6 +1,7 @@ package io.ipfs.kotlin.defaults import io.ktor.client.* +import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json @@ -13,8 +14,12 @@ internal fun createKTOR() = HttpClient { ignoreUnknownKeys = true }) } + install(HttpTimeout) { + // this socketTimeout can occur w/ okhttp engine when posting larger file + socketTimeoutMillis = 600_000 // 10 minutes + } } -expect internal fun createFileSystem() : FileSystem +expect internal fun createFileSystem(): FileSystem From 549cdd907bb4cb4bdfb591946c10aa9795393ca8 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 19:03:15 -0400 Subject: [PATCH 32/38] update ktor --- buildSrc/src/main/kotlin/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index fe5b10e..ca69032 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -5,6 +5,6 @@ object Versions { const val jupiter = "5.6.2" const val okhttp = "4.10.0" const val coroutines = "1.6.4" - const val ktor = "2.0.3" + const val ktor = "2.1.0" const val okio = "3.2.0" } \ No newline at end of file From 65999be3f39cafea5ded201c6d76ff9f1eb21e3c Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 20:16:45 -0400 Subject: [PATCH 33/38] add a prepareCallCmd to handle streaming data for add and get --- .../kotlin/io/ipfs/kotlin/IPFSConnection.kt | 13 ++++++++++++- .../kotlin/io/ipfs/kotlin/commands/Add.kt | 5 +---- .../kotlin/io/ipfs/kotlin/commands/Get.kt | 8 ++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt index bf67317..341660f 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/IPFSConnection.kt @@ -11,18 +11,29 @@ open class IPFSConnection(val config: IPFSConfiguration) { var lastError: MessageWithCode? = null - suspend fun callCmd(cmd: String): HttpResponse { + private fun buildRequest(cmd: String, block: HttpRequestBuilder.() -> Unit = {}): HttpRequestBuilder { val request = HttpRequestBuilder().apply { url(config.base_url + cmd) contentType(ContentType.Any) config.basicAuthCredentials?.apply { basicAuth(username, password) } + block() } + return request + } + + suspend fun callCmd(cmd: String): HttpResponse { + val request = buildRequest(cmd) return config.ktorClient.post(request) } + suspend fun prepareCallCmd(cmd: String, block: HttpRequestBuilder.() -> Unit = {}): HttpStatement { + val request = buildRequest(cmd, block) + return config.ktorClient.preparePost(request) + } + fun setErrorByJSON(jsonString: String) { lastError = Json.decodeFromString(jsonString) } diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index a81cbc8..f59cab7 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -113,10 +113,7 @@ class Add(val ipfs: IPFSConnection) { val request = MultiPartFormDataContent(formData(withBuilder)) val progress = progressListener != null val result: List = - ipfs.config.ktorClient.preparePost("${ipfs.config.base_url}add?progress=$progress") { - ipfs.config.basicAuthCredentials?.apply { - basicAuth(username, password) - } + ipfs.prepareCallCmd("add?progress=$progress") { onUpload { bytesSentTotal, contentLength -> val uploadProgress = UploadProgress(bytesSentTotal, contentLength) progressListener?.invoke(uploadProgress, null) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt index 4071a89..e133552 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt @@ -1,8 +1,8 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection +import io.ktor.client.call.* import io.ktor.client.statement.* -import io.ktor.http.* import io.ktor.utils.io.* class Get(val ipfs: IPFSConnection) { @@ -31,9 +31,9 @@ class Get(val ipfs: IPFSConnection) { * @param handler Callback which handle processing the input stream. When the callback return the stream and the request body will be closed. */ suspend fun catReadChannel(hash: String, handler: (stream: ByteReadChannel) -> Unit): Unit = - ipfs.callCmd("cat?arg=$hash").let { response -> - val channel = response.bodyAsChannel() - handler.invoke(channel) + ipfs.prepareCallCmd("cat?arg=$hash").execute { httpResponse -> + val channel: ByteReadChannel = httpResponse.body() + handler(channel) } } \ No newline at end of file From cff2f9a460159a48aafecda0333051d91e45ad1d Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 20:16:59 -0400 Subject: [PATCH 34/38] reformat --- .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt index f59cab7..0f551c9 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Add.kt @@ -2,7 +2,6 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ipfs.kotlin.model.NamedResponse -import io.ktor.client.call.* import io.ktor.client.plugins.* import io.ktor.client.request.* import io.ktor.client.request.forms.* @@ -11,14 +10,14 @@ import io.ktor.http.* import io.ktor.utils.io.* import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import okio.BufferedSource import okio.Path data class UploadProgress(val bytesSent: Long, val byteSize: Long) { - val percentage = (bytesSent.toDouble() / byteSize.toDouble()) * 100.0 + val percentage = (bytesSent.toDouble() / byteSize.toDouble()) * 100.0 } + data class AddProgress(val bytesProcessed: Long, val byteSize: Long) { - val percentage = (bytesProcessed.toDouble() / byteSize.toDouble()) * 100.0 + val percentage = (bytesProcessed.toDouble() / byteSize.toDouble()) * 100.0 } typealias UploadAndAddProgressListener = ((UploadProgress?, AddProgress?) -> Unit) From 782553bb147217c6cf490cd1bc9b36a4a932a8c2 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 20:25:52 -0400 Subject: [PATCH 35/38] return as channel instead of callback --- .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt index e133552..ac28e28 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt @@ -30,10 +30,9 @@ class Get(val ipfs: IPFSConnection) { * @param hash The hash of the content in base58. * @param handler Callback which handle processing the input stream. When the callback return the stream and the request body will be closed. */ - suspend fun catReadChannel(hash: String, handler: (stream: ByteReadChannel) -> Unit): Unit = + suspend fun catReadChannel(hash: String): ByteReadChannel = ipfs.prepareCallCmd("cat?arg=$hash").execute { httpResponse -> - val channel: ByteReadChannel = httpResponse.body() - handler(channel) + return@execute httpResponse.body() } } \ No newline at end of file From fb69325e76cd740fde5479f32b0bc994da1f539b Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 20:43:32 -0400 Subject: [PATCH 36/38] Return content length with cat's ByteReadChannel when streaming --- .../src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt index ac28e28..453dd42 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt @@ -3,6 +3,7 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ktor.client.call.* import io.ktor.client.statement.* +import io.ktor.http.* import io.ktor.utils.io.* class Get(val ipfs: IPFSConnection) { @@ -30,9 +31,11 @@ class Get(val ipfs: IPFSConnection) { * @param hash The hash of the content in base58. * @param handler Callback which handle processing the input stream. When the callback return the stream and the request body will be closed. */ - suspend fun catReadChannel(hash: String): ByteReadChannel = + suspend fun catReadChannel(hash: String): ByteReadChannelAndContentLength = ipfs.prepareCallCmd("cat?arg=$hash").execute { httpResponse -> - return@execute httpResponse.body() + return@execute ByteReadChannelAndContentLength(httpResponse.body(), httpResponse.contentLength()!!) } -} \ No newline at end of file +} + +data class ByteReadChannelAndContentLength(val byteReadChannel: ByteReadChannel, val contentLength: Long) \ No newline at end of file From ec4d9d4062bc43930541e457bcef0cb50ba0c687 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 21:20:04 -0400 Subject: [PATCH 37/38] fix getting content length --- ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt index 453dd42..9bfecde 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt @@ -33,7 +33,7 @@ class Get(val ipfs: IPFSConnection) { */ suspend fun catReadChannel(hash: String): ByteReadChannelAndContentLength = ipfs.prepareCallCmd("cat?arg=$hash").execute { httpResponse -> - return@execute ByteReadChannelAndContentLength(httpResponse.body(), httpResponse.contentLength()!!) + return@execute ByteReadChannelAndContentLength(httpResponse.body(), httpResponse.headers["X-Content-Length"]!!.toLong()) } } From cdc20a08e34d63b79f3f659fa314487b852f7072 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Sat, 13 Aug 2022 23:08:33 -0400 Subject: [PATCH 38/38] revert back to returning in callback handler to prevent channel closing --- .../kotlin/io/ipfs/kotlin/commands/Get.kt | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt index 9bfecde..f79c638 100644 --- a/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt +++ b/ipfs-api/src/commonMain/kotlin/io/ipfs/kotlin/commands/Get.kt @@ -3,7 +3,6 @@ package io.ipfs.kotlin.commands import io.ipfs.kotlin.IPFSConnection import io.ktor.client.call.* import io.ktor.client.statement.* -import io.ktor.http.* import io.ktor.utils.io.* class Get(val ipfs: IPFSConnection) { @@ -31,11 +30,21 @@ class Get(val ipfs: IPFSConnection) { * @param hash The hash of the content in base58. * @param handler Callback which handle processing the input stream. When the callback return the stream and the request body will be closed. */ - suspend fun catReadChannel(hash: String): ByteReadChannelAndContentLength = + suspend fun catReadChannel(hash: String, handler: CatReadChannelHandler) = ipfs.prepareCallCmd("cat?arg=$hash").execute { httpResponse -> - return@execute ByteReadChannelAndContentLength(httpResponse.body(), httpResponse.headers["X-Content-Length"]!!.toLong()) + httpResponse.apply { + handler( + ByteReadChannelAndContentLength( + httpResponse.body(), + httpResponse.headers["X-Content-Length"]!!.toLong() + ) + ) + } + return@execute } - + } +typealias CatReadChannelHandler = suspend HttpResponse.(ByteReadChannelAndContentLength) -> Unit + data class ByteReadChannelAndContentLength(val byteReadChannel: ByteReadChannel, val contentLength: Long) \ No newline at end of file