diff --git a/Cargo.lock b/Cargo.lock index 301940508..b625b015c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,15 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - [[package]] name = "anstream" version = "0.6.4" @@ -417,19 +408,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows", -] - [[package]] name = "gimli" version = "0.28.1" @@ -444,9 +422,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "goblin" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +checksum = "bb07a4ffed2093b118a525b1d8f5204ae274faed5604537caf7135d0f18d9887" dependencies = [ "log", "plain", @@ -626,29 +604,6 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "pin-utils", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "memchr" version = "2.6.4" @@ -725,16 +680,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num_cpus" version = "1.16.0" @@ -761,13 +706,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] -name = "oneshot" +name = "oneshot-uniffi" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f6640c6bda7731b1fdbab747981a0f896dd1fedaf9f4a53fa237a04a84431f4" -dependencies = [ - "loom", -] +checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c" [[package]] name = "openssl" @@ -813,12 +755,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "paste" version = "1.0.14" @@ -882,50 +818,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.3", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - [[package]] name = "reqwest" version = "0.11.22" @@ -983,12 +875,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - [[package]] name = "ryu" version = "1.0.15" @@ -1004,26 +890,20 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scroll" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" dependencies = [ "scroll_derive", ] [[package]] name = "scroll_derive" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", @@ -1105,15 +985,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "siphasher" version = "0.3.11" @@ -1129,12 +1000,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - [[package]] name = "smawk" version = "0.3.2" @@ -1249,16 +1114,6 @@ dependencies = [ "syn", ] -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -1336,21 +1191,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tracing-core" version = "0.1.32" @@ -1358,36 +1201,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", ] [[package]] @@ -1440,13 +1253,13 @@ checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "uniffi" -version = "0.25.2" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +version = "0.25.3" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "anyhow", "camino", "clap", - "uniffi_bindgen 0.25.2", + "uniffi_bindgen 0.25.3", "uniffi_build", "uniffi_core", "uniffi_macros", @@ -1461,8 +1274,8 @@ dependencies = [ [[package]] name = "uniffi_bindgen" -version = "0.25.2" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +version = "0.25.3" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "anyhow", "askama", @@ -1485,18 +1298,18 @@ dependencies = [ [[package]] name = "uniffi_build" -version = "0.25.2" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +version = "0.25.3" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "anyhow", "camino", - "uniffi_bindgen 0.25.2", + "uniffi_bindgen 0.25.3", ] [[package]] name = "uniffi_checksum_derive" -version = "0.25.2" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +version = "0.25.3" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "quote", "syn", @@ -1504,23 +1317,23 @@ dependencies = [ [[package]] name = "uniffi_core" -version = "0.25.2" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +version = "0.25.3" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "anyhow", "bytes", "camino", "log", "once_cell", - "oneshot", + "oneshot-uniffi", "paste", "static_assertions", ] [[package]] name = "uniffi_macros" -version = "0.25.2" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +version = "0.25.3" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "bincode", "camino", @@ -1537,8 +1350,8 @@ dependencies = [ [[package]] name = "uniffi_meta" -version = "0.25.2" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +version = "0.25.3" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "anyhow", "bytes", @@ -1548,8 +1361,8 @@ dependencies = [ [[package]] name = "uniffi_testing" -version = "0.25.2" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +version = "0.25.3" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "anyhow", "camino", @@ -1560,8 +1373,8 @@ dependencies = [ [[package]] name = "uniffi_udl" -version = "0.25.2" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +version = "0.25.3" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "anyhow", "textwrap", @@ -1587,12 +1400,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - [[package]] name = "vcpkg" version = "0.2.15" @@ -1699,7 +1506,7 @@ dependencies = [ [[package]] name = "weedle2" version = "4.0.0" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d380d164cfdba9e091c461baa6855f0a2294ac5b#d380d164cfdba9e091c461baa6855f0a2294ac5b" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=22a9192162744b8a46997dcdcf628a7dba769570#22a9192162744b8a46997dcdcf628a7dba769570" dependencies = [ "nom", ] @@ -1726,15 +1533,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -1883,6 +1681,7 @@ version = "0.1.0" dependencies = [ "http", "serde", + "serde_json", "thiserror", "uniffi", ] @@ -1901,7 +1700,5 @@ version = "0.1.0" dependencies = [ "http", "reqwest", - "serde_json", - "uniffi", "wp_api", ] diff --git a/Cargo.toml b/Cargo.toml index eb0b7b959..720336272 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ resolver = "2" [workspace.dependencies] # External traits in UDL is only available since https://github.com/mozilla/uniffi-rs/pull/1867 # Point to a specific commit until a new version is released -uniffi = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d380d164cfdba9e091c461baa6855f0a2294ac5b" } +uniffi = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "22a9192162744b8a46997dcdcf628a7dba769570" } # We need to match the version used in `reqwest`: https://github.com/seanmonstar/reqwest/blob/master/Cargo.toml#L84 # So that we can implement our own traits and it'll work with both reqwest types as well as http types # diff --git a/native/android/common.gradle b/native/android/common.gradle new file mode 100644 index 000000000..4c7e231ef --- /dev/null +++ b/native/android/common.gradle @@ -0,0 +1,80 @@ +// Adopted from https://github.com/mozilla/application-services/blob/v120.0.1/publish.gradle#L206-L226 +// +// A convenience function for configuring a `uniffi-bindgen` task, +// with appropriate dependency info. This will call `uniffi-bindgen` +// for the provided `moduleName`'s `.dylib` file in order to generate Kotlin language +// bindings and include them in the source set for the project. +ext.configureUniFFIBindgen = { moduleName -> + android.libraryVariants.all { variant -> + def uniffiGeneratedPath = "$buildDir/generated/source/uniffi/${variant.name}/java" + def dylibFilePath = "${project.projectDir}/../../../target/release/lib${moduleName}.dylib" + def t = tasks.register("generate${variant.name.capitalize()}UniFFIBindings", Exec) { + workingDir project.rootDir + commandLine 'cargo', 'run', '--release', '--bin', 'uniffi_bindgen', 'generate', '--library', dylibFilePath, '--out-dir', uniffiGeneratedPath, '--language', 'kotlin' + outputs.dir uniffiGeneratedPath + // Re-generate if the interface definition changes. + inputs.file dylibFilePath + // Re-generate if our uniffi-bindgen tooling changes. + inputs.dir "${project.rootDir}/../../uniffi_bindgen/" + // Re-generate if our uniffi-bindgen version changes. + inputs.file "${project.rootDir}/../../Cargo.lock" + // Re-generate if the module source code changes + inputs.dir "${project.rootDir}/../../${moduleName}/" + } + variant.registerJavaGeneratingTask(t.get(), new File(buildDir, uniffiGeneratedPath)) + def sourceSet = variant.sourceSets.find { it.name == variant.name } + sourceSet.java.srcDir new File(buildDir, "generated/source/uniffi/${variant.name}/java/uniffi") + } +} + +ext.addJnaDependencies = { + dependencies { + implementation "net.java.dev.jna:jna:5.13.0@aar" + androidTestImplementation "net.java.dev.jna:jna:5.13.0@aar" + testImplementation "net.java.dev.jna:jna:5.13.0" + } +} + +ext.setupCargo = { moduleName, nativeRustTarget -> + cargo { + module = "../../../$moduleName/" + libname = moduleName + profile = "release" + targets = ["arm", "arm64", "x86", "x86_64", nativeRustTarget] + targetDirectory = '../../../target' + + exec { spec, toolchain -> + // https://doc.rust-lang.org/rustc/command-line-arguments.html#-g-include-debug-information + spec.environment("RUSTFLAGS", "-g") + } + } + tasks.matching { it.name.matches(/merge.*JniLibFolders/) }.configureEach { + it.inputs.dir(new File(buildDir, "rustJniLibs/android")) + it.dependsOn("cargoBuild") + } + + tasks.matching { it.name.matches("test") }.configureEach { + it.dependsOn("cargoBuild") + } +} + +ext.getNativeRustTarget = { resourcePrefix -> + switch (resourcePrefix) { + case 'darwin': + // For unit tests to work in Apple Silicon, we need to return 'darwin-aarch64' here + // However, that runs the cargo task as `cargoBuildDarwin-aarch64` which is not properly + // cached by cargo and requires a rebuild every time. This results in a significant + // development time loss, so for now, we are returning 'darwin' and using instrumented + // tests instead. + // return 'darwin-aarch64' + return 'darwin' + case 'darwin-aarch64': + return 'darwin-aarch64' + case 'darwin-x86-64': + return 'darwin-x86-64' + case 'linux-x86-64': + return 'linux-x86-64' + case 'win32-x86-64': + return 'win32-x86-64-gnu' + } +} diff --git a/native/android/lib/build.gradle b/native/android/lib/build.gradle deleted file mode 100644 index 4a9d62d79..000000000 --- a/native/android/lib/build.gradle +++ /dev/null @@ -1,109 +0,0 @@ -plugins { - id("com.android.library") - id("org.jetbrains.kotlin.android") - id("org.mozilla.rust-android-gradle.rust-android") - id("com.automattic.android.publish-to-s3") -} - -apply from: 'uniffi.gradle' - -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) - } -} - -android { - namespace = "org.wordpress.rs" - - compileSdk = 33 - - defaultConfig { - minSdk = 24 - - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - - ndk { - debugSymbolLevel 'FULL' - } - } - - sourceSets { - androidTest.jniLibs.srcDirs += "$buildDir/rustJniLibs/android" - } - - packagingOptions { - doNotStrip "**/*.so" - } -} - -repositories { - mavenCentral() - google() -} - -dependencies { - implementation "net.java.dev.jna:jna:5.13.0@aar" - androidTestImplementation "net.java.dev.jna:jna:5.13.0@aar" - - androidTestImplementation "androidx.test:runner:1.4.0" - androidTestImplementation "androidx.test:rules:1.4.0" - androidTestImplementation "junit:junit:4.13.2" - - testImplementation "junit:junit:4.13.2" - testImplementation "net.java.dev.jna:jna:5.13.0" -} - -cargo { - module = "../../../wp_api/" - libname = "wp_api" - profile = "release" - targets = ["arm", "arm64", "x86", "x86_64", getNativeRustTarget()] - targetDirectory = '../../../target' - - exec { spec, toolchain -> - // https://doc.rust-lang.org/rustc/command-line-arguments.html#-g-include-debug-information - spec.environment("RUSTFLAGS", "-g") - } -} - -project.afterEvaluate { - publishing { - publications { - MavenPublication(MavenPublication) { - from components.release - - groupId "org.wordpress" - artifactId "rs" - // version is set by 'publish-to-s3' plugin - } - } - } -} - -tasks.matching { it.name.matches(/merge.*JniLibFolders/) }.configureEach { - it.inputs.dir(new File(buildDir, "rustJniLibs/android")) - it.dependsOn("cargoBuild") -} - -tasks.matching { it.name.matches("test") }.configureEach { - it.dependsOn("cargoBuild") -} - -ext.configureUniFFIBindgen("../../../wp_api/src/wp_api.udl") - -def getNativeRustTarget() { - // This seems to return 'darwin' for both Apple Silicon and Intel architectures - // We don't use Intel macs anymore, so we should default to 'darwin-aarch64' - switch (com.sun.jna.Platform.RESOURCE_PREFIX) { - case 'darwin': - case 'darwin-aarch64': - return 'darwin-aarch64' - case 'darwin-x86-64': - return 'darwin-x86-64' - case 'linux-x86-64': - return 'linux-x86-64' - case 'win32-x86-64': - return 'win32-x86-64-gnu' - } -} diff --git a/native/android/lib/src/androidTest/kotlin/wordpress/rs/LibraryTest.kt b/native/android/lib/src/androidTest/kotlin/wordpress/rs/LibraryTest.kt deleted file mode 100644 index 458b8e6ad..000000000 --- a/native/android/lib/src/androidTest/kotlin/wordpress/rs/LibraryTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package wordpress.rs - -import org.junit.Assert.assertEquals -import org.junit.Before -import org.junit.Test - -class LibraryTest { - @Before - fun setup() { - } - - @Test - fun testAddCustom() { - assertEquals(Library().addCustomFromRust(2, 4), 6) - } - - @Test - fun testCombineStrings() { - assertEquals(Library().combineStringsFromRust("this", "that"), "this-that") - } -} diff --git a/native/android/lib/src/main/kotlin/wordpress/rs/Library.kt b/native/android/lib/src/main/kotlin/wordpress/rs/Library.kt deleted file mode 100644 index f01bff11e..000000000 --- a/native/android/lib/src/main/kotlin/wordpress/rs/Library.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package wordpress.rs - -import uniffi.wordpress_api.addCustom -import uniffi.wordpress_api.combineStrings -import uniffi.wordpress_api.panicFromRust - -class Library { - fun addCustomFromRust(a: Int, b: Int): Int { - return addCustom(a, b) - } - - fun combineStringsFromRust(a: String, b: String): String { - return combineStrings(a, b) - } - - fun crashFromRust() { - return panicFromRust(); - } -} diff --git a/native/android/lib/src/test/kotlin/wordpress/rs/LibraryTest.kt b/native/android/lib/src/test/kotlin/wordpress/rs/LibraryTest.kt deleted file mode 100644 index 2fe1dd1ac..000000000 --- a/native/android/lib/src/test/kotlin/wordpress/rs/LibraryTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package wordpress.rs - -import org.junit.Assert.assertEquals -import org.junit.Before -import org.junit.Test - -class LibraryTest { - @Before - fun setup() { - } - - @Test - fun testAddCustom() { - assertEquals(Library().addCustomFromRust(2, 4), 6) - } - - @Test(expected = uniffi.wordpress_api.InternalException::class) - fun testCrashFromRust() { - Library().crashFromRust() - } -} diff --git a/native/android/lib/uniffi.gradle b/native/android/lib/uniffi.gradle deleted file mode 100644 index 50903777c..000000000 --- a/native/android/lib/uniffi.gradle +++ /dev/null @@ -1,23 +0,0 @@ -// Adopted from https://github.com/mozilla/application-services/blob/v120.0.1/publish.gradle#L206-L226 -// -// A convenience function for configuring a `uniffi-bindgen` task, -// with appropriate dependency info. This fill call `uniffi-bindgen` -// on the provided `.udl` file in order to generate Kotlin language -// bindings and include them in the source set for the project. -ext.configureUniFFIBindgen = { udlFilePath -> - android.libraryVariants.all { variant -> - def uniffiGeneratedPath = "generated/source/uniffi/${variant.name}/java" - def t = tasks.register("generate${variant.name.capitalize()}UniFFIBindings", Exec) { - workingDir project.rootDir - commandLine 'cargo', 'run', '--release', '--bin', 'uniffi_bindgen', 'generate', "${project.projectDir}/${udlFilePath}", '--out-dir', "${buildDir}/${uniffiGeneratedPath}", '--language', 'kotlin' - outputs.dir "${buildDir}/${uniffiGeneratedPath}" - // Re-generate if the interface definition changes. - inputs.file "${project.projectDir}/${udlFilePath}" - // Re-generate if our uniffi-bindgen tooling changes. - inputs.dir "${project.rootDir}/../../uniffi_bindgen/" - // Re-generate if our uniffi-bindgen version changes. - inputs.file "${project.rootDir}/../../Cargo.lock" - } - variant.registerJavaGeneratingTask(t.get(), new File(buildDir, uniffiGeneratedPath)) - } -} diff --git a/native/android/settings.gradle b/native/android/settings.gradle index 074edc917..830105c30 100644 --- a/native/android/settings.gradle +++ b/native/android/settings.gradle @@ -22,4 +22,4 @@ plugins { } rootProject.name = "wordpress-rs" -include("lib") +include("wp_api") diff --git a/native/android/wp_api/build.gradle b/native/android/wp_api/build.gradle new file mode 100644 index 000000000..30e6d1704 --- /dev/null +++ b/native/android/wp_api/build.gradle @@ -0,0 +1,73 @@ +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + id("org.mozilla.rust-android-gradle.rust-android") + id("com.automattic.android.publish-to-s3") +} + +apply from: '../common.gradle' + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +android { + namespace = "rs.wordpress.wp_api" + + compileSdk = 33 + + defaultConfig { + minSdk = 24 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + + ndk { + debugSymbolLevel 'FULL' + } + } + + sourceSets { + androidTest.jniLibs.srcDirs += "$buildDir/rustJniLibs/android" + } + + packagingOptions { + doNotStrip "**/*.so" + } +} + +repositories { + mavenCentral() + google() +} + +dependencies { + implementation("com.squareup.okhttp3:okhttp:4.12.0") + + androidTestImplementation "androidx.test:runner:1.4.0" + androidTestImplementation "androidx.test:rules:1.4.0" + androidTestImplementation "junit:junit:4.13.2" + androidTestImplementation 'org.jetbrains.kotlin:kotlin-test' + + testImplementation "junit:junit:4.13.2" +} + +ext.setupCargo("wp_api", ext.getNativeRustTarget(com.sun.jna.Platform.RESOURCE_PREFIX)) +ext.configureUniFFIBindgen("wp_api") +ext.addJnaDependencies() + +project.afterEvaluate { + publishing { + publications { + MavenPublication(MavenPublication) { + from components.release + + groupId "rs.wordpress" + artifactId "wp_api" + // version is set by 'publish-to-s3' plugin + } + } + } +} + diff --git a/native/android/wp_api/src/androidTest/kotlin/rs/wordpress/wp_api/LibraryTest.kt b/native/android/wp_api/src/androidTest/kotlin/rs/wordpress/wp_api/LibraryTest.kt new file mode 100644 index 000000000..7bac8a6cb --- /dev/null +++ b/native/android/wp_api/src/androidTest/kotlin/rs/wordpress/wp_api/LibraryTest.kt @@ -0,0 +1,46 @@ +/* + * This Kotlin source file was generated by the Gradle 'init' task. + */ +package rs.wordpress.wp_api + +import org.junit.Before +import org.junit.Test +import uniffi.wp_api.PostObject +import uniffi.wp_api.RequestMethod +import uniffi.wp_api.WpApiException +import uniffi.wp_api.WpAuthentication +import kotlin.test.assertFailsWith + +class LibraryTest { + private val siteUrl = "_omitted_" + private val authentication = WpAuthentication(authToken = "_omitted_") + private val library = Library(siteUrl, authentication) + + @Before + fun setup() { + } + + @Test + fun testBasicPostListRequest() { + val request = library.postListRequest() + assert(request.method == RequestMethod.GET) + assert(request.url == "$siteUrl/wp-json/wp/v2/posts?context=edit") + } + + @Test + fun testMakeBasicPostListRequest() { + val postListResponse = library.makePostListRequest() + val firstPost: PostObject = postListResponse.postList!!.first() + assert(firstPost.title?.raw == "Hello world!") + } + + @Test + fun testBasicAuthenticationError() { + val unauthenticatedLibrary = Library(siteUrl, WpAuthentication("invalid_token")) + val exception = assertFailsWith { + unauthenticatedLibrary.makePostListRequest() + } + val expectedStatusCode: UShort = 401u + assert(exception.statusCode == expectedStatusCode) + } +} diff --git a/native/android/wp_api/src/main/AndroidManifest.xml b/native/android/wp_api/src/main/AndroidManifest.xml new file mode 100644 index 000000000..f145d83b0 --- /dev/null +++ b/native/android/wp_api/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + diff --git a/native/android/wp_api/src/main/kotlin/rs/wordpress/wp_api/Library.kt b/native/android/wp_api/src/main/kotlin/rs/wordpress/wp_api/Library.kt new file mode 100644 index 000000000..41c219051 --- /dev/null +++ b/native/android/wp_api/src/main/kotlin/rs/wordpress/wp_api/Library.kt @@ -0,0 +1,37 @@ +/* + * This Kotlin source file was generated by the Gradle 'init' task. + */ +package rs.wordpress.wp_api + +import okhttp3.OkHttpClient +import okhttp3.Request +import uniffi.wp_api.PostListResponse +import uniffi.wp_api.WpApiHelper +import uniffi.wp_api.WpAuthentication +import uniffi.wp_api.WpNetworkRequest +import uniffi.wp_api.WpNetworkResponse +import uniffi.wp_api.parsePostListResponse + +class Library(siteUrl: String, authentication: WpAuthentication) { + private val wpApiHelper = WpApiHelper(siteUrl, authentication) + private val client = OkHttpClient() + + fun postListRequest(): WpNetworkRequest = wpApiHelper.postListRequest() + + fun makePostListRequest(): PostListResponse { + val wpNetworkRequest = postListRequest() + return parsePostListResponse(request(wpNetworkRequest)) + } + + private fun request(wpNetworkRequest: WpNetworkRequest): WpNetworkResponse { + val requestBuilder = Request.Builder() + .url(wpNetworkRequest.url) + wpNetworkRequest.headerMap?.forEach { (key, value) -> + requestBuilder.header(key, value) + } + + client.newCall(requestBuilder.build()).execute().use { response -> + return WpNetworkResponse(response.body!!.bytes(), response.code.toUShort()) + } + } +} diff --git a/native/android/wp_api/src/test/kotlin/rs/wordpress/wp_api/LibraryTest.kt b/native/android/wp_api/src/test/kotlin/rs/wordpress/wp_api/LibraryTest.kt new file mode 100644 index 000000000..09942ceed --- /dev/null +++ b/native/android/wp_api/src/test/kotlin/rs/wordpress/wp_api/LibraryTest.kt @@ -0,0 +1,12 @@ +/* + * This Kotlin source file was generated by the Gradle 'init' task. + */ +package rs.wordpress.wp_api + +import org.junit.Before + +class LibraryTest { + @Before + fun setup() { + } +} diff --git a/wp_api/Cargo.toml b/wp_api/Cargo.toml index b7499a463..239e36345 100644 --- a/wp_api/Cargo.toml +++ b/wp_api/Cargo.toml @@ -10,6 +10,7 @@ name = "wp_api" [dependencies] http = { workspace = true } serde = { version = "1.0", features = [ "derive" ] } +serde_json = "1.0" thiserror = "1.0" uniffi = { workspace = true } diff --git a/wp_api/src/lib.rs b/wp_api/src/lib.rs index 7810eb738..4fefa6714 100644 --- a/wp_api/src/lib.rs +++ b/wp_api/src/lib.rs @@ -1,6 +1,6 @@ #![allow(dead_code, unused_variables)] -use std::{collections::HashMap, sync::Arc}; +use std::collections::HashMap; pub use api_error::*; pub use pages::*; @@ -10,50 +10,46 @@ pub mod api_error; pub mod pages; pub mod posts; -pub trait WPNetworkingInterface: Send + Sync { - fn request(&self, request: WPNetworkRequest) -> WPNetworkResponse; +pub struct WPApiHelper { + site_url: String, + authentication: WPAuthentication, } -pub enum RequestMethod { - GET, - POST, - PUT, - DELETE, -} - -pub trait NetworkResponseStatus: Send + Sync { - fn as_u16(&self) -> u16; - fn is_informational(&self) -> bool; - fn is_success(&self) -> bool; - fn is_redirection(&self) -> bool; - fn is_client_error(&self) -> bool; - fn is_server_error(&self) -> bool; -} - -impl NetworkResponseStatus for http::StatusCode { - fn as_u16(&self) -> u16 { - self.as_u16() +impl WPApiHelper { + pub fn new(site_url: String, authentication: WPAuthentication) -> Self { + Self { + site_url, + authentication, + } } - fn is_informational(&self) -> bool { - self.is_informational() - } - - fn is_success(&self) -> bool { - self.is_success() - } - - fn is_redirection(&self) -> bool { - self.is_redirection() + pub fn post_list_request(&self) -> WPNetworkRequest { + let url = format!("{}/wp-json/wp/v2/posts?context=edit", self.site_url); + + let mut header_map = HashMap::new(); + header_map.insert( + "Authorization".into(), + format!("Basic {}", self.authentication.auth_token).into(), + ); + WPNetworkRequest { + method: RequestMethod::GET, + url, + header_map: Some(header_map), + } } +} - fn is_client_error(&self) -> bool { - self.is_client_error() - } +#[derive(Debug, Clone)] +// TODO: This will probably become an `enum` where we support multiple authentication types. +pub struct WPAuthentication { + pub auth_token: String, +} - fn is_server_error(&self) -> bool { - self.is_informational() - } +pub enum RequestMethod { + GET, + POST, + PUT, + DELETE, } pub struct WPNetworkRequest { @@ -68,30 +64,36 @@ pub struct WPNetworkRequest { } pub struct WPNetworkResponse { - pub status: Arc, + pub status_code: u16, pub body: Vec, } -#[derive(Debug, Clone)] -// TODO: This will probably become an `enum` where we support multiple authentication types. -pub struct WPAuthentication { - pub auth_token: String, -} - -pub trait WPApiInterface: Send + Sync { - fn list_posts(&self, params: Option) -> Result; - fn create_post(&self, params: Option) -> PostCreateResponse; - fn retrieve_post( - &self, - post_id: u32, - params: Option, - ) -> PostRetrieveResponse; - - fn update_post(&self, post_id: u32, params: Option) -> PostUpdateResponse; - - fn delete_post(&self, post_id: u32, params: Option) -> PostDeleteResponse; - - fn list_pages(&self, params: Option) -> PageListResponse; +pub fn parse_post_list_response( + response: WPNetworkResponse, +) -> Result { + // TODO: Further parse the response body to include error message + // TODO: Lots of unwraps to get a basic setup working + if let Some(client_error_type) = ClientErrorType::from_status_code(response.status_code) { + return Err(WPApiError::ClientError { + error_type: client_error_type, + status_code: response.status_code, + }); + } + let status = http::StatusCode::from_u16(response.status_code).unwrap(); + if status.is_server_error() { + return Err(WPApiError::ServerError { + status_code: response.status_code, + }); + } + let post_list: Vec = serde_json::from_slice(&response.body).or_else(|err| { + Err(WPApiError::ParsingError { + reason: err.to_string(), + response: std::str::from_utf8(&response.body).unwrap().to_string(), + }) + })?; + Ok(PostListResponse { + post_list: Some(post_list), + }) } uniffi::include_scaffolding!("wp_api"); diff --git a/wp_api/src/wp_api.udl b/wp_api/src/wp_api.udl index e3eb5bb0a..b7e181a4b 100644 --- a/wp_api/src/wp_api.udl +++ b/wp_api/src/wp_api.udl @@ -1,7 +1,8 @@ namespace wp_api { + [Throws=WPApiError] + PostListResponse parse_post_list_response(WPNetworkResponse response); }; - enum ClientErrorType { "BadRequest", "Unauthorized", @@ -17,33 +18,10 @@ interface WPApiError { UnknownError(); }; -[Trait] -interface WPNetworkingInterface { - WPNetworkResponse request(WPNetworkRequest request); -}; - dictionary WPAuthentication { string auth_token; }; -// https://developer.wordpress.org/rest-api/reference/posts/ -// TODO: The schema and some of the action arguments for `/posts` endpoint has the notion of `context`. -// This is an `enum` value, but it can only contain partial values per field. -// This is an important design element to get right, because it's a common pattern for the API. -// -// IMPORTANT: This design does not include error handling yet! -[Trait] -interface WPApiInterface { - [Throws=WPApiError] - PostListResponse list_posts(PostListParams? params); - PostCreateResponse create_post(PostCreateParams? params); - PostRetrieveResponse retrieve_post(u32 post_id, PostRetrieveParams? params); - PostUpdateResponse update_post(u32 post_id, PostUpdateParams? params); - PostDeleteResponse delete_post(u32 post_id, PostDeleteParams? params); - - PageListResponse list_pages(PageListParams? params); -}; - enum RequestMethod { "GET", "POST", @@ -51,25 +29,20 @@ enum RequestMethod { "DELETE" }; +interface WPApiHelper { + constructor(string url, WPAuthentication authentication); + WPNetworkRequest post_list_request(); +}; + dictionary WPNetworkRequest { RequestMethod method; string url; record? header_map; }; -[Trait] -interface NetworkResponseStatus { - u16 as_u16(); - boolean is_informational(); - boolean is_success(); - boolean is_redirection(); - boolean is_client_error(); - boolean is_server_error(); -}; - dictionary WPNetworkResponse { bytes body; - NetworkResponseStatus status; + u16 status_code; }; dictionary PostListResponse { diff --git a/wp_cli/src/main.rs b/wp_cli/src/main.rs index e5f9c0ab5..4ac30d3ee 100644 --- a/wp_cli/src/main.rs +++ b/wp_cli/src/main.rs @@ -1,6 +1,7 @@ use std::fs::read_to_string; use wp_api::WPAuthentication; +use wp_networking::WPNetworking; fn main() { // A very naive approach just to get things working for now - this whole code will be deleted @@ -14,26 +15,7 @@ fn main() { auth_token: auth_base64_token.into(), }; - let post_list = wp_networking::wp_api(url.into(), authentication.clone()) - .list_posts(None) - .unwrap(); + let wp_networking = WPNetworking::new(url.into(), authentication); + let post_list = wp_networking.list_posts(None).unwrap(); println!("{:?}", post_list); - - // let post_list_with_custom_networking = wp_networking::wp_api_with_custom_networking( - // mock_authentication.clone(), - // Arc::new(CustomWPNetworking {}), - // ) - // .list_posts(None); - // println!( - // "Post List with custom networking: {:?}", - // post_list_with_custom_networking - // ); } - -// struct CustomWPNetworking {} -// -// impl WPNetworkingInterface for CustomWPNetworking { -// fn request(&self, _request: WPNetworkRequest) -> WPNetworkResponse { -// todo!() -// } -// } diff --git a/wp_networking/Cargo.toml b/wp_networking/Cargo.toml index 8beb4aaf7..0f44c93d6 100644 --- a/wp_networking/Cargo.toml +++ b/wp_networking/Cargo.toml @@ -3,16 +3,7 @@ name = "wp_networking" version = "0.1.0" edition = "2021" -[lib] -crate-type = ["lib", "cdylib", "staticlib"] -name = "wp_networking" - [dependencies] http = { workspace = true } -reqwest = { version = "0.11.22", features = ["blocking", "json"] } -serde_json = "1.0" -uniffi = { workspace = true } +reqwest = { version = "0.11.22", features = ["blocking"] } wp_api = { path = "../wp_api" } - -[build-dependencies] -uniffi = { workspace = true , features = [ "build", "cli" ] } diff --git a/wp_networking/build.rs b/wp_networking/build.rs deleted file mode 100644 index d065ab5d6..000000000 --- a/wp_networking/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - uniffi::generate_scaffolding("src/wp_networking.udl").unwrap(); -} diff --git a/wp_networking/src/lib.rs b/wp_networking/src/lib.rs index 45e5c58e2..fc88b8517 100644 --- a/wp_networking/src/lib.rs +++ b/wp_networking/src/lib.rs @@ -1,176 +1,52 @@ #![allow(dead_code, unused_variables)] -use std::{collections::HashMap, sync::Arc}; -use reqwest::{blocking::Client, header::HeaderMap}; +use http::HeaderMap; +use reqwest::blocking::Client; use wp_api::{ - ClientErrorType, PageListParams, PageListResponse, PostCreateParams, PostCreateResponse, - PostDeleteParams, PostDeleteResponse, PostListParams, PostListResponse, PostObject, - PostRetrieveParams, PostRetrieveResponse, PostUpdateParams, PostUpdateResponse, WPApiError, - WPApiInterface, WPAuthentication, WPNetworkRequest, WPNetworkResponse, WPNetworkingInterface, + PostListParams, PostListResponse, WPApiError, WPApiHelper, WPAuthentication, WPNetworkResponse, }; -pub fn add_custom(left: i32, right: i32) -> i32 { - left + right -} - -pub fn combine_strings(a: String, b: String) -> String { - format!("{}-{}", a, b) -} - -pub fn panic_from_rust() { - std::fs::read_to_string("doesnt_exist.txt").unwrap(); -} - -pub fn wp_api(site_url: String, authentication: WPAuthentication) -> Arc { - Arc::new(WPApi { - site_url, - authentication, - networking_interface: Arc::new(WPNetworking::default()), - }) -} - -pub fn wp_api_with_custom_networking( - site_url: String, - authentication: WPAuthentication, - networking_interface: Arc, -) -> Arc { - Arc::new(WPApi { - site_url, - authentication, - networking_interface, - }) -} - -struct WPNetworking { +pub struct WPNetworking { client: Client, + helper: WPApiHelper, } -impl Default for WPNetworking { - fn default() -> Self { +impl WPNetworking { + pub fn new(site_url: String, authentication: WPAuthentication) -> Self { Self { - client: Client::new(), + client: reqwest::blocking::Client::new(), + helper: WPApiHelper::new(site_url, authentication), } } -} - -impl WPNetworkingInterface for WPNetworking { - fn request(&self, request: WPNetworkRequest) -> wp_api::WPNetworkResponse { - let method = match request.method { - wp_api::RequestMethod::GET => reqwest::Method::GET, - wp_api::RequestMethod::POST => reqwest::Method::POST, - wp_api::RequestMethod::PUT => reqwest::Method::PUT, - wp_api::RequestMethod::DELETE => reqwest::Method::DELETE, - }; - - let request_headers: HeaderMap = (&request.header_map.unwrap()).try_into().unwrap(); - // TODO: Error handling + pub fn list_posts( + &self, + params: Option, + ) -> Result { + let wp_request = self.helper.post_list_request(); + let request_headers: HeaderMap = (&wp_request.header_map.unwrap()).try_into().unwrap(); let response = self .client - .request(method, request.url) + .request(request_method(wp_request.method), wp_request.url) .headers(request_headers) .send() .unwrap(); - WPNetworkResponse { - status: Arc::new(response.status()), - body: response.text().unwrap().as_bytes().to_vec(), - } + wp_api::parse_post_list_response(wp_network_response(response)) } } -struct WPApi { - site_url: String, - authentication: WPAuthentication, - networking_interface: Arc, -} - -impl WPApiInterface for WPApi { - fn list_posts(&self, params: Option) -> Result { - let mut header_map = HashMap::new(); - // TODO: Authorization headers should be generated through its type not like a cave man - header_map.insert( - "Authorization".into(), - format!("Basic {}", self.authentication.auth_token).into(), - ); - - let response = self.networking_interface.request(WPNetworkRequest { - method: wp_api::RequestMethod::GET, - // TODO: Centralize the endpoints - url: format!("{}/wp-json/wp/v2/posts?context=edit", self.site_url).into(), - header_map: Some(header_map), - }); - parse_list_posts_response(&response) - } - - fn create_post(&self, params: Option) -> PostCreateResponse { - todo!() - } - - fn retrieve_post( - &self, - post_id: u32, - params: Option, - ) -> PostRetrieveResponse { - todo!() - } - - fn update_post(&self, post_id: u32, params: Option) -> PostUpdateResponse { - todo!() - } - - fn delete_post(&self, post_id: u32, params: Option) -> PostDeleteResponse { - todo!() - } - - fn list_pages(&self, params: Option) -> PageListResponse { - todo!() +fn request_method(method: wp_api::RequestMethod) -> http::Method { + match method { + wp_api::RequestMethod::GET => reqwest::Method::GET, + wp_api::RequestMethod::POST => reqwest::Method::POST, + wp_api::RequestMethod::PUT => reqwest::Method::PUT, + wp_api::RequestMethod::DELETE => reqwest::Method::DELETE, } } -fn parse_list_posts_response(response: &WPNetworkResponse) -> Result { - let status_code = response.status.as_u16(); - // TODO: Further parse the response body to include error message - if let Some(client_error_type) = ClientErrorType::from_status_code(status_code) { - return Err(WPApiError::ClientError { - error_type: client_error_type, - status_code, - }); - } - if response.status.is_server_error() { - return Err(WPApiError::ServerError { status_code }); +fn wp_network_response(response: reqwest::blocking::Response) -> WPNetworkResponse { + WPNetworkResponse { + status_code: response.status().as_u16(), + body: response.bytes().unwrap().to_vec(), } - let post_list: Vec = serde_json::from_slice(&response.body).or_else(|err| { - Err(WPApiError::ParsingError { - reason: err.to_string(), - response: std::str::from_utf8(&response.body).unwrap().to_string(), - }) - })?; - Ok(PostListResponse { - post_list: Some(post_list), - }) } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add_custom(2, 2); - assert_eq!(result, 4); - } - - #[test] - fn test_combine_strings() { - let result = combine_strings("this".into(), "that".into()); - assert_eq!(result, "this-that"); - } - - #[test] - #[should_panic] - fn test_panic_from_rust() { - panic_from_rust() - } -} - -uniffi::include_scaffolding!("wp_networking"); diff --git a/wp_networking/src/wp_networking.udl b/wp_networking/src/wp_networking.udl deleted file mode 100644 index 673b52e88..000000000 --- a/wp_networking/src/wp_networking.udl +++ /dev/null @@ -1,21 +0,0 @@ -[ExternalTrait="wp_api"] -typedef extern WPApiInterface; - -[ExternalTrait="wp_api"] -typedef extern WPNetworkingInterface; - -[External="wp_api"] -typedef extern WPAuthentication; - -// These are test functions that we are keeping while we figure out the design in case -// we need them for further testing. -namespace wp_networking { - i32 add_custom(i32 a, i32 b); - string combine_strings(string a, string b); - void panic_from_rust(); - - // TODO: We should have a type for the `site_url`, but it's not yet clear what that type should - // look like or what it should contain, so we are using a placeholder string type for now. - WPApiInterface wp_api(string site_url, WPAuthentication authentication); - WPApiInterface wp_api_with_custom_networking(string site_url, WPAuthentication authentication, WPNetworkingInterface networking_interface); -};