This is primarily to improve the experience in environments that start Syncthing from a graphical environment, e.g., Windows. When already running, instead of printing an error we open the GUI. If the GUI is not available (but the lockfile indicates we are running), print an error and exit. If --no-browser is given or STNOBROWSER is set, act like before. Closes #10736. Marking as `fix` because this does not deserve to trigger a minor release on its own. --------- Signed-off-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
+55
-35
@@ -313,21 +313,6 @@ func (c *serveCmd) Run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func openGUI() error {
|
||||
cfg, err := loadOrDefaultConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if guiCfg := cfg.GUI(); guiCfg.Enabled {
|
||||
if err := openURL(guiCfg.URL()); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
slog.Error("Browser: GUI is currently disabled")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func logPackages() string {
|
||||
packages := slogutil.PackageDescrs()
|
||||
|
||||
@@ -418,6 +403,28 @@ func upgradeViaRest() error {
|
||||
}
|
||||
|
||||
func (c *serveCmd) syncthingMain() {
|
||||
// Ensure we are the only running instance
|
||||
lf := flock.New(locations.Get(locations.LockFile))
|
||||
locked, err := lf.TryLock()
|
||||
switch {
|
||||
case err != nil:
|
||||
slog.Error("Failed to acquire lock", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
|
||||
case !locked && c.NoBrowser:
|
||||
slog.Error("Failed to acquire lock: is another Syncthing instance already running?")
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
|
||||
case !locked:
|
||||
slog.Info("Seems to already be running, launching GUI instead (use --no-browser to prevent)")
|
||||
cmd := browserCmd{Verify: true}
|
||||
if err := cmd.Run(); err != nil {
|
||||
slog.Error("Failed to open browser", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitNoRestart.AsInt())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if c.DebugProfileBlock {
|
||||
startBlockProfiler()
|
||||
}
|
||||
@@ -436,18 +443,7 @@ func (c *serveCmd) syncthingMain() {
|
||||
)
|
||||
if err != nil {
|
||||
slog.Error("Failed to load/generate certificate", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Ensure we are the only running instance
|
||||
lf := flock.New(locations.Get(locations.LockFile))
|
||||
locked, err := lf.TryLock()
|
||||
if err != nil {
|
||||
slog.Error("Failed to acquire lock", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
} else if !locked {
|
||||
slog.Error("Failed to acquire lock: is another Syncthing instance already running?")
|
||||
os.Exit(1)
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -502,13 +498,13 @@ func (c *serveCmd) syncthingMain() {
|
||||
|
||||
if err := syncthing.TryMigrateDatabase(ctx, c.DBDeleteRetentionInterval); err != nil {
|
||||
slog.Error("Failed to migrate old-style database", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
sdb, err := syncthing.OpenDatabase(locations.Get(locations.Database), c.DBDeleteRetentionInterval)
|
||||
if err != nil {
|
||||
slog.Error("Error opening database", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
|
||||
if c.DebugPerfStats {
|
||||
@@ -915,7 +911,7 @@ func (u upgradeCmd) Run() error {
|
||||
switch {
|
||||
case err != nil && !os.IsNotExist(err):
|
||||
slog.Error("Failed to lock for upgrade", slogutil.Error(err))
|
||||
os.Exit(1)
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
case locked || os.IsNotExist(err):
|
||||
// We got the lock, or the config directory didn't exist, so we
|
||||
// can do a direct upgrade
|
||||
@@ -935,14 +931,38 @@ func (u upgradeCmd) Run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type browserCmd struct{}
|
||||
type browserCmd struct {
|
||||
Verify bool `help:"Verify that the GUI is reachable before launching browser"`
|
||||
}
|
||||
|
||||
func (browserCmd) Run() error {
|
||||
if err := openGUI(); err != nil {
|
||||
slog.Error("Failed to open web UI", slogutil.Error(err))
|
||||
func (c browserCmd) Run() error {
|
||||
cfg, err := loadOrDefaultConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
guiCfg := cfg.GUI()
|
||||
if !guiCfg.Enabled {
|
||||
slog.Error("Browser: GUI is currently disabled")
|
||||
os.Exit(svcutil.ExitError.AsInt())
|
||||
}
|
||||
return nil
|
||||
url := guiCfg.URL()
|
||||
|
||||
if c.Verify {
|
||||
// Do an HTTP request to verify the GUI/API is up and available
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = http.DefaultClient.Do(req) //nolint:bodyclose // we're exiting in a millisecond
|
||||
if err != nil {
|
||||
slog.Error("GUI not available", slogutil.Error(err))
|
||||
os.Exit(svcutil.ExitError.AsInt()) //nolint:gocritic // deferred cancel
|
||||
}
|
||||
}
|
||||
|
||||
return openURL(url)
|
||||
}
|
||||
|
||||
type debugCmd struct {
|
||||
|
||||
@@ -171,10 +171,11 @@ func (c *serveCmd) monitorMain() {
|
||||
exiterr := &exec.ExitError{}
|
||||
if errors.As(err, &exiterr) {
|
||||
exitCode := exiterr.ExitCode()
|
||||
if stopped || c.NoRestart {
|
||||
switch {
|
||||
case stopped || c.NoRestart:
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
if exitCode == svcutil.ExitUpgrade.AsInt() {
|
||||
|
||||
case exitCode == svcutil.ExitUpgrade.AsInt():
|
||||
// Restart the monitor process to release the .old
|
||||
// binary as part of the upgrade process.
|
||||
slog.Info("Restarting monitor...")
|
||||
@@ -182,6 +183,10 @@ func (c *serveCmd) monitorMain() {
|
||||
slog.Error("Failed to restart monitor", slogutil.Error(err))
|
||||
}
|
||||
os.Exit(exitCode)
|
||||
|
||||
case exitCode == svcutil.ExitNoRestart.AsInt():
|
||||
// Requested to not restart the child
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ const (
|
||||
ExitNoUpgradeAvailable ExitStatus = 2
|
||||
ExitRestart ExitStatus = 3
|
||||
ExitUpgrade ExitStatus = 4
|
||||
ExitNoRestart ExitStatus = 5 // do not get restarted by monitor
|
||||
)
|
||||
|
||||
func (s ExitStatus) AsInt() int {
|
||||
|
||||
Reference in New Issue
Block a user