lifecycle.go 2.1 KB

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