package main import ( "fmt" "net/url" "git.koval.net/cyclane/cctv/server/ingest" "git.koval.net/cyclane/cctv/server/models" "github.com/pocketbase/pocketbase/core" "golang.org/x/sync/errgroup" ) func handleCameraUpdate(e *core.RecordEvent) error { if e.Record.Collection().Name != "cameras" { return e.Next() } camera := &models.Camera{} camera.SetProxyRecord(e.Record) log := e.App.Logger().With("camera", camera.Id) // Encrypt password password := camera.PasswordRaw() log.Info("Old password", "password", password) if err := camera.SetPassword(password, e.App.EncryptionEnv()); err != nil { return fmt.Errorf("failed to encrypt password: %w", err) } log.Info("New password", "password", camera.PasswordRaw()) onvifProfiles, err := ingest.GetOnvifProfiles(e.Context, camera.OnvifHost(), camera.Username(), password) if err != nil { return fmt.Errorf("failed to find onvif profiles: %w", err) } if err := e.Next(); err != nil { return err } streams, err := e.App.FindCollectionByNameOrId("streams") if err != nil { return fmt.Errorf("failed to find streams collection: %w", err) } errGroup := &errgroup.Group{} for _, p := range onvifProfiles { log.Debug("Found ONVIF profile", "name", p.Name, "token", p.Token) errGroup.Go(func() error { log := log.With("profile", p.Token) rawURL := p.URI.String() rtspUrl := p.URI rtspUrl.User = url.UserPassword(camera.Username(), password) stats, err := ingest.GetStreamStats(e.Context, log, rtspUrl, string(p.Token)) if err != nil { return fmt.Errorf("failed to get stream stats for profile %s: %w", p.Token, err) } log.Debug("Retrieved stream stats", "fps", stats.FPS, "width", stats.Width, "height", stats.Height) stream := &models.Stream{} stream.SetProxyRecord(core.NewRecord(streams)) stream.SetCameraID(camera.Id) stream.SetURL(rawURL) stream.SetFPS(stats.FPS) stream.SetWidth(stats.Width) stream.SetHeight(stats.Height) return e.App.Save(stream) }) } return errGroup.Wait() }