lifecycle.go 2 KB
Newer Older
1
2
3
4
5
6
7
package lifecycle

import (
	"context"
	"fmt"
	"log"
	"log/slog"
8
	"os"
9
10
	"os/signal"
	"syscall"
11

12
13
	"github.com/ollama/ollama/app/store"
	"github.com/ollama/ollama/app/tray"
14
15
16
17
18
19
20
21
22
23
24
25
26
27
)

func Run() {
	InitLogging()

	ctx, cancel := context.WithCancel(context.Background())
	var done chan int

	t, err := tray.NewTray()
	if err != nil {
		log.Fatalf("Failed to start: %s", err)
	}
	callbacks := t.GetCallbacks()

28
29
30
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)

31
32
33
34
35
	go func() {
		slog.Debug("starting callback loop")
		for {
			select {
			case <-callbacks.Quit:
36
37
38
39
				slog.Debug("quit called")
				t.Quit()
			case <-signals:
				slog.Debug("shutting down due to signal")
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
				t.Quit()
			case <-callbacks.Update:
				err := DoUpgrade(cancel, done)
				if err != nil {
					slog.Warn(fmt.Sprintf("upgrade attempt failed: %s", err))
				}
			case <-callbacks.ShowLogs:
				ShowLogs()
			case <-callbacks.DoFirstUse:
				err := GetStarted()
				if err != nil {
					slog.Warn(fmt.Sprintf("Failed to launch getting started shell: %s", err))
				}
			}
		}
	}()

	// Are we first use?
	if !store.GetFirstTimeRun() {
		slog.Debug("First time run")
		err = t.DisplayFirstUseNotification()
		if err != nil {
			slog.Debug(fmt.Sprintf("XXX failed to display first use notification %v", err))
		}
		store.SetFirstTimeRun(true)
	} else {
		slog.Debug("Not first time, skipping first run notification")
	}

	if IsServerRunning(ctx) {
70
71
		slog.Info("Detected another instance of ollama running, exiting")
		os.Exit(1)
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
	} else {
		done, err = SpawnServer(ctx, CLIName)
		if err != nil {
			// TODO - should we retry in a backoff loop?
			// TODO - should we pop up a warning and maybe add a menu item to view application logs?
			slog.Error(fmt.Sprintf("Failed to spawn ollama server %s", err))
			done = make(chan int, 1)
			done <- 1
		}
	}

	StartBackgroundUpdaterChecker(ctx, t.UpdateAvailable)

	t.Run()
	cancel()
	slog.Info("Waiting for ollama server to shutdown...")
	if done != nil {
		<-done
	}
	slog.Info("Ollama app exiting")
}