summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/server/main.go118
1 files changed, 108 insertions, 10 deletions
diff --git a/cmd/server/main.go b/cmd/server/main.go
index 862916e..02635f3 100644
--- a/cmd/server/main.go
+++ b/cmd/server/main.go
@@ -2,7 +2,9 @@ package main
import (
"context"
+ "crypto/sha256"
"flag"
+ "fmt"
"log"
"log/slog"
"os"
@@ -11,14 +13,21 @@ import (
"syscall"
"time"
+ "github.com/kyren223/eko/embeds"
"github.com/kyren223/eko/internal/server"
"github.com/kyren223/eko/internal/server/api"
"github.com/kyren223/eko/internal/server/ctxkeys"
+ "github.com/kyren223/eko/internal/webserver"
"github.com/kyren223/eko/pkg/assert"
"gopkg.in/natefinch/lumberjack.v2"
)
-const port = 7223
+const (
+ port = 7223
+ TosEnvVar = "EKO_SERVER_TOS_FILE"
+ PrivacyEnvVar = "EKO_SERVER_PRIVACY_FILE"
+ LogDirEnvVar = "EKO_SERVER_LOG_DIR"
+)
var prod = true
@@ -27,31 +36,60 @@ func main() {
flag.Parse()
prod = !(*prodFlag)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
setupLogging()
- slog.Info("starting eko-server...")
+ handleReload()
+ handleShutdown(cancel)
+
+ if ok := reloadTosAndPrivacy(); !ok {
+ return
+ }
api.ConnectToDatabase()
assert.AddFlush(api.DB())
defer api.DB().Close()
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
+ go webserver.ServeEkoWebsite()
+
+ server := server.NewServer(ctx, port)
+ server.Run() // blocks
+ slog.Info("exited gracefully")
+}
+
+func handleReload() {
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, syscall.SIGHUP)
+
+ go func() {
+ for range c {
+ slog.Info("SIGHUP received, reloading...")
+ reloadTosAndPrivacy()
+ slog.Info("reload completed")
+ }
+ }()
+
+ slog.Info("reload handler ready")
+}
+
+func handleShutdown(cancel context.CancelFunc) {
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
+
go func() {
signal := <-signalChan
- slog.Info("received signal", "signal", signal)
+ slog.Info("shutdown signal received", "signal", signal)
cancel()
}()
- server := server.NewServer(ctx, port)
- server.Run() // blocks
+ slog.Info("shutdown handler ready")
}
func setupLogging() {
- logDir := os.Getenv("EKO_SERVER_LOG_DIR")
+ logDir := os.Getenv(LogDirEnvVar)
if logDir == "" {
logDir = "logs"
}
@@ -63,7 +101,7 @@ func setupLogging() {
rotator := &lumberjack.Logger{
Filename: filepath.Join(logDir, "server.log"),
MaxSize: 100, // megabytes
- MaxAge: 28, // days
+ MaxAge: 7, // days (see Privacy Section 3: Log Retention)
}
level := slog.LevelDebug
@@ -80,9 +118,11 @@ func setupLogging() {
slog.SetDefault(logger)
slog.SetLogLoggerLevel(level) // TODO: remove me after fully migrating to slog
+ slog.Info("logging handler ready")
+
go func() {
for {
- now := time.Now()
+ now := time.Now().UTC() // UTC Time (see Privacy Section 3)
next := now.Truncate(24 * time.Hour).Add(24 * time.Hour)
time.Sleep(time.Until(next)) // sleep until next midnight
@@ -95,3 +135,61 @@ func setupLogging() {
}
}()
}
+
+func reloadTosAndPrivacy() bool {
+ if embeds.TosPrivacyHash.Load() == nil {
+ if prod {
+ embeds.TosPrivacyHash.Store("")
+ embeds.TermsOfService.Store("")
+ embeds.PrivacyPolicy.Store("")
+ } else {
+ // Set stub values for development
+ embeds.TermsOfService.Store(embeds.StubTos)
+ embeds.PrivacyPolicy.Store(embeds.StubPrivacy)
+ tosPrivacy := []byte(string(embeds.StubTos) + string(embeds.StubPrivacy))
+ stubHash := fmt.Sprintf("%x", sha256.Sum256(tosPrivacy))
+ embeds.TosPrivacyHash.Store(stubHash)
+ return true
+ }
+ }
+
+ tosFile := os.Getenv(TosEnvVar)
+ privacyFile := os.Getenv(PrivacyEnvVar)
+ if tosFile == "" || privacyFile == "" {
+ if prod {
+ slog.Error("TOS or Privacy env vars are undefined", TosEnvVar, tosFile, PrivacyEnvVar, privacyFile)
+ return false
+ }
+ }
+ tos, err := os.ReadFile(tosFile)
+ if err != nil {
+ slog.Error("error reading TOS file", "error", err)
+ return false
+ }
+ privacy, err := os.ReadFile(privacyFile)
+ if err != nil {
+ slog.Error("error reading Privacy file", "error", err)
+ return false
+ }
+
+ tosPrivacy := []byte(string(tos) + string(privacy))
+ hash := fmt.Sprintf("%x", sha256.Sum256(tosPrivacy))
+
+ oldHash := embeds.TosPrivacyHash.Load().(string)
+ if oldHash == hash {
+ slog.Info("updated nothing, tos+privacy hash remained the same", "hash", hash)
+ return true
+ }
+
+ embeds.TermsOfService.Store(tos)
+ embeds.PrivacyPolicy.Store(privacy)
+ embeds.TosPrivacyHash.Store(hash)
+
+ if oldHash == "" {
+ slog.Info("loaded Terms of Service and Privacy Policy", "hash", hash)
+ } else {
+ slog.Info("updated tos+privacy, hash changed", "hash", hash, "old_hash", hash)
+ }
+
+ return true
+}