apps/bookmarks/main.go 1.9 K raw
1
package main
2
3
import (
4
	"context"
5
	"html/template"
6
	"log"
7
	"log/slog"
8
	"net/http"
9
	"os"
10
	"time"
11
12
	"github.com/stevedylandev/andromeda/pkg/auth"
13
	"github.com/stevedylandev/andromeda/pkg/config"
14
	"github.com/stevedylandev/andromeda/pkg/sqlite"
15
)
16
17
func main() {
18
	config.LoadDotEnv(".env")
19
	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
20
21
	dbPath := config.Getenv("BOOKMARKS_DB_PATH", "bookmarks.sqlite")
22
	db, err := sqlite.Open(dbPath, schema)
23
	if err != nil {
24
		log.Fatal(err)
25
	}
26
	defer db.Close()
27
28
	sessions := &auth.Store{DB: db, CookieName: "session", CookieSecure: config.GetenvBool("COOKIE_SECURE", false)}
29
	if err := sessions.EnsureSchema(); err != nil {
30
		log.Fatal(err)
31
	}
32
	sessions.PruneExpired()
33
34
	tmpl := template.Must(template.ParseFS(appFS, "templates/*.html"))
35
	app := &App{
36
		DB:           db,
37
		Log:          logger,
38
		Templates:    tmpl,
39
		Sessions:     sessions,
40
		Password:     os.Getenv("BOOKMARKS_PASSWORD"),
41
		APIKey:       os.Getenv("BOOKMARKS_API_KEY"),
42
		CookieSecure: sessions.CookieSecure,
43
	}
44
45
	go app.faviconBackfill(context.Background())
46
47
	addr := config.Getenv("HOST", "127.0.0.1") + ":" + config.Getenv("PORT", "3000")
48
	logger.Info("bookmarks server running", "addr", addr)
49
	if err := http.ListenAndServe(addr, app.routes()); err != nil {
50
		log.Fatal(err)
51
	}
52
}
53
54
func (a *App) faviconBackfill(ctx context.Context) {
55
	pending, err := listLinksMissingFavicon(a.DB)
56
	if err != nil {
57
		a.Log.Error("favicon backfill query", "err", err)
58
		return
59
	}
60
	if len(pending) == 0 {
61
		return
62
	}
63
	a.Log.Info("favicon backfill", "count", len(pending))
64
	for _, row := range pending {
65
		if fav := discoverFavicon(ctx, row.URL); fav != "" {
66
			if err := updateLinkFavicon(a.DB, row.ID, &fav); err != nil {
67
				a.Log.Error("favicon backfill update", "id", row.ID, "err", err)
68
			}
69
		}
70
		time.Sleep(250 * time.Millisecond)
71
	}
72
	a.Log.Info("favicon backfill done")
73
}