1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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()
}
|