Skip to content

Commit

Permalink
Completes the conversion of the Convert Request/Response to Proto
Browse files Browse the repository at this point in the history
  • Loading branch information
timothyfroehlich committed Jan 10, 2025
1 parent 9f23207 commit 0ceca74
Show file tree
Hide file tree
Showing 47 changed files with 160 additions and 439 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ jobs:
- name: Build all
run: cargo build --all-targets --all-features
- name: Test all
run: cargo test --all-targets --features=reflection,fetch,dcf_info
run: cargo test --all-targets --features=fetch,dcf_info
############ Figma resources
figma-resources:
runs-on: ubuntu-latest
Expand Down
70 changes: 0 additions & 70 deletions common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/

import com.google.protobuf.gradle.id
import org.gradle.process.internal.DefaultExecOperations

plugins {
id("java-library")
Expand Down Expand Up @@ -49,75 +48,6 @@ sourceSets {
}
}

/**
* Serde gen task
*
* Generates the Java files from our Rust code
*
* @property executor: ExecOperations class
* @property rustSrcs The files to watch to see if we should rebuild (should be filtered to not
* include the target dir
* @property generatedCodeDir Where the generated code will be output
* @constructor Create empty Serde gen task
*/
@CacheableTask
abstract class SerdeGenTask @Inject constructor(private val executor: DefaultExecOperations) :
DefaultTask() {

@get:PathSensitive(PathSensitivity.RELATIVE)
@get:InputFiles
abstract val rustSrcs: ConfigurableFileCollection

@get:OutputDirectory abstract val generatedCodeDir: DirectoryProperty

@get:Internal abstract val cargoTargetDir: DirectoryProperty

init {
group = "DesignCompose Developer"
}

@TaskAction
fun run() {
generatedCodeDir.get().asFileTree.forEach { it.delete() }
executor.exec {
val localBinCargo =
project.providers
.systemProperty("user.home")
.map { File(it, ".cargo/bin/cargo") }
.get()
executable = if (localBinCargo.exists()) localBinCargo.absolutePath else "cargo"

environment("CARGO_TARGET_DIR", cargoTargetDir.get().toString())
workingDir(rustSrcs.asPath)
args(
listOf(
"run",
"-q",
"--release",
"--features=reflection",
"--bin=reflection",
"--",
"--out-dir",
generatedCodeDir.get().toString(),
)
)
}
}
}

// Configure the task, setting the locations of the source and outputs
val serdeGenTask =
tasks.register<SerdeGenTask>("generateSerdegenCode") {
rustSrcs.from(
layout.projectDirectory.files("../crates/figma_import").filterNot { name == "target" }
)
generatedCodeDir.set(layout.buildDirectory.dir("generated/serdegen/java"))
cargoTargetDir.set(layout.buildDirectory.dir("serdeGenCargoTarget"))
}

// Connect the outputs to the java source set, so it'll automatically be compiled
project.sourceSets.main { java { srcDir(serdeGenTask.flatMap { it.generatedCodeDir }) } }

// Protobuf configuration
project.sourceSets.main { proto { srcDir(rootProject.layout.projectDirectory.dir("proto")) } }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,7 @@

package com.android.designcompose.common

class DocumentServerParams(
private val nodeQueries: ArrayList<String>? = null,
private val ignoredImages: HashMap<String, Array<String>>? = null,
) {
fun toJsonSnippet(): String {
val queriesStr = nodeQueries?.joinToString(",") { "\"$it\"" } ?: ""
val ignoredImagesStr =
ignoredImages?.keys?.joinToString(",") { node ->
val images = ignoredImages[node]?.joinToString(",") { "\"$it\"" }
"{ \"node\": \"$node\", \"images\": [$images] }"
} ?: ""

var jsonStr = "\"ignored_images\": [$ignoredImagesStr], "
jsonStr += "\"queries\": [$queriesStr]"
return jsonStr
}
}
data class DocumentServerParams(
val nodeQueries: ArrayList<String>? = null,
val ignoredImages: HashMap<String, Array<String>>? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ package com.android.designcompose.common
import com.android.designcompose.definition.DesignComposeDefinition
import com.android.designcompose.definition.DesignComposeDefinitionHeader
import com.android.designcompose.definition.view.View
import com.android.designcompose.live_update.ConvertResponse
import com.android.designcompose.live_update.figma.FigmaDocInfo
import com.android.designcompose.live_update.figma.ServerFigmaDoc
import com.google.protobuf.ByteString
import com.google.protobuf.kotlin.toByteString
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
Expand All @@ -33,8 +35,7 @@ class GenericDocContent(
val variantViewMap: HashMap<String, HashMap<String, View>>,
val variantPropertyMap: VariantPropertyMap,
val nodeIdMap: HashMap<String, View>,
private val imageSessionData: ByteArray,
val imageSession: String?,
val imageSession: ByteString,
val branches: List<FigmaDocInfo>? = null,
val project_files: List<FigmaDocInfo>? = null,
) {
Expand All @@ -57,7 +58,7 @@ class GenericDocContent(
val outputStream = ByteArrayOutputStream()
header.writeDelimitedTo(outputStream)
document.writeDelimitedTo(outputStream)
outputStream.write(imageSessionData)
outputStream.write(imageSession.toByteArray())
return outputStream.toByteArray()
} catch (error: Throwable) {
feedback.documentSaveError(error.toString(), docId)
Expand All @@ -68,19 +69,19 @@ class GenericDocContent(

/// Read a serialized server document from the given stream. Deserialize it and save it to disk.
fun decodeServerBaseDoc(
docBytes: ByteArray,
docResponse: ConvertResponse.Document,
docId: DesignDocId,
feedback: FeedbackImpl,
): GenericDocContent? {
val docStream = docBytes.inputStream()
val header = decodeHeader(docStream, docId, feedback) ?: return null

val header = docResponse.header
feedback.documentDecodeSuccess(header.dcVersion, header.name, header.lastModified, docId)

// Server sends content in the format of ServerFigmaDoc, which has additional data
val serverDoc = ServerFigmaDoc.parseDelimitedFrom(docStream)
// val serverDoc = ServerFigmaDoc.parseDelimitedFrom(docStream)
val serverDoc = docResponse.serverDoc
serverDoc.errorsList?.forEach { feedback.documentUpdateWarnings(docId, it) }
val content = serverDoc.figmaDoc
val imageSessionData = decodeImageSession(docStream)
feedback.documentDecodeSuccess(header.dcVersion, header.name, header.lastModified, docId)

val viewMap = content.views()
val variantViewMap = createVariantViewMap(viewMap)
Expand All @@ -93,8 +94,7 @@ fun decodeServerBaseDoc(
variantViewMap,
variantPropertyMap,
nodeIdMap,
imageSessionData.imageSessionData,
imageSessionData.imageSession,
docResponse.imageSessionJson,
serverDoc.branchesList,
serverDoc.projectFilesList,
)
Expand All @@ -111,7 +111,9 @@ fun decodeDiskBaseDoc(
val header = decodeHeader(docStream, docId, feedback) ?: return null
val content = DesignComposeDefinition.parseDelimitedFrom(docStream)

val imageSessionData = decodeImageSession(docStream)
// Proto bytes are parsed to their immutable ByteString representation. It's just a ByteArray
// that's immutable, basically.
val imageSession = docStream.readBytes().toByteString()
val viewMap = content.views()
val variantMap = createVariantViewMap(viewMap)
val variantPropertyMap = createVariantPropertyMap(viewMap)
Expand All @@ -126,8 +128,7 @@ fun decodeDiskBaseDoc(
variantMap,
variantPropertyMap,
nodeIdMap,
imageSessionData.imageSessionData,
imageSessionData.imageSession,
imageSession,
)
}

Expand Down Expand Up @@ -200,35 +201,3 @@ private fun decodeHeader(
}
return header
}

private data class ImageSession(val imageSessionData: ByteArray, var imageSession: String?) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as ImageSession

if (!imageSessionData.contentEquals(other.imageSessionData)) return false
if (imageSession != other.imageSession) return false

return true
}

override fun hashCode(): Int {
var result = imageSessionData.contentHashCode()
result = 31 * result + (imageSession?.hashCode() ?: 0)
return result
}
}

private fun decodeImageSession(docStream: InputStream): ImageSession {
// The image session data is a JSON blob attached after the proto document content.
val imageSessionData = docStream.readBytes()
val imageSession =
if (imageSessionData.isNotEmpty()) {
String(imageSessionData, Charsets.UTF_8)
} else {
null
}
return ImageSession(imageSessionData, imageSession)
}
1 change: 1 addition & 0 deletions crates/dc_jni/src/android_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

include!(concat!(env!("OUT_DIR"), "/designcompose.live_update.rs"));
pub mod convert_request;
4 changes: 2 additions & 2 deletions crates/dc_jni/src/android_interface/convert_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn fetch_doc(
) -> Result<ConvertResponse, Error> {
let image_session: Option<ImageContextSession> = {
match &rq.image_session_json {
Some(json) => match serde_json::from_str(json.as_str()) {
Some(json) => match serde_json::from_slice(json) {
Ok(session) => Some(session),
Err(_) => None,
},
Expand Down Expand Up @@ -85,7 +85,7 @@ pub fn fetch_doc(
server_doc: Some(server_doc),
// Return the image session as a JSON blob; we might want to encode this differently so we
// can be more robust if there's corruption.
image_session_json: serde_json::to_string(&doc.image_session())?,
image_session_json: serde_json::to_vec(&doc.image_session())?,
},
)),
})
Expand Down
120 changes: 0 additions & 120 deletions crates/dc_jni/src/android_interface/layout_node.rs

This file was deleted.

Loading

0 comments on commit 0ceca74

Please sign in to comment.