feat: loader logic
This commit is contained in:
@@ -200,6 +200,7 @@ func (e *client) loadWorld(w *world.World) {
|
|||||||
|
|
||||||
func (e *client) Run() error {
|
func (e *client) Run() error {
|
||||||
e.BuildUI(e.window)
|
e.BuildUI(e.window)
|
||||||
|
e.window.SetMaster()
|
||||||
e.window.ShowAndRun()
|
e.window.ShowAndRun()
|
||||||
e.RequestRefresh()
|
e.RequestRefresh()
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+88
-90
@@ -26,6 +26,7 @@ type loader struct {
|
|||||||
textGrid *widget.TextGrid
|
textGrid *widget.TextGrid
|
||||||
btn *widget.Button
|
btn *widget.Button
|
||||||
fatalError bool
|
fatalError bool
|
||||||
|
loaded chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -42,10 +43,10 @@ func NewLoader(s storage.Storage, conn connector.Connector, app fyne.App) (*load
|
|||||||
l := &loader{
|
l := &loader{
|
||||||
app: app,
|
app: app,
|
||||||
connector: conn,
|
connector: conn,
|
||||||
// client: cli,
|
storage: s,
|
||||||
storage: s,
|
textGrid: widget.NewTextGrid(),
|
||||||
textGrid: widget.NewTextGrid(),
|
window: app.NewWindow("Loader"),
|
||||||
window: app.NewWindow("Loader"),
|
loaded: make(chan struct{}),
|
||||||
}
|
}
|
||||||
l.btn = widget.NewButton("OK", l.onButtonAction)
|
l.btn = widget.NewButton("OK", l.onButtonAction)
|
||||||
l.btn.Disable()
|
l.btn.Disable()
|
||||||
@@ -63,83 +64,70 @@ func NewLoader(s storage.Storage, conn connector.Connector, app fyne.App) (*load
|
|||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
func (l *loader) initPlugin() (mc.Client, error) {
|
||||||
Комментарий временный, удалить после реализации.
|
exists, pluginPath, err := l.storage.FileExists(libUIPluginFile)
|
||||||
|
if err != nil {
|
||||||
# Порядок инициализации
|
l.appendFatalError(fmt.Errorf("Client plugin file lookup error: %w", err))
|
||||||
|
return nil, err
|
||||||
- При ошибках Connector: не фатальное состояние, отображать состояние недоступности сети, предлагать повторить попытку.
|
}
|
||||||
- При ошибках Storage: фатальное, отобразить рекомендацию переустановить клиента, выход после confirm от пользователя.
|
if !exists {
|
||||||
|
l.logText("Client plugin file not found, fetching available versions")
|
||||||
1. Проверяем полный путь libUIPluginFile с помощью Storage.FileExists;
|
v, err := l.connector.CheckVersion()
|
||||||
|
if err != nil {
|
||||||
2. Если libUIPluginFile не существует в Storage:
|
l.logError(err)
|
||||||
2.1. запрашиваем Connector.CheckVersion,
|
return nil, err
|
||||||
2.2. с помощью хэлпера latestVersion(...) определяем самую свежую версию;
|
}
|
||||||
2.3. загружаем полученную версию через Connector.DownloadVersion,
|
l.logText(fmt.Sprintf("Received %d versions", len(v)))
|
||||||
2.4. сохраняем libUIPluginFile в Storage.WriteFile.
|
latest, ok, err := latestVersion(v)
|
||||||
|
if err != nil {
|
||||||
3. Загружаем libUIPluginFile full path в loadClientPlugin;
|
l.logError(err)
|
||||||
*/
|
return nil, err
|
||||||
func (l *loader) initUIPlugin() (mc.Client, error) {
|
}
|
||||||
// l.appendText(fmt.Sprintf("Checking client plugin at %s", libUIPluginFile))
|
if !ok {
|
||||||
// exists, err := l.storage.FileExists(libUIPluginFile)
|
l.logError(errors.New("Server did not responded with a suitable client version"))
|
||||||
// if err != nil {
|
return nil, err
|
||||||
// l.appendFatalError(err)
|
}
|
||||||
// return nil, err
|
l.logText(fmt.Sprintf("Downloading version %s", latest.Version))
|
||||||
// }
|
data, err := l.connector.DownloadVersion(latest.URL)
|
||||||
// if !exists {
|
if err != nil {
|
||||||
// l.appendText("Client plugin not found, checking available versions")
|
l.logError(fmt.Errorf("Version %s download error: %w", latest.Version, err))
|
||||||
// v, err := l.connector.CheckVersion()
|
return nil, err
|
||||||
// if err != nil {
|
}
|
||||||
// l.appendError(err)
|
err = l.storage.WriteFile(libUIPluginFile, data)
|
||||||
// return nil, err
|
if err != nil {
|
||||||
// }
|
l.appendFatalError(fmt.Errorf("Plugin file write error: %w", err))
|
||||||
// l.appendText(fmt.Sprintf("Received %d versions", len(v)))
|
return nil, err
|
||||||
// latest, ok, err := latestVersion(v)
|
}
|
||||||
// if err != nil {
|
}
|
||||||
// l.appendError(err)
|
l.logText(fmt.Sprintf("Loading client plugin from %s", pluginPath))
|
||||||
// return nil, err
|
cli, err := loadClientPlugin(l.storage, l.connector, l.app, pluginPath, pluginInitSymbol)
|
||||||
// }
|
if err != nil {
|
||||||
// if !ok {
|
l.appendFatalError(err)
|
||||||
// l.appendError(errors.New("Server did not responded with a suitable client version"))
|
return nil, err
|
||||||
// return nil, err
|
}
|
||||||
// }
|
return cli, nil
|
||||||
// l.appendText(fmt.Sprintf("Downloading version %s", latest.Version))
|
|
||||||
// data, err := l.connector.DownloadVersion(latest.URL)
|
|
||||||
// if err != nil {
|
|
||||||
// l.appendError(fmt.Errorf("Version %s download error: %w", latest.Version, err))
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// err = l.storage.WriteFile(libUIPluginFile, data)
|
|
||||||
// if err != nil {
|
|
||||||
// l.appendFatalError(fmt.Errorf("Write plugin file error: %w", err))
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// l.appendText(fmt.Sprintf("Loading client plugin from %s", libUIPluginFile))
|
|
||||||
// cli, err := loadClientPlugin(s, conn, app, "./client.so", pluginInitSymbol)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loader) startLoading() {
|
func (l *loader) init() {
|
||||||
l.fatalError = false
|
l.fatalError = false
|
||||||
fyne.Do(func() {
|
fyne.Do(func() {
|
||||||
l.textGrid.SetText("")
|
l.textGrid.SetText("")
|
||||||
l.btn.Hide()
|
l.btn.Hide()
|
||||||
l.btn.Disable()
|
l.btn.Disable()
|
||||||
})
|
})
|
||||||
l.appendText("Loading...")
|
|
||||||
var err error
|
var err error
|
||||||
l.client, err = l.initUIPlugin()
|
l.client, err = l.initPlugin()
|
||||||
|
if err == nil {
|
||||||
|
fyne.Do(func() {
|
||||||
|
l.window.Hide()
|
||||||
|
err = l.client.Run()
|
||||||
|
})
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fyne.Do(func() {
|
fyne.Do(func() {
|
||||||
if l.fatalError {
|
if l.fatalError {
|
||||||
l.btn.SetText("Quit")
|
l.btn.SetText("Quit")
|
||||||
l.appendText("Please re-install application.")
|
l.logText("Please re-install application.")
|
||||||
} else {
|
} else {
|
||||||
l.btn.SetText("Retry")
|
l.btn.SetText("Retry")
|
||||||
}
|
}
|
||||||
@@ -147,6 +135,8 @@ func (l *loader) startLoading() {
|
|||||||
l.btn.Show()
|
l.btn.Show()
|
||||||
l.window.Show()
|
l.window.Show()
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
l.loaded <- struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,40 +144,48 @@ func (l *loader) onButtonAction() {
|
|||||||
if l.fatalError {
|
if l.fatalError {
|
||||||
l.app.Quit()
|
l.app.Quit()
|
||||||
} else {
|
} else {
|
||||||
go l.startLoading()
|
go l.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loader) Run(ctx context.Context) error {
|
func (l *loader) logText(v string) {
|
||||||
go l.startLoading()
|
|
||||||
l.app.Run()
|
|
||||||
|
|
||||||
// final := make(chan struct{}, 1)
|
|
||||||
// if l.connector != nil {
|
|
||||||
// go l.backgroundLoop(ctx, final)
|
|
||||||
// defer func() { final <- struct{}{} }()
|
|
||||||
// }
|
|
||||||
// if err := l.client.Run(); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// final <- struct{}{}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *loader) appendText(v string) {
|
|
||||||
fmt.Println(v)
|
|
||||||
fyne.Do(func() { l.textGrid.Append(v) })
|
fyne.Do(func() { l.textGrid.Append(v) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loader) appendError(err error) {
|
func (l *loader) logError(err error) {
|
||||||
l.appendText(fmt.Sprintf("❌ %s", err))
|
l.logText(fmt.Sprintf("❌ %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loader) appendFatalError(err error) {
|
func (l *loader) appendFatalError(err error) {
|
||||||
l.appendError(err)
|
l.logError(err)
|
||||||
l.fatalError = true
|
l.fatalError = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *loader) Run(ctx context.Context) error {
|
||||||
|
go l.init()
|
||||||
|
l.app.Run()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil
|
||||||
|
case <-l.loaded:
|
||||||
|
return l.runClient(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *loader) runClient(ctx context.Context) error {
|
||||||
|
if l.client == nil {
|
||||||
|
return errors.New("run: client wasn't initialized, this is an program fatal error.")
|
||||||
|
}
|
||||||
|
final := make(chan struct{}, 1)
|
||||||
|
go l.backgroundLoop(ctx, final)
|
||||||
|
defer func() { final <- struct{}{} }()
|
||||||
|
if err := l.client.Run(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
final <- struct{}{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (l *loader) backgroundLoop(ctx context.Context, final <-chan struct{}) {
|
func (l *loader) backgroundLoop(ctx context.Context, final <-chan struct{}) {
|
||||||
checkConnTimer := time.NewTimer(checkConnectionTimeout)
|
checkConnTimer := time.NewTimer(checkConnectionTimeout)
|
||||||
checkVersionTimer := time.NewTimer(checkVersionTimeout)
|
checkVersionTimer := time.NewTimer(checkVersionTimeout)
|
||||||
|
|||||||
+11
-4
@@ -163,10 +163,10 @@ func (s *fsStorage) SaveOrderAsync(id client.GameID, turn uint, o order.Order, c
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *fsStorage) FileExists(path string) (bool, error) {
|
func (s *fsStorage) FileExists(path string) (bool, string, error) {
|
||||||
absPath, err := s.resolvePath(path)
|
absPath, err := s.resolvePath(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var exists bool
|
var exists bool
|
||||||
@@ -175,7 +175,13 @@ func (s *fsStorage) FileExists(path string) (bool, error) {
|
|||||||
exists, opErr = s.fileExistsUnlocked(absPath)
|
exists, opErr = s.fileExistsUnlocked(absPath)
|
||||||
return opErr
|
return opErr
|
||||||
})
|
})
|
||||||
return exists, err
|
if err != nil {
|
||||||
|
return false, "", err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
return false, "", nil
|
||||||
|
}
|
||||||
|
return true, absPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *fsStorage) ReadFile(path string) ([]byte, error) {
|
func (s *fsStorage) ReadFile(path string) ([]byte, error) {
|
||||||
@@ -254,7 +260,8 @@ func (s *fsStorage) ListFiles() ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *fsStorage) StateExists() (bool, error) {
|
func (s *fsStorage) StateExists() (bool, error) {
|
||||||
return s.FileExists(stateFileName)
|
exists, _, err := s.FileExists(stateFileName)
|
||||||
|
return exists, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *fsStorage) LoadState() (client.State, error) {
|
func (s *fsStorage) LoadState() (client.State, error) {
|
||||||
|
|||||||
@@ -172,13 +172,28 @@ func TestRawFileCRUDAndList(t *testing.T) {
|
|||||||
t.Fatalf("write beta: %v", err)
|
t.Fatalf("write beta: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
alphaExists, err := s.FileExists("nested/alpha.txt")
|
alphaExists, alphaPath, err := s.FileExists("nested/alpha.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("file exists: %v", err)
|
t.Fatalf("file exists: %v", err)
|
||||||
}
|
}
|
||||||
if !alphaExists {
|
if !alphaExists {
|
||||||
t.Fatal("nested/alpha.txt should exist")
|
t.Fatal("nested/alpha.txt should exist")
|
||||||
}
|
}
|
||||||
|
wantAlphaPath := filepath.Join(s.storageRoot, "nested", "alpha.txt")
|
||||||
|
if alphaPath != wantAlphaPath {
|
||||||
|
t.Fatalf("file path = %q, want %q", alphaPath, wantAlphaPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
missingExists, missingPath, err := s.FileExists("missing.txt")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("missing file exists: %v", err)
|
||||||
|
}
|
||||||
|
if missingExists {
|
||||||
|
t.Fatal("missing.txt should not exist")
|
||||||
|
}
|
||||||
|
if missingPath != "" {
|
||||||
|
t.Fatalf("missing file path = %q, want empty string", missingPath)
|
||||||
|
}
|
||||||
|
|
||||||
alphaData, err := s.ReadFile("nested/alpha.txt")
|
alphaData, err := s.ReadFile("nested/alpha.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
type Storage interface {
|
type Storage interface {
|
||||||
UIStorage
|
UIStorage
|
||||||
FileExists(string) (bool, error)
|
FileExists(string) (bool, string, error)
|
||||||
ReadFile(string) ([]byte, error)
|
ReadFile(string) ([]byte, error)
|
||||||
WriteFile(string, []byte) error
|
WriteFile(string, []byte) error
|
||||||
DeleteFile(string) error
|
DeleteFile(string) error
|
||||||
|
|||||||
Reference in New Issue
Block a user