Skip to content

Commit

Permalink
[LEIP-277] Upload attachments without cyf wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
hb0 committed Oct 23, 2024
1 parent d391a01 commit c8afb33
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ import java.nio.file.Files
* Serializes a [Attachment] in the [MeasurementSerializer.TRANSFER_FILE_FORMAT_VERSION].
*
* @author Armin Schnabel
* @version 1.0.0
* @since 7.10.0
*/
class AttachmentSerializer {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ class MeasurementSerializer {
* layer serialized in the [MeasurementSerializer.TRANSFER_FILE_FORMAT_VERSION] format, ready to be
* transferred.
*
* Attention:
* We don't wrap the attachments in the `cyf` wrapper, as:
* - Most our project currently prefer the plain JPG, CSV, ZIP, etc. formats
* - We have a version in meta data, and currently have version 1 for attachment files format.
*
* No compression is used as we're mostly transferring JPG files right now which are pre-compressed.
*
* @param fileOutputStream the `FileInputStream` to write the compressed data to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import de.cyface.persistence.content.AbstractCyfaceTable.Companion.DATABASE_QUER
import de.cyface.persistence.model.Attachment
import de.cyface.persistence.model.Measurement
import de.cyface.protos.model.Event
import de.cyface.protos.model.File.FileType
import de.cyface.protos.model.LocationRecords
import de.cyface.protos.model.MeasurementBytes
import de.cyface.serializer.DataSerializable
Expand All @@ -45,8 +44,6 @@ import java.io.IOException
* Serializes [MeasurementSerializer.TRANSFER_FILE_FORMAT_VERSION] files.
*
* @author Armin Schnabel
* @version 3.1.0
* @since 5.0.0
*/
object TransferFileSerializer {
/**
Expand Down Expand Up @@ -253,13 +250,16 @@ object TransferFileSerializer {
* Implements the core algorithm of loading data of a [Attachment] from the [PersistenceLayer]
* and serializing it into an array of bytes, ready to be transferred.
*
* We use the {@param loader} to access the measurement data. FIXME?
*
* We assemble the data using a buffer to avoid OOM exceptions.
*
* **ATTENTION:** The caller must make sure the {@param bufferedOutputStream} is closed when no longer needed
* or the app crashes.
*
* Attention:
* We don't wrap the attachments in the `cyf` wrapper, as:
* - Most our project currently prefer the plain JPG, CSV, ZIP, etc. formats
* - We have a version in meta data, and currently have version 1 for attachment files format.
*
* @param bufferedOutputStream The `OutputStream` to which the serialized data should be written. Injecting
* this allows us to compress the serialized data without the need to write it into a temporary file.
* We require a [BufferedOutputStream] for performance reasons.
Expand All @@ -274,7 +274,7 @@ object TransferFileSerializer {
) {
val attachment = loadAttachment(reference)

val builder = de.cyface.protos.model.Measurement.newBuilder()
/*val builder = de.cyface.protos.model.Measurement.newBuilder()
.setFormatVersion(MeasurementSerializer.TRANSFER_FILE_FORMAT_VERSION.toInt())
when (reference.type) {
// TODO: zip all attachments
Expand All @@ -289,18 +289,19 @@ object TransferFileSerializer {
else -> {
throw IllegalArgumentException("Unsupported type: ${reference.type}")
}
}
}*/

// Currently loading one image per transfer file into memory (~ 2-5 MB / image).
// - To load add all high-res image data or video data in the future we cannot use the pre-compiled
// builder but have to stream the data without loading it into memory to avoid an OOM exception.
val transferFileHeader = DataSerializable.transferFileHeader()
val measurementBytes = builder.build().toByteArray()
//val uploadBytes = builder.build().toByteArray()
val uploadBytes = attachment.bytes.toByteArray()
try {
// The stream must be closed by the caller in a finally catch
withContext(Dispatchers.IO) {
bufferedOutputStream.write(transferFileHeader)
bufferedOutputStream.write(measurementBytes)
bufferedOutputStream.write(uploadBytes)
bufferedOutputStream.flush()
}
} catch (e: IOException) {
Expand All @@ -310,7 +311,7 @@ object TransferFileSerializer {
TAG, String.format(
"Serialized attachment: %s",
DataSerializable.humanReadableSize(
(transferFileHeader.size + measurementBytes.size).toLong(),
(transferFileHeader.size + uploadBytes.size).toLong(),
true
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import de.cyface.persistence.exception.NoSuchMeasurementException
import de.cyface.persistence.model.AttachmentStatus
import de.cyface.persistence.model.Measurement
import de.cyface.persistence.model.MeasurementStatus
import de.cyface.persistence.model.ParcelableGeoLocation
import de.cyface.persistence.serialization.MeasurementSerializer
import de.cyface.protos.model.File.FileType
import de.cyface.synchronization.ErrorHandler.ErrorCode
Expand Down Expand Up @@ -301,6 +300,7 @@ class SyncAdapter private constructor(

if (isSyncRequestAborted(account, authority)) return

@Suppress("SpellCheckingInspection")
val indexWithinMeasurement = 1 + syncedAttachments + attachmentIndex // ccyf is index 0
val progressListener = DefaultUploadProgressListener(
measurementCount,
Expand All @@ -313,6 +313,7 @@ class SyncAdapter private constructor(
val attachmentMeta = attachmentMeta(measurementMeta, attachment.id)
error = !syncAttachment(
attachmentMeta,
attachment.type,
syncPerformer,
transferTempFile,
syncResult,
Expand Down Expand Up @@ -433,6 +434,7 @@ class SyncAdapter private constructor(

private suspend fun syncAttachment(
attachment: Attachment,
attachmentType: FileType,
syncPerformer: SyncPerformer,
transferFile: File?,
syncResult: SyncResult,
Expand All @@ -456,7 +458,7 @@ class SyncAdapter private constructor(
} else {
val attachmentId = attachment.identifier.attachmentIdentifier
val fileName =
"${attachment.identifier.deviceIdentifier}_${attachment.identifier.measurementIdentifier}_$attachmentId.${TRANSFER_FILE_EXTENSION}"
"${attachment.identifier.deviceIdentifier}_${attachment.identifier.measurementIdentifier}_$attachmentId.${attachmentType.name.lowercase()}"
val result = syncPerformer.sendData(
uploader,
syncResult,
Expand Down Expand Up @@ -745,11 +747,6 @@ class SyncAdapter private constructor(
*/
const val MOCK_IS_CONNECTED_TO_RETURN_TRUE = "mocked_periodic_sync_check_false"

/**
* The file extension of the attachment file which is transmitted on synchronization.
*/
private const val TRANSFER_FILE_EXTENSION = "cyf"

/**
* The file extension of the measurement file which is transmitted on synchronization.
*/
Expand Down

0 comments on commit c8afb33

Please sign in to comment.