From 5f7ca22b8f839e8ad945b1f747425275b3539132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lie=20DELHAIE?= Date: Thu, 11 Sep 2025 17:41:57 +0200 Subject: [PATCH] wip --- cmd/cli/commands/sync/sync.go | 21 ++----- .../tools/prompt/credentials/credentials.go | 11 ++++ cmd/gui/window/mainwindow/mainwindow.go | 59 ++++++++++++++++++- pkg/remote/remote.go | 22 +++++++ pkg/sync/sync.go | 10 ++-- 5 files changed, 100 insertions(+), 23 deletions(-) diff --git a/cmd/cli/commands/sync/sync.go b/cmd/cli/commands/sync/sync.go index b373a1e..1d6b671 100644 --- a/cmd/cli/commands/sync/sync.go +++ b/cmd/cli/commands/sync/sync.go @@ -9,7 +9,6 @@ import ( "cloudsave/pkg/repository" "cloudsave/pkg/sync" "context" - "errors" "flag" "fmt" "os" @@ -38,23 +37,15 @@ func (p *SyncCmd) SetFlags(f *flag.FlagSet) { } func (p *SyncCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { - games, err := p.Service.AllGames() + + remoteCred := make(map[string]map[string]string) + rs, err := remote.All() if err != nil { - fmt.Fprintln(os.Stderr, "error: failed to load datastore:", err) + fmt.Fprintln(os.Stderr, "error: failed to connect to the remote:", err) return subcommands.ExitFailure } - remoteCred := make(map[string]map[string]string) - for _, g := range games { - r, err := remote.One(g.ID) - if err != nil { - if errors.Is(err, remote.ErrNoRemote) { - fmt.Println("⬛", g.Name+": no remote configured") - continue - } - fmt.Fprintln(os.Stderr, "error: failed to load datastore:", err) - return subcommands.ExitFailure - } + for _, r := range rs { cli, err := connect(remoteCred, r) if err != nil { fmt.Fprintln(os.Stderr, "error: failed to connect to the remote:", err) @@ -92,7 +83,7 @@ func (p *SyncCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) } }) - syncer.SetErrorCallback(func(err error) { + syncer.SetErrorCallback(func(err error, g repository.Metadata) { destroyPg() fmt.Println("❌", g.Name+": "+err.Error()) }) diff --git a/cmd/cli/tools/prompt/credentials/credentials.go b/cmd/cli/tools/prompt/credentials/credentials.go index a0c6f38..01c9f0f 100644 --- a/cmd/cli/tools/prompt/credentials/credentials.go +++ b/cmd/cli/tools/prompt/credentials/credentials.go @@ -35,6 +35,17 @@ func init() { datastorePath = filepath.Join(roaming, "cloudsave") } +func Get(server string) (string, string, error) { + var err error + store, err := load() + if err == nil { + if c, ok := store[server]; ok { + return c.Username, c.Password, nil + } + } + return "","",fmt.Errorf("not found") +} + func Read(server string) (string, string, error) { var err error store, err := load() diff --git a/cmd/gui/window/mainwindow/mainwindow.go b/cmd/gui/window/mainwindow/mainwindow.go index 0eda3e6..7d7cd70 100644 --- a/cmd/gui/window/mainwindow/mainwindow.go +++ b/cmd/gui/window/mainwindow/mainwindow.go @@ -2,8 +2,12 @@ package mainwindow import ( "cloudsave/cmd/gui/window/about" + "cloudsave/cmd/gui/window/credential" "cloudsave/cmd/gui/window/loading" "cloudsave/pkg/data" + "cloudsave/pkg/remote" + "cloudsave/pkg/remote/client" + "cloudsave/pkg/sync" "fmt" "os" "path/filepath" @@ -103,9 +107,7 @@ func Make(a fyne.App, d *data.Service) fyne.Window { }), widget.NewToolbarSeparator(), widget.NewToolbarAction(theme.UploadIcon(), func() { - go func() { - fmt.Println("todo") - }() + doSync(d, w) }), widget.NewToolbarSpacer(), widget.NewToolbarAction(theme.HelpIcon(), func() { @@ -118,3 +120,54 @@ func Make(a fyne.App, d *data.Service) fyne.Window { w.SetContent(content) return w } + +func doSync(d *data.Service, w fyne.Window) error { + remotes, err := remote.All() + if err != nil { + return err + } + + i := 0 + nextCh := make(chan struct{}) + doneCh := make(chan struct{}) + + var cd *credential.CredentialDialog + + go func() { + nextCh <- struct{}{} + }() + + for { + select { + case <-doneCh: + return nil + case <-nextCh: + { + cd = credential.Make(remotes[i].URL, func(v bool) { + if !v { + return + } + + username, password := cd.Credentials() + cli := client.New(remotes[i].URL, username, password) + + sync.NewSyncer(cli, d) + + fmt.Println(i) + + if i < len(remotes) { + go func() { + nextCh <- struct{}{} + }() + } else { + go func() { + doneCh <- struct{}{} + }() + } + + }, w) + cd.Show() + } + } + } +} diff --git a/pkg/remote/remote.go b/pkg/remote/remote.go index 6570d3d..4f30e58 100644 --- a/pkg/remote/remote.go +++ b/pkg/remote/remote.go @@ -57,6 +57,28 @@ func One(gameID string) (Remote, error) { return r, nil } +func All() ([]Remote, error) { + d, err := os.ReadDir(filepath.Clean(datastorepath)) + if err != nil { + return nil, fmt.Errorf("failed to load datastore: %w", err) + } + + var res []Remote + for _, g := range d { + r, err := One(g.Name()) + if err != nil { + if errors.Is(err, ErrNoRemote) { + continue + } + return nil, fmt.Errorf("failed to load remote: %w", err) + } + + res = append(res, r) + } + + return res, nil +} + func Set(gameID, url string) error { r := Remote{ URL: url, diff --git a/pkg/sync/sync.go b/pkg/sync/sync.go index 534b33d..a5a6cd5 100644 --- a/pkg/sync/sync.go +++ b/pkg/sync/sync.go @@ -19,7 +19,7 @@ type ( service *data.Service stateCallback func(s State, g repository.Metadata) - errorCallback func(err error) + errorCallback func(err error, g repository.Metadata) conflictCallback func(a, b repository.Metadata) ConflictResolution } ) @@ -63,7 +63,7 @@ func (s *Syncer) SetStateCallback(fn func(s State, g repository.Metadata)) { s.stateCallback = fn } -func (s *Syncer) SetErrorCallback(fn func(err error)) { +func (s *Syncer) SetErrorCallback(fn func(err error, g repository.Metadata)) { s.errorCallback = fn } @@ -74,20 +74,20 @@ func (s *Syncer) SetConflictCallback(fn func(a, b repository.Metadata) ConflictR func (s *Syncer) Sync() { games, err := s.service.AllGames() if err != nil { - s.errorCallback(fmt.Errorf("failed to get all games: %w", err)) + s.errorCallback(fmt.Errorf("failed to get all games: %w", err), repository.Metadata{}) return } for _, g := range games { r, err := remote.One(g.ID) if err != nil { - s.errorCallback(fmt.Errorf("%w: %s", ErrDatastore, err)) + s.errorCallback(fmt.Errorf("%w: %s", ErrDatastore, err), g) } if r.URL != s.cli.BaseURL() { continue } if err := s.sync(g); err != nil { - s.errorCallback(err) + s.errorCallback(err, g) } } }