lifecycle.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package lifecycle
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "log/slog"
  7. "os"
  8. "os/signal"
  9. "syscall"
  10. "github.com/ollama/ollama/app/store"
  11. "github.com/ollama/ollama/app/tray"
  12. )
  13. func Run() {
  14. InitLogging()
  15. ctx, cancel := context.WithCancel(context.Background())
  16. var done chan int
  17. t, err := tray.NewTray()
  18. if err != nil {
  19. log.Fatalf("Failed to start: %s", err)
  20. }
  21. callbacks := t.GetCallbacks()
  22. signals := make(chan os.Signal, 1)
  23. signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
  24. go func() {
  25. slog.Debug("starting callback loop")
  26. for {
  27. select {
  28. case <-callbacks.Quit:
  29. slog.Debug("quit called")
  30. t.Quit()
  31. case <-signals:
  32. slog.Debug("shutting down due to signal")
  33. t.Quit()
  34. case <-callbacks.Update:
  35. err := DoUpgrade(cancel, done)
  36. if err != nil {
  37. slog.Warn(fmt.Sprintf("upgrade attempt failed: %s", err))
  38. }
  39. case <-callbacks.ShowLogs:
  40. ShowLogs()
  41. case <-callbacks.DoFirstUse:
  42. err := GetStarted()
  43. if err != nil {
  44. slog.Warn(fmt.Sprintf("Failed to launch getting started shell: %s", err))
  45. }
  46. }
  47. }
  48. }()
  49. // Are we first use?
  50. if !store.GetFirstTimeRun() {
  51. slog.Debug("First time run")
  52. err = t.DisplayFirstUseNotification()
  53. if err != nil {
  54. slog.Debug(fmt.Sprintf("XXX failed to display first use notification %v", err))
  55. }
  56. store.SetFirstTimeRun(true)
  57. } else {
  58. slog.Debug("Not first time, skipping first run notification")
  59. }
  60. if IsServerRunning(ctx) {
  61. slog.Info("Detected another instance of ollama running, exiting")
  62. os.Exit(1)
  63. } else {
  64. done, err = SpawnServer(ctx, CLIName)
  65. if err != nil {
  66. // TODO - should we retry in a backoff loop?
  67. // TODO - should we pop up a warning and maybe add a menu item to view application logs?
  68. slog.Error(fmt.Sprintf("Failed to spawn ollama server %s", err))
  69. done = make(chan int, 1)
  70. done <- 1
  71. }
  72. }
  73. StartBackgroundUpdaterChecker(ctx, t.UpdateAvailable)
  74. t.Run()
  75. cancel()
  76. slog.Info("Waiting for ollama server to shutdown...")
  77. if done != nil {
  78. <-done
  79. }
  80. slog.Info("Ollama app exiting")
  81. }