[client] Stage incoming file drop payloads through a platform sink

Android cannot address the user's shared storage by path, so a received
file had to land in app-private storage and be copied out afterwards,
needing twice the space of the transfer.

Put the staging area behind a Sink interface the receiver writes every
payload through. The filesystem spool implements it unchanged and stays
the default; a platform that cannot be addressed by path implements the
gomobile-bound half instead and stages payloads wherever it can reach.

The writer reports its own total rather than returning a written count:
gomobile copies a []byte argument into a fresh Java array and carries no
count back out.

A failed delivery now drops the staged payloads. The filesystem spool
swept them up on its next pass, but a sink holding entries the engine
cannot address by path has no such fallback.
This commit is contained in:
Zoltán Papp
2026-08-25 18:45:38 +02:00
parent b165e0126e
commit 861e0d5609
11 changed files with 518 additions and 26 deletions
+10 -2
View File
@@ -61,8 +61,10 @@ func (s *Spool) Received(id OfferID, index int) (int64, error) {
return info.Size(), nil
}
// Write appends the payload at offset, truncating any bytes past it first.
func (s *Spool) Write(id OfferID, index int, offset int64, r io.Reader, limit int64) (int64, error) {
// Write appends the payload at offset, truncating any bytes past it first. The
// announced name plays no part: payloads are staged under their index and only
// take their name in Deliver.
func (s *Spool) Write(id OfferID, index int, _ string, offset int64, r io.Reader, limit int64) (int64, error) {
if offset < 0 {
return 0, fmt.Errorf("negative offset %d", offset)
}
@@ -92,6 +94,12 @@ func (s *Spool) Write(id OfferID, index int, offset int64, r io.Reader, limit in
return offset + written, nil
}
// Deliver moves an offer's staged payloads into destDir under their announced
// names and returns where each one landed.
func (s *Spool) Deliver(offer Offer, destDir string) ([]string, error) {
return deliver(s, offer, destDir)
}
// Path returns the staged path of one item for the platform layer to deliver from.
func (s *Spool) Path(id OfferID, index int) string {
return s.filePath(id, index)