[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
+13 -2
View File
@@ -28,8 +28,10 @@ type FileDrop struct {
listener FileDropListener
}
// NewFileDrop opens the file drop state of the given profile.
func NewFileDrop(configDir, profileID string) (*FileDrop, error) {
// NewFileDrop opens the file drop state of the given profile. A nil sink leaves
// payloads staged and delivered on the filesystem, under the destination
// directory the policy names.
func NewFileDrop(configDir, profileID string, sink FileDropSink) (*FileDrop, error) {
if configDir == "" || profileID == "" {
return nil, errors.New("file drop requires a config dir and profile ID")
}
@@ -39,12 +41,21 @@ func NewFileDrop(configDir, profileID string) (*FileDrop, error) {
return nil, err
}
var platformSink filedrop.Sink
if sink != nil {
platformSink, err = filedrop.NewPlatformSink(newPlatformSinkAdapter(sink))
if err != nil {
return nil, fmt.Errorf("wrap file drop sink: %w", err)
}
}
fd := &FileDrop{configDir: configDir, profileID: profileID}
manager, err := filedrop.NewManager(filedrop.ManagerConfig{
Profile: profilemanager.ID(profileID),
DataDir: filepath.Join(configDir, filedropDataSubdir, profileID),
Store: filedrop.NewProfileStore(prefs.prefs),
Events: fd.publish,
Sink: platformSink,
})
if err != nil {
return nil, fmt.Errorf("create file drop manager: %w", err)