about summary refs log tree commit diff stats
path: root/searchix.go
diff options
context:
space:
mode:
authorAlan Pearce2024-05-13 21:50:14 +0200
committerAlan Pearce2024-05-13 22:25:46 +0200
commit6b40e0c0fa90f11be14a93f1d6275779fd645cac (patch)
tree0df5bea87242450829ca441d235c077a0e09a149 /searchix.go
parent2722f24af87f437ed9fcb8cc743ad1784141fd3a (diff)
downloadsearchix-6b40e0c0fa90f11be14a93f1d6275779fd645cac.tar.lz
searchix-6b40e0c0fa90f11be14a93f1d6275779fd645cac.tar.zst
searchix-6b40e0c0fa90f11be14a93f1d6275779fd645cac.zip
refactor: combine import and web server into one binary
Diffstat (limited to 'searchix.go')
-rw-r--r--searchix.go116
1 files changed, 116 insertions, 0 deletions
diff --git a/searchix.go b/searchix.go
new file mode 100644
index 0000000..9a0b16e
--- /dev/null
+++ b/searchix.go
@@ -0,0 +1,116 @@
+package main
+
+import (
+	"flag"
+	"log"
+	"log/slog"
+	"os"
+	"os/signal"
+	"sync"
+	"time"
+
+	"searchix/internal/config"
+	"searchix/internal/importer"
+	"searchix/internal/index"
+	"searchix/internal/server"
+
+	"github.com/pelletier/go-toml/v2"
+)
+
+var (
+	configFile = flag.String("config", "config.toml", "config file to use")
+	liveReload = flag.Bool("live", false, "whether to enable live reloading (development)")
+	replace    = flag.Bool("replace", false, "whether to replace existing database, if it exists")
+)
+
+func nextOccurrenceOfLocalTime(t toml.LocalTime) time.Time {
+	now := time.Now()
+	dayTime := t
+	nextRun := time.Date(
+		now.Year(),
+		now.Month(),
+		now.Day(),
+		dayTime.Hour,
+		dayTime.Minute,
+		dayTime.Second,
+		0,
+		time.Local,
+	)
+	if nextRun.Before(now) {
+		return nextRun.AddDate(0, 0, 1)
+	}
+
+	return nextRun
+}
+
+func main() {
+	flag.Parse()
+
+	conf, err := config.GetConfig(*configFile)
+	if err != nil {
+		log.Panicf("error parsing configuration file: %v", err)
+	}
+	slog.SetLogLoggerLevel(conf.LogLevel)
+	log.SetFlags(log.LstdFlags | log.Lmsgprefix)
+	log.SetPrefix("searchix: ")
+
+	read, write, exists, err := index.OpenOrCreate(conf.DataPath, *replace)
+	if err != nil {
+		log.Fatalf("Failed to open or create index: %v", err)
+	}
+
+	if !exists {
+		err = importer.Start(conf, write, *replace)
+		if err != nil {
+			log.Fatalf("Failed to build index: %v", err)
+		}
+	}
+
+	c := make(chan os.Signal, 2)
+	signal.Notify(c, os.Interrupt)
+	sv, err := server.New(conf, read, *liveReload)
+	if err != nil {
+		log.Fatalf("error setting up server: %v", err)
+	}
+	wg := &sync.WaitGroup{}
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		sig := <-c
+		log.Printf("signal captured: %v", sig)
+		<-sv.Stop()
+		slog.Debug("server stopped")
+	}()
+
+	go func() {
+		nextRun := nextOccurrenceOfLocalTime(conf.Importer.UpdateAt)
+		for {
+			slog.Debug("scheduling next run", "next-run", nextRun)
+			<-time.After(time.Until(nextRun))
+			wg.Add(1)
+			slog.Info("updating index")
+			err = importer.Start(conf, write, false)
+			wg.Done()
+			if err != nil {
+				slog.Warn("error updating index", "error", err)
+			} else {
+				slog.Info("update complete")
+			}
+			nextRun = nextRun.AddDate(0, 0, 1)
+		}
+	}()
+
+	sErr := make(chan error)
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		sErr <- sv.Start()
+	}()
+
+	err = <-sErr
+	if err != nil {
+		// Error starting or closing listener:
+		log.Fatalf("error: %v", err)
+	}
+	wg.Wait()
+}