mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-24 16:41:30 +02:00
Files move directly between peers over the overlay, with no server in the path. The receiver listens on the WireGuard address only, so the port is unreachable from outside the tunnel, and every offer is matched to a known peer before anything is read. Consent is the default: an offer carries metadata alone, and no payload moves until the receiver accepts. Policy is per profile and device-local — off, ask, or auto-accept, with per-sender exceptions on top. Policy and history live in the profile's preferences, so removing a profile takes its file drop state with it. Transfers interrupted by a restart are settled on load; nothing survives to finish them, and left alone they would sit in the log as permanently pending. The Android bindings pull payload bytes through a chunk-returning stream: gomobile copies a []byte argument into a fresh Java array and never copies it back, so a fill-my-buffer method would hand back the right length with no data.
79 lines
2.2 KiB
Go
79 lines
2.2 KiB
Go
//go:build android
|
|
|
|
package android
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/netbirdio/netbird/client/internal"
|
|
)
|
|
|
|
// FileDrop returns the handle of the active profile, creating it on first use.
|
|
// The UI calls this to list transfers and change settings while disconnected.
|
|
func (c *Client) FileDrop(configDir string) (*FileDrop, error) {
|
|
profile, err := NewProfileManager(configDir).GetActiveProfile()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get active profile: %w", err)
|
|
}
|
|
return c.fileDropFor(configDir, profile.ID)
|
|
}
|
|
|
|
// fileDropFor returns the handle of one profile, replacing the cached one when
|
|
// the profile changed. The listener is carried over so a profile switch does not
|
|
// silence the UI.
|
|
func (c *Client) fileDropFor(configDir, profileID string) (*FileDrop, error) {
|
|
c.fileDropMu.Lock()
|
|
|
|
if c.fileDrop != nil && c.fileDrop.ProfileID() == profileID {
|
|
fd := c.fileDrop
|
|
c.fileDropMu.Unlock()
|
|
return fd, nil
|
|
}
|
|
|
|
fd, err := NewFileDrop(configDir, profileID)
|
|
if err != nil {
|
|
c.fileDropMu.Unlock()
|
|
return nil, err
|
|
}
|
|
ensureFileDropDestination(fd)
|
|
|
|
old := c.fileDrop
|
|
if old != nil {
|
|
fd.SetListener(old.Listener())
|
|
}
|
|
c.fileDrop = fd
|
|
c.fileDropMu.Unlock()
|
|
|
|
// Closing waits out the in-flight uploads of the profile being left, which is
|
|
// far too long to hold the lock every caller of this goes through.
|
|
if old != nil {
|
|
if err := old.Close(); err != nil {
|
|
log.Warnf("failed to close previous file drop manager: %v", err)
|
|
}
|
|
}
|
|
|
|
return fd, nil
|
|
}
|
|
|
|
// attachFileDrop hands the connect client the file drop manager of the profile
|
|
// the engine is starting for. The profile is derived from the config path rather
|
|
// than read from the active profile state, so a switch racing the startup cannot
|
|
// pair one profile's engine with another's transfers. A failure is not fatal:
|
|
// the tunnel is worth more than the feature, so the engine runs on without it.
|
|
func (c *Client) attachFileDrop(cc *internal.ConnectClient, cfgFile string) {
|
|
configDir, profileID, err := profileLocationFor(cfgFile)
|
|
if err != nil {
|
|
log.Warnf("file drop is unavailable: %v", err)
|
|
return
|
|
}
|
|
|
|
fd, err := c.fileDropFor(configDir, profileID)
|
|
if err != nil {
|
|
log.Warnf("file drop is unavailable: %v", err)
|
|
return
|
|
}
|
|
cc.SetFileDropManager(fd.manager)
|
|
}
|