feat(stream): persistent stream server with file swapping

This commit is contained in:
Deivid Soto 2026-04-07 19:08:37 +02:00
parent 080fdf4d76
commit 5994a30447
11 changed files with 354 additions and 282 deletions

View file

@ -20,6 +20,9 @@ type DaemonConfig struct {
DownloadDir string
PollInterval time.Duration
HeartbeatInterval time.Duration
StreamPort int // port for the HTTP stream server (reported in heartbeat)
LanIP string // LAN IP (reported in heartbeat for stream URL resolution)
TailscaleIP string // Tailscale IP (reported in heartbeat for stream URL resolution)
}
// Daemon manages the main loop: register, heartbeat, poll tasks.
@ -211,6 +214,9 @@ func (d *Daemon) heartbeat(ctx context.Context) {
Version: d.cfg.Version,
OS: runtime.GOOS,
DownloadDir: d.cfg.DownloadDir,
StreamPort: d.cfg.StreamPort,
LanIP: d.cfg.LanIP,
TailscaleIP: d.cfg.TailscaleIP,
}
if free, total, err := DiskInfo(d.cfg.DownloadDir); err == nil {
req.DiskFreeBytes = free
@ -297,6 +303,12 @@ func (d *Daemon) handleEvent(event ServerEvent) {
}
}
// UpdateStreamPort updates the stream port reported in heartbeats.
// Called after the persistent stream server binds (actual port may differ from configured).
func (d *Daemon) UpdateStreamPort(port int) {
d.cfg.StreamPort = port
}
// TriggerPoll requests an immediate task poll cycle.
// Used when a resume event is received to pick up re-pending tasks faster.
func (d *Daemon) TriggerPoll() {

View file

@ -178,6 +178,7 @@ func (t *WSTransport) SendProgress(_ context.Context, update StatusUpdate) (*Sta
FileName string `json:"fileName,omitempty"`
FilePath string `json:"filePath,omitempty"`
StreamURL string `json:"streamUrl,omitempty"`
StreamReady bool `json:"streamReady,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
}{
Type: "progress",
@ -192,6 +193,7 @@ func (t *WSTransport) SendProgress(_ context.Context, update StatusUpdate) (*Sta
FileName: update.FileName,
FilePath: update.FilePath,
StreamURL: update.StreamURL,
StreamReady: update.StreamReady,
ErrorMessage: update.ErrorMessage,
}

View file

@ -56,6 +56,9 @@ type HeartbeatRequest struct {
DownloadDir string `json:"downloadDir,omitempty"`
DiskFreeBytes int64 `json:"diskFreeBytes,omitempty"`
DiskTotalBytes int64 `json:"diskTotalBytes,omitempty"`
StreamPort int `json:"streamPort,omitempty"`
LanIP string `json:"lanIp,omitempty"`
TailscaleIP string `json:"tailscaleIp,omitempty"`
}
// Task represents a download task claimed from the server.
@ -107,6 +110,7 @@ type StatusUpdate struct {
FileName string `json:"fileName,omitempty"`
FilePath string `json:"filePath,omitempty"`
StreamURL string `json:"streamUrl,omitempty"`
StreamReady bool `json:"streamReady,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
}